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