encrypter.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. var MODES = require('./modes')
  2. var AuthCipher = require('./authCipher')
  3. var Buffer = require('safe-buffer').Buffer
  4. var StreamCipher = require('./streamCipher')
  5. var Transform = require('cipher-base')
  6. var aes = require('./aes')
  7. var ebtk = require('evp_bytestokey')
  8. var inherits = require('inherits')
  9. function Cipher (mode, key, iv) {
  10. Transform.call(this)
  11. this._cache = new Splitter()
  12. this._cipher = new aes.AES(key)
  13. this._prev = Buffer.from(iv)
  14. this._mode = mode
  15. this._autopadding = true
  16. }
  17. inherits(Cipher, Transform)
  18. Cipher.prototype._update = function (data) {
  19. this._cache.add(data)
  20. var chunk
  21. var thing
  22. var out = []
  23. while ((chunk = this._cache.get())) {
  24. thing = this._mode.encrypt(this, chunk)
  25. out.push(thing)
  26. }
  27. return Buffer.concat(out)
  28. }
  29. var PADDING = Buffer.alloc(16, 0x10)
  30. Cipher.prototype._final = function () {
  31. var chunk = this._cache.flush()
  32. if (this._autopadding) {
  33. chunk = this._mode.encrypt(this, chunk)
  34. this._cipher.scrub()
  35. return chunk
  36. }
  37. if (!chunk.equals(PADDING)) {
  38. this._cipher.scrub()
  39. throw new Error('data not multiple of block length')
  40. }
  41. }
  42. Cipher.prototype.setAutoPadding = function (setTo) {
  43. this._autopadding = !!setTo
  44. return this
  45. }
  46. function Splitter () {
  47. this.cache = Buffer.allocUnsafe(0)
  48. }
  49. Splitter.prototype.add = function (data) {
  50. this.cache = Buffer.concat([this.cache, data])
  51. }
  52. Splitter.prototype.get = function () {
  53. if (this.cache.length > 15) {
  54. var out = this.cache.slice(0, 16)
  55. this.cache = this.cache.slice(16)
  56. return out
  57. }
  58. return null
  59. }
  60. Splitter.prototype.flush = function () {
  61. var len = 16 - this.cache.length
  62. var padBuff = Buffer.allocUnsafe(len)
  63. var i = -1
  64. while (++i < len) {
  65. padBuff.writeUInt8(len, i)
  66. }
  67. return Buffer.concat([this.cache, padBuff])
  68. }
  69. function createCipheriv (suite, password, iv) {
  70. var config = MODES[suite.toLowerCase()]
  71. if (!config) throw new TypeError('invalid suite type')
  72. if (typeof password === 'string') password = Buffer.from(password)
  73. if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
  74. if (typeof iv === 'string') iv = Buffer.from(iv)
  75. if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
  76. if (config.type === 'stream') {
  77. return new StreamCipher(config.module, password, iv)
  78. } else if (config.type === 'auth') {
  79. return new AuthCipher(config.module, password, iv)
  80. }
  81. return new Cipher(config.module, password, iv)
  82. }
  83. function createCipher (suite, password) {
  84. var config = MODES[suite.toLowerCase()]
  85. if (!config) throw new TypeError('invalid suite type')
  86. var keys = ebtk(password, false, config.key, config.iv)
  87. return createCipheriv(suite, keys.key, keys.iv)
  88. }
  89. exports.createCipheriv = createCipheriv
  90. exports.createCipher = createCipher