Skip to content
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

add normalize option for ecdsa signatures #10

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Changelog
* Fixed RSA block length and offset checks in RSAEngine.processBlock.
* Fixed RSASigner.verifySignature to return false when signature is bad.
* Add HKDF support (IETF RFC 5869)
* Add optional `normalize` boolean on `generateSignature` and `normalize` function on `ECSignature` to convert an ecdsa signature to lower-s form

#### Version 1.0.2 (2019-11-15)

Expand Down
17 changes: 16 additions & 1 deletion lib/ecc/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,25 @@ class ECPublicKey extends ECAsymmetricKey implements PublicKey {
/// A [Signature] created with ECC.
class ECSignature implements Signature {
final BigInt r;
final BigInt s;
BigInt s;

ECSignature(this.r, this.s);

/**
* 'normalize' this signature by converting its s to lower-s form if necessary
* This is required to validate this signature with some libraries such as libsecp256k1
* which enforce lower-s form for all signatures to combat ecdsa signature malleability
*
* Returns false if the signature was already normalized, or true if it changed
*/
bool normalize(ECDomainParameters curveParams) {
if (s.compareTo(curveParams.n >> 1) > 0) {
s = curveParams.n - s;
return true;
}
return false;
}

String toString() => "(${r.toString()},${s.toString()})";

bool operator ==(other) {
Expand Down
6 changes: 4 additions & 2 deletions lib/signers/ecdsa_signer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ECDSASigner implements Signer {
}
}

Signature generateSignature(Uint8List message) {
Signature generateSignature(Uint8List message, {bool normalize = false}) {
message = _hashMessageIfNeeded(message);

var n = _pvkey.parameters.n;
Expand Down Expand Up @@ -124,7 +124,9 @@ class ECDSASigner implements Signer {
s = (k.modInverse(n) * (e + (d * r))) % n;
} while (s == BigInt.zero);

return new ECSignature(r, s);
var signature = new ECSignature(r, s);
if (normalize) signature.normalize(_pvkey.parameters);
return signature;
}

bool verifySignature(Uint8List message, covariant ECSignature signature) {
Expand Down
2 changes: 1 addition & 1 deletion lib/signers/rsa_signer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class RSASigner implements Signer {
_rsa.init(forSigning, params);
}

RSASignature generateSignature(Uint8List message) {
RSASignature generateSignature(Uint8List message, {bool normalize = false}) {
if (!_forSigning) {
throw new StateError(
"Signer was not initialised for signature generation");
Expand Down
2 changes: 1 addition & 1 deletion lib/src/api/signer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract class Signer extends Algorithm {
void init(bool forSigning, CipherParameters params);

/// Sign the passed in [message] (usually the output of a hash function)
Signature generateSignature(Uint8List message);
Signature generateSignature(Uint8List message, {bool normalize = false});

/// Verify the [message] against the [signature].
bool verifySignature(Uint8List message, Signature signature);
Expand Down
9 changes: 9 additions & 0 deletions test/signers/ecdsa_signer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ void main() {
_newSignature("4087581495017442027693712553398765118791696551913571321320",
"4593990646726045634082084213208629584972116888758459298644"),
]);

runSignerTests(new Signer("SHA-1/DET-ECDSA"), signParams, verifyParams, [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit ........",
_newSignature("6052012072724008730564193612572794050491696411960275629627",
"2161019278549597185578307509265728228343111084484752661213"),
"En un lugar de La Mancha, de cuyo nombre no quiero acordarme ...",
_newSignature("4087581495017442027693712553398765118791696551913571321320",
"1683111088660635129753705209967429428795077884424382985437"),
], normalize: true);
}

ECSignature _newSignature(String r, String s) =>
Expand Down
8 changes: 4 additions & 4 deletions test/test/signer_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "package:pointycastle/pointycastle.dart";
import "./src/helpers.dart";

void runSignerTests(Signer signer, CipherParameters signParams(),
CipherParameters verifyParams(), List messageSignaturePairs) {
CipherParameters verifyParams(), List messageSignaturePairs, {bool normalize = false}) {
group("${signer.algorithmName}:", () {
group("generateSignature:", () {
for (var i = 0; i < messageSignaturePairs.length; i += 2) {
Expand All @@ -18,7 +18,7 @@ void runSignerTests(Signer signer, CipherParameters signParams(),
test(
"${formatAsTruncated(message)}",
() => _runGenerateSignatureTest(
signer, signParams, message, signature));
signer, signParams, message, signature, normalize: normalize));
}
});

Expand All @@ -37,11 +37,11 @@ void runSignerTests(Signer signer, CipherParameters signParams(),
}

void _runGenerateSignatureTest(Signer signer, CipherParameters params(),
String message, Signature expectedSignature) {
String message, Signature expectedSignature, {bool normalize = false}) {
signer.reset();
signer.init(true, params());

var signature = signer.generateSignature(createUint8ListFromString(message));
var signature = signer.generateSignature(createUint8ListFromString(message), normalize: normalize);

expect(signature, expectedSignature);
}
Expand Down