487 lines
17 KiB
JavaScript
487 lines
17 KiB
JavaScript
/**
|
|
* Twofish cipher tests.
|
|
*
|
|
* Test vectors from the official Twofish paper:
|
|
* https://www.schneier.com/academic/twofish/
|
|
*
|
|
* Note: PKCS5 padding adds an extra block when input is exactly block-aligned.
|
|
* Round-trip tests verify correct encryption/decryption behavior.
|
|
*
|
|
* @author Medjedtxm
|
|
* @copyright Crown Copyright 2026
|
|
* @license Apache-2.0
|
|
*/
|
|
|
|
import TestRegister from "../../lib/TestRegister.mjs";
|
|
|
|
TestRegister.addTests([
|
|
// ============================================================
|
|
// OFFICIAL TEST VECTORS from Bruce Schneier's Twofish paper:
|
|
// https://www.schneier.com/academic/twofish/
|
|
// https://www.schneier.com/wp-content/uploads/2015/12/ecb_ival.txt
|
|
// ============================================================
|
|
{
|
|
name: "Twofish Official Vector: 128-bit zero key, zero plaintext",
|
|
input: "00000000000000000000000000000000",
|
|
expectedOutput: "9f589f5cf6122c32b6bfec2f2ae8c35a",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00000000000000000000000000000000", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Hex", "NO"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Official Vector: 192-bit zero key, zero plaintext",
|
|
input: "00000000000000000000000000000000",
|
|
expectedOutput: "efa71f788965bd4453f860178fc19101",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "000000000000000000000000000000000000000000000000", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Hex", "NO"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Official Vector: 256-bit zero key, zero plaintext",
|
|
input: "00000000000000000000000000000000",
|
|
expectedOutput: "57ff739d4dc92c1bd7fc01700cc8216f",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "0000000000000000000000000000000000000000000000000000000000000000", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Hex", "NO"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
// Decrypt verification of official vectors
|
|
{
|
|
name: "Twofish Official Vector Decrypt: 128-bit zero key",
|
|
input: "9f589f5cf6122c32b6bfec2f2ae8c35a",
|
|
expectedOutput: "00000000000000000000000000000000",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00000000000000000000000000000000", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Hex", "NO"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
// ============================================================
|
|
// Round-trip tests for ECB mode with various key sizes
|
|
// ============================================================
|
|
{
|
|
name: "Twofish Round-trip: ECB 128-bit key",
|
|
input: "Hello, World!!!",
|
|
expectedOutput: "Hello, World!!!",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: ECB 192-bit key",
|
|
input: "Testing Twofish with 192-bit key",
|
|
expectedOutput: "Testing Twofish with 192-bit key",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: ECB 256-bit key",
|
|
input: "Testing Twofish with 256-bit key encryption",
|
|
expectedOutput: "Testing Twofish with 256-bit key encryption",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Round-trip tests for CBC mode
|
|
{
|
|
name: "Twofish Round-trip: CBC 128-bit key",
|
|
input: "The quick brown fox jumps over the lazy dog",
|
|
expectedOutput: "The quick brown fox jumps over the lazy dog",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: CBC 192-bit key",
|
|
input: "Testing Twofish with 192-bit key in CBC mode",
|
|
expectedOutput: "Testing Twofish with 192-bit key in CBC mode",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: CBC 256-bit key",
|
|
input: "Testing Twofish with 256-bit key in CBC mode",
|
|
expectedOutput: "Testing Twofish with 256-bit key in CBC mode",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"CBC", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Round-trip tests for CFB mode
|
|
{
|
|
name: "Twofish Round-trip: CFB 128-bit key",
|
|
input: "Testing Twofish CFB mode encryption",
|
|
expectedOutput: "Testing Twofish CFB mode encryption",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "deadbeefcafebabe0123456789abcdef", option: "Hex" },
|
|
{ string: "0102030405060708090a0b0c0d0e0f10", option: "Hex" },
|
|
"CFB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "deadbeefcafebabe0123456789abcdef", option: "Hex" },
|
|
{ string: "0102030405060708090a0b0c0d0e0f10", option: "Hex" },
|
|
"CFB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Round-trip tests for OFB mode
|
|
{
|
|
name: "Twofish Round-trip: OFB 128-bit key",
|
|
input: "Testing Twofish OFB mode encryption",
|
|
expectedOutput: "Testing Twofish OFB mode encryption",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"OFB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
"OFB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Round-trip tests for CTR mode
|
|
{
|
|
name: "Twofish Round-trip: CTR 128-bit key",
|
|
input: "Testing Twofish CTR mode encryption",
|
|
expectedOutput: "Testing Twofish CTR mode encryption",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "00000000000000000000000000000001", option: "Hex" },
|
|
"CTR", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "00000000000000000000000000000001", option: "Hex" },
|
|
"CTR", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// UTF8 key tests
|
|
{
|
|
name: "Twofish Round-trip: UTF8 key (16 bytes)",
|
|
input: "Secret message!",
|
|
expectedOutput: "Secret message!",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "MySecretPassword", option: "UTF8" },
|
|
{ string: "InitVectorHere!!", option: "UTF8" },
|
|
"CBC", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "MySecretPassword", option: "UTF8" },
|
|
{ string: "InitVectorHere!!", option: "UTF8" },
|
|
"CBC", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Various input length tests
|
|
{
|
|
name: "Twofish Round-trip: 1 byte input",
|
|
input: "A",
|
|
expectedOutput: "A",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: 15 byte input",
|
|
input: "123456789012345",
|
|
expectedOutput: "123456789012345",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: 16 byte input (exact block)",
|
|
input: "1234567890123456",
|
|
expectedOutput: "1234567890123456",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: 17 byte input",
|
|
input: "12345678901234567",
|
|
expectedOutput: "12345678901234567",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Twofish Round-trip: 32 byte input (two blocks)",
|
|
input: "12345678901234567890123456789012",
|
|
expectedOutput: "12345678901234567890123456789012",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Binary data test
|
|
{
|
|
name: "Twofish Round-trip: Binary data",
|
|
input: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
|
expectedOutput: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
"CBC", "Raw", "Hex", "PKCS5"
|
|
]
|
|
},
|
|
{
|
|
op: "Twofish Decrypt",
|
|
args: [
|
|
{ string: "ffeeddccbbaa99887766554433221100", option: "Hex" },
|
|
{ string: "00112233445566778899aabbccddeeff", option: "Hex" },
|
|
"CBC", "Hex", "Raw", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
// Consistency test - same input should always produce same output
|
|
{
|
|
name: "Twofish Encrypt: 128-bit key consistency test",
|
|
input: "TestData12345678",
|
|
expectedOutput: "8aed2d3a85dc3e0b663ba1fe1fdaf056771d591428af301d69fa1e227d083527",
|
|
recipeConfig: [
|
|
{
|
|
op: "Twofish Encrypt",
|
|
args: [
|
|
{ string: "00000000000000000000000000000000", option: "Hex" },
|
|
{ string: "", option: "Hex" },
|
|
"ECB", "Raw", "Hex", "PKCS5"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]);
|