Ryan X. Charles
11 years ago
8 changed files with 464 additions and 28305 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,41 @@ |
|||||
|
'use strict'; |
||||
|
var imports = require('soop').imports(); |
||||
|
var sjcl = require('sjcl'); |
||||
|
var ECIES = require('../common/ECIES'); |
||||
|
|
||||
|
ECIES.symmetricEncrypt = function(key, iv, message) { |
||||
|
var skey = sjcl.codec.hex.toBits(key.toString('hex')); |
||||
|
var siv = sjcl.codec.hex.toBits(iv.toString('hex')); |
||||
|
var smessage = sjcl.codec.hex.toBits(message.toString('hex')); |
||||
|
|
||||
|
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."](); |
||||
|
var params = {iv: siv, ks: 256, ts: 128, iter: 1000, mode: 'cbc'}; |
||||
|
var encrypted = sjcl.encrypt(skey, smessage, params); |
||||
|
var enchex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(JSON.parse(encrypted).ct)); |
||||
|
|
||||
|
var encbuf = new Buffer(enchex, 'hex'); |
||||
|
|
||||
|
var r = Buffer.concat([iv, encbuf]); |
||||
|
|
||||
|
return r; |
||||
|
}; |
||||
|
|
||||
|
ECIES.symmetricDecrypt = function(key, encrypted) { |
||||
|
var skey = sjcl.codec.hex.toBits(key.toString('hex')); |
||||
|
var iv = encrypted.slice(0, 16); |
||||
|
var todecrypt = encrypted.slice(16, encrypted.length); |
||||
|
|
||||
|
var siv = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(iv.toString('hex'))); |
||||
|
var sct = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(todecrypt.toString('hex'))); |
||||
|
|
||||
|
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."](); |
||||
|
var obj = {iv: siv, v: 1, iter: 1000, ks: 256, ts: 128, mode: 'cbc', adata: '', cipher: 'aes', ct: sct}; |
||||
|
var str = JSON.stringify(obj); |
||||
|
|
||||
|
var decrypted = sjcl.decrypt(skey, str); |
||||
|
var decbuf = new Buffer(decrypted); |
||||
|
|
||||
|
return decbuf; |
||||
|
}; |
||||
|
|
||||
|
module.exports = require('soop')(ECIES); |
@ -0,0 +1,113 @@ |
|||||
|
'use strict'; |
||||
|
var imports = require('soop').imports(); |
||||
|
var coinUtil = imports.coinUtil || require('../../util'); |
||||
|
var Point = imports.Point || require('../Point'); |
||||
|
var SecureRandom = imports.SecureRandom || require('../SecureRandom'); |
||||
|
var Key = imports.Key || require('../Key'); |
||||
|
|
||||
|
// http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
|
||||
|
var ECIES = function() { |
||||
|
}; |
||||
|
|
||||
|
ECIES.encryptObj = function(pubkey, message, r, iv) { |
||||
|
var ecies = new ECIES(); |
||||
|
ecies.KB = pubkey; |
||||
|
ecies.message = message; |
||||
|
r = ecies.r = ecies.rand(r); |
||||
|
var R = ecies.R; |
||||
|
var S = ecies.S = ecies.getSfromPubkey(); |
||||
|
var buf = ECIES.kdf(S); |
||||
|
var kE = ecies.kE = buf.slice(0, 32); |
||||
|
var kM = ecies.kM = buf.slice(32, 64); |
||||
|
iv = iv || SecureRandom.getRandomBuffer(16); |
||||
|
var c = ecies.c = ECIES.symmetricEncrypt(kE, iv, message); |
||||
|
var d = ecies.d = ECIES.mac(kM, c); |
||||
|
return ecies; |
||||
|
}; |
||||
|
|
||||
|
ECIES.encrypt = function(pubkey, message, r, iv) { |
||||
|
var ecies = ECIES.encryptObj(pubkey, message, r, iv); |
||||
|
var key = new Key(); |
||||
|
key.compressed = false; |
||||
|
key.public = ecies.R.toUncompressedPubKey(); |
||||
|
key.compressed = true; |
||||
|
var Rbuf = key.public; |
||||
|
var buf = Buffer.concat([Rbuf, ecies.c, ecies.d]); |
||||
|
return buf; |
||||
|
}; |
||||
|
|
||||
|
ECIES.decryptObj = function(ecies) { |
||||
|
var kB = ecies.kB; |
||||
|
var R = ecies.R; |
||||
|
var c = ecies.c; |
||||
|
var d = ecies.d; |
||||
|
var P = Point.multiply(R, kB); |
||||
|
var S = P.x.toBuffer({size: 32}); |
||||
|
var buf = ECIES.kdf(S); |
||||
|
var kE = ecies.kE = buf.slice(0, 32); |
||||
|
var kM = ecies.kM = buf.slice(32, 64); |
||||
|
var d2 = ECIES.mac(kM, c); |
||||
|
if (d.toString('hex') !== d2.toString('hex')) |
||||
|
throw new Error('MAC check incorrect. Data is invalid.'); |
||||
|
var decrypted = ECIES.symmetricDecrypt(kE, c); |
||||
|
return decrypted; |
||||
|
}; |
||||
|
|
||||
|
ECIES.decrypt = function(privkey, buf) { |
||||
|
if (buf.length < 33 + 0 + 64) |
||||
|
throw new Error('invalid length of encrypted data'); |
||||
|
var ecies = new ECIES(); |
||||
|
ecies.kB = privkey; |
||||
|
var Rbuf = buf.slice(0, 33); |
||||
|
var key = new Key(); |
||||
|
key.public = Rbuf; |
||||
|
key.compressed = false; |
||||
|
ecies.R = Point.fromUncompressedPubKey(key.public); |
||||
|
ecies.c = buf.slice(33, buf.length - 64); |
||||
|
ecies.d = buf.slice(buf.length - 64, buf.length); |
||||
|
return ECIES.decryptObj(ecies); |
||||
|
}; |
||||
|
|
||||
|
ECIES.kdf = function(S) { |
||||
|
var buf = coinUtil.sha512(S); |
||||
|
return buf; |
||||
|
}; |
||||
|
|
||||
|
ECIES.mac = function(data, key) { |
||||
|
var buf = coinUtil.sha512hmac(data, key); |
||||
|
return buf; |
||||
|
}; |
||||
|
|
||||
|
ECIES.prototype.rand = function(r) { |
||||
|
if (r) { |
||||
|
this.key = new Key(); |
||||
|
this.key.private = r; |
||||
|
this.key.regenerateSync(); |
||||
|
} else { |
||||
|
this.key = Key.generateSync(); |
||||
|
}; |
||||
|
this.r = this.key.private; |
||||
|
this.key.compressed = false; |
||||
|
this.R = Point.fromUncompressedPubKey(this.key.public); |
||||
|
return this.r; |
||||
|
}; |
||||
|
|
||||
|
ECIES.prototype.getSfromPubkey = function() { |
||||
|
var key2 = new Key(); |
||||
|
key2.public = this.KB; |
||||
|
key2.compressed = false; |
||||
|
var KBP = Point.fromUncompressedPubKey(key2.public); |
||||
|
this.P = Point.multiply(KBP, this.r); |
||||
|
this.S = this.P.x.toBuffer({size: 32}); |
||||
|
return this.S; |
||||
|
}; |
||||
|
|
||||
|
ECIES.prototype.getSfromPrivkey = function() { |
||||
|
var R = this.R; |
||||
|
var kB = this.kB; |
||||
|
var SP = Point.multiply(R, kB); |
||||
|
var S = SP.x.toBuffer({size: 32}); |
||||
|
return S; |
||||
|
}; |
||||
|
|
||||
|
module.exports = require('soop')(ECIES); |
Loading…
Reference in new issue