You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
9.7 KiB
283 lines
9.7 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines |
|
{ |
|
/** |
|
* A class that provides CAST6 key encryption operations, |
|
* such as encoding data and generating keys. |
|
* |
|
* All the algorithms herein are from the Internet RFC |
|
* |
|
* RFC2612 - CAST6 (128bit block, 128-256bit key) |
|
* |
|
* and implement a simplified cryptography interface. |
|
*/ |
|
public sealed class Cast6Engine |
|
: Cast5Engine |
|
{ |
|
//==================================== |
|
// Useful constants |
|
//==================================== |
|
private const int ROUNDS = 12; |
|
private const int BLOCK_SIZE = 16; // bytes = 128 bits |
|
|
|
/* |
|
* Put the round and mask keys into an array. |
|
* Kr0[i] => _Kr[i*4 + 0] |
|
*/ |
|
private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s) |
|
private uint []_Km = new uint[ROUNDS*4]; // the masking round key(s) |
|
|
|
/* |
|
* Key setup |
|
*/ |
|
private int []_Tr = new int[24 * 8]; |
|
private uint []_Tm = new uint[24 * 8]; |
|
private uint[] _workingKey = new uint[8]; |
|
|
|
public Cast6Engine() |
|
{ |
|
} |
|
|
|
public override string AlgorithmName |
|
{ |
|
get { return "CAST6"; } |
|
} |
|
|
|
public override void Reset() |
|
{ |
|
} |
|
|
|
public override int GetBlockSize() |
|
{ |
|
return BLOCK_SIZE; |
|
} |
|
|
|
//================================== |
|
// Private Implementation |
|
//================================== |
|
/* |
|
* Creates the subkeys using the same nomenclature |
|
* as described in RFC2612. |
|
* |
|
* See section 2.4 |
|
*/ |
|
internal override void SetKey( |
|
byte[] key) |
|
{ |
|
uint Cm = 0x5a827999; |
|
uint Mm = 0x6ed9eba1; |
|
int Cr = 19; |
|
int Mr = 17; |
|
/* |
|
* Determine the key size here, if required |
|
* |
|
* if keysize < 256 bytes, pad with 0 |
|
* |
|
* Typical key sizes => 128, 160, 192, 224, 256 |
|
*/ |
|
for (int i=0; i< 24; i++) |
|
{ |
|
for (int j=0; j< 8; j++) |
|
{ |
|
_Tm[i*8 + j] = Cm; |
|
Cm += Mm; //mod 2^32; |
|
_Tr[i*8 + j] = Cr; |
|
Cr = (Cr + Mr) & 0x1f; // mod 32 |
|
} |
|
} |
|
|
|
byte[] tmpKey = new byte[64]; |
|
key.CopyTo(tmpKey, 0); |
|
|
|
// now create ABCDEFGH |
|
for (int i = 0; i < 8; i++) |
|
{ |
|
_workingKey[i] = Pack.BE_To_UInt32(tmpKey, i*4); |
|
} |
|
|
|
// Generate the key schedule |
|
for (int i = 0; i < 12; i++) |
|
{ |
|
// KAPPA <- W2i(KAPPA) |
|
int i2 = i*2 *8; |
|
_workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]); |
|
_workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); |
|
_workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); |
|
_workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); |
|
_workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); |
|
_workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); |
|
_workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); |
|
_workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); |
|
// KAPPA <- W2i+1(KAPPA) |
|
i2 = (i*2 + 1)*8; |
|
_workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]); |
|
_workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); |
|
_workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); |
|
_workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); |
|
_workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); |
|
_workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); |
|
_workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); |
|
_workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); |
|
// Kr_(i) <- KAPPA |
|
_Kr[i*4] = (int)(_workingKey[0] & 0x1f); |
|
_Kr[i*4 + 1] = (int)(_workingKey[2] & 0x1f); |
|
_Kr[i*4 + 2] = (int)(_workingKey[4] & 0x1f); |
|
_Kr[i*4 + 3] = (int)(_workingKey[6] & 0x1f); |
|
// Km_(i) <- KAPPA |
|
_Km[i*4] = _workingKey[7]; |
|
_Km[i*4 + 1] = _workingKey[5]; |
|
_Km[i*4 + 2] = _workingKey[3]; |
|
_Km[i*4 + 3] = _workingKey[1]; |
|
} |
|
} |
|
|
|
/** |
|
* Encrypt the given input starting at the given offset and place |
|
* the result in the provided buffer starting at the given offset. |
|
* |
|
* @param src The plaintext buffer |
|
* @param srcIndex An offset into src |
|
* @param dst The ciphertext buffer |
|
* @param dstIndex An offset into dst |
|
*/ |
|
internal override int EncryptBlock( |
|
byte[] src, |
|
int srcIndex, |
|
byte[] dst, |
|
int dstIndex) |
|
{ |
|
// process the input block |
|
// batch the units up into 4x32 bit chunks and go for it |
|
uint A = Pack.BE_To_UInt32(src, srcIndex); |
|
uint B = Pack.BE_To_UInt32(src, srcIndex + 4); |
|
uint C = Pack.BE_To_UInt32(src, srcIndex + 8); |
|
uint D = Pack.BE_To_UInt32(src, srcIndex + 12); |
|
uint[] result = new uint[4]; |
|
CAST_Encipher(A, B, C, D, result); |
|
// now stuff them into the destination block |
|
Pack.UInt32_To_BE(result[0], dst, dstIndex); |
|
Pack.UInt32_To_BE(result[1], dst, dstIndex + 4); |
|
Pack.UInt32_To_BE(result[2], dst, dstIndex + 8); |
|
Pack.UInt32_To_BE(result[3], dst, dstIndex + 12); |
|
return BLOCK_SIZE; |
|
} |
|
|
|
/** |
|
* Decrypt the given input starting at the given offset and place |
|
* the result in the provided buffer starting at the given offset. |
|
* |
|
* @param src The plaintext buffer |
|
* @param srcIndex An offset into src |
|
* @param dst The ciphertext buffer |
|
* @param dstIndex An offset into dst |
|
*/ |
|
internal override int DecryptBlock( |
|
byte[] src, |
|
int srcIndex, |
|
byte[] dst, |
|
int dstIndex) |
|
{ |
|
// process the input block |
|
// batch the units up into 4x32 bit chunks and go for it |
|
uint A = Pack.BE_To_UInt32(src, srcIndex); |
|
uint B = Pack.BE_To_UInt32(src, srcIndex + 4); |
|
uint C = Pack.BE_To_UInt32(src, srcIndex + 8); |
|
uint D = Pack.BE_To_UInt32(src, srcIndex + 12); |
|
uint[] result = new uint[4]; |
|
CAST_Decipher(A, B, C, D, result); |
|
// now stuff them into the destination block |
|
Pack.UInt32_To_BE(result[0], dst, dstIndex); |
|
Pack.UInt32_To_BE(result[1], dst, dstIndex + 4); |
|
Pack.UInt32_To_BE(result[2], dst, dstIndex + 8); |
|
Pack.UInt32_To_BE(result[3], dst, dstIndex + 12); |
|
return BLOCK_SIZE; |
|
} |
|
|
|
/** |
|
* Does the 12 quad rounds rounds to encrypt the block. |
|
* |
|
* @param A the 00-31 bits of the plaintext block |
|
* @param B the 32-63 bits of the plaintext block |
|
* @param C the 64-95 bits of the plaintext block |
|
* @param D the 96-127 bits of the plaintext block |
|
* @param result the resulting ciphertext |
|
*/ |
|
private void CAST_Encipher( |
|
uint A, |
|
uint B, |
|
uint C, |
|
uint D, |
|
uint[] result) |
|
{ |
|
for (int i = 0; i < 6; i++) |
|
{ |
|
int x = i*4; |
|
// BETA <- Qi(BETA) |
|
C ^= F1(D, _Km[x], _Kr[x]); |
|
B ^= F2(C, _Km[x + 1], _Kr[x + 1]); |
|
A ^= F3(B, _Km[x + 2], _Kr[x + 2]); |
|
D ^= F1(A, _Km[x + 3], _Kr[x + 3]); |
|
} |
|
for (int i = 6; i < 12; i++) |
|
{ |
|
int x = i*4; |
|
// BETA <- QBARi(BETA) |
|
D ^= F1(A, _Km[x + 3], _Kr[x + 3]); |
|
A ^= F3(B, _Km[x + 2], _Kr[x + 2]); |
|
B ^= F2(C, _Km[x + 1], _Kr[x + 1]); |
|
C ^= F1(D, _Km[x], _Kr[x]); |
|
} |
|
result[0] = A; |
|
result[1] = B; |
|
result[2] = C; |
|
result[3] = D; |
|
} |
|
|
|
/** |
|
* Does the 12 quad rounds rounds to decrypt the block. |
|
* |
|
* @param A the 00-31 bits of the ciphertext block |
|
* @param B the 32-63 bits of the ciphertext block |
|
* @param C the 64-95 bits of the ciphertext block |
|
* @param D the 96-127 bits of the ciphertext block |
|
* @param result the resulting plaintext |
|
*/ |
|
private void CAST_Decipher( |
|
uint A, |
|
uint B, |
|
uint C, |
|
uint D, |
|
uint[] result) |
|
{ |
|
for (int i = 0; i < 6; i++) |
|
{ |
|
int x = (11-i)*4; |
|
// BETA <- Qi(BETA) |
|
C ^= F1(D, _Km[x], _Kr[x]); |
|
B ^= F2(C, _Km[x + 1], _Kr[x + 1]); |
|
A ^= F3(B, _Km[x + 2], _Kr[x + 2]); |
|
D ^= F1(A, _Km[x + 3], _Kr[x + 3]); |
|
} |
|
for (int i=6; i<12; i++) |
|
{ |
|
int x = (11-i)*4; |
|
// BETA <- QBARi(BETA) |
|
D ^= F1(A, _Km[x + 3], _Kr[x + 3]); |
|
A ^= F3(B, _Km[x + 2], _Kr[x + 2]); |
|
B ^= F2(C, _Km[x + 1], _Kr[x + 1]); |
|
C ^= F1(D, _Km[x], _Kr[x]); |
|
} |
|
result[0] = A; |
|
result[1] = B; |
|
result[2] = C; |
|
result[3] = D; |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|