Permalink
Browse files

Add sameness / equality checks.

  • Loading branch information...
Dan Bornstein
Dan Bornstein committed Mar 1, 2012
1 parent a757de7 commit e83e5651d723ba41b6884b7d5d98e635716c3755
Showing with 152 additions and 3 deletions.
  1. +11 −0 README.md
  2. +42 −0 lib/ursa.js
  3. +1 −1 package.json
  4. +4 −0 test/fixture.js
  5. +58 −2 test/test.js
  6. +27 −0 test/zorch.pem
  7. +9 −0 test/zorch.pub
View
@@ -120,6 +120,11 @@ This function is similar to `crypto.createVerify()`, except this function
takes a hash algorithm name (e.g., `"sha256"`) and not a crypto+hash name
combination (e.g., `"RSA-SHA256"`).
+### ursa.equalKeys(key1, key2)
+
+This returns `true` if and only if both arguments are key objects of
+the same type (public or private) and their contents match.
+
### ursa.generatePrivateKey(modulusBits, exponent)
Create and return a freshly-generated private key (aka a keypair).
@@ -158,6 +163,12 @@ Note that, even though all the public key operations work on private
keys, this function only returns true if the given object is a
public key, per se.
+### ursa.matchingPublicKeys(key1, key2)
+
+This returns `true` if and only if both arguments are key objects of
+some sort (either can be public or private, and they don't have to
+be the same) and their public aspects match each other.
+
### ursa.sshFingerprint(sshKey, sshEncoding, outEncoding)
Return the SSH-style public key fingerprint of the given SSH-format
View
@@ -446,6 +446,46 @@ function assertPublicKey(obj) {
assert(isPublicKey(obj));
}
+/**
+ * Check whether the two objects are both keys of some sort and
+ * have the same public part.
+ */
+function matchingPublicKeys(key1, key2) {
+ if (!(isKey(key1) && isKey(key2))) {
+ return false;
+ }
+
+ // This isn't the most efficient implementation, but it will suffice:
+ // We convert both to ssh form, which has very little leeway for
+ // variation, and compare bytes.
+
+ var ssh1 = key1.toPublicSsh(UTF8);
+ var ssh2 = key2.toPublicSsh(UTF8);
+
+ return ssh1 === ssh2;
+}
+
+/**
+ * Check whether the two objects are both keys of some sort, are
+ * both public or both private, and have the same contents.
+ */
+function equalKeys(key1, key2) {
+ // See above for rationale. In this case, there's no ssh form for
+ // private keys, so we just use PEM for that.
+
+ if (isPrivateKey(key1) && isPrivateKey(key2)) {
+ var pem1 = key1.toPrivatePem(UTF8);
+ var pem2 = key2.toPrivatePem(UTF8);
+ return pem1 === pem2;
+ }
+
+ if (isPublicKey(key1) && isPublicKey(key2)) {
+ return matchingPublicKeys(key1, key2);
+ }
+
+ return false;
+}
+
/**
* Create a signer object.
*/
@@ -504,9 +544,11 @@ module.exports = {
createPublicKey: createPublicKey,
createSigner: createSigner,
createVerifier: createVerifier,
+ equalKeys: equalKeys,
generatePrivateKey: generatePrivateKey,
isKey: isKey,
isPrivateKey: isPrivateKey,
isPublicKey: isPublicKey,
+ matchingPublicKeys: matchingPublicKeys,
sshFingerprint: sshFingerprint
};
View
@@ -1,6 +1,6 @@
{
"name": "ursa",
- "version": "0.6.3",
+ "version": "0.6.4",
"keywords": [
"crypto", "key", "openssl", "private", "public", "rsa", "sign",
"signature", "verify", "verification", "hash", "digest"
View
@@ -31,6 +31,8 @@ var PASS_PRIVATE_KEY = fs.readFileSync(__dirname + "/blort-pass.pem");
var PRIVATE_KEY = fs.readFileSync(__dirname + "/blort.pem");
var PUBLIC_KEY = fs.readFileSync(__dirname + "/blort.pub");
var SSH_PUBLIC_KEY_FILE = fs.readFileSync(__dirname + "/blort.sshpub");
+var PRIVATE_KEY_2 = fs.readFileSync(__dirname + "/zorch.pem");
+var PUBLIC_KEY_2 = fs.readFileSync(__dirname + "/zorch.pub");
var PASSWORD = new Buffer("biscuits", UTF8);
@@ -115,8 +117,10 @@ module.exports = {
PLAINTEXT_SHA256_SIGNATURE: PLAINTEXT_SHA256_SIGNATURE,
PRIVATE_CIPHERTEXT_HEX: PRIVATE_CIPHERTEXT_HEX,
PRIVATE_KEY: PRIVATE_KEY,
+ PRIVATE_KEY_2: PRIVATE_KEY_2,
PUBLIC_CIPHERTEXT_HEX: PUBLIC_CIPHERTEXT_HEX,
PUBLIC_KEY: PUBLIC_KEY,
+ PUBLIC_KEY_2: PUBLIC_KEY_2,
SSH_PUBLIC_KEY: SSH_PUBLIC_KEY,
SSH_PUBLIC_KEY_FINGERPRINT_HEX: SSH_PUBLIC_KEY_FINGERPRINT_HEX,
View
@@ -286,7 +286,7 @@ function testGeneratedKey() {
assert.equal(decoded, fixture.PLAINTEXT);
}
-function testSshFingerprint() {
+function test_sshFingerprint() {
var key = fixture.SSH_PUBLIC_KEY;
var finger = ursa.sshFingerprint(fixture.SSH_PUBLIC_KEY);
assert.equal(finger.toString(fixture.HEX),
@@ -302,6 +302,60 @@ function testSshFingerprint() {
assert.equal(finger, fixture.SSH_PUBLIC_KEY_FINGERPRINT_HEX);
}
+function test_equalKeys() {
+ var pub = ursa.createPublicKey(fixture.PUBLIC_KEY);
+ var priv = ursa.createPrivateKey(fixture.PRIVATE_KEY);
+ var samePub = ursa.createPublicKey(fixture.PUBLIC_KEY);
+ var samePriv = ursa.createPrivateKey(fixture.PRIVATE_KEY);
+ var diffPub = ursa.createPublicKey(fixture.PUBLIC_KEY_2);
+ var diffPriv = ursa.createPrivateKey(fixture.PRIVATE_KEY_2);
+
+ assert.equal(ursa.equalKeys("1", "2"), false);
+ assert.equal(ursa.equalKeys(123, 123), false);
+ assert.equal(ursa.equalKeys(pub, null), false);
+ assert.equal(ursa.equalKeys(true, pub), false);
+
+ assert.equal(ursa.equalKeys(pub, pub), true);
+ assert.equal(ursa.equalKeys(priv, priv), true);
+ assert.equal(ursa.equalKeys(pub, priv), false);
+ assert.equal(ursa.equalKeys(priv, pub), false);
+
+ assert.equal(ursa.equalKeys(pub, samePub), true);
+ assert.equal(ursa.equalKeys(priv, samePriv), true);
+
+ assert.equal(ursa.equalKeys(pub, diffPub), false);
+ assert.equal(ursa.equalKeys(priv, diffPriv), false);
+}
+
+function test_matchingPublicKeys() {
+ var pub = ursa.createPublicKey(fixture.PUBLIC_KEY);
+ var priv = ursa.createPrivateKey(fixture.PRIVATE_KEY);
+ var samePub = ursa.createPublicKey(fixture.PUBLIC_KEY);
+ var samePriv = ursa.createPrivateKey(fixture.PRIVATE_KEY);
+ var diffPub = ursa.createPublicKey(fixture.PUBLIC_KEY_2);
+ var diffPriv = ursa.createPrivateKey(fixture.PRIVATE_KEY_2);
+
+ assert.equal(ursa.matchingPublicKeys("1", "2"), false);
+ assert.equal(ursa.matchingPublicKeys(123, 123), false);
+ assert.equal(ursa.matchingPublicKeys(pub, null), false);
+ assert.equal(ursa.matchingPublicKeys(true, pub), false);
+
+ assert.equal(ursa.matchingPublicKeys(pub, pub), true);
+ assert.equal(ursa.matchingPublicKeys(priv, priv), true);
+ assert.equal(ursa.matchingPublicKeys(pub, priv), true);
+ assert.equal(ursa.matchingPublicKeys(priv, pub), true);
+
+ assert.equal(ursa.matchingPublicKeys(pub, samePub), true);
+ assert.equal(ursa.matchingPublicKeys(priv, samePriv), true);
+ assert.equal(ursa.matchingPublicKeys(pub, samePriv), true);
+ assert.equal(ursa.matchingPublicKeys(priv, samePub), true);
+
+ assert.equal(ursa.matchingPublicKeys(pub, diffPub), false);
+ assert.equal(ursa.matchingPublicKeys(pub, diffPriv), false);
+ assert.equal(ursa.matchingPublicKeys(priv, diffPriv), false);
+ assert.equal(ursa.matchingPublicKeys(priv, diffPub), false);
+}
+
function testSigner() {
var key = ursa.createPrivateKey(fixture.PRIVATE_KEY);
var signer = ursa.createSigner(fixture.SHA256);
@@ -341,7 +395,9 @@ test_fail_createPrivateKey();
testPublicKey();
testPrivateKey();
testGeneratedKey();
-testSshFingerprint();
+test_sshFingerprint();
+test_equalKeys();
+test_matchingPublicKeys();
testSigner();
testVerifier();
View
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAtZPKWwG02rHQAZP95ckEo/rY7nAOJO+TRT5Kf7Ym4xJGBMCc
+5Ach5j4o1OFzKWaHgtfGM01Le3fdGx4VwxLcSlUI9ixvlhhKEqkRpGr8vphCDx0v
+g+jXseQ2axrR6uHrdYA+8ASnfiuxILDXCRLwmPlliFA4D0qoWenOmqeNT7+98opZ
+eN0BQxiOE/MXluSVpdVK/IQo5ggFDMBrHmq2+5L2I7JNkZOxADcilecrSrg1bt3F
+ppKWGt49tpcCldOFx50iXE7ca1y4fOtBx0rm4JPzmFIYB1hu3mIT/xd3p2MY5dMr
+Q9kYbeRcxcal1xXreLyWf2KslrPwwxZFR9QVoQIDAQABAoIBAGhaJ1FmCaolxoUh
+qCkG/cO/xixB+d8AUILa6bW72V1mgxb4GzJxZuoLjyvI5YZFhluL5jxVj6vFlyye
+faM+k5ukgyH3J6n7C5bt01XKprZiipRlEYmdp1h071FeeIWkkM1WhtUp15iLQ6Cm
+AO8WE2/W5KMSdyVSoq4J0NLQuEW705nRBw0KvKOu/16MI3ASIYAhDh2N+celiq0B
+QEFdMNIY4mQwRmoW8+nTVh3szVd6GXMH0etcQlDz7dLwXYm4qSw+dQusFjYZ6s4U
+HKjIxFsCy32B8XoLKi2gKY0u4SE56H9Qcp05y1fZe20lfenf3Der0ucrX0THj1/Z
+HLSTJgECgYEA6qlVbK0gm/iX8p62U/t3e1NtHyv3UlmmFPuHS4Z/cX4hErym0FJk
+ln/Ggo2cSlyw83TjQFPRGvCDbULa/pKJow0PyGk0+LHELk5bguGtq0EMpd2ZmUKs
+QIPcWXzbzismuH3x8zcNvErCEWvU7aDW8NznZes/a4aIjUR8DdG/l6UCgYEAxha2
+/EBp5YTubNIIVSROUMpzYmrJJSMdvCz7eu0yfREQFzAbgyhdOkBx7jdAzAVAINOw
+iVNP2h/DcOwGgcTun7RpBQ4QToDviNKQwp2Vh/DTYpuGzYgDJzmb+UawXQhXR9/F
+eWzYkb2HFZVQ6Quhd0uFE71B4NFD1FPqEDfERU0CgYBBPt/fnauJcm9dKD/tzeeE
+xMd8eU8E+KQzBVSy7SyWM8miWg3PsnkBV3msZw9jpa4VoxRkmGl1ohYI1SPq0Hew
+fDs9L/NoipTPgz3ygCk3ipinrZu9f0pBjehAgXTkOB9GAM67Hz2UcvzOtzq275eT
+1PgJ4IT7sqZZEQelGAK7eQKBgDunK4Pbggh0d7idp5S8UjlSPl0s+1YLtTCt+y2R
+sNqpAMd63U4qIakhLy4lxYWrLxyzoz43sJxnZFvlODBsNdAybE3xZke93GS/xIhX
+HGjLxVy0qWvLwedWGfp/pyzdDiu+36Epfi6lfMCrLqp/rihWvcSsAeLKIjsW6i3o
+HVshAoGActqcGaI+rt5A1FFwzNbZYiu8QLjtMV+Je8oryP58HZTfDf31vkIi3MdR
+G4jDp9POKxkn+AIfX6GOt2skC+mJGACbjPXCcuSaIYS6LyUmdZ22N+063yiiex2M
+irL6oqJcmS8k8DD34fhNPC+Z8KMkcqp0xNm9ikmJLNmEY5eeaiI=
+-----END RSA PRIVATE KEY-----
View
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtZPKWwG02rHQAZP95ckE
+o/rY7nAOJO+TRT5Kf7Ym4xJGBMCc5Ach5j4o1OFzKWaHgtfGM01Le3fdGx4VwxLc
+SlUI9ixvlhhKEqkRpGr8vphCDx0vg+jXseQ2axrR6uHrdYA+8ASnfiuxILDXCRLw
+mPlliFA4D0qoWenOmqeNT7+98opZeN0BQxiOE/MXluSVpdVK/IQo5ggFDMBrHmq2
++5L2I7JNkZOxADcilecrSrg1bt3FppKWGt49tpcCldOFx50iXE7ca1y4fOtBx0rm
+4JPzmFIYB1hu3mIT/xd3p2MY5dMrQ9kYbeRcxcal1xXreLyWf2KslrPwwxZFR9QV
+oQIDAQAB
+-----END PUBLIC KEY-----

0 comments on commit e83e565

Please sign in to comment.