Compare commits

..

18 Commits

Author SHA1 Message Date
David Dias
f979fcd3c2 chore: release version v0.7.2 2016-11-30 11:27:17 +00:00
David Dias
0af48bbebc chore: update contributors 2016-11-30 11:27:16 +00:00
David Dias
3f9d8d557c Merge pull request #42 from libp2p/feat/better-compat
Better compatability
2016-11-30 11:23:14 +00:00
Friedel Ziegelmayer
91a3b50ac9 feat(deps): update to multihashing-async@0.3.0 2016-11-29 18:11:58 +01:00
Friedel Ziegelmayer
148d16ab25 feat(rsa): add fallback pure js fallback for webcrypto-ossl 2016-11-29 17:54:41 +01:00
Friedel Ziegelmayer
6d15450438 feat(ecdh): use node core instead of webcrypto-ossl 2016-11-29 16:36:56 +01:00
David Dias
ebe1cecdeb Merge pull request #39 from libp2p/greenkeeper-protocol-buffers-3.2.1
protocol-buffers@3.2.1
2016-11-26 13:21:08 +01:00
greenkeeperio-bot
904cfb27bd chore(package): update protocol-buffers to version 3.2.1
https://greenkeeper.io/
2016-11-26 06:11:28 +01:00
Friedel Ziegelmayer
7790beb207 Merge pull request #37 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.13
node-webcrypto-ossl@1.0.13 breaks build 🚨
2016-11-23 23:26:31 +01:00
greenkeeperio-bot
6308461f0f chore(package): update node-webcrypto-ossl to version 1.0.13
https://greenkeeper.io/
2016-11-23 22:20:49 +01:00
Friedel Ziegelmayer
95a0f1f0c2 Merge pull request #34 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.10
node-webcrypto-ossl@1.0.10 breaks build 🚨
2016-11-16 10:53:36 +01:00
greenkeeperio-bot
0c64122342 chore(package): update node-webcrypto-ossl to version 1.0.10
https://greenkeeper.io/
2016-11-15 07:46:24 +01:00
David Dias
ce5044b4d7 chore: release version v0.7.1 2016-11-11 08:38:28 +00:00
David Dias
1daf429a74 chore: update contributors 2016-11-11 08:38:27 +00:00
David Dias
22e95bc8a4 Merge pull request #29 from libp2p/aes-interop
AES Interop
2016-11-11 08:30:18 +00:00
Friedel Ziegelmayer
9994023490 fix(aes): replace subtle.crypto with browserify-aes
Due to the design of `AES-CTR` in the webcrypto spec, there
is no streaming mode provided. This results in the counter
not being reused between subsequent calls to `encrypt` or
`decrypt`. As both the node.js and the go implementation rely
on this webcrypto had to be replaced.
2016-11-10 17:19:45 +01:00
Friedel Ziegelmayer
393fa17512 test(aes): add failing interop tests 2016-11-10 12:55:49 +01:00
Friedel Ziegelmayer
3cc26d167f chore(benchmarks): lint happy 2016-11-07 11:37:32 +01:00
30 changed files with 2819 additions and 419 deletions

View File

@@ -33,5 +33,5 @@ suite
console.log(String(event.target)) console.log(String(event.target))
}) })
.run({ .run({
'async': true async: true
}) })

View File

@@ -1,6 +1,8 @@
'use strict' 'use strict'
const Benchmark = require('benchmark') const Benchmark = require('benchmark')
const async = require('async')
const crypto = require('../src') const crypto = require('../src')
const suite = new Benchmark.Suite('key-stretcher') const suite = new Benchmark.Suite('key-stretcher')
@@ -10,38 +12,38 @@ const keys = []
const ciphers = ['AES-128', 'AES-256', 'Blowfish'] const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512'] const hashes = ['SHA1', 'SHA256', 'SHA512']
crypto.generateEphemeralKeyPair('P-256', (err, res) => { async.waterfall([
(cb) => crypto.generateEphemeralKeyPair('P-256', cb),
(res, cb) => res.genSharedKey(res.key, cb)
], (err, secret) => {
if (err) { if (err) {
throw err throw err
} }
res.genSharedKey(res.key, (err, secret) => { ciphers.forEach((cipher) => hashes.forEach((hash) => {
if (err) { setup(cipher, hash, secret)
throw err }))
}
ciphers.forEach((cipher) => {
hashes.forEach((hash) => {
suite.add(`keyStretcher ${cipher} ${hash}`, (d) => {
crypto.keyStretcher(cipher, hash, secret, (err, k) => {
if (err) {
throw err
}
keys.push(k) suite
d.resolve() .on('cycle', (event) => {
}) console.log(String(event.target))
}, { })
defer: true .run({
}) async: true
})
}) })
})
}) })
suite function setup (cipher, hash, secret) {
.on('cycle', (event) => { suite.add(`keyStretcher ${cipher} ${hash}`, (d) => {
console.log(String(event.target)) crypto.keyStretcher(cipher, hash, secret, (err, k) => {
}) if (err) {
.run({ throw err
'async': true }
keys.push(k)
d.resolve()
})
}, {
defer: true
}) })
}

View File

@@ -48,5 +48,5 @@ suite
console.log(String(event.target)) console.log(String(event.target))
}) })
.run({ .run({
'async': true async: true
}) })

View File

@@ -1,19 +1,22 @@
{ {
"name": "libp2p-crypto", "name": "libp2p-crypto",
"version": "0.7.0", "version": "0.7.2",
"description": "Crypto primitives for libp2p", "description": "Crypto primitives for libp2p",
"main": "src/index.js", "main": "src/index.js",
"browser": { "browser": {
"node-webcrypto-ossl": false, "node-webcrypto-ossl": false,
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js", "./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js",
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js", "./src/crypto/hmac.js": "./src/crypto/hmac-browser.js",
"./src/crypto/aes.js": "./src/crypto/aes-browser.js" "./src/crypto/ecdh.js": "./src/crypto/ecdh-browser.js",
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js",
"./src/crypto/rsa.js": "./src/crypto/rsa-browser.js"
}, },
"scripts": { "scripts": {
"lint": "aegir-lint", "lint": "aegir-lint",
"build": "aegir-build", "build": "aegir-build",
"test": "aegir-test", "test": "npm run test:node && npm run test:no-webcrypto && npm run test:browser",
"test:node": "aegir-test --env node", "test:node": "aegir-test --env node",
"test:no-webcrypto": "NO_WEBCRYPTO=true aegir-test --env node",
"test:browser": "aegir-test --env browser", "test:browser": "aegir-test --env browser",
"release": "aegir-release", "release": "aegir-release",
"release-minor": "aegir-release --type minor", "release-minor": "aegir-release --type minor",
@@ -32,10 +35,13 @@
"dependencies": { "dependencies": {
"asn1.js": "^4.8.1", "asn1.js": "^4.8.1",
"async": "^2.1.2", "async": "^2.1.2",
"multihashing-async": "^0.2.0", "browserify-aes": "^1.0.6",
"node-webcrypto-ossl": "^1.0.7", "keypair": "^1.0.0",
"multihashing-async": "^0.3.0",
"nodeify": "^1.0.0", "nodeify": "^1.0.0",
"protocol-buffers": "^3.1.6", "pem-jwk": "^1.5.1",
"protocol-buffers": "^3.2.1",
"rsa-pem-to-jwk": "^1.1.3",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
}, },
"devDependencies": { "devDependencies": {
@@ -44,6 +50,9 @@
"chai": "^3.5.0", "chai": "^3.5.0",
"pre-commit": "^1.1.3" "pre-commit": "^1.1.3"
}, },
"optionalDependencies": {
"node-webcrypto-ossl": "^1.0.13"
},
"pre-commit": [ "pre-commit": [
"lint", "lint",
"test" "test"

View File

@@ -1,52 +0,0 @@
'use strict'
const nodeify = require('nodeify')
const crypto = require('./webcrypto')()
exports.create = function (key, iv, callback) {
nodeify(crypto.subtle.importKey(
'raw',
key,
{
name: 'AES-CTR'
},
false,
['encrypt', 'decrypt']
).then((key) => {
const counter = copy(iv)
return {
encrypt (data, cb) {
nodeify(crypto.subtle.encrypt(
{
name: 'AES-CTR',
counter: counter,
length: 128
},
key,
data
).then((raw) => Buffer.from(raw)), cb)
},
decrypt (data, cb) {
nodeify(crypto.subtle.decrypt(
{
name: 'AES-CTR',
counter: counter,
length: 128
},
key,
data
).then((raw) => Buffer.from(raw)), cb)
}
}
}), callback)
}
function copy (buf) {
const fresh = new Buffer(buf.length)
buf.copy(fresh)
return fresh
}

View File

@@ -1,20 +1,20 @@
'use strict' 'use strict'
const crypto = require('crypto') const ciphers = require('./ciphers')
const ciphers = { const CIPHER_MODES = {
16: 'aes-128-ctr', 16: 'aes-128-ctr',
32: 'aes-256-ctr' 32: 'aes-256-ctr'
} }
exports.create = function (key, iv, callback) { exports.create = function (key, iv, callback) {
const name = ciphers[key.length] const mode = CIPHER_MODES[key.length]
if (!name) { if (!mode) {
return callback(new Error('Invalid key length')) return callback(new Error('Invalid key length'))
} }
const cipher = crypto.createCipheriv(name, key, iv) const cipher = ciphers.createCipheriv(mode, key, iv)
const decipher = crypto.createDecipheriv(name, key, iv) const decipher = ciphers.createDecipheriv(mode, key, iv)
const res = { const res = {
encrypt (data, cb) { encrypt (data, cb) {

View File

@@ -0,0 +1,8 @@
'use strict'
const crypto = require('browserify-aes')
module.exports = {
createCipheriv: crypto.createCipheriv,
createDecipheriv: crypto.createDecipheriv
}

8
src/crypto/ciphers.js Normal file
View File

@@ -0,0 +1,8 @@
'use strict'
const crypto = require('crypto')
module.exports = {
createCipheriv: crypto.createCipheriv,
createDecipheriv: crypto.createDecipheriv
}

129
src/crypto/ecdh-browser.js Normal file
View File

@@ -0,0 +1,129 @@
'use strict'
const crypto = require('./webcrypto')()
const nodeify = require('nodeify')
const BN = require('asn1.js').bignum
const util = require('./util')
const toBase64 = util.toBase64
const toBn = util.toBn
const bits = {
'P-256': 256,
'P-384': 384,
'P-521': 521
}
exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: curve
},
true,
['deriveBits']
).then((pair) => {
// forcePrivate is used for testing only
const genSharedKey = (theirPub, forcePrivate, cb) => {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = undefined
}
let privateKey
if (forcePrivate) {
privateKey = crypto.subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
name: 'ECDH',
namedCurve: curve
},
false,
['deriveBits']
)
} else {
privateKey = Promise.resolve(pair.privateKey)
}
const keys = Promise.all([
crypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
),
privateKey
])
nodeify(keys.then((keys) => crypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
public: keys[0]
},
keys[1],
bits[curve]
)).then((bits) => Buffer.from(bits)), cb)
}
return crypto.subtle.exportKey(
'jwk',
pair.publicKey
).then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
}
const curveLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
// Marshal converts a jwk encodec ECDH public key into the
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
// go-ipfs uses)
function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv]
return Buffer.concat([
new Buffer([4]), // uncompressed point
toBn(jwk.x).toBuffer('be', byteLen),
toBn(jwk.y).toBuffer('be', byteLen)
], 1 + byteLen * 2)
}
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(new Buffer([4]))) {
throw new Error('Invalid key format')
}
const x = new BN(key.slice(1, byteLen + 1))
const y = new BN(key.slice(1 + byteLen))
return {
kty: 'EC',
crv: curve,
x: toBase64(x),
y: toBase64(y),
ext: true
}
}
function unmarshalPrivateKey (curve, key) {
const result = unmarshalPublicKey(curve, key.public)
result.d = toBase64(new BN(key.private))
return result
}

View File

@@ -1,101 +1,41 @@
'use strict' 'use strict'
const crypto = require('./webcrypto')() const crypto = require('crypto')
const nodeify = require('nodeify') const setImmediate = require('async/setImmediate')
const BN = require('asn1.js').bignum
const util = require('./util') const curves = {
const toBase64 = util.toBase64 'P-256': 'prime256v1',
const toBn = util.toBn 'P-384': 'secp384r1',
'P-521': 'secp521r1'
}
exports.generateEphmeralKeyPair = function (curve, callback) { exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(crypto.subtle.generateKey( if (!curves[curve]) {
{ return callback(new Error(`Unkown curve: ${curve}`))
name: 'ECDH', }
namedCurve: curve const ecdh = crypto.createECDH(curves[curve])
}, ecdh.generateKeys()
true,
['deriveBits'] setImmediate(() => callback(null, {
).then((pair) => { key: ecdh.getPublicKey(),
// forcePrivate is used for testing only genSharedKey (theirPub, forcePrivate, cb) {
const genSharedKey = (theirPub, forcePrivate, cb) => {
if (typeof forcePrivate === 'function') { if (typeof forcePrivate === 'function') {
cb = forcePrivate cb = forcePrivate
forcePrivate = undefined forcePrivate = null
} }
const privateKey = forcePrivate || pair.privateKey if (forcePrivate) {
nodeify(crypto.subtle.importKey( ecdh.setPrivateKey(forcePrivate.private)
'jwk', }
unmarshalPublicKey(curve, theirPub),
{ let secret
name: 'ECDH', try {
namedCurve: curve secret = ecdh.computeSecret(theirPub)
}, } catch (err) {
false, return cb(err)
[] }
).then((publicKey) => {
return crypto.subtle.deriveBits( setImmediate(() => cb(null, secret))
{
name: 'ECDH',
namedCurve: curve,
public: publicKey
},
privateKey,
256
)
}).then((bits) => {
// return p.derive(pub.getPublic()).toBuffer('be')
return Buffer.from(bits)
}), cb)
} }
}))
return crypto.subtle.exportKey(
'jwk',
pair.publicKey
).then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
}
const curveLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
// Marshal converts a jwk encodec ECDH public key into the
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
// go-ipfs uses)
function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv]
return Buffer.concat([
Buffer([4]), // uncompressed point
toBn(jwk.x).toBuffer('be', byteLen),
toBn(jwk.y).toBuffer('be', byteLen)
], 1 + byteLen * 2)
}
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(Buffer([4]))) {
throw new Error('Invalid key format')
}
const x = new BN(key.slice(1, byteLen + 1))
const y = new BN(key.slice(1 + byteLen))
return {
kty: 'EC',
crv: curve,
x: toBase64(x),
y: toBase64(y),
ext: true
}
} }

119
src/crypto/rsa-browser.js Normal file
View File

@@ -0,0 +1,119 @@
'use strict'
const nodeify = require('nodeify')
const crypto = require('./webcrypto')()
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
nodeify(crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: 'SHA-256'}
},
true,
['sign', 'verify']
)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
const privateKey = crypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
true,
['sign']
)
nodeify(Promise.all([
privateKey,
derivePublicFromPrivate(key)
]).then((keys) => exportKey({
privateKey: keys[0],
publicKey: keys[1]
})).then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
exports.getRandomValues = function (arr) {
return Buffer.from(crypto.getRandomValues(arr))
}
exports.hashAndSign = function (key, msg, callback) {
nodeify(crypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
false,
['sign']
).then((privateKey) => {
return crypto.subtle.sign(
{name: 'RSASSA-PKCS1-v1_5'},
privateKey,
Uint8Array.from(msg)
)
}).then((sig) => Buffer.from(sig)), callback)
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nodeify(crypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
false,
['verify']
).then((publicKey) => {
return crypto.subtle.verify(
{name: 'RSASSA-PKCS1-v1_5'},
publicKey,
sig,
msg
)
}), callback)
}
function exportKey (pair) {
return Promise.all([
crypto.subtle.exportKey('jwk', pair.privateKey),
crypto.subtle.exportKey('jwk', pair.publicKey)
])
}
function derivePublicFromPrivate (jwKey) {
return crypto.subtle.importKey(
'jwk',
{
kty: jwKey.kty,
n: jwKey.n,
e: jwKey.e,
alg: jwKey.alg,
kid: jwKey.kid
},
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
true,
['verify']
)
}

114
src/crypto/rsa-utils.js Normal file
View File

@@ -0,0 +1,114 @@
'use strict'
const asn1 = require('asn1.js')
const util = require('./util')
const toBase64 = util.toBase64
const toBn = util.toBn
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
this.seq().obj(
this.key('version').int(),
this.key('modulus').int(),
this.key('publicExponent').int(),
this.key('privateExponent').int(),
this.key('prime1').int(),
this.key('prime2').int(),
this.key('exponent1').int(),
this.key('exponent2').int(),
this.key('coefficient').int()
)
})
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
this.seq().obj(
this.key('algorithm').objid({
'1.2.840.113549.1.1.1': 'rsa'
}),
this.key('none').optional().null_(),
this.key('curve').optional().objid(),
this.key('params').optional().seq().obj(
this.key('p').int(),
this.key('q').int(),
this.key('g').int()
)
)
})
const PublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('algorithm').use(AlgorithmIdentifier),
this.key('subjectPublicKey').bitstr()
)
})
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('modulus').int(),
this.key('publicExponent').int()
)
})
// Convert a PKCS#1 in ASN1 DER format to a JWK key
exports.pkcs1ToJwk = function (bytes) {
const asn1 = RSAPrivateKey.decode(bytes, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
d: toBase64(asn1.privateExponent),
p: toBase64(asn1.prime1),
q: toBase64(asn1.prime2),
dp: toBase64(asn1.exponent1),
dq: toBase64(asn1.exponent2),
qi: toBase64(asn1.coefficient),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key into PKCS#1 in ASN1 DER format
exports.jwkToPkcs1 = function (jwk) {
return RSAPrivateKey.encode({
version: 0,
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e),
privateExponent: toBn(jwk.d),
prime1: toBn(jwk.p),
prime2: toBn(jwk.q),
exponent1: toBn(jwk.dp),
exponent2: toBn(jwk.dq),
coefficient: toBn(jwk.qi)
}, 'der')
}
// Convert a PKCIX in ASN1 DER format to a JWK key
exports.pkixToJwk = function (bytes) {
const ndata = PublicKey.decode(bytes, 'der')
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key to PKCIX in ASN1 DER format
exports.jwkToPkix = function (jwk) {
return PublicKey.encode({
algorithm: {
algorithm: 'rsa',
none: null
},
subjectPublicKey: {
data: RSAPublicKey.encode({
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e)
}, 'der')
}
}, 'der')
}

View File

@@ -1,228 +1,80 @@
'use strict' 'use strict'
const nodeify = require('nodeify') // Node.js land
const asn1 = require('asn1.js') // First we look if node-webrypto-ossl is available
// otherwise we fall back to using keypair + node core
const util = require('./util') let webcrypto
const toBase64 = util.toBase64 try {
const toBn = util.toBn webcrypto = require('node-webcrypto-ossl')
const crypto = require('./webcrypto')() } catch (err) {
// not available, use the code below
exports.generateKey = function (bits, callback) {
nodeify(crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: 'SHA-256'}
},
true,
['sign', 'verify']
)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
} }
// Takes a jwk key if (webcrypto && !process.env.NO_WEBCRYPTO) {
exports.unmarshalPrivateKey = function (key, callback) { module.exports = require('./rsa-browser')
const privateKey = crypto.subtle.importKey( } else {
'jwk', const crypto = require('crypto')
key, const keypair = require('keypair')
{ const setImmediate = require('async/setImmediate')
name: 'RSASSA-PKCS1-v1_5', const pemToJwk = require('pem-jwk').pem2jwk
hash: {name: 'SHA-256'} const jwkToPem = require('pem-jwk').jwk2pem
},
true,
['sign']
)
nodeify(Promise.all([ exports.utils = require('./rsa-utils')
privateKey,
derivePublicFromPrivate(key)
]).then((keys) => exportKey({
privateKey: keys[0],
publicKey: keys[1]
})).then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
exports.getRandomValues = function (arr) { exports.generateKey = function (bits, callback) {
return Buffer.from(crypto.getRandomValues(arr)) const done = (err, res) => setImmediate(() => {
} callback(err, res)
})
exports.hashAndSign = function (key, msg, callback) { let key
nodeify(crypto.subtle.importKey( try {
'jwk', key = keypair({
key, bits: bits
{ })
name: 'RSASSA-PKCS1-v1_5', } catch (err) {
hash: {name: 'SHA-256'} done(err)
}, return
false,
['sign']
).then((privateKey) => {
return crypto.subtle.sign(
{name: 'RSASSA-PKCS1-v1_5'},
privateKey,
Uint8Array.from(msg)
)
}).then((sig) => Buffer.from(sig)), callback)
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nodeify(crypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
false,
['verify']
).then((publicKey) => {
return crypto.subtle.verify(
{name: 'RSASSA-PKCS1-v1_5'},
publicKey,
sig,
msg
)
}), callback)
}
function exportKey (pair) {
return Promise.all([
crypto.subtle.exportKey('jwk', pair.privateKey),
crypto.subtle.exportKey('jwk', pair.publicKey)
])
}
function derivePublicFromPrivate (jwKey) {
return crypto.subtle.importKey(
'jwk',
{
kty: jwKey.kty,
n: jwKey.n,
e: jwKey.e,
alg: jwKey.alg,
kid: jwKey.kid
},
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
true,
['verify']
)
}
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
this.seq().obj(
this.key('version').int(),
this.key('modulus').int(),
this.key('publicExponent').int(),
this.key('privateExponent').int(),
this.key('prime1').int(),
this.key('prime2').int(),
this.key('exponent1').int(),
this.key('exponent2').int(),
this.key('coefficient').int()
)
})
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
this.seq().obj(
this.key('algorithm').objid({
'1.2.840.113549.1.1.1': 'rsa'
}),
this.key('none').optional().null_(),
this.key('curve').optional().objid(),
this.key('params').optional().seq().obj(
this.key('p').int(),
this.key('q').int(),
this.key('g').int()
)
)
})
const PublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('algorithm').use(AlgorithmIdentifier),
this.key('subjectPublicKey').bitstr()
)
})
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('modulus').int(),
this.key('publicExponent').int()
)
})
// Convert a PKCS#1 in ASN1 DER format to a JWK key
exports.pkcs1ToJwk = function (bytes) {
const asn1 = RSAPrivateKey.decode(bytes, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
d: toBase64(asn1.privateExponent),
p: toBase64(asn1.prime1),
q: toBase64(asn1.prime2),
dp: toBase64(asn1.exponent1),
dq: toBase64(asn1.exponent2),
qi: toBase64(asn1.coefficient),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key into PKCS#1 in ASN1 DER format
exports.jwkToPkcs1 = function (jwk) {
return RSAPrivateKey.encode({
version: 0,
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e),
privateExponent: toBn(jwk.d),
prime1: toBn(jwk.p),
prime2: toBn(jwk.q),
exponent1: toBn(jwk.dp),
exponent2: toBn(jwk.dq),
coefficient: toBn(jwk.qi)
}, 'der')
}
// Convert a PKCIX in ASN1 DER format to a JWK key
exports.pkixToJwk = function (bytes) {
const ndata = PublicKey.decode(bytes, 'der')
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key to PKCIX in ASN1 DER format
exports.jwkToPkix = function (jwk) {
return PublicKey.encode({
algorithm: {
algorithm: 'rsa',
none: null
},
subjectPublicKey: {
data: RSAPublicKey.encode({
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e)
}, 'der')
} }
}, 'der')
done(null, {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
})
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
}
exports.getRandomValues = function (arr) {
return crypto.randomBytes(arr.length)
}
exports.hashAndSign = function (key, msg, callback) {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
setImmediate(() => {
callback(null, sign.sign(jwkToPem(key)))
})
}
exports.hashAndVerify = function (key, sig, msg, callback) {
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
setImmediate(() => {
callback(null, verify.verify(jwkToPem(key), sig))
})
}
} }

View File

@@ -1,7 +1,11 @@
'use strict' 'use strict'
module.exports = function getWebCrypto () { module.exports = function getWebCrypto () {
const WebCrypto = require('node-webcrypto-ossl') try {
const webCrypto = new WebCrypto() const WebCrypto = require('node-webcrypto-ossl')
return webCrypto const webCrypto = new WebCrypto()
return webCrypto
} catch (err) {
// fallback to other things
}
} }

View File

@@ -17,7 +17,7 @@ class RsaPublicKey {
} }
marshal () { marshal () {
return crypto.jwkToPkix(this._key) return crypto.utils.jwkToPkix(this._key)
} }
get bytes () { get bytes () {
@@ -71,7 +71,7 @@ class RsaPrivateKey {
} }
marshal () { marshal () {
return crypto.jwkToPkcs1(this._key) return crypto.utils.jwkToPkcs1(this._key)
} }
get bytes () { get bytes () {
@@ -92,7 +92,7 @@ class RsaPrivateKey {
} }
function unmarshalRsaPrivateKey (bytes, callback) { function unmarshalRsaPrivateKey (bytes, callback) {
const jwk = crypto.pkcs1ToJwk(bytes) const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => { crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) { if (err) {
return callback(err) return callback(err)
@@ -103,7 +103,7 @@ function unmarshalRsaPrivateKey (bytes, callback) {
} }
function unmarshalRsaPublicKey (bytes) { function unmarshalRsaPublicKey (bytes) {
const jwk = crypto.pkixToJwk(bytes) const jwk = crypto.utils.pkixToJwk(bytes)
return new RsaPublicKey(jwk) return new RsaPublicKey(jwk)
} }

View File

@@ -3,7 +3,11 @@
'use strict' 'use strict'
const expect = require('chai').expect const expect = require('chai').expect
const series = require('async/series')
const crypto = require('../src') const crypto = require('../src')
const fixtures = require('./fixtures/aes')
const goFixtures = require('./fixtures/go-aes')
const bytes = { const bytes = {
16: 'AES-128', 16: 'AES-128',
@@ -22,16 +26,90 @@ describe('AES-CTR', () => {
crypto.aes.create(key, iv, (err, cipher) => { crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist expect(err).to.not.exist
cipher.encrypt(new Buffer('hello'), (err, res) => { series([
expect(err).to.not.exist encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher)
], done)
})
})
})
Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - fixed - encrypt and decrypt`, (done) => {
const key = new Buffer(parseInt(byte, 10))
key.fill(5)
cipher.decrypt(res, (err, res) => { const iv = new Buffer(16)
iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist
series(fixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = new Buffer(rawIn)
const output = new Buffer(fixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist
expect(res).to.be.eql(new Buffer('hello')) expect(res).to.have.length(output.length)
done() expect(res).to.be.eql(output)
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist
expect(res).to.be.eql(input)
cb()
})
}) })
}) }), done)
})
})
})
Object.keys(bytes).forEach((byte) => {
if (!goFixtures[byte]) {
return
}
it(`${bytes[byte]} - go interop - encrypt and decrypt`, (done) => {
const key = new Buffer(parseInt(byte, 10))
key.fill(5)
const iv = new Buffer(16)
iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist
series(goFixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = new Buffer(rawIn)
const output = new Buffer(goFixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist
expect(res).to.have.length(output.length)
expect(res).to.be.eql(output)
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist
expect(res).to.be.eql(input)
cb()
})
})
}), done)
}) })
}) })
}) })
}) })
function encryptAndDecrypt (cipher) {
const data = new Buffer(100)
data.fill(Math.ceil(Math.random() * 100))
return (cb) => {
cipher.encrypt(data, (err, res) => {
expect(err).to.not.exist
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist
expect(res).to.be.eql(data)
cb()
})
})
}
}

View File

@@ -14,6 +14,11 @@ const lengths = {
'P-384': 97, 'P-384': 97,
'P-521': 133 'P-521': 133
} }
const secretLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
describe('generateEphemeralKeyPair', () => { describe('generateEphemeralKeyPair', () => {
curves.forEach((curve) => { curves.forEach((curve) => {
@@ -28,7 +33,7 @@ describe('generateEphemeralKeyPair', () => {
keys[0].genSharedKey(keys[1].key, (err, shared) => { keys[0].genSharedKey(keys[1].key, (err, shared) => {
expect(err).to.not.exist expect(err).to.not.exist
expect(shared).to.have.length(32) expect(shared).to.have.length(secretLengths[curve])
done() done()
}) })
}) })
@@ -39,12 +44,29 @@ describe('generateEphemeralKeyPair', () => {
it('generates a shared secret', (done) => { it('generates a shared secret', (done) => {
const curve = fixtures.curve const curve = fixtures.curve
crypto.generateEphemeralKeyPair(curve, (err, alice) => { parallel([
(cb) => crypto.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.generateEphemeralKeyPair(curve, cb)
], (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist
const alice = res[0]
const bob = res[1]
bob.key = fixtures.bob.public
alice.genSharedKey(fixtures.bob.public, (err, s1) => { parallel([
(cb) => alice.genSharedKey(bob.key, cb),
(cb) => bob.genSharedKey(alice.key, fixtures.bob, cb)
], (err, secrets) => {
expect(err).to.not.exist expect(err).to.not.exist
expect(s1).to.have.length(32)
expect(
secrets[0]
).to.be.eql(
secrets[1]
)
expect(secrets[0]).to.have.length(32)
done() done()
}) })
}) })

27
test/fixtures/aes.js vendored Normal file
View File

@@ -0,0 +1,27 @@
'use strict'
const fixes16 = [
require('./fix1.json'),
require('./fix2.json'),
require('./fix3.json'),
require('./fix4.json'),
require('./fix5.json')
]
const fixes32 = [
require('./fix6.json'),
require('./fix7.json'),
require('./fix8.json'),
require('./fix9.json'),
require('./fix10.json')
]
module.exports = {
16: {
inputs: fixes16.map((f) => f.input),
outputs: fixes16.map((f) => f.output)
},
32: {
inputs: fixes32.map((f) => f.input),
outputs: fixes32.map((f) => f.output)
}
}

212
test/fixtures/fix1.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47
]
},
"output": {
"type": "Buffer",
"data": [
121,
104,
0,
151,
57,
137,
22,
239,
234,
151,
58,
15,
100,
22,
228,
110,
85,
248,
249,
15,
145,
128,
223,
25,
192,
175,
132,
169,
98,
203,
231,
106,
224,
102,
206,
244,
29,
213,
36,
2,
26,
213,
94,
29,
134,
219,
136,
73,
212,
176,
33,
95,
198,
91,
148,
139,
132,
252,
182,
115,
116,
160,
146,
194,
0,
97,
181,
0,
193,
149,
21,
51,
248,
97,
32,
62,
86,
153,
238,
67,
38,
34,
55,
143,
70,
193,
99,
107,
31,
67,
90,
97,
55,
63,
69,
203,
33,
233,
74,
237
]
}
}

212
test/fixtures/fix10.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72
]
},
"output": {
"type": "Buffer",
"data": [
201,
224,
56,
64,
167,
224,
124,
49,
19,
51,
208,
226,
216,
50,
12,
73,
15,
255,
156,
108,
98,
179,
144,
110,
33,
151,
43,
64,
227,
153,
120,
39,
21,
151,
41,
61,
245,
20,
31,
23,
109,
213,
109,
55,
35,
40,
122,
109,
41,
10,
32,
176,
25,
184,
91,
176,
177,
134,
138,
252,
160,
2,
108,
43,
222,
239,
174,
2,
145,
74,
34,
131,
237,
214,
235,
102,
26,
204,
124,
64,
101,
134,
186,
45,
55,
29,
52,
55,
171,
95,
172,
86,
242,
101,
141,
153,
222,
161,
128,
83
]
}
}

212
test/fixtures/fix2.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24
]
},
"output": {
"type": "Buffer",
"data": [
109,
172,
127,
179,
110,
222,
79,
219,
87,
76,
70,
204,
166,
110,
184,
229,
90,
49,
160,
252,
78,
58,
73,
51,
152,
218,
3,
200,
10,
124,
152,
117,
137,
40,
23,
127,
56,
57,
203,
31,
101,
227,
31,
198,
223,
86,
98,
120,
100,
86,
116,
144,
142,
127,
68,
175,
249,
232,
22,
83,
22,
68,
60,
230,
146,
22,
153,
193,
67,
5,
51,
253,
239,
210,
80,
31,
254,
103,
185,
145,
123,
99,
205,
175,
156,
144,
191,
67,
31,
236,
43,
98,
197,
235,
31,
50,
69,
228,
100,
64
]
}
}

212
test/fixtures/fix3.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7
]
},
"output": {
"type": "Buffer",
"data": [
191,
93,
126,
191,
180,
42,
118,
144,
28,
188,
211,
191,
211,
130,
170,
153,
134,
240,
179,
83,
75,
23,
42,
68,
158,
200,
123,
155,
57,
169,
152,
133,
33,
114,
90,
29,
131,
91,
70,
105,
83,
45,
40,
47,
77,
96,
97,
8,
40,
1,
110,
245,
106,
172,
152,
146,
5,
114,
132,
0,
179,
31,
44,
78,
19,
109,
92,
199,
226,
36,
12,
74,
180,
241,
224,
107,
83,
13,
167,
27,
251,
101,
193,
98,
49,
90,
225,
197,
75,
213,
144,
52,
235,
130,
92,
247,
219,
139,
209,
132
]
}
}

212
test/fixtures/fix4.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25
]
},
"output": {
"type": "Buffer",
"data": [
191,
110,
53,
190,
250,
44,
190,
136,
22,
209,
131,
200,
112,
31,
61,
183,
247,
95,
4,
249,
69,
147,
238,
74,
18,
71,
197,
115,
141,
226,
102,
92,
91,
128,
181,
172,
67,
109,
17,
165,
52,
10,
55,
31,
55,
225,
253,
140,
154,
35,
104,
62,
119,
103,
197,
152,
125,
134,
140,
181,
170,
76,
75,
114,
195,
188,
68,
197,
28,
47,
116,
82,
34,
128,
232,
122,
14,
229,
122,
161,
36,
212,
161,
164,
145,
86,
215,
233,
222,
50,
143,
89,
131,
32,
130,
196,
109,
36,
204,
254
]
}
}

212
test/fixtures/fix5.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48
]
},
"output": {
"type": "Buffer",
"data": [
97,
142,
8,
37,
69,
173,
124,
180,
97,
70,
45,
91,
196,
126,
184,
135,
213,
104,
171,
89,
231,
63,
43,
42,
7,
245,
75,
165,
205,
182,
24,
50,
170,
217,
128,
112,
114,
215,
209,
145,
135,
235,
179,
212,
5,
81,
142,
199,
53,
221,
39,
239,
167,
21,
237,
168,
145,
249,
250,
108,
2,
247,
89,
73,
228,
227,
255,
155,
121,
157,
205,
96,
43,
32,
112,
209,
173,
96,
143,
43,
220,
140,
26,
205,
34,
34,
53,
157,
41,
167,
125,
235,
243,
85,
13,
14,
93,
109,
233,
186
]
}
}

212
test/fixtures/fix6.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68
]
},
"output": {
"type": "Buffer",
"data": [
198,
59,
91,
107,
222,
214,
31,
230,
112,
1,
199,
174,
17,
224,
194,
225,
138,
65,
58,
160,
31,
249,
102,
16,
74,
46,
85,
30,
232,
249,
120,
108,
38,
165,
105,
27,
12,
98,
98,
108,
130,
163,
16,
137,
116,
104,
153,
188,
5,
251,
163,
244,
0,
58,
1,
207,
25,
78,
188,
210,
205,
221,
48,
132,
72,
209,
11,
67,
14,
42,
218,
71,
148,
252,
126,
183,
60,
32,
93,
36,
125,
103,
191,
117,
82,
241,
190,
176,
1,
129,
118,
112,
139,
153,
178,
56,
61,
91,
52,
198
]
}
}

212
test/fixtures/fix7.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10
]
},
"output": {
"type": "Buffer",
"data": [
206,
241,
99,
120,
248,
163,
57,
30,
216,
86,
255,
192,
89,
193,
176,
17,
78,
62,
80,
149,
189,
235,
27,
157,
175,
248,
7,
19,
222,
64,
111,
199,
204,
163,
26,
16,
95,
221,
70,
32,
239,
4,
58,
162,
253,
237,
8,
51,
94,
3,
165,
186,
223,
210,
116,
101,
228,
82,
103,
76,
74,
44,
51,
117,
189,
140,
132,
230,
188,
243,
24,
158,
149,
93,
147,
226,
113,
195,
31,
24,
9,
19,
27,
132,
180,
152,
26,
65,
125,
144,
86,
167,
41,
144,
158,
204,
76,
46,
181,
110
]
}
}

212
test/fixtures/fix8.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75
]
},
"output": {
"type": "Buffer",
"data": [
153,
161,
201,
66,
87,
46,
242,
87,
136,
238,
151,
198,
129,
122,
62,
205,
142,
252,
109,
187,
238,
183,
63,
95,
240,
97,
220,
209,
37,
144,
237,
84,
251,
149,
152,
222,
89,
200,
208,
119,
213,
38,
65,
19,
2,
252,
193,
125,
94,
76,
182,
198,
243,
121,
253,
16,
45,
254,
82,
47,
146,
206,
41,
105,
254,
237,
236,
141,
118,
214,
197,
228,
59,
125,
45,
200,
61,
24,
110,
26,
235,
92,
175,
255,
85,
119,
57,
160,
145,
107,
206,
28,
62,
10,
166,
89,
7,
20,
246,
243
]
}
}

212
test/fixtures/fix9.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35
]
},
"output": {
"type": "Buffer",
"data": [
79,
215,
22,
29,
132,
130,
214,
248,
237,
124,
234,
54,
215,
78,
0,
211,
246,
222,
54,
91,
53,
2,
49,
40,
0,
202,
188,
25,
184,
121,
164,
235,
189,
97,
14,
0,
83,
166,
88,
62,
55,
49,
79,
153,
136,
193,
133,
206,
172,
99,
207,
73,
246,
216,
192,
107,
50,
206,
167,
242,
25,
180,
63,
184,
201,
61,
90,
242,
223,
192,
13,
140,
31,
240,
112,
157,
250,
90,
142,
3,
40,
12,
106,
63,
73,
42,
79,
82,
20,
41,
187,
173,
23,
85,
59,
253,
212,
191,
109,
46
]
}
}

20
test/fixtures/go-aes.js vendored Normal file
View File

@@ -0,0 +1,20 @@
'use strict'
module.exports = {
16: {
inputs: [
[47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47],
[24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24],
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
[25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25],
[48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48]
],
outputs: [
[121, 104, 0, 151, 57, 137, 22, 239, 234, 151, 58, 15, 100, 22, 228, 110, 85, 248, 249, 15, 145, 128, 223, 25, 192, 175, 132, 169, 98, 203, 231, 106, 224, 102, 206, 244, 29, 213, 36, 2, 26, 213, 94, 29, 134, 219, 136, 73, 212, 176, 33, 95, 198, 91, 148, 139, 132, 252, 182, 115, 116, 160, 146, 194, 0, 97, 181, 0, 193, 149, 21, 51, 248, 97, 32, 62, 86, 153, 238, 67, 38, 34, 55, 143, 70, 193, 99, 107, 31, 67, 90, 97, 55, 63, 69, 203, 33, 233, 74, 237],
[109, 172, 127, 179, 110, 222, 79, 219, 87, 76, 70, 204, 166, 110, 184, 229, 90, 49, 160, 252, 78, 58, 73, 51, 152, 218, 3, 200, 10, 124, 152, 117, 137, 40, 23, 127, 56, 57, 203, 31, 101, 227, 31, 198, 223, 86, 98, 120, 100, 86, 116, 144, 142, 127, 68, 175, 249, 232, 22, 83, 22, 68, 60, 230, 146, 22, 153, 193, 67, 5, 51, 253, 239, 210, 80, 31, 254, 103, 185, 145, 123, 99, 205, 175, 156, 144, 191, 67, 31, 236, 43, 98, 197, 235, 31, 50, 69, 228, 100, 64],
[191, 93, 126, 191, 180, 42, 118, 144, 28, 188, 211, 191, 211, 130, 170, 153, 134, 240, 179, 83, 75, 23, 42, 68, 158, 200, 123, 155, 57, 169, 152, 133, 33, 114, 90, 29, 131, 91, 70, 105, 83, 45, 40, 47, 77, 96, 97, 8, 40, 1, 110, 245, 106, 172, 152, 146, 5, 114, 132, 0, 179, 31, 44, 78, 19, 109, 92, 199, 226, 36, 12, 74, 180, 241, 224, 107, 83, 13, 167, 27, 251, 101, 193, 98, 49, 90, 225, 197, 75, 213, 144, 52, 235, 130, 92, 247, 219, 139, 209, 132],
[191, 110, 53, 190, 250, 44, 190, 136, 22, 209, 131, 200, 112, 31, 61, 183, 247, 95, 4, 249, 69, 147, 238, 74, 18, 71, 197, 115, 141, 226, 102, 92, 91, 128, 181, 172, 67, 109, 17, 165, 52, 10, 55, 31, 55, 225, 253, 140, 154, 35, 104, 62, 119, 103, 197, 152, 125, 134, 140, 181, 170, 76, 75, 114, 195, 188, 68, 197, 28, 47, 116, 82, 34, 128, 232, 122, 14, 229, 122, 161, 36, 212, 161, 164, 145, 86, 215, 233, 222, 50, 143, 89, 131, 32, 130, 196, 109, 36, 204, 254],
[97, 142, 8, 37, 69, 173, 124, 180, 97, 70, 45, 91, 196, 126, 184, 135, 213, 104, 171, 89, 231, 63, 43, 42, 7, 245, 75, 165, 205, 182, 24, 50, 170, 217, 128, 112, 114, 215, 209, 145, 135, 235, 179, 212, 5, 81, 142, 199, 53, 221, 39, 239, 167, 21, 237, 168, 145, 249, 250, 108, 2, 247, 89, 73, 228, 227, 255, 155, 121, 157, 205, 96, 43, 32, 112, 209, 173, 96, 143, 43, 220, 140, 26, 205, 34, 34, 53, 157, 41, 167, 125, 235, 243, 85, 13, 14, 93, 109, 233, 186]
]
}
}

View File

@@ -3,9 +3,9 @@
module.exports = { module.exports = {
curve: 'P-256', curve: 'P-256',
bob: { bob: {
private: [ private: new Buffer([
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170 181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
], ]),
public: new Buffer([ public: new Buffer([
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90 4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
]) ])