Skip to content

Commit 43db6a1

Browse files
committed
Reject non-canonical public keys
As specified by RFC 8032 section 5.1.3
1 parent fa3894e commit 43db6a1

2 files changed

Lines changed: 26 additions & 0 deletions

File tree

packages/ed25519/ed25519.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5188,4 +5188,15 @@ describe("ed25519", () => {
51885188
const xPrivateKey = convertSecretKeyToX25519(edPrivateKey);
51895189
expect(encode(xPrivateKey)).toEqual(xGoodPrivateKey);
51905190
});
5191+
5192+
it("should reject non-canonical public key", () => {
5193+
const canonicalPk = new Uint8Array(32);
5194+
canonicalPk[0] = 1;
5195+
const noncanonicalPk = new Uint8Array([0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]);
5196+
const message = new Uint8Array([1,2,3]);
5197+
const signature = new Uint8Array(64);
5198+
signature[0] = 1;
5199+
expect(verify(canonicalPk, message, signature)).toBe(true);
5200+
expect(verify(noncanonicalPk, message, signature)).toBe(false);
5201+
});
51915202
});

packages/ed25519/ed25519.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,15 @@ function iscanonical(s: Uint8Array) {
737737
return c !== 0;
738738
}
739739

740+
function ispkcanonical(p: Uint8Array) {
741+
let c = ((p[0] - 0xed) >> 8) & 1;
742+
for (let i = 1; i < 31; i++) {
743+
c |= p[i] ^ 0xff;
744+
}
745+
c |= (p[31] & 0x7f) ^ 0x7f;
746+
return c !== 0;
747+
}
748+
740749
function reduce(r: Uint8Array) {
741750
const x = new Float64Array(64);
742751
for (let i = 0; i < 64; i++) {
@@ -845,10 +854,16 @@ export function verify(publicKey: Uint8Array, message: Uint8Array, signature: Ui
845854
if (signature.length !== SIGNATURE_LENGTH) {
846855
throw new Error(`ed25519: signature must be ${SIGNATURE_LENGTH} bytes`);
847856
}
857+
if (publicKey.length !== PUBLIC_KEY_LENGTH) {
858+
throw new Error(`ed25519: public key must be ${PUBLIC_KEY_LENGTH} bytes`);
859+
}
848860

849861
if (!iscanonical(signature.subarray(32))) {
850862
return false;
851863
}
864+
if (!ispkcanonical(publicKey)) {
865+
return false;
866+
}
852867
if (unpackneg(q, publicKey)) {
853868
return false;
854869
}

0 commit comments

Comments
 (0)