feistel-cipher
Advanced tools
Comparing version 1.3.14 to 1.4.0
@@ -18,9 +18,23 @@ import { Readable } from './utils/base256'; | ||
/** | ||
* Obfuscate the passed data | ||
* | ||
* @param {string} data - The data to obfuscate | ||
* @returns {Readable} The byte array of the obfuscated result. | ||
*/ | ||
* Obfuscate the passed data | ||
* | ||
* @param {string} data - The data to obfuscate | ||
* @returns {Readable} The readable string of the obfuscated result. | ||
*/ | ||
encrypt(data: string): Readable; | ||
/** | ||
* Obfuscate numbers | ||
* | ||
* @param {number} n - The data to obfuscate | ||
* @returns {number} The obfuscated number. | ||
*/ | ||
encryptNumber(n: number): number; | ||
/** | ||
*Obfuscate strings | ||
* | ||
* @param {string} str - The data to obfuscate | ||
* @returns {Readable} The readable string of the obfuscated result. | ||
*/ | ||
encryptString(str: string): Readable; | ||
/** | ||
* Deobfuscate the passed data | ||
@@ -32,4 +46,12 @@ * | ||
decrypt(obfuscated: Readable): string; | ||
/** | ||
* Deobfuscate the passed number | ||
* | ||
* @param {number} obfuscated - The number to use | ||
* @returns {number} The deobfuscated number. | ||
*/ | ||
decryptNumber(obfuscated: number): number; | ||
private round; | ||
private roundBytes; | ||
} | ||
//# sourceMappingURL=fpe.d.ts.map |
@@ -27,2 +27,3 @@ "use strict"; | ||
const base256_1 = require("./utils/base256"); | ||
const bytes_1 = require("./utils/bytes"); | ||
const hash_1 = require("./utils/hash"); | ||
@@ -50,7 +51,7 @@ const strings_1 = require("./utils/strings"); | ||
/** | ||
* Obfuscate the passed data | ||
* | ||
* @param {string} data - The data to obfuscate | ||
* @returns {Readable} The byte array of the obfuscated result. | ||
*/ | ||
* Obfuscate the passed data | ||
* | ||
* @param {string} data - The data to obfuscate | ||
* @returns {Readable} The readable string of the obfuscated result. | ||
*/ | ||
encrypt(data) { | ||
@@ -80,2 +81,51 @@ let parts = (0, strings_1.split)(data); | ||
/** | ||
* Obfuscate numbers | ||
* | ||
* @param {number} n - The data to obfuscate | ||
* @returns {number} The obfuscated number. | ||
*/ | ||
encryptNumber(n) { | ||
if (n < 256) { | ||
if (n === 0) { | ||
return 0; | ||
} | ||
const buf = Buffer.alloc(2); | ||
buf.writeUInt16BE(n); | ||
return (0, base256_1.readable2Buffer)(this.encrypt(buf.toString())).readUInt16BE(); | ||
} | ||
let buf = Buffer.alloc(4); | ||
buf.writeUInt32BE(n); | ||
let parts = (0, bytes_1.splitBytes)(buf); | ||
// Apply the FPE Feistel cipher | ||
for (let i = 0; i < this.rounds; ++i) { // eslint-disable-line no-loops/no-loops | ||
const left = parts[1]; | ||
if (parts[1].length < parts[0].length) { | ||
parts[1] = Buffer.concat([parts[1], xor_1.NEUTRAL]); | ||
} | ||
const rnd = this.roundBytes(parts[1], i); | ||
let tmp = parts[0]; | ||
let crop = false; | ||
if (tmp.length + 1 === rnd.length) { | ||
tmp = Buffer.concat([tmp, xor_1.NEUTRAL]); | ||
crop = true; | ||
} | ||
let right = (0, xor_1.xorBytes)(tmp, rnd); | ||
if (crop) { | ||
right = right.fill(right, 0, right.length - 1, 'binary'); | ||
} | ||
parts = [left, right]; | ||
} | ||
buf = Buffer.concat([parts[0], parts[1]]); | ||
return buf.readUInt32BE(); | ||
} | ||
/** | ||
*Obfuscate strings | ||
* | ||
* @param {string} str - The data to obfuscate | ||
* @returns {Readable} The readable string of the obfuscated result. | ||
*/ | ||
encryptString(str) { | ||
return this.encrypt(str); | ||
} | ||
/** | ||
* Deobfuscate the passed data | ||
@@ -119,2 +169,52 @@ * | ||
} | ||
/** | ||
* Deobfuscate the passed number | ||
* | ||
* @param {number} obfuscated - The number to use | ||
* @returns {number} The deobfuscated number. | ||
*/ | ||
decryptNumber(obfuscated) { | ||
if (obfuscated === 0) { | ||
return 0; | ||
} | ||
let buf = Buffer.alloc(2); | ||
let short = true; | ||
try { | ||
buf.writeUInt16BE(obfuscated); | ||
} | ||
catch (e) { | ||
buf = Buffer.alloc(4); | ||
buf.writeUInt32BE(obfuscated); | ||
short = false; | ||
} | ||
// Apply the FPE Feistel cipher | ||
const parts = (0, bytes_1.splitBytes)(buf); | ||
let [left, right] = parts; | ||
// Compensating the way Split() works by moving the first byte at right to the end of left if using an odd number of rounds | ||
if (this.rounds % 2 !== 0 && left.length !== right.length) { | ||
left = Buffer.concat([left, Buffer.from([right[0]])]); | ||
right = Buffer.alloc(0).fill(right, 1, undefined, 'binary'); | ||
} | ||
for (let i = 0; i < this.rounds; ++i) { // eslint-disable-line no-loops/no-loops | ||
let leftRound = left; | ||
if (left.length < right.length) { | ||
leftRound = Buffer.concat([leftRound, xor_1.NEUTRAL]); | ||
} | ||
const rnd = this.roundBytes(leftRound, this.rounds - i - 1); | ||
let rightRound = right; | ||
let extended = false; | ||
if (rightRound.length + 1 === rnd.length) { | ||
rightRound = Buffer.concat([rightRound, Buffer.alloc(0).fill(left, left.length - 1, undefined, 'binary')]); | ||
extended = true; | ||
} | ||
let tmp = (0, xor_1.xorBytes)(rightRound, rnd); | ||
right = left; | ||
if (extended) { | ||
tmp = Buffer.alloc(0).fill(tmp, 0, tmp.length - 1, 'binary'); | ||
} | ||
left = tmp; | ||
} | ||
buf = Buffer.concat([left, right]); | ||
return short ? buf.readUInt16BE() : buf.readUInt32BE(); | ||
} | ||
// Feistel implementation | ||
@@ -127,3 +227,10 @@ // Round is the function applied at each round of the obfuscation process to the right side of the Feistel cipher | ||
} | ||
// RoundBytes operates like round() on byte arrays | ||
roundBytes(item, index) { | ||
const addition = (0, bytes_1.addBytes)(item, (0, bytes_1.extractBytes)(Buffer.from(this.key), index, item.length)); | ||
const hashed = (0, hash_1.H)(addition, this.engine); | ||
const extracted = (0, strings_1.extract)(hashed.toString('hex'), index, item.length); | ||
return Buffer.from([...extracted].map(c => Buffer.from(c).readInt8())); | ||
} | ||
} | ||
exports.FPECipher = FPECipher; |
@@ -39,2 +39,6 @@ "use strict"; | ||
exports.SHA_3 = exports.SHA_256 = exports.KECCAK = exports.BLAKE2b = void 0; | ||
if (typeof window !== 'undefined') { | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-var-requires | ||
window.Buffer = window.Buffer || require('buffer').Buffer; | ||
} | ||
__exportStar(require("./feistel"), exports); | ||
@@ -41,0 +45,0 @@ __exportStar(require("./fpe"), exports); |
@@ -0,3 +1,6 @@ | ||
/// <reference types="node" /> | ||
export declare const xor: (str1: string, str2: string) => string; | ||
export declare const xorBytes: (bytes1: Buffer, bytes2: Buffer) => Buffer; | ||
export declare const NEUTRAL_BYTE: string; | ||
export declare const NEUTRAL: Buffer; | ||
//# sourceMappingURL=xor.d.ts.map |
@@ -24,3 +24,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.NEUTRAL_BYTE = exports.xor = void 0; | ||
exports.NEUTRAL = exports.NEUTRAL_BYTE = exports.xorBytes = exports.xor = void 0; | ||
// xor applies XOR operation on two strings in the sense that each charCode are xored | ||
@@ -31,2 +31,8 @@ const xor = (str1, str2) => { | ||
exports.xor = xor; | ||
// xorBytes applies XOR operation on thow byte arrays in the sense that each bit value are xored | ||
const xorBytes = (bytes1, bytes2) => { | ||
return Buffer.from(bytes1).reduce((xored, c, idx) => Buffer.concat([xored, Buffer.from([c ^ bytes2[idx]])]), Buffer.alloc(0)); | ||
}; | ||
exports.xorBytes = xorBytes; | ||
exports.NEUTRAL_BYTE = Buffer.from([0]).toString(); | ||
exports.NEUTRAL = Buffer.from([0]); |
{ | ||
"name": "feistel-cipher", | ||
"version": "1.3.14", | ||
"version": "1.4.0", | ||
"description": "Feistel cipher implementation for format-preserving encryption", | ||
@@ -39,10 +39,10 @@ "main": "dist/lib/src/typescript/index.js", | ||
"@types/keccak": "^3.0.1", | ||
"@types/mocha": "^9.1.1", | ||
"@types/node": "^18.7.15", | ||
"@typescript-eslint/eslint-plugin": "^5.36.2", | ||
"@typescript-eslint/parser": "^5.36.2", | ||
"@types/mocha": "^10.0.0", | ||
"@types/node": "^18.8.5", | ||
"@typescript-eslint/eslint-plugin": "^5.40.0", | ||
"@typescript-eslint/parser": "^5.40.0", | ||
"blakejs": "^1.2.1", | ||
"browserify": "17.0.0", | ||
"chai": "^4.3.6", | ||
"eslint": "^8.23.0", | ||
"eslint": "^8.25.0", | ||
"eslint-plugin-no-loops": "~0.3.0", | ||
@@ -53,3 +53,3 @@ "keccak": "^3.0.2", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.8.2" | ||
"typescript": "^4.8.4" | ||
}, | ||
@@ -56,0 +56,0 @@ "resolutions": { |
@@ -84,2 +84,11 @@ # feistel-cipher | ||
If you want to use FPE for numbers, you might want to use the `encryptNumber()` method on the `FPECipher` which will return a number that you may pad if need be to match your requirements: | ||
```typescript | ||
const obfuscatedNumber = cipher.encryptNumber(sourceNumber) | ||
const deobfuscatedNumber = cipher.decryptNumber(obfuscatedNumber) | ||
assert(sourceNumber == deobfuscatedNumber) | ||
``` | ||
_NB: For stability and security purposes, the number `0` always returns itself._ | ||
### Dependencies | ||
@@ -86,0 +95,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
57401
34
1034
120