feistel-cipher
Advanced tools
Comparing version 1.1.6 to 1.2.0
/// <reference types="node" /> | ||
/** | ||
* The Cipher class is the main entry point to the Feistel cipher. | ||
* You should instantiate it with the key you want to use and the number of rounds to apply. | ||
* The Cipher class is the main entry point to the Feistel cipher if you want to use the SHA-256 hash function at each round. | ||
* You should instantiate it with the base key you want to use and the number of rounds to apply. | ||
* For better security, you should choose a 256-bit key or longer, and 10 rounds is a good start. | ||
* Once instantiated, use the apply() or unapply() methods on the Cipher instance with the appropriate data. | ||
* Once instantiated, use the encrypt() or decrypt() methods on the Cipher instance with the appropriate data. | ||
* | ||
* @throws wrong arguments | ||
*/ | ||
@@ -24,10 +26,7 @@ export declare class Cipher { | ||
* @returns {string} The deobfuscated string. | ||
* @throws invalid obfuscated data | ||
*/ | ||
decrypt(obfuscated: Buffer): string; | ||
private add; | ||
private extract; | ||
private round; | ||
private split; | ||
private xor; | ||
} | ||
//# sourceMappingURL=feistel.d.ts.map |
@@ -24,12 +24,19 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const crypto_1 = require("crypto"); | ||
const sha256 = (msg) => crypto_1.createHash('sha256').update(msg).digest(); | ||
const hash_1 = require("./utils/hash"); | ||
const padding_1 = require("./utils/padding"); | ||
const strings_1 = require("./utils/strings"); | ||
const xor_1 = require("./utils/xor"); | ||
/** | ||
* The Cipher class is the main entry point to the Feistel cipher. | ||
* You should instantiate it with the key you want to use and the number of rounds to apply. | ||
* The Cipher class is the main entry point to the Feistel cipher if you want to use the SHA-256 hash function at each round. | ||
* You should instantiate it with the base key you want to use and the number of rounds to apply. | ||
* For better security, you should choose a 256-bit key or longer, and 10 rounds is a good start. | ||
* Once instantiated, use the apply() or unapply() methods on the Cipher instance with the appropriate data. | ||
* Once instantiated, use the encrypt() or decrypt() methods on the Cipher instance with the appropriate data. | ||
* | ||
* @throws wrong arguments | ||
*/ | ||
class Cipher { | ||
constructor(key, rounds) { | ||
if (key === '' || rounds === 0) { | ||
throw new Error('wrong arguments'); | ||
} | ||
this.key = key; | ||
@@ -46,8 +53,8 @@ this.rounds = rounds; | ||
if (data.length % 2 == 1) { | ||
data = data.padStart(data.length + 1, PADDING_CHARACTER); | ||
data = data.padStart(data.length + 1, padding_1.PADDING_CHARACTER); | ||
} | ||
// Apply the Feistel cipher | ||
let parts = this.split(data); | ||
let parts = strings_1.split(data); | ||
for (let i = 0; i < this.rounds; ++i) { // eslint-disable-line no-loops/no-loops | ||
const tmp = this.xor(parts[0], this.round(parts[1], i)); | ||
const tmp = xor_1.xor(parts[0], this.round(parts[1], i)); | ||
parts = [parts[1], tmp]; | ||
@@ -62,2 +69,3 @@ } | ||
* @returns {string} The deobfuscated string. | ||
* @throws invalid obfuscated data | ||
*/ | ||
@@ -70,55 +78,20 @@ decrypt(obfuscated) { | ||
// Apply Feistel cipher | ||
const parts = this.split(o); | ||
const parts = strings_1.split(o); | ||
let a = parts[1]; | ||
let b = parts[0]; | ||
for (let i = 0; i < this.rounds; ++i) { // eslint-disable-line no-loops/no-loops | ||
const tmp = this.xor(a, this.round(b, this.rounds - i - 1)); | ||
const tmp = xor_1.xor(a, this.round(b, this.rounds - i - 1)); | ||
a = b; | ||
b = tmp; | ||
} | ||
return unpad(b + a); | ||
return padding_1.unpad(b + a); | ||
} | ||
// Feistel implementation | ||
// Add adds two strings in the sense that each charCode are added | ||
add(str1, str2) { | ||
if (str1.length != str2.length) { | ||
throw new Error('to be added, strings must be of the same length'); | ||
} | ||
return Array.from(str1).reduce((addedString, c, idx) => addedString + String.fromCharCode(c.charCodeAt(0) + str2.charCodeAt(idx)), ''); | ||
} | ||
// Extract returns an extraction of the passed string of the desired length from the passed start index. | ||
// If the desired length is too long, the key string is repeated. | ||
extract(from, startIndex, desiredLength) { | ||
startIndex = startIndex % from.length; | ||
const lengthNeeded = startIndex + desiredLength; | ||
return from.repeat(Math.ceil(lengthNeeded / from.length)).substr(startIndex, desiredLength); | ||
} | ||
// Round is the function applied at each round of the obfuscation process to the right side of the Feistel cipher | ||
round(item, index) { | ||
const addition = this.add(item, this.extract(this.key, index, item.length)); | ||
const hashed = sha256(addition).toString('hex'); | ||
return this.extract(hashed, index, item.length); | ||
const addition = strings_1.add(item, strings_1.extract(this.key, index, item.length)); | ||
const hashed = hash_1.Hash(addition).toString('hex'); | ||
return strings_1.extract(hashed, index, item.length); | ||
} | ||
// Split splits a string in two equal parts | ||
split(str) { | ||
if (str.length % 2 != 0) { | ||
throw new Error('invalid string length: cannot be split'); | ||
} | ||
const half = str.length / 2; | ||
return [str.substr(0, half), str.substr(half)]; | ||
} | ||
// Xor function XOR two strings in the sense that each charCode are xored | ||
xor(str1, str2) { | ||
return Array.from(str1).reduce((xored, c, idx) => xored + String.fromCharCode(c.charCodeAt(0) ^ str2.charCodeAt(idx)), ''); | ||
} | ||
} | ||
exports.Cipher = Cipher; | ||
//--- PADDING utilities | ||
// Unicode U+0002: start of text | ||
const PADDING_CHARACTER = '\u0002'; | ||
const unpad = (str) => { | ||
while (str.startsWith(PADDING_CHARACTER)) { // eslint-disable-line no-loops/no-loops | ||
str = str.substr(1); | ||
} | ||
return str; | ||
}; |
export * from './feistel'; | ||
export * from './custom'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -28,1 +28,2 @@ "use strict"; | ||
__export(require("./feistel")); | ||
__export(require("./custom")); |
{ | ||
"name": "feistel-cipher", | ||
"version": "1.1.6", | ||
"version": "1.2.0", | ||
"description": "Feistel cipher implementation for (almost) format-preserving encryption", | ||
@@ -11,3 +11,4 @@ "main": "dist/lib/src/typescript/index.js", | ||
"test": "tsc && mocha 'test/src/typescript/node.spec.ts' --require ts-node/register && browserify ./dist/test/src/typescript/browser.spec.js -o dist/test/src/typescript/index.js && live-server --port=9001 --mount=/:test/src/typescript", | ||
"fix-test": "eslint test --ext .ts --fix" | ||
"fix-test": "eslint test --ext .ts --fix", | ||
"test-node": "tsc && mocha 'test/src/typescript/node.spec.ts' --require ts-node/register" | ||
}, | ||
@@ -14,0 +15,0 @@ "repository": { |
@@ -43,3 +43,3 @@ # feistel-cipher | ||
To get an obfuscated string from a source data, first instantiate a `Cipher` object, passing it a key and a number of rounds. | ||
To get an obfuscated string from a source data using the SHA-256 hashing function at each round, first instantiate a `Cipher` object, passing it a key and a number of rounds. | ||
Then, use the `encrypt()` method with the source data as argument. The result will be a `Buffer`. | ||
@@ -64,7 +64,17 @@ To ensure maximum security, I recommend you use a 256-bit key or longer and a minimum of 10 rounds. | ||
``` | ||
_NB: This is the same default behaviour as in my Golang implementation (see below)._ | ||
You may also want to use your own set of keys with `CustomCipher` and a number of rounds depending on the number of provided keys, eg. | ||
```typescript | ||
const cipher = new feistel.CustomCipher([ | ||
'1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', | ||
'9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba', | ||
'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789' | ||
]) | ||
``` | ||
### Other implementations | ||
For those interested, I also made another implementation this Feistel cipher in [Golang](https://github.com/cyrildever/feistel). | ||
For those interested, I also made another implementation of this Feistel cipher in [Golang](https://github.com/cyrildever/feistel). | ||
@@ -71,0 +81,0 @@ |
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
32364
25
518
87