-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES256 signature cannot be verified by own public key #1
Comments
Will leave the above for context, but here's the simplified code. For clarification, the ES256 test passes on my machine with the hard-coded x,y,d parameters. My issue seems to be isolated to the generation of my keypair via pointycastle: final ECKeyGenerator generator = KeyGenerator("EC");
generator.init(
ParametersWithRandom(
ECKeyGeneratorParameters(
ECDomainParameters("secp256r1"),
),
NativeDartRandom(),
),
);
final AsymmetricKeyPair pair = generator.generateKeyPair();
final d = convert.base64Encode(
_bigIntToBytes(
(pair.privateKey as ECPrivateKey).d,
32,
).toList(),
);
final x = convert.base64Encode(
_bigIntToBytes(
(pair.publicKey as ECPublicKey).Q.x.toBigInteger(),
32,
).toList(),
);
final y = convert.base64Encode(
_bigIntToBytes(
(pair.publicKey as ECPublicKey).Q.y.toBigInteger(),
32,
).toList(),
);
print("x: $x");
print("y: $y");
print("d: $d");
final allKeyPair = JsonWebKey.fromJson({
"kty": "EC",
"crv": "P-256",
"x": x,
"y": y,
"d": d,
});
var keyPair = ck.KeyPair.fromJwk(allKeyPair.toJson());
var signer = keyPair.createSigner(ck.algorithms.signing.ecdsa.sha256);
var verifier = keyPair.createVerifier(ck.algorithms.signing.ecdsa.sha256);
final hash = Uint8List.fromList("TEST".codeUnits);
var sig = signer.sign(hash);
final valid = verifier.verify(hash, sig);
print("valid? $valid");
// false here's an example of some of the x,y,d values I'm generating:
(so I guess this technically belongs in crypto_keys now?) |
hey there, I have a similar problem in verifying the ES256 signed JWT. I am generating the JWT to authenticate with my google iot core server. the format of the JWT is: this is the JWT token that gets generated: This is the function used to generate the JWT token. I'm using this on flutter framework. I load my ec_private.pem file from assets as a string. encode it to utf8 and then base64url.encode it.
Also when i generate a JWT token from jwt.io using the same ec_private.pem key, and hardcode the key in my client, it gets authenticated. Its just this jwt doesnt get authenticated and i get a NotAuthorised return code from the server. I tried digging in, but without any luck. |
I was actually able to solve this with a similar library, but forgot to update: thanks for the reminder! I totally forgot all of the context of this, though, so I won't be of much help for jose specifically. First, we create a import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
class NativeDartRandom implements SecureRandom {
final Random random = Random.secure();
@override
String get algorithmName => "dart.math.Random.secure()";
@override
BigInt nextBigInteger(int bitLength) {
// produces a string of length [bitLength] and then parses it with BigInt.parse
return BigInt.parse(
Iterable.generate(
bitLength,
(_) => random.nextBool() ? "1" : "0",
).join(""),
radix: 2,
);
}
@override
Uint8List nextBytes(int count) =>
Uint8List.fromList(List.generate(count, (_) => nextUint8()));
@override
int nextUint8() => random.nextInt(256);
@override
int nextUint16() => random.nextInt(256 * 256);
@override
int nextUint32() => random.nextInt(256 * 256 * 256 * 256);
@override
void seed(CipherParameters params) {
throw UnsupportedError("Seed not supported for this SecureRandom");
}
}
and use that as part of the key generation code: import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/key_generators/ec_key_generator.dart';
import 'package:pointycastle/ecc/api.dart';
import './native_dart_random.dart';
import './helpers.dart';
import './types.dart';
/// Generate and serialize an EC keypair.
/// Must be run in [compute] to avoid jank (hence null argument).
/// await compute(generateKeyPair, null)
SerializedKeyPair generateKeyPair(_) {
final ECKeyGenerator generator = KeyGenerator("EC");
generator.init(
ParametersWithRandom(
ECKeyGeneratorParameters(kDomain),
NativeDartRandom(),
),
);
final pair = generator.generateKeyPair();
return SerializedKeyPair(
privateKey: serializePrivateKey(pair.privateKey as ECPrivateKey),
publicKey: serializePublicKey(pair.publicKey as ECPublicKey),
);
} and then create our own ES256Signer: import 'dart:typed_data';
import 'package:pointycastle/pointycastle.dart';
import 'package:corsac_jwt/corsac_jwt.dart';
import './helpers.dart';
const kAlgorithmName = "SHA-256/DET-ECDSA";
const _kBitLength = 32;
class ES256Signer implements JWTSigner {
String get algorithm => 'ES256';
final AsymmetricKeyPair<PublicKey, PrivateKey> pair;
ES256Signer({
this.pair,
});
@override
List<int> sign(List<int> data) {
final pcSigner = Signer(kAlgorithmName);
pcSigner.init(
true,
PrivateKeyParameter(pair.privateKey),
);
final ECSignature sig = pcSigner.generateSignature(data);
var bytes = Uint8List(_kBitLength * 2);
bytes.setRange(
0,
_kBitLength,
bigIntToBytes(sig.r, _kBitLength).toList().reversed,
);
bytes.setRange(
_kBitLength,
_kBitLength * 2,
bigIntToBytes(sig.s, _kBitLength).toList().reversed,
);
return bytes;
}
@override
bool verify(List<int> data, List<int> signature) {
final verifier = Signer(kAlgorithmName);
verifier.init(false, PublicKeyParameter(pair.publicKey));
final sig = ECSignature(
bigIntFromBytes(signature.take(_kBitLength)),
bigIntFromBytes(signature.skip(_kBitLength)),
);
return verifier.verifySignature(data, sig);
}
} then we can finally use all of that to create the JWT import 'package:meta/meta.dart';
import 'package:corsac_jwt/corsac_jwt.dart';
import 'package:dot_app/constants.dart';
import './crypto/es256_signer.dart';
import './crypto/helpers.dart';
import './crypto/types.dart';
import './did.dart';
// play well with serialized output of generator
String build({
@required SerializedKeyPair serializedKeyPair,
@required String id,
}) {
final builder = JWTBuilder()
..issuer = serializedKeyPair.publicKey
..audience = DID.dot
..issuedAt = DateTime.now()
..expiresAt = DateTime.now().add(kJWTValidityDuration)
..notBefore = DateTime.now()
..setClaim('did', DID.build(id));
final signer = ES256Signer(pair: deserializeKeyPair(serializedKeyPair));
final signedToken = builder.getSignedToken(signer);
return signedToken.toString();
} |
I guess the problem lies with the In version 0.2.0, I implemented a method to generate non-symmetric keys. See example8 in |
i'm super far removed from this codebase at this point, but agreed, that was almost definitely the issue 👍 |
Howdy, and happy holidays!
I'm testing out this library for signing ES256 JWTs for authenticating against a backend, and having a bit of trouble after getting past the basics. I've narrowed the error down to the sign/verify lines that eventually delegate to pointycastle.
This code is how I'm generating my keypairs and JWKs with pointcastle. Assume that this code is copy-pasted above the other examples.
Using pointycastle directly like this works just fine:
And here's how I'd use these generated keypairs with jose, but this is failing to validate.
As far as I can tell, this line in
JsonWebSignature#getPayloadFor
is returning false. Reducing the problem even further, based on the code from the crypto_keys test file,If it would be helpful (i.e, I'm not doing something incredibly silly just be reading the code) I can make a separate dart project and try and reproduce the code in isolation.
The text was updated successfully, but these errors were encountered: