JS ed25519
This commit is contained in:
parent
b94ba6b726
commit
b5c6e3d101
18 changed files with 172 additions and 145 deletions
65
js/crypto.js
65
js/crypto.js
|
@ -77,11 +77,11 @@ window.textsecure.crypto = function() {
|
|||
|
||||
if (textsecure.nacl.USE_NACL) {
|
||||
return textsecure.nacl.postNaclMessage({command: "bytesToPriv", priv: privKey}).then(function(message) {
|
||||
var priv = message.res;
|
||||
var priv = message.res.slice(0, 32);
|
||||
if (!isIdentity)
|
||||
new Uint8Array(priv)[0] |= 0x01;
|
||||
return textsecure.nacl.postNaclMessage({command: "privToPub", priv: priv}).then(function(message) {
|
||||
return { pubKey: prependVersion(message.res), privKey: priv };
|
||||
return { pubKey: prependVersion(message.res.slice(0, 32)), privKey: priv };
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
@ -239,21 +239,25 @@ window.textsecure.crypto = function() {
|
|||
/*****************************
|
||||
*** Internal Crypto stuff ***
|
||||
*****************************/
|
||||
var validatePubKeyFormat = function(pubKey) {
|
||||
if (pubKey === undefined || ((pubKey.byteLength != 33 || new Uint8Array(pubKey)[0] != 5) && pubKey.byteLength != 32))
|
||||
throw new Error("Invalid public key");
|
||||
if (pubKey.byteLength == 33)
|
||||
return pubKey.slice(1);
|
||||
else
|
||||
console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey");
|
||||
}
|
||||
|
||||
testing_only.ECDHE = function(pubKey, privKey) {
|
||||
if (privKey === undefined || privKey.byteLength != 32)
|
||||
throw new Error("Invalid private key");
|
||||
|
||||
if (pubKey === undefined || ((pubKey.byteLength != 33 || new Uint8Array(pubKey)[0] != 5) && pubKey.byteLength != 32))
|
||||
throw new Error("Invalid public key");
|
||||
if (pubKey.byteLength == 33)
|
||||
pubKey = pubKey.slice(1);
|
||||
else
|
||||
console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey");
|
||||
pubKey = validatePubKeyFormat(pubKey);
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
if (textsecure.nacl.USE_NACL) {
|
||||
textsecure.nacl.postNaclMessage({command: "ECDHE", priv: privKey, pub: pubKey}).then(function(message) {
|
||||
resolve(message.res);
|
||||
resolve(message.res.slice(0, 32));
|
||||
});
|
||||
} else {
|
||||
resolve(toArrayBuffer(curve25519(new Uint16Array(privKey), new Uint16Array(pubKey))));
|
||||
|
@ -262,6 +266,49 @@ window.textsecure.crypto = function() {
|
|||
}
|
||||
var ECDHE = function(pubKey, privKey) { return testing_only.ECDHE(pubKey, privKey); }
|
||||
|
||||
testing_only.Ed25519Sign = function(privKey, message) {
|
||||
if (privKey === undefined || privKey.byteLength != 32)
|
||||
throw new Error("Invalid private key");
|
||||
|
||||
if (message === undefined)
|
||||
throw new Error("Invalid message");
|
||||
|
||||
if (textsecure.nacl.USE_NACL) {
|
||||
return textsecure.nacl.postNaclMessage({command: "Ed25519Sign", priv: privKey, msg: message}).then(function(message) {
|
||||
return message.res;
|
||||
});
|
||||
} else {
|
||||
throw new Error("Ed25519 in JS not yet supported");
|
||||
}
|
||||
}
|
||||
var Ed25519Sign = function(privKey, pubKeyToSign) {
|
||||
pubKeyToSign = validatePubKeyFormat(pubKeyToSign);
|
||||
return testing_only.Ed25519Sign(privKey, pubKeyToSign);
|
||||
}
|
||||
|
||||
testing_only.Ed25519Verify = function(pubKey, msg, sig) {
|
||||
pubKey = validatePubKeyFormat(pubKey);
|
||||
|
||||
if (msg === undefined)
|
||||
throw new Error("Invalid message");
|
||||
|
||||
if (sig === undefined || sig.byteLength != 64)
|
||||
throw new Error("Invalid signature");
|
||||
|
||||
if (textsecure.nacl.USE_NACL) {
|
||||
return textsecure.nacl.postNaclMessage({command: "Ed25519Verify", pub: pubKey, msg: msg, sig: sig}).then(function(message) {
|
||||
if (!message.res)
|
||||
throw new Error("Invalid signature");
|
||||
});
|
||||
} else {
|
||||
throw new Error("Ed25519 in JS not yet supported");
|
||||
}
|
||||
}
|
||||
var Ed25519Verify = function(pubKey, signedPubKey, sig) {
|
||||
signedPubKey = validatePubKeyFormat(signedPubKey);
|
||||
return testing_only.Ed25519Verify(pubKey, signedPubKey, sig);
|
||||
}
|
||||
|
||||
testing_only.HKDF = function(input, salt, info) {
|
||||
// Specific implementation of RFC 5869 that only returns exactly 64 bytes
|
||||
return HmacSHA256(salt, input).then(function(PRK) {
|
||||
|
|
37
js/test.js
37
js/test.js
|
@ -163,7 +163,7 @@ textsecure.registerOnLoadFunction(function() {
|
|||
target[0] &= 248;
|
||||
target[31] &= 127;
|
||||
target[31] |= 64;
|
||||
if (String.fromCharCode.apply(null, new Uint8Array(aliceKeyPair.privKey)) != String.fromCharCode.apply(null, target))
|
||||
if (getString(aliceKeyPair.privKey) != getString(target))
|
||||
return false;
|
||||
|
||||
return textsecure.crypto.testing_only.privToPub(bob_priv, true).then(function(bobKeyPair) {
|
||||
|
@ -171,21 +171,21 @@ textsecure.registerOnLoadFunction(function() {
|
|||
target[0] &= 248;
|
||||
target[31] &= 127;
|
||||
target[31] |= 64;
|
||||
if (String.fromCharCode.apply(null, new Uint8Array(bobKeyPair.privKey)) != String.fromCharCode.apply(null, target))
|
||||
if (getString(bobKeyPair.privKey) != getString(target))
|
||||
return false;
|
||||
|
||||
if (String.fromCharCode.apply(null, new Uint8Array(aliceKeyPair.pubKey)) != String.fromCharCode.apply(null, new Uint8Array(alice_pub)))
|
||||
if (getString(aliceKeyPair.pubKey) != getString(alice_pub))
|
||||
return false;
|
||||
|
||||
if (String.fromCharCode.apply(null, new Uint8Array(bobKeyPair.pubKey)) != String.fromCharCode.apply(null, new Uint8Array(bob_pub)))
|
||||
if (getString(bobKeyPair.pubKey) != getString(bob_pub))
|
||||
return false;
|
||||
|
||||
return textsecure.crypto.testing_only.ECDHE(bobKeyPair.pubKey, aliceKeyPair.privKey).then(function(ss) {
|
||||
if (String.fromCharCode.apply(null, new Uint16Array(ss)) != String.fromCharCode.apply(null, new Uint16Array(shared_sec)))
|
||||
if (getString(ss) != getString(shared_sec))
|
||||
return false;
|
||||
|
||||
return textsecure.crypto.testing_only.ECDHE(aliceKeyPair.pubKey, bobKeyPair.privKey).then(function(ss) {
|
||||
if (String.fromCharCode.apply(null, new Uint16Array(ss)) != String.fromCharCode.apply(null, new Uint16Array(shared_sec)))
|
||||
if (getString(ss) != getString(shared_sec))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
@ -193,7 +193,30 @@ textsecure.registerOnLoadFunction(function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
}, "Simple Curve25519 test vector");
|
||||
}, "Simple Curve25519 test vectors");
|
||||
|
||||
TEST(function() {
|
||||
// Some self-generated test vectors
|
||||
var priv = hexToArrayBuffer("48a8892cc4e49124b7b57d94fa15becfce071830d6449004685e387c62409973");
|
||||
var pub = hexToArrayBuffer("0555f1bfede27b6a03e0dd389478ffb01462e5c52dbbac32cf870f00af1ed9af3a");
|
||||
var msg = hexToArrayBuffer("617364666173646661736466");
|
||||
var sig = hexToArrayBuffer("2bc06c745acb8bae10fbc607ee306084d0c28e2b3bb819133392473431291fd0"+
|
||||
"dfa9c7f11479996cf520730d2901267387e08d85bbf2af941590e3035a545285");
|
||||
|
||||
return textsecure.crypto.testing_only.privToPub(priv, false).then(function(pubCalc) {
|
||||
//if (getString(pub) != getString(pubCalc))
|
||||
// return false;
|
||||
|
||||
return textsecure.crypto.testing_only.Ed25519Sign(priv, msg).then(function(sigCalc) {
|
||||
if (getString(sig) != getString(sigCalc))
|
||||
return false;
|
||||
|
||||
return textsecure.crypto.testing_only.Ed25519Verify(pub, msg, sig).then(function() {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
});
|
||||
}, "Simple Ed25519 tests");
|
||||
|
||||
// TextSecure implements a slightly tweaked version of RFC 5869 and thus this test fails
|
||||
// If you tweak the HKDF as noted in the comment there, this test passes
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue