From e088eedc8ffbd0f57dcfe21f592c43951cc77c71 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 7 Feb 2019 00:08:32 -0700 Subject: [PATCH] v1.2.0: add jwk thumbprinting --- README.md | 9 +++++++++ bin/rasha.js | 13 +++++++++++++ lib/rasha.js | 24 ++++++++++++++++++++++++ package.json | 2 +- test.sh | 8 +++++++- 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e2d5fb2..66cbc7e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ RSA tools. Lightweight. Zero Dependencies. Universal compatibility. * [x] Fast and Easy RSA Key Generation * [x] PEM-to-JWK * [x] JWK-to-PEM +* [x] JWK thumbprint * [x] SSH "pub" format * [ ] ECDSA * **Need EC or ECDSA tools?** Check out [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js) @@ -174,6 +175,14 @@ Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQAB -----END PUBLIC KEY----- ``` +## JWK Thumbprint + +```js +Rasha.thumbprint({ jwk: jwk }).then(function (thumbprint) { + console.log(thumbprint); +}); +``` + Testing ------- diff --git a/bin/rasha.js b/bin/rasha.js index 4a8598b..8f653f8 100755 --- a/bin/rasha.js +++ b/bin/rasha.js @@ -46,7 +46,16 @@ try { // ignore } +var thumbprint = ('thumbprint' === format); +if (thumbprint) { + format = 'public'; +} + if ('string' === typeof key) { + if (thumbprint) { + Rasha.thumbprint({ pem: key }).then(console.info); + return; + } if ('tpl' === format) { var block = PEM.parseBlock(key); var asn1 = ASN1.parse(block.der); @@ -63,6 +72,10 @@ if ('string' === typeof key) { process.exit(1); }); } else { + if (thumbprint) { + Rasha.thumbprint({ jwk: key }).then(console.info); + return; + } Rasha.export({ jwk: key, format: format }).then(function (pem) { if (sign) { signMessage(pem, msg); return; } console.info(pem); diff --git a/lib/rasha.js b/lib/rasha.js index 67d1d0b..d16e610 100644 --- a/lib/rasha.js +++ b/lib/rasha.js @@ -5,6 +5,7 @@ var SSH = require('./ssh.js'); var PEM = require('./pem.js'); var x509 = require('./x509.js'); var ASN1 = require('./asn1.js'); +var Enc = require('./encoding.js'); /*global Promise*/ RSA.generate = function (opts) { @@ -202,3 +203,26 @@ RSA.nueter = function (jwk) { }); return jwk; }; + +RSA.__thumbprint = function (jwk) { + var buf = require('crypto').createHash('sha256') + // alphabetically sorted keys [ 'e', 'kty', 'n' ] + .update('{"e":"' + jwk.e + '","kty":"RSA","n":"' + jwk.n + '"}') + .digest() + ; + return Enc.bufToUrlBase64(buf); +}; + +RSA.thumbprint = function (opts) { + return Promise.resolve().then(function () { + var jwk; + if ('RSA' === opts.kty) { + jwk = opts; + } else if (opts.jwk) { + jwk = opts.jwk; + } else { + jwk = RSA.importSync(opts); + } + return RSA.__thumbprint(jwk); + }); +}; diff --git a/package.json b/package.json index 21a17c4..f57fd3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rasha", - "version": "1.1.0", + "version": "1.2.0", "description": "💯 PEM-to-JWK and JWK-to-PEM for RSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.", "homepage": "https://git.coolaj86.com/coolaj86/rasha.js", "main": "index.js", diff --git a/test.sh b/test.sh index db1ea9d..56ab318 100755 --- a/test.sh +++ b/test.sh @@ -149,7 +149,7 @@ rndkey 768 rndkey 1024 rndkey 2048 # first secure key size -if [ "${RASHA_TEST_LARGE_KEYS}" == "true" ]; then +if [ "${RASHA_TEST_LARGE_KEYS}" == "true" ]; then rndkey 3072 rndkey 4096 # largest reasonable key size else @@ -164,6 +164,12 @@ echo "Pass" rm fixtures/*.1.* +echo "" +echo "Testing Thumbprints" +node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs1.pem thumbprint +node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.json thumbprint +echo "PASS" + echo "" echo "" echo "PASSED:"