| 'use strict'; |
| |
| var assert = require('minimalistic-assert'); |
| var inherits = require('inherits'); |
| |
| var des = require('../des'); |
| var utils = des.utils; |
| var Cipher = des.Cipher; |
| |
| function DESState() { |
| this.tmp = new Array(2); |
| this.keys = null; |
| } |
| |
| function DES(options) { |
| Cipher.call(this, options); |
| |
| var state = new DESState(); |
| this._desState = state; |
| |
| this.deriveKeys(state, options.key); |
| } |
| inherits(DES, Cipher); |
| module.exports = DES; |
| |
| DES.create = function create(options) { |
| return new DES(options); |
| }; |
| |
| var shiftTable = [ |
| 1, 1, 2, 2, 2, 2, 2, 2, |
| 1, 2, 2, 2, 2, 2, 2, 1 |
| ]; |
| |
| DES.prototype.deriveKeys = function deriveKeys(state, key) { |
| state.keys = new Array(16 * 2); |
| |
| assert.equal(key.length, this.blockSize, 'Invalid key length'); |
| |
| var kL = utils.readUInt32BE(key, 0); |
| var kR = utils.readUInt32BE(key, 4); |
| |
| utils.pc1(kL, kR, state.tmp, 0); |
| kL = state.tmp[0]; |
| kR = state.tmp[1]; |
| for (var i = 0; i < state.keys.length; i += 2) { |
| var shift = shiftTable[i >>> 1]; |
| kL = utils.r28shl(kL, shift); |
| kR = utils.r28shl(kR, shift); |
| utils.pc2(kL, kR, state.keys, i); |
| } |
| }; |
| |
| DES.prototype._update = function _update(inp, inOff, out, outOff) { |
| var state = this._desState; |
| |
| var l = utils.readUInt32BE(inp, inOff); |
| var r = utils.readUInt32BE(inp, inOff + 4); |
| |
| // Initial Permutation |
| utils.ip(l, r, state.tmp, 0); |
| l = state.tmp[0]; |
| r = state.tmp[1]; |
| |
| if (this.type === 'encrypt') |
| this._encrypt(state, l, r, state.tmp, 0); |
| else |
| this._decrypt(state, l, r, state.tmp, 0); |
| |
| l = state.tmp[0]; |
| r = state.tmp[1]; |
| |
| utils.writeUInt32BE(out, l, outOff); |
| utils.writeUInt32BE(out, r, outOff + 4); |
| }; |
| |
| DES.prototype._pad = function _pad(buffer, off) { |
| var value = buffer.length - off; |
| for (var i = off; i < buffer.length; i++) |
| buffer[i] = value; |
| |
| return true; |
| }; |
| |
| DES.prototype._unpad = function _unpad(buffer) { |
| var pad = buffer[buffer.length - 1]; |
| for (var i = buffer.length - pad; i < buffer.length; i++) |
| assert.equal(buffer[i], pad); |
| |
| return buffer.slice(0, buffer.length - pad); |
| }; |
| |
| DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) { |
| var l = lStart; |
| var r = rStart; |
| |
| // Apply f() x16 times |
| for (var i = 0; i < state.keys.length; i += 2) { |
| var keyL = state.keys[i]; |
| var keyR = state.keys[i + 1]; |
| |
| // f(r, k) |
| utils.expand(r, state.tmp, 0); |
| |
| keyL ^= state.tmp[0]; |
| keyR ^= state.tmp[1]; |
| var s = utils.substitute(keyL, keyR); |
| var f = utils.permute(s); |
| |
| var t = r; |
| r = (l ^ f) >>> 0; |
| l = t; |
| } |
| |
| // Reverse Initial Permutation |
| utils.rip(r, l, out, off); |
| }; |
| |
| DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) { |
| var l = rStart; |
| var r = lStart; |
| |
| // Apply f() x16 times |
| for (var i = state.keys.length - 2; i >= 0; i -= 2) { |
| var keyL = state.keys[i]; |
| var keyR = state.keys[i + 1]; |
| |
| // f(r, k) |
| utils.expand(l, state.tmp, 0); |
| |
| keyL ^= state.tmp[0]; |
| keyR ^= state.tmp[1]; |
| var s = utils.substitute(keyL, keyR); |
| var f = utils.permute(s); |
| |
| var t = l; |
| l = (r ^ f) >>> 0; |
| r = t; |
| } |
| |
| // Reverse Initial Permutation |
| utils.rip(l, r, out, off); |
| }; |