Initial Commit

This commit is contained in:
2023-06-21 12:46:23 -04:00
commit c70248a520
1352 changed files with 336780 additions and 0 deletions

View File

@@ -0,0 +1,550 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of the AES (Rijndael), from FIPS-197.
* <p>
* For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
*
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
*
* There are three levels of tradeoff of speed vs memory
* Because java has no preprocessor, they are written as three separate classes from which to choose
*
* The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
* and 4 for decryption.
*
* The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
* adding 12 rotate operations per round to compute the values contained in the other tables from
* the contents of the first.
*
* The slowest version uses no static tables at all and computes the values in each round.
* </p>
* <p>
* This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
* </p>
*/
public class AesEngine
: IBlockCipher
{
// The S box
private static readonly byte[] S =
{
99, 124, 119, 123, 242, 107, 111, 197,
48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240,
173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204,
52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154,
7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160,
82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91,
106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133,
69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245,
188, 182, 218, 33, 16, 255, 243, 210,
205, 12, 19, 236, 95, 151, 68, 23,
196, 167, 126, 61, 100, 93, 25, 115,
96, 129, 79, 220, 34, 42, 144, 136,
70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92,
194, 211, 172, 98, 145, 149, 228, 121,
231, 200, 55, 109, 141, 213, 78, 169,
108, 86, 244, 234, 101, 122, 174, 8,
186, 120, 37, 46, 28, 166, 180, 198,
232, 221, 116, 31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3, 246, 14,
97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148,
155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104,
65, 153, 45, 15, 176, 84, 187, 22,
};
// The inverse S-box
private static readonly byte[] Si =
{
82, 9, 106, 213, 48, 54, 165, 56,
191, 64, 163, 158, 129, 243, 215, 251,
124, 227, 57, 130, 155, 47, 255, 135,
52, 142, 67, 68, 196, 222, 233, 203,
84, 123, 148, 50, 166, 194, 35, 61,
238, 76, 149, 11, 66, 250, 195, 78,
8, 46, 161, 102, 40, 217, 36, 178,
118, 91, 162, 73, 109, 139, 209, 37,
114, 248, 246, 100, 134, 104, 152, 22,
212, 164, 92, 204, 93, 101, 182, 146,
108, 112, 72, 80, 253, 237, 185, 218,
94, 21, 70, 87, 167, 141, 157, 132,
144, 216, 171, 0, 140, 188, 211, 10,
247, 228, 88, 5, 184, 179, 69, 6,
208, 44, 30, 143, 202, 63, 15, 2,
193, 175, 189, 3, 1, 19, 138, 107,
58, 145, 17, 65, 79, 103, 220, 234,
151, 242, 207, 206, 240, 180, 230, 115,
150, 172, 116, 34, 231, 173, 53, 133,
226, 249, 55, 232, 28, 117, 223, 110,
71, 241, 26, 113, 29, 41, 197, 137,
111, 183, 98, 14, 170, 24, 190, 27,
252, 86, 62, 75, 198, 210, 121, 32,
154, 219, 192, 254, 120, 205, 90, 244,
31, 221, 168, 51, 136, 7, 199, 49,
177, 18, 16, 89, 39, 128, 236, 95,
96, 81, 127, 169, 25, 181, 74, 13,
45, 229, 122, 159, 147, 201, 156, 239,
160, 224, 59, 77, 174, 42, 245, 176,
200, 235, 187, 60, 131, 83, 153, 97,
23, 43, 4, 126, 186, 119, 214, 38,
225, 105, 20, 99, 85, 33, 12, 125,
};
// vector used in calculating key schedule (powers of x in GF(256))
private static readonly int[] rcon = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
// precomputation tables of calculations for rounds
private static readonly int[] T0 =
{
unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff),
unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102),
unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d),
unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa),
unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41),
unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453),
unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d),
unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83),
unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2),
unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795),
unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a),
unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df),
unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912),
unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc),
unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7),
unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413),
unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040),
unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d),
unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0),
unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed),
unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a),
unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78),
unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080),
unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1),
unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020),
unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18),
unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488),
unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a),
unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0),
unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54),
unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b),
unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad),
unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992),
unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd),
unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3),
unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda),
unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8),
unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4),
unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a),
unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697),
unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96),
unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c),
unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7),
unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969),
unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9),
unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9),
unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715),
unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5),
unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65),
unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929),
unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d),
unchecked((int) 0x3a16162c)
};
private static readonly int[] Tinv0 =
{
unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b),
unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad),
unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526),
unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d),
unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03),
unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458),
unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899),
unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d),
unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1),
unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f),
unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3),
unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3),
unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a),
unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506),
unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05),
unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd),
unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491),
unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6),
unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7),
unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000),
unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd),
unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68),
unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4),
unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c),
unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e),
unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af),
unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644),
unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8),
unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85),
unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc),
unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411),
unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322),
unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6),
unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850),
unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e),
unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf),
unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd),
unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa),
unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea),
unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235),
unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1),
unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43),
unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1),
unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb),
unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a),
unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7),
unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418),
unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478),
unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16),
unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08),
unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48),
unchecked((int) 0x4257b8d0)
};
private int Shift(
int r,
int shift)
{
return ((int)(((uint) r >> shift) | (uint)(r << (32 - shift))));
}
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const int m1 = unchecked((int) 0x80808080);
private const int m2 = unchecked((int) 0x7f7f7f7f);
private const int m3 = unchecked((int) 0x0000001b);
private int FFmulX(
int x)
{
return ((int) (((x & m2) << 1) ^ (( (uint) (x & m1) >> 7) * m3)));
}
/*
The following defines provide alternative definitions of FFmulX that might
give improved performance if a fast 32-bit multiply is not available.
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
private static final int m4 = 0x1b1b1b1b;
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
*/
private int Inv_Mcol(
int x)
{
int f2 = FFmulX(x);
int f4 = FFmulX(f2);
int f8 = FFmulX(f4);
int f9 = x ^ f8;
return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
}
private int SubWord(int x) {
return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
}
/**
* Calculate the necessary round keys
* The number of calculations depends on key size and block size
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
* This code is written assuming those are the only possible values
*/
private int[,] GenerateWorkingKey(
byte[] key,
bool forEncryption)
{
int KC = key.Length / 4; // key length in words
int t;
if ((KC != 4) && (KC != 6) && (KC != 8)) {
throw new ArgumentException("Key length not 128/192/256 bits.");
}
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
int[,] W = new int[ROUNDS+1, 4]; // 4 words in a block
//
// copy the key into the round key array
//
t = 0;
for (int i = 0; i < key.Length; t++)
{
W[t >> 2, t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
i+=4;
}
//
// while not enough round key material calculated
// calculate new values
//
int k = (ROUNDS + 1) << 2;
for (int i = KC; (i < k); i++)
{
int temp = W[(i-1)>>2, (i-1)&3];
if ((i % KC) == 0) {
temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
} else if ((KC > 6) && ((i % KC) == 4)) {
temp = SubWord(temp);
}
W[i>>2, i&3] = W[(i - KC)>>2, (i-KC)&3] ^ temp;
}
if (!forEncryption)
{
for (int j = 1; j < ROUNDS; j++)
{
for (int i = 0; i < 4; i++)
{
W[j, i] = Inv_Mcol(W[j, i]);
}
}
}
return W;
}
private int ROUNDS;
private int[,] WorkingKey;
private int C0, C1, C2, C3;
private bool forEncryption;
private const int BLOCK_SIZE = 16;
/**
* default constructor - 128 bit block size.
*/
public AesEngine()
{
}
/**
* initialise an AES cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter == null)
throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
this.forEncryption = forEncryption;
}
public string AlgorithmName
{
get { return "AES"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (WorkingKey == null)
{
throw new InvalidOperationException("AES engine not initialised");
}
if ((inOff + (32 / 2)) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + (32 / 2)) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
UnPackBlock(input, inOff);
if (forEncryption)
{
EncryptBlock(WorkingKey);
}
else
{
DecryptBlock(WorkingKey);
}
PackBlock(output, outOff);
return BLOCK_SIZE;
}
public void Reset()
{
}
private void UnPackBlock(
byte[] bytes,
int off)
{
int index = off;
C0 = (bytes[index++] & 0xff);
C0 |= (bytes[index++] & 0xff) << 8;
C0 |= (bytes[index++] & 0xff) << 16;
C0 |= bytes[index++] << 24;
C1 = (bytes[index++] & 0xff);
C1 |= (bytes[index++] & 0xff) << 8;
C1 |= (bytes[index++] & 0xff) << 16;
C1 |= bytes[index++] << 24;
C2 = (bytes[index++] & 0xff);
C2 |= (bytes[index++] & 0xff) << 8;
C2 |= (bytes[index++] & 0xff) << 16;
C2 |= bytes[index++] << 24;
C3 = (bytes[index++] & 0xff);
C3 |= (bytes[index++] & 0xff) << 8;
C3 |= (bytes[index++] & 0xff) << 16;
C3 |= bytes[index++] << 24;
}
private void PackBlock(
byte[] bytes,
int off)
{
int index = off;
bytes[index++] = (byte)C0;
bytes[index++] = (byte)(C0 >> 8);
bytes[index++] = (byte)(C0 >> 16);
bytes[index++] = (byte)(C0 >> 24);
bytes[index++] = (byte)C1;
bytes[index++] = (byte)(C1 >> 8);
bytes[index++] = (byte)(C1 >> 16);
bytes[index++] = (byte)(C1 >> 24);
bytes[index++] = (byte)C2;
bytes[index++] = (byte)(C2 >> 8);
bytes[index++] = (byte)(C2 >> 16);
bytes[index++] = (byte)(C2 >> 24);
bytes[index++] = (byte)C3;
bytes[index++] = (byte)(C3 >> 8);
bytes[index++] = (byte)(C3 >> 16);
bytes[index++] = (byte)(C3 >> 24);
}
private void EncryptBlock(
int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[0, 0];
C1 ^= KW[0, 1];
C2 ^= KW[0, 2];
C3 ^= KW[0, 3];
for (r = 1; r < ROUNDS - 1;)
{
r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255],16) ^ Shift(T0[(C3>>24)&255],8) ^ KW[r,0];
r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1];
r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2];
r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3];
C0 = T0[r0&255] ^ Shift(T0[(r1>>8)&255], 24) ^ Shift(T0[(r2>>16)&255], 16) ^ Shift(T0[(r3>>24)&255], 8) ^ KW[r,0];
C1 = T0[r1&255] ^ Shift(T0[(r2>>8)&255], 24) ^ Shift(T0[(r3>>16)&255], 16) ^ Shift(T0[(r0>>24)&255], 8) ^ KW[r,1];
C2 = T0[r2&255] ^ Shift(T0[(r3>>8)&255], 24) ^ Shift(T0[(r0>>16)&255], 16) ^ Shift(T0[(r1>>24)&255], 8) ^ KW[r,2];
C3 = T0[r3&255] ^ Shift(T0[(r0>>8)&255], 24) ^ Shift(T0[(r1>>16)&255], 16) ^ Shift(T0[(r2>>24)&255], 8) ^ KW[r++,3];
}
r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255], 16) ^ Shift(T0[(C3>>24)&255], 8) ^ KW[r,0];
r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1];
r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2];
r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
}
private void DecryptBlock(
int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[ROUNDS,0];
C1 ^= KW[ROUNDS,1];
C2 ^= KW[ROUNDS,2];
C3 ^= KW[ROUNDS,3];
for (r = ROUNDS-1; r>1;)
{
r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0];
r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1];
r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2];
r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--,3];
C0 = Tinv0[r0&255] ^ Shift(Tinv0[(r3>>8)&255], 24) ^ Shift(Tinv0[(r2>>16)&255], 16) ^ Shift(Tinv0[(r1>>24)&255], 8) ^ KW[r,0];
C1 = Tinv0[r1&255] ^ Shift(Tinv0[(r0>>8)&255], 24) ^ Shift(Tinv0[(r3>>16)&255], 16) ^ Shift(Tinv0[(r2>>24)&255], 8) ^ KW[r,1];
C2 = Tinv0[r2&255] ^ Shift(Tinv0[(r1>>8)&255], 24) ^ Shift(Tinv0[(r0>>16)&255], 16) ^ Shift(Tinv0[(r3>>24)&255], 8) ^ KW[r,2];
C3 = Tinv0[r3&255] ^ Shift(Tinv0[(r2>>8)&255], 24) ^ Shift(Tinv0[(r1>>16)&255], 16) ^ Shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--,3];
}
r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0];
r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1];
r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2];
r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r,3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
}
}
}

View File

@@ -0,0 +1,865 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of the AES (Rijndael)), from FIPS-197.
* <p>
* For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
*
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
*
* There are three levels of tradeoff of speed vs memory
* Because java has no preprocessor), they are written as three separate classes from which to choose
*
* The fastest uses 8Kbytes of static tables to precompute round calculations), 4 256 word tables for encryption
* and 4 for decryption.
*
* The middle performance version uses only one 256 word table for each), for a total of 2Kbytes),
* adding 12 rotate operations per round to compute the values contained in the other tables from
* the contents of the first
*
* The slowest version uses no static tables at all and computes the values in each round
* </p>
* <p>
* This file contains the fast version with 8Kbytes of static tables for round precomputation
* </p>
*/
public class AesFastEngine
: IBlockCipher
{
// The S box
private static readonly byte[] S = {
(byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
(byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
(byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
(byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
(byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
(byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
(byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
(byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
(byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
(byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
(byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
(byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
(byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
(byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
(byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
(byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
(byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
(byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
(byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
(byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
(byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
(byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
(byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
(byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
(byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
(byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
(byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
(byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
(byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
(byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
(byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
(byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
};
// The inverse S-box
private static readonly byte[] Si = {
(byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
(byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
(byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
(byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
(byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
(byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
(byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
(byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
(byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
(byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
(byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
(byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
(byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
(byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
(byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
(byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
(byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
(byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
(byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
(byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
(byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
(byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
(byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
(byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
(byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
(byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
(byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
(byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
(byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
(byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
(byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
(byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
};
// vector used in calculating key schedule (powers of x in GF(256))
private static readonly int[] rcon = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
// precomputation tables of calculations for rounds
private static readonly int[] T0 =
{
unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff),
unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102),
unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d),
unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa),
unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41),
unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453),
unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d),
unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83),
unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2),
unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795),
unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a),
unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df),
unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912),
unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc),
unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7),
unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413),
unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040),
unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d),
unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0),
unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed),
unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a),
unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78),
unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080),
unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1),
unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020),
unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18),
unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488),
unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a),
unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0),
unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54),
unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b),
unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad),
unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992),
unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd),
unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3),
unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda),
unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8),
unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4),
unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a),
unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697),
unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96),
unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c),
unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7),
unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969),
unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9),
unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9),
unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715),
unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5),
unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65),
unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929),
unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d),
unchecked((int) 0x3a16162c)};
private static readonly int[] T1 =
{
unchecked((int) 0x6363c6a5), unchecked((int) 0x7c7cf884), unchecked((int) 0x7777ee99), unchecked((int) 0x7b7bf68d), unchecked((int) 0xf2f2ff0d),
unchecked((int) 0x6b6bd6bd), unchecked((int) 0x6f6fdeb1), unchecked((int) 0xc5c59154), unchecked((int) 0x30306050), unchecked((int) 0x01010203),
unchecked((int) 0x6767cea9), unchecked((int) 0x2b2b567d), unchecked((int) 0xfefee719), unchecked((int) 0xd7d7b562), unchecked((int) 0xabab4de6),
unchecked((int) 0x7676ec9a), unchecked((int) 0xcaca8f45), unchecked((int) 0x82821f9d), unchecked((int) 0xc9c98940), unchecked((int) 0x7d7dfa87),
unchecked((int) 0xfafaef15), unchecked((int) 0x5959b2eb), unchecked((int) 0x47478ec9), unchecked((int) 0xf0f0fb0b), unchecked((int) 0xadad41ec),
unchecked((int) 0xd4d4b367), unchecked((int) 0xa2a25ffd), unchecked((int) 0xafaf45ea), unchecked((int) 0x9c9c23bf), unchecked((int) 0xa4a453f7),
unchecked((int) 0x7272e496), unchecked((int) 0xc0c09b5b), unchecked((int) 0xb7b775c2), unchecked((int) 0xfdfde11c), unchecked((int) 0x93933dae),
unchecked((int) 0x26264c6a), unchecked((int) 0x36366c5a), unchecked((int) 0x3f3f7e41), unchecked((int) 0xf7f7f502), unchecked((int) 0xcccc834f),
unchecked((int) 0x3434685c), unchecked((int) 0xa5a551f4), unchecked((int) 0xe5e5d134), unchecked((int) 0xf1f1f908), unchecked((int) 0x7171e293),
unchecked((int) 0xd8d8ab73), unchecked((int) 0x31316253), unchecked((int) 0x15152a3f), unchecked((int) 0x0404080c), unchecked((int) 0xc7c79552),
unchecked((int) 0x23234665), unchecked((int) 0xc3c39d5e), unchecked((int) 0x18183028), unchecked((int) 0x969637a1), unchecked((int) 0x05050a0f),
unchecked((int) 0x9a9a2fb5), unchecked((int) 0x07070e09), unchecked((int) 0x12122436), unchecked((int) 0x80801b9b), unchecked((int) 0xe2e2df3d),
unchecked((int) 0xebebcd26), unchecked((int) 0x27274e69), unchecked((int) 0xb2b27fcd), unchecked((int) 0x7575ea9f), unchecked((int) 0x0909121b),
unchecked((int) 0x83831d9e), unchecked((int) 0x2c2c5874), unchecked((int) 0x1a1a342e), unchecked((int) 0x1b1b362d), unchecked((int) 0x6e6edcb2),
unchecked((int) 0x5a5ab4ee), unchecked((int) 0xa0a05bfb), unchecked((int) 0x5252a4f6), unchecked((int) 0x3b3b764d), unchecked((int) 0xd6d6b761),
unchecked((int) 0xb3b37dce), unchecked((int) 0x2929527b), unchecked((int) 0xe3e3dd3e), unchecked((int) 0x2f2f5e71), unchecked((int) 0x84841397),
unchecked((int) 0x5353a6f5), unchecked((int) 0xd1d1b968), unchecked((int) 0x00000000), unchecked((int) 0xededc12c), unchecked((int) 0x20204060),
unchecked((int) 0xfcfce31f), unchecked((int) 0xb1b179c8), unchecked((int) 0x5b5bb6ed), unchecked((int) 0x6a6ad4be), unchecked((int) 0xcbcb8d46),
unchecked((int) 0xbebe67d9), unchecked((int) 0x3939724b), unchecked((int) 0x4a4a94de), unchecked((int) 0x4c4c98d4), unchecked((int) 0x5858b0e8),
unchecked((int) 0xcfcf854a), unchecked((int) 0xd0d0bb6b), unchecked((int) 0xefefc52a), unchecked((int) 0xaaaa4fe5), unchecked((int) 0xfbfbed16),
unchecked((int) 0x434386c5), unchecked((int) 0x4d4d9ad7), unchecked((int) 0x33336655), unchecked((int) 0x85851194), unchecked((int) 0x45458acf),
unchecked((int) 0xf9f9e910), unchecked((int) 0x02020406), unchecked((int) 0x7f7ffe81), unchecked((int) 0x5050a0f0), unchecked((int) 0x3c3c7844),
unchecked((int) 0x9f9f25ba), unchecked((int) 0xa8a84be3), unchecked((int) 0x5151a2f3), unchecked((int) 0xa3a35dfe), unchecked((int) 0x404080c0),
unchecked((int) 0x8f8f058a), unchecked((int) 0x92923fad), unchecked((int) 0x9d9d21bc), unchecked((int) 0x38387048), unchecked((int) 0xf5f5f104),
unchecked((int) 0xbcbc63df), unchecked((int) 0xb6b677c1), unchecked((int) 0xdadaaf75), unchecked((int) 0x21214263), unchecked((int) 0x10102030),
unchecked((int) 0xffffe51a), unchecked((int) 0xf3f3fd0e), unchecked((int) 0xd2d2bf6d), unchecked((int) 0xcdcd814c), unchecked((int) 0x0c0c1814),
unchecked((int) 0x13132635), unchecked((int) 0xececc32f), unchecked((int) 0x5f5fbee1), unchecked((int) 0x979735a2), unchecked((int) 0x444488cc),
unchecked((int) 0x17172e39), unchecked((int) 0xc4c49357), unchecked((int) 0xa7a755f2), unchecked((int) 0x7e7efc82), unchecked((int) 0x3d3d7a47),
unchecked((int) 0x6464c8ac), unchecked((int) 0x5d5dbae7), unchecked((int) 0x1919322b), unchecked((int) 0x7373e695), unchecked((int) 0x6060c0a0),
unchecked((int) 0x81811998), unchecked((int) 0x4f4f9ed1), unchecked((int) 0xdcdca37f), unchecked((int) 0x22224466), unchecked((int) 0x2a2a547e),
unchecked((int) 0x90903bab), unchecked((int) 0x88880b83), unchecked((int) 0x46468cca), unchecked((int) 0xeeeec729), unchecked((int) 0xb8b86bd3),
unchecked((int) 0x1414283c), unchecked((int) 0xdedea779), unchecked((int) 0x5e5ebce2), unchecked((int) 0x0b0b161d), unchecked((int) 0xdbdbad76),
unchecked((int) 0xe0e0db3b), unchecked((int) 0x32326456), unchecked((int) 0x3a3a744e), unchecked((int) 0x0a0a141e), unchecked((int) 0x494992db),
unchecked((int) 0x06060c0a), unchecked((int) 0x2424486c), unchecked((int) 0x5c5cb8e4), unchecked((int) 0xc2c29f5d), unchecked((int) 0xd3d3bd6e),
unchecked((int) 0xacac43ef), unchecked((int) 0x6262c4a6), unchecked((int) 0x919139a8), unchecked((int) 0x959531a4), unchecked((int) 0xe4e4d337),
unchecked((int) 0x7979f28b), unchecked((int) 0xe7e7d532), unchecked((int) 0xc8c88b43), unchecked((int) 0x37376e59), unchecked((int) 0x6d6ddab7),
unchecked((int) 0x8d8d018c), unchecked((int) 0xd5d5b164), unchecked((int) 0x4e4e9cd2), unchecked((int) 0xa9a949e0), unchecked((int) 0x6c6cd8b4),
unchecked((int) 0x5656acfa), unchecked((int) 0xf4f4f307), unchecked((int) 0xeaeacf25), unchecked((int) 0x6565caaf), unchecked((int) 0x7a7af48e),
unchecked((int) 0xaeae47e9), unchecked((int) 0x08081018), unchecked((int) 0xbaba6fd5), unchecked((int) 0x7878f088), unchecked((int) 0x25254a6f),
unchecked((int) 0x2e2e5c72), unchecked((int) 0x1c1c3824), unchecked((int) 0xa6a657f1), unchecked((int) 0xb4b473c7), unchecked((int) 0xc6c69751),
unchecked((int) 0xe8e8cb23), unchecked((int) 0xdddda17c), unchecked((int) 0x7474e89c), unchecked((int) 0x1f1f3e21), unchecked((int) 0x4b4b96dd),
unchecked((int) 0xbdbd61dc), unchecked((int) 0x8b8b0d86), unchecked((int) 0x8a8a0f85), unchecked((int) 0x7070e090), unchecked((int) 0x3e3e7c42),
unchecked((int) 0xb5b571c4), unchecked((int) 0x6666ccaa), unchecked((int) 0x484890d8), unchecked((int) 0x03030605), unchecked((int) 0xf6f6f701),
unchecked((int) 0x0e0e1c12), unchecked((int) 0x6161c2a3), unchecked((int) 0x35356a5f), unchecked((int) 0x5757aef9), unchecked((int) 0xb9b969d0),
unchecked((int) 0x86861791), unchecked((int) 0xc1c19958), unchecked((int) 0x1d1d3a27), unchecked((int) 0x9e9e27b9), unchecked((int) 0xe1e1d938),
unchecked((int) 0xf8f8eb13), unchecked((int) 0x98982bb3), unchecked((int) 0x11112233), unchecked((int) 0x6969d2bb), unchecked((int) 0xd9d9a970),
unchecked((int) 0x8e8e0789), unchecked((int) 0x949433a7), unchecked((int) 0x9b9b2db6), unchecked((int) 0x1e1e3c22), unchecked((int) 0x87871592),
unchecked((int) 0xe9e9c920), unchecked((int) 0xcece8749), unchecked((int) 0x5555aaff), unchecked((int) 0x28285078), unchecked((int) 0xdfdfa57a),
unchecked((int) 0x8c8c038f), unchecked((int) 0xa1a159f8), unchecked((int) 0x89890980), unchecked((int) 0x0d0d1a17), unchecked((int) 0xbfbf65da),
unchecked((int) 0xe6e6d731), unchecked((int) 0x424284c6), unchecked((int) 0x6868d0b8), unchecked((int) 0x414182c3), unchecked((int) 0x999929b0),
unchecked((int) 0x2d2d5a77), unchecked((int) 0x0f0f1e11), unchecked((int) 0xb0b07bcb), unchecked((int) 0x5454a8fc), unchecked((int) 0xbbbb6dd6),
unchecked((int) 0x16162c3a)};
private static readonly int[] T2 =
{
unchecked((int) 0x63c6a563), unchecked((int) 0x7cf8847c), unchecked((int) 0x77ee9977), unchecked((int) 0x7bf68d7b), unchecked((int) 0xf2ff0df2),
unchecked((int) 0x6bd6bd6b), unchecked((int) 0x6fdeb16f), unchecked((int) 0xc59154c5), unchecked((int) 0x30605030), unchecked((int) 0x01020301),
unchecked((int) 0x67cea967), unchecked((int) 0x2b567d2b), unchecked((int) 0xfee719fe), unchecked((int) 0xd7b562d7), unchecked((int) 0xab4de6ab),
unchecked((int) 0x76ec9a76), unchecked((int) 0xca8f45ca), unchecked((int) 0x821f9d82), unchecked((int) 0xc98940c9), unchecked((int) 0x7dfa877d),
unchecked((int) 0xfaef15fa), unchecked((int) 0x59b2eb59), unchecked((int) 0x478ec947), unchecked((int) 0xf0fb0bf0), unchecked((int) 0xad41ecad),
unchecked((int) 0xd4b367d4), unchecked((int) 0xa25ffda2), unchecked((int) 0xaf45eaaf), unchecked((int) 0x9c23bf9c), unchecked((int) 0xa453f7a4),
unchecked((int) 0x72e49672), unchecked((int) 0xc09b5bc0), unchecked((int) 0xb775c2b7), unchecked((int) 0xfde11cfd), unchecked((int) 0x933dae93),
unchecked((int) 0x264c6a26), unchecked((int) 0x366c5a36), unchecked((int) 0x3f7e413f), unchecked((int) 0xf7f502f7), unchecked((int) 0xcc834fcc),
unchecked((int) 0x34685c34), unchecked((int) 0xa551f4a5), unchecked((int) 0xe5d134e5), unchecked((int) 0xf1f908f1), unchecked((int) 0x71e29371),
unchecked((int) 0xd8ab73d8), unchecked((int) 0x31625331), unchecked((int) 0x152a3f15), unchecked((int) 0x04080c04), unchecked((int) 0xc79552c7),
unchecked((int) 0x23466523), unchecked((int) 0xc39d5ec3), unchecked((int) 0x18302818), unchecked((int) 0x9637a196), unchecked((int) 0x050a0f05),
unchecked((int) 0x9a2fb59a), unchecked((int) 0x070e0907), unchecked((int) 0x12243612), unchecked((int) 0x801b9b80), unchecked((int) 0xe2df3de2),
unchecked((int) 0xebcd26eb), unchecked((int) 0x274e6927), unchecked((int) 0xb27fcdb2), unchecked((int) 0x75ea9f75), unchecked((int) 0x09121b09),
unchecked((int) 0x831d9e83), unchecked((int) 0x2c58742c), unchecked((int) 0x1a342e1a), unchecked((int) 0x1b362d1b), unchecked((int) 0x6edcb26e),
unchecked((int) 0x5ab4ee5a), unchecked((int) 0xa05bfba0), unchecked((int) 0x52a4f652), unchecked((int) 0x3b764d3b), unchecked((int) 0xd6b761d6),
unchecked((int) 0xb37dceb3), unchecked((int) 0x29527b29), unchecked((int) 0xe3dd3ee3), unchecked((int) 0x2f5e712f), unchecked((int) 0x84139784),
unchecked((int) 0x53a6f553), unchecked((int) 0xd1b968d1), unchecked((int) 0x00000000), unchecked((int) 0xedc12ced), unchecked((int) 0x20406020),
unchecked((int) 0xfce31ffc), unchecked((int) 0xb179c8b1), unchecked((int) 0x5bb6ed5b), unchecked((int) 0x6ad4be6a), unchecked((int) 0xcb8d46cb),
unchecked((int) 0xbe67d9be), unchecked((int) 0x39724b39), unchecked((int) 0x4a94de4a), unchecked((int) 0x4c98d44c), unchecked((int) 0x58b0e858),
unchecked((int) 0xcf854acf), unchecked((int) 0xd0bb6bd0), unchecked((int) 0xefc52aef), unchecked((int) 0xaa4fe5aa), unchecked((int) 0xfbed16fb),
unchecked((int) 0x4386c543), unchecked((int) 0x4d9ad74d), unchecked((int) 0x33665533), unchecked((int) 0x85119485), unchecked((int) 0x458acf45),
unchecked((int) 0xf9e910f9), unchecked((int) 0x02040602), unchecked((int) 0x7ffe817f), unchecked((int) 0x50a0f050), unchecked((int) 0x3c78443c),
unchecked((int) 0x9f25ba9f), unchecked((int) 0xa84be3a8), unchecked((int) 0x51a2f351), unchecked((int) 0xa35dfea3), unchecked((int) 0x4080c040),
unchecked((int) 0x8f058a8f), unchecked((int) 0x923fad92), unchecked((int) 0x9d21bc9d), unchecked((int) 0x38704838), unchecked((int) 0xf5f104f5),
unchecked((int) 0xbc63dfbc), unchecked((int) 0xb677c1b6), unchecked((int) 0xdaaf75da), unchecked((int) 0x21426321), unchecked((int) 0x10203010),
unchecked((int) 0xffe51aff), unchecked((int) 0xf3fd0ef3), unchecked((int) 0xd2bf6dd2), unchecked((int) 0xcd814ccd), unchecked((int) 0x0c18140c),
unchecked((int) 0x13263513), unchecked((int) 0xecc32fec), unchecked((int) 0x5fbee15f), unchecked((int) 0x9735a297), unchecked((int) 0x4488cc44),
unchecked((int) 0x172e3917), unchecked((int) 0xc49357c4), unchecked((int) 0xa755f2a7), unchecked((int) 0x7efc827e), unchecked((int) 0x3d7a473d),
unchecked((int) 0x64c8ac64), unchecked((int) 0x5dbae75d), unchecked((int) 0x19322b19), unchecked((int) 0x73e69573), unchecked((int) 0x60c0a060),
unchecked((int) 0x81199881), unchecked((int) 0x4f9ed14f), unchecked((int) 0xdca37fdc), unchecked((int) 0x22446622), unchecked((int) 0x2a547e2a),
unchecked((int) 0x903bab90), unchecked((int) 0x880b8388), unchecked((int) 0x468cca46), unchecked((int) 0xeec729ee), unchecked((int) 0xb86bd3b8),
unchecked((int) 0x14283c14), unchecked((int) 0xdea779de), unchecked((int) 0x5ebce25e), unchecked((int) 0x0b161d0b), unchecked((int) 0xdbad76db),
unchecked((int) 0xe0db3be0), unchecked((int) 0x32645632), unchecked((int) 0x3a744e3a), unchecked((int) 0x0a141e0a), unchecked((int) 0x4992db49),
unchecked((int) 0x060c0a06), unchecked((int) 0x24486c24), unchecked((int) 0x5cb8e45c), unchecked((int) 0xc29f5dc2), unchecked((int) 0xd3bd6ed3),
unchecked((int) 0xac43efac), unchecked((int) 0x62c4a662), unchecked((int) 0x9139a891), unchecked((int) 0x9531a495), unchecked((int) 0xe4d337e4),
unchecked((int) 0x79f28b79), unchecked((int) 0xe7d532e7), unchecked((int) 0xc88b43c8), unchecked((int) 0x376e5937), unchecked((int) 0x6ddab76d),
unchecked((int) 0x8d018c8d), unchecked((int) 0xd5b164d5), unchecked((int) 0x4e9cd24e), unchecked((int) 0xa949e0a9), unchecked((int) 0x6cd8b46c),
unchecked((int) 0x56acfa56), unchecked((int) 0xf4f307f4), unchecked((int) 0xeacf25ea), unchecked((int) 0x65caaf65), unchecked((int) 0x7af48e7a),
unchecked((int) 0xae47e9ae), unchecked((int) 0x08101808), unchecked((int) 0xba6fd5ba), unchecked((int) 0x78f08878), unchecked((int) 0x254a6f25),
unchecked((int) 0x2e5c722e), unchecked((int) 0x1c38241c), unchecked((int) 0xa657f1a6), unchecked((int) 0xb473c7b4), unchecked((int) 0xc69751c6),
unchecked((int) 0xe8cb23e8), unchecked((int) 0xdda17cdd), unchecked((int) 0x74e89c74), unchecked((int) 0x1f3e211f), unchecked((int) 0x4b96dd4b),
unchecked((int) 0xbd61dcbd), unchecked((int) 0x8b0d868b), unchecked((int) 0x8a0f858a), unchecked((int) 0x70e09070), unchecked((int) 0x3e7c423e),
unchecked((int) 0xb571c4b5), unchecked((int) 0x66ccaa66), unchecked((int) 0x4890d848), unchecked((int) 0x03060503), unchecked((int) 0xf6f701f6),
unchecked((int) 0x0e1c120e), unchecked((int) 0x61c2a361), unchecked((int) 0x356a5f35), unchecked((int) 0x57aef957), unchecked((int) 0xb969d0b9),
unchecked((int) 0x86179186), unchecked((int) 0xc19958c1), unchecked((int) 0x1d3a271d), unchecked((int) 0x9e27b99e), unchecked((int) 0xe1d938e1),
unchecked((int) 0xf8eb13f8), unchecked((int) 0x982bb398), unchecked((int) 0x11223311), unchecked((int) 0x69d2bb69), unchecked((int) 0xd9a970d9),
unchecked((int) 0x8e07898e), unchecked((int) 0x9433a794), unchecked((int) 0x9b2db69b), unchecked((int) 0x1e3c221e), unchecked((int) 0x87159287),
unchecked((int) 0xe9c920e9), unchecked((int) 0xce8749ce), unchecked((int) 0x55aaff55), unchecked((int) 0x28507828), unchecked((int) 0xdfa57adf),
unchecked((int) 0x8c038f8c), unchecked((int) 0xa159f8a1), unchecked((int) 0x89098089), unchecked((int) 0x0d1a170d), unchecked((int) 0xbf65dabf),
unchecked((int) 0xe6d731e6), unchecked((int) 0x4284c642), unchecked((int) 0x68d0b868), unchecked((int) 0x4182c341), unchecked((int) 0x9929b099),
unchecked((int) 0x2d5a772d), unchecked((int) 0x0f1e110f), unchecked((int) 0xb07bcbb0), unchecked((int) 0x54a8fc54), unchecked((int) 0xbb6dd6bb),
unchecked((int) 0x162c3a16)};
private static readonly int[] T3 =
{
unchecked((int) 0xc6a56363), unchecked((int) 0xf8847c7c), unchecked((int) 0xee997777), unchecked((int) 0xf68d7b7b), unchecked((int) 0xff0df2f2),
unchecked((int) 0xd6bd6b6b), unchecked((int) 0xdeb16f6f), unchecked((int) 0x9154c5c5), unchecked((int) 0x60503030), unchecked((int) 0x02030101),
unchecked((int) 0xcea96767), unchecked((int) 0x567d2b2b), unchecked((int) 0xe719fefe), unchecked((int) 0xb562d7d7), unchecked((int) 0x4de6abab),
unchecked((int) 0xec9a7676), unchecked((int) 0x8f45caca), unchecked((int) 0x1f9d8282), unchecked((int) 0x8940c9c9), unchecked((int) 0xfa877d7d),
unchecked((int) 0xef15fafa), unchecked((int) 0xb2eb5959), unchecked((int) 0x8ec94747), unchecked((int) 0xfb0bf0f0), unchecked((int) 0x41ecadad),
unchecked((int) 0xb367d4d4), unchecked((int) 0x5ffda2a2), unchecked((int) 0x45eaafaf), unchecked((int) 0x23bf9c9c), unchecked((int) 0x53f7a4a4),
unchecked((int) 0xe4967272), unchecked((int) 0x9b5bc0c0), unchecked((int) 0x75c2b7b7), unchecked((int) 0xe11cfdfd), unchecked((int) 0x3dae9393),
unchecked((int) 0x4c6a2626), unchecked((int) 0x6c5a3636), unchecked((int) 0x7e413f3f), unchecked((int) 0xf502f7f7), unchecked((int) 0x834fcccc),
unchecked((int) 0x685c3434), unchecked((int) 0x51f4a5a5), unchecked((int) 0xd134e5e5), unchecked((int) 0xf908f1f1), unchecked((int) 0xe2937171),
unchecked((int) 0xab73d8d8), unchecked((int) 0x62533131), unchecked((int) 0x2a3f1515), unchecked((int) 0x080c0404), unchecked((int) 0x9552c7c7),
unchecked((int) 0x46652323), unchecked((int) 0x9d5ec3c3), unchecked((int) 0x30281818), unchecked((int) 0x37a19696), unchecked((int) 0x0a0f0505),
unchecked((int) 0x2fb59a9a), unchecked((int) 0x0e090707), unchecked((int) 0x24361212), unchecked((int) 0x1b9b8080), unchecked((int) 0xdf3de2e2),
unchecked((int) 0xcd26ebeb), unchecked((int) 0x4e692727), unchecked((int) 0x7fcdb2b2), unchecked((int) 0xea9f7575), unchecked((int) 0x121b0909),
unchecked((int) 0x1d9e8383), unchecked((int) 0x58742c2c), unchecked((int) 0x342e1a1a), unchecked((int) 0x362d1b1b), unchecked((int) 0xdcb26e6e),
unchecked((int) 0xb4ee5a5a), unchecked((int) 0x5bfba0a0), unchecked((int) 0xa4f65252), unchecked((int) 0x764d3b3b), unchecked((int) 0xb761d6d6),
unchecked((int) 0x7dceb3b3), unchecked((int) 0x527b2929), unchecked((int) 0xdd3ee3e3), unchecked((int) 0x5e712f2f), unchecked((int) 0x13978484),
unchecked((int) 0xa6f55353), unchecked((int) 0xb968d1d1), unchecked((int) 0x00000000), unchecked((int) 0xc12ceded), unchecked((int) 0x40602020),
unchecked((int) 0xe31ffcfc), unchecked((int) 0x79c8b1b1), unchecked((int) 0xb6ed5b5b), unchecked((int) 0xd4be6a6a), unchecked((int) 0x8d46cbcb),
unchecked((int) 0x67d9bebe), unchecked((int) 0x724b3939), unchecked((int) 0x94de4a4a), unchecked((int) 0x98d44c4c), unchecked((int) 0xb0e85858),
unchecked((int) 0x854acfcf), unchecked((int) 0xbb6bd0d0), unchecked((int) 0xc52aefef), unchecked((int) 0x4fe5aaaa), unchecked((int) 0xed16fbfb),
unchecked((int) 0x86c54343), unchecked((int) 0x9ad74d4d), unchecked((int) 0x66553333), unchecked((int) 0x11948585), unchecked((int) 0x8acf4545),
unchecked((int) 0xe910f9f9), unchecked((int) 0x04060202), unchecked((int) 0xfe817f7f), unchecked((int) 0xa0f05050), unchecked((int) 0x78443c3c),
unchecked((int) 0x25ba9f9f), unchecked((int) 0x4be3a8a8), unchecked((int) 0xa2f35151), unchecked((int) 0x5dfea3a3), unchecked((int) 0x80c04040),
unchecked((int) 0x058a8f8f), unchecked((int) 0x3fad9292), unchecked((int) 0x21bc9d9d), unchecked((int) 0x70483838), unchecked((int) 0xf104f5f5),
unchecked((int) 0x63dfbcbc), unchecked((int) 0x77c1b6b6), unchecked((int) 0xaf75dada), unchecked((int) 0x42632121), unchecked((int) 0x20301010),
unchecked((int) 0xe51affff), unchecked((int) 0xfd0ef3f3), unchecked((int) 0xbf6dd2d2), unchecked((int) 0x814ccdcd), unchecked((int) 0x18140c0c),
unchecked((int) 0x26351313), unchecked((int) 0xc32fecec), unchecked((int) 0xbee15f5f), unchecked((int) 0x35a29797), unchecked((int) 0x88cc4444),
unchecked((int) 0x2e391717), unchecked((int) 0x9357c4c4), unchecked((int) 0x55f2a7a7), unchecked((int) 0xfc827e7e), unchecked((int) 0x7a473d3d),
unchecked((int) 0xc8ac6464), unchecked((int) 0xbae75d5d), unchecked((int) 0x322b1919), unchecked((int) 0xe6957373), unchecked((int) 0xc0a06060),
unchecked((int) 0x19988181), unchecked((int) 0x9ed14f4f), unchecked((int) 0xa37fdcdc), unchecked((int) 0x44662222), unchecked((int) 0x547e2a2a),
unchecked((int) 0x3bab9090), unchecked((int) 0x0b838888), unchecked((int) 0x8cca4646), unchecked((int) 0xc729eeee), unchecked((int) 0x6bd3b8b8),
unchecked((int) 0x283c1414), unchecked((int) 0xa779dede), unchecked((int) 0xbce25e5e), unchecked((int) 0x161d0b0b), unchecked((int) 0xad76dbdb),
unchecked((int) 0xdb3be0e0), unchecked((int) 0x64563232), unchecked((int) 0x744e3a3a), unchecked((int) 0x141e0a0a), unchecked((int) 0x92db4949),
unchecked((int) 0x0c0a0606), unchecked((int) 0x486c2424), unchecked((int) 0xb8e45c5c), unchecked((int) 0x9f5dc2c2), unchecked((int) 0xbd6ed3d3),
unchecked((int) 0x43efacac), unchecked((int) 0xc4a66262), unchecked((int) 0x39a89191), unchecked((int) 0x31a49595), unchecked((int) 0xd337e4e4),
unchecked((int) 0xf28b7979), unchecked((int) 0xd532e7e7), unchecked((int) 0x8b43c8c8), unchecked((int) 0x6e593737), unchecked((int) 0xdab76d6d),
unchecked((int) 0x018c8d8d), unchecked((int) 0xb164d5d5), unchecked((int) 0x9cd24e4e), unchecked((int) 0x49e0a9a9), unchecked((int) 0xd8b46c6c),
unchecked((int) 0xacfa5656), unchecked((int) 0xf307f4f4), unchecked((int) 0xcf25eaea), unchecked((int) 0xcaaf6565), unchecked((int) 0xf48e7a7a),
unchecked((int) 0x47e9aeae), unchecked((int) 0x10180808), unchecked((int) 0x6fd5baba), unchecked((int) 0xf0887878), unchecked((int) 0x4a6f2525),
unchecked((int) 0x5c722e2e), unchecked((int) 0x38241c1c), unchecked((int) 0x57f1a6a6), unchecked((int) 0x73c7b4b4), unchecked((int) 0x9751c6c6),
unchecked((int) 0xcb23e8e8), unchecked((int) 0xa17cdddd), unchecked((int) 0xe89c7474), unchecked((int) 0x3e211f1f), unchecked((int) 0x96dd4b4b),
unchecked((int) 0x61dcbdbd), unchecked((int) 0x0d868b8b), unchecked((int) 0x0f858a8a), unchecked((int) 0xe0907070), unchecked((int) 0x7c423e3e),
unchecked((int) 0x71c4b5b5), unchecked((int) 0xccaa6666), unchecked((int) 0x90d84848), unchecked((int) 0x06050303), unchecked((int) 0xf701f6f6),
unchecked((int) 0x1c120e0e), unchecked((int) 0xc2a36161), unchecked((int) 0x6a5f3535), unchecked((int) 0xaef95757), unchecked((int) 0x69d0b9b9),
unchecked((int) 0x17918686), unchecked((int) 0x9958c1c1), unchecked((int) 0x3a271d1d), unchecked((int) 0x27b99e9e), unchecked((int) 0xd938e1e1),
unchecked((int) 0xeb13f8f8), unchecked((int) 0x2bb39898), unchecked((int) 0x22331111), unchecked((int) 0xd2bb6969), unchecked((int) 0xa970d9d9),
unchecked((int) 0x07898e8e), unchecked((int) 0x33a79494), unchecked((int) 0x2db69b9b), unchecked((int) 0x3c221e1e), unchecked((int) 0x15928787),
unchecked((int) 0xc920e9e9), unchecked((int) 0x8749cece), unchecked((int) 0xaaff5555), unchecked((int) 0x50782828), unchecked((int) 0xa57adfdf),
unchecked((int) 0x038f8c8c), unchecked((int) 0x59f8a1a1), unchecked((int) 0x09808989), unchecked((int) 0x1a170d0d), unchecked((int) 0x65dabfbf),
unchecked((int) 0xd731e6e6), unchecked((int) 0x84c64242), unchecked((int) 0xd0b86868), unchecked((int) 0x82c34141), unchecked((int) 0x29b09999),
unchecked((int) 0x5a772d2d), unchecked((int) 0x1e110f0f), unchecked((int) 0x7bcbb0b0), unchecked((int) 0xa8fc5454), unchecked((int) 0x6dd6bbbb),
unchecked((int) 0x2c3a1616)};
private static readonly int[] Tinv0 =
{
unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b),
unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad),
unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526),
unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d),
unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03),
unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458),
unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899),
unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d),
unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1),
unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f),
unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3),
unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3),
unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a),
unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506),
unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05),
unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd),
unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491),
unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6),
unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7),
unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000),
unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd),
unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68),
unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4),
unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c),
unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e),
unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af),
unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644),
unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8),
unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85),
unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc),
unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411),
unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322),
unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6),
unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850),
unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e),
unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf),
unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd),
unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa),
unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea),
unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235),
unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1),
unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43),
unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1),
unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb),
unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a),
unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7),
unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418),
unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478),
unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16),
unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08),
unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48),
unchecked((int) 0x4257b8d0)};
private static readonly int[] Tinv1 =
{
unchecked((int) 0xa7f45150), unchecked((int) 0x65417e53), unchecked((int) 0xa4171ac3), unchecked((int) 0x5e273a96), unchecked((int) 0x6bab3bcb),
unchecked((int) 0x459d1ff1), unchecked((int) 0x58faacab), unchecked((int) 0x03e34b93), unchecked((int) 0xfa302055), unchecked((int) 0x6d76adf6),
unchecked((int) 0x76cc8891), unchecked((int) 0x4c02f525), unchecked((int) 0xd7e54ffc), unchecked((int) 0xcb2ac5d7), unchecked((int) 0x44352680),
unchecked((int) 0xa362b58f), unchecked((int) 0x5ab1de49), unchecked((int) 0x1bba2567), unchecked((int) 0x0eea4598), unchecked((int) 0xc0fe5de1),
unchecked((int) 0x752fc302), unchecked((int) 0xf04c8112), unchecked((int) 0x97468da3), unchecked((int) 0xf9d36bc6), unchecked((int) 0x5f8f03e7),
unchecked((int) 0x9c921595), unchecked((int) 0x7a6dbfeb), unchecked((int) 0x595295da), unchecked((int) 0x83bed42d), unchecked((int) 0x217458d3),
unchecked((int) 0x69e04929), unchecked((int) 0xc8c98e44), unchecked((int) 0x89c2756a), unchecked((int) 0x798ef478), unchecked((int) 0x3e58996b),
unchecked((int) 0x71b927dd), unchecked((int) 0x4fe1beb6), unchecked((int) 0xad88f017), unchecked((int) 0xac20c966), unchecked((int) 0x3ace7db4),
unchecked((int) 0x4adf6318), unchecked((int) 0x311ae582), unchecked((int) 0x33519760), unchecked((int) 0x7f536245), unchecked((int) 0x7764b1e0),
unchecked((int) 0xae6bbb84), unchecked((int) 0xa081fe1c), unchecked((int) 0x2b08f994), unchecked((int) 0x68487058), unchecked((int) 0xfd458f19),
unchecked((int) 0x6cde9487), unchecked((int) 0xf87b52b7), unchecked((int) 0xd373ab23), unchecked((int) 0x024b72e2), unchecked((int) 0x8f1fe357),
unchecked((int) 0xab55662a), unchecked((int) 0x28ebb207), unchecked((int) 0xc2b52f03), unchecked((int) 0x7bc5869a), unchecked((int) 0x0837d3a5),
unchecked((int) 0x872830f2), unchecked((int) 0xa5bf23b2), unchecked((int) 0x6a0302ba), unchecked((int) 0x8216ed5c), unchecked((int) 0x1ccf8a2b),
unchecked((int) 0xb479a792), unchecked((int) 0xf207f3f0), unchecked((int) 0xe2694ea1), unchecked((int) 0xf4da65cd), unchecked((int) 0xbe0506d5),
unchecked((int) 0x6234d11f), unchecked((int) 0xfea6c48a), unchecked((int) 0x532e349d), unchecked((int) 0x55f3a2a0), unchecked((int) 0xe18a0532),
unchecked((int) 0xebf6a475), unchecked((int) 0xec830b39), unchecked((int) 0xef6040aa), unchecked((int) 0x9f715e06), unchecked((int) 0x106ebd51),
unchecked((int) 0x8a213ef9), unchecked((int) 0x06dd963d), unchecked((int) 0x053eddae), unchecked((int) 0xbde64d46), unchecked((int) 0x8d5491b5),
unchecked((int) 0x5dc47105), unchecked((int) 0xd406046f), unchecked((int) 0x155060ff), unchecked((int) 0xfb981924), unchecked((int) 0xe9bdd697),
unchecked((int) 0x434089cc), unchecked((int) 0x9ed96777), unchecked((int) 0x42e8b0bd), unchecked((int) 0x8b890788), unchecked((int) 0x5b19e738),
unchecked((int) 0xeec879db), unchecked((int) 0x0a7ca147), unchecked((int) 0x0f427ce9), unchecked((int) 0x1e84f8c9), unchecked((int) 0x00000000),
unchecked((int) 0x86800983), unchecked((int) 0xed2b3248), unchecked((int) 0x70111eac), unchecked((int) 0x725a6c4e), unchecked((int) 0xff0efdfb),
unchecked((int) 0x38850f56), unchecked((int) 0xd5ae3d1e), unchecked((int) 0x392d3627), unchecked((int) 0xd90f0a64), unchecked((int) 0xa65c6821),
unchecked((int) 0x545b9bd1), unchecked((int) 0x2e36243a), unchecked((int) 0x670a0cb1), unchecked((int) 0xe757930f), unchecked((int) 0x96eeb4d2),
unchecked((int) 0x919b1b9e), unchecked((int) 0xc5c0804f), unchecked((int) 0x20dc61a2), unchecked((int) 0x4b775a69), unchecked((int) 0x1a121c16),
unchecked((int) 0xba93e20a), unchecked((int) 0x2aa0c0e5), unchecked((int) 0xe0223c43), unchecked((int) 0x171b121d), unchecked((int) 0x0d090e0b),
unchecked((int) 0xc78bf2ad), unchecked((int) 0xa8b62db9), unchecked((int) 0xa91e14c8), unchecked((int) 0x19f15785), unchecked((int) 0x0775af4c),
unchecked((int) 0xdd99eebb), unchecked((int) 0x607fa3fd), unchecked((int) 0x2601f79f), unchecked((int) 0xf5725cbc), unchecked((int) 0x3b6644c5),
unchecked((int) 0x7efb5b34), unchecked((int) 0x29438b76), unchecked((int) 0xc623cbdc), unchecked((int) 0xfcedb668), unchecked((int) 0xf1e4b863),
unchecked((int) 0xdc31d7ca), unchecked((int) 0x85634210), unchecked((int) 0x22971340), unchecked((int) 0x11c68420), unchecked((int) 0x244a857d),
unchecked((int) 0x3dbbd2f8), unchecked((int) 0x32f9ae11), unchecked((int) 0xa129c76d), unchecked((int) 0x2f9e1d4b), unchecked((int) 0x30b2dcf3),
unchecked((int) 0x52860dec), unchecked((int) 0xe3c177d0), unchecked((int) 0x16b32b6c), unchecked((int) 0xb970a999), unchecked((int) 0x489411fa),
unchecked((int) 0x64e94722), unchecked((int) 0x8cfca8c4), unchecked((int) 0x3ff0a01a), unchecked((int) 0x2c7d56d8), unchecked((int) 0x903322ef),
unchecked((int) 0x4e4987c7), unchecked((int) 0xd138d9c1), unchecked((int) 0xa2ca8cfe), unchecked((int) 0x0bd49836), unchecked((int) 0x81f5a6cf),
unchecked((int) 0xde7aa528), unchecked((int) 0x8eb7da26), unchecked((int) 0xbfad3fa4), unchecked((int) 0x9d3a2ce4), unchecked((int) 0x9278500d),
unchecked((int) 0xcc5f6a9b), unchecked((int) 0x467e5462), unchecked((int) 0x138df6c2), unchecked((int) 0xb8d890e8), unchecked((int) 0xf7392e5e),
unchecked((int) 0xafc382f5), unchecked((int) 0x805d9fbe), unchecked((int) 0x93d0697c), unchecked((int) 0x2dd56fa9), unchecked((int) 0x1225cfb3),
unchecked((int) 0x99acc83b), unchecked((int) 0x7d1810a7), unchecked((int) 0x639ce86e), unchecked((int) 0xbb3bdb7b), unchecked((int) 0x7826cd09),
unchecked((int) 0x18596ef4), unchecked((int) 0xb79aec01), unchecked((int) 0x9a4f83a8), unchecked((int) 0x6e95e665), unchecked((int) 0xe6ffaa7e),
unchecked((int) 0xcfbc2108), unchecked((int) 0xe815efe6), unchecked((int) 0x9be7bad9), unchecked((int) 0x366f4ace), unchecked((int) 0x099fead4),
unchecked((int) 0x7cb029d6), unchecked((int) 0xb2a431af), unchecked((int) 0x233f2a31), unchecked((int) 0x94a5c630), unchecked((int) 0x66a235c0),
unchecked((int) 0xbc4e7437), unchecked((int) 0xca82fca6), unchecked((int) 0xd090e0b0), unchecked((int) 0xd8a73315), unchecked((int) 0x9804f14a),
unchecked((int) 0xdaec41f7), unchecked((int) 0x50cd7f0e), unchecked((int) 0xf691172f), unchecked((int) 0xd64d768d), unchecked((int) 0xb0ef434d),
unchecked((int) 0x4daacc54), unchecked((int) 0x0496e4df), unchecked((int) 0xb5d19ee3), unchecked((int) 0x886a4c1b), unchecked((int) 0x1f2cc1b8),
unchecked((int) 0x5165467f), unchecked((int) 0xea5e9d04), unchecked((int) 0x358c015d), unchecked((int) 0x7487fa73), unchecked((int) 0x410bfb2e),
unchecked((int) 0x1d67b35a), unchecked((int) 0xd2db9252), unchecked((int) 0x5610e933), unchecked((int) 0x47d66d13), unchecked((int) 0x61d79a8c),
unchecked((int) 0x0ca1377a), unchecked((int) 0x14f8598e), unchecked((int) 0x3c13eb89), unchecked((int) 0x27a9ceee), unchecked((int) 0xc961b735),
unchecked((int) 0xe51ce1ed), unchecked((int) 0xb1477a3c), unchecked((int) 0xdfd29c59), unchecked((int) 0x73f2553f), unchecked((int) 0xce141879),
unchecked((int) 0x37c773bf), unchecked((int) 0xcdf753ea), unchecked((int) 0xaafd5f5b), unchecked((int) 0x6f3ddf14), unchecked((int) 0xdb447886),
unchecked((int) 0xf3afca81), unchecked((int) 0xc468b93e), unchecked((int) 0x3424382c), unchecked((int) 0x40a3c25f), unchecked((int) 0xc31d1672),
unchecked((int) 0x25e2bc0c), unchecked((int) 0x493c288b), unchecked((int) 0x950dff41), unchecked((int) 0x01a83971), unchecked((int) 0xb30c08de),
unchecked((int) 0xe4b4d89c), unchecked((int) 0xc1566490), unchecked((int) 0x84cb7b61), unchecked((int) 0xb632d570), unchecked((int) 0x5c6c4874),
unchecked((int) 0x57b8d042)};
private static readonly int[] Tinv2 =
{
unchecked((int) 0xf45150a7), unchecked((int) 0x417e5365), unchecked((int) 0x171ac3a4), unchecked((int) 0x273a965e), unchecked((int) 0xab3bcb6b),
unchecked((int) 0x9d1ff145), unchecked((int) 0xfaacab58), unchecked((int) 0xe34b9303), unchecked((int) 0x302055fa), unchecked((int) 0x76adf66d),
unchecked((int) 0xcc889176), unchecked((int) 0x02f5254c), unchecked((int) 0xe54ffcd7), unchecked((int) 0x2ac5d7cb), unchecked((int) 0x35268044),
unchecked((int) 0x62b58fa3), unchecked((int) 0xb1de495a), unchecked((int) 0xba25671b), unchecked((int) 0xea45980e), unchecked((int) 0xfe5de1c0),
unchecked((int) 0x2fc30275), unchecked((int) 0x4c8112f0), unchecked((int) 0x468da397), unchecked((int) 0xd36bc6f9), unchecked((int) 0x8f03e75f),
unchecked((int) 0x9215959c), unchecked((int) 0x6dbfeb7a), unchecked((int) 0x5295da59), unchecked((int) 0xbed42d83), unchecked((int) 0x7458d321),
unchecked((int) 0xe0492969), unchecked((int) 0xc98e44c8), unchecked((int) 0xc2756a89), unchecked((int) 0x8ef47879), unchecked((int) 0x58996b3e),
unchecked((int) 0xb927dd71), unchecked((int) 0xe1beb64f), unchecked((int) 0x88f017ad), unchecked((int) 0x20c966ac), unchecked((int) 0xce7db43a),
unchecked((int) 0xdf63184a), unchecked((int) 0x1ae58231), unchecked((int) 0x51976033), unchecked((int) 0x5362457f), unchecked((int) 0x64b1e077),
unchecked((int) 0x6bbb84ae), unchecked((int) 0x81fe1ca0), unchecked((int) 0x08f9942b), unchecked((int) 0x48705868), unchecked((int) 0x458f19fd),
unchecked((int) 0xde94876c), unchecked((int) 0x7b52b7f8), unchecked((int) 0x73ab23d3), unchecked((int) 0x4b72e202), unchecked((int) 0x1fe3578f),
unchecked((int) 0x55662aab), unchecked((int) 0xebb20728), unchecked((int) 0xb52f03c2), unchecked((int) 0xc5869a7b), unchecked((int) 0x37d3a508),
unchecked((int) 0x2830f287), unchecked((int) 0xbf23b2a5), unchecked((int) 0x0302ba6a), unchecked((int) 0x16ed5c82), unchecked((int) 0xcf8a2b1c),
unchecked((int) 0x79a792b4), unchecked((int) 0x07f3f0f2), unchecked((int) 0x694ea1e2), unchecked((int) 0xda65cdf4), unchecked((int) 0x0506d5be),
unchecked((int) 0x34d11f62), unchecked((int) 0xa6c48afe), unchecked((int) 0x2e349d53), unchecked((int) 0xf3a2a055), unchecked((int) 0x8a0532e1),
unchecked((int) 0xf6a475eb), unchecked((int) 0x830b39ec), unchecked((int) 0x6040aaef), unchecked((int) 0x715e069f), unchecked((int) 0x6ebd5110),
unchecked((int) 0x213ef98a), unchecked((int) 0xdd963d06), unchecked((int) 0x3eddae05), unchecked((int) 0xe64d46bd), unchecked((int) 0x5491b58d),
unchecked((int) 0xc471055d), unchecked((int) 0x06046fd4), unchecked((int) 0x5060ff15), unchecked((int) 0x981924fb), unchecked((int) 0xbdd697e9),
unchecked((int) 0x4089cc43), unchecked((int) 0xd967779e), unchecked((int) 0xe8b0bd42), unchecked((int) 0x8907888b), unchecked((int) 0x19e7385b),
unchecked((int) 0xc879dbee), unchecked((int) 0x7ca1470a), unchecked((int) 0x427ce90f), unchecked((int) 0x84f8c91e), unchecked((int) 0x00000000),
unchecked((int) 0x80098386), unchecked((int) 0x2b3248ed), unchecked((int) 0x111eac70), unchecked((int) 0x5a6c4e72), unchecked((int) 0x0efdfbff),
unchecked((int) 0x850f5638), unchecked((int) 0xae3d1ed5), unchecked((int) 0x2d362739), unchecked((int) 0x0f0a64d9), unchecked((int) 0x5c6821a6),
unchecked((int) 0x5b9bd154), unchecked((int) 0x36243a2e), unchecked((int) 0x0a0cb167), unchecked((int) 0x57930fe7), unchecked((int) 0xeeb4d296),
unchecked((int) 0x9b1b9e91), unchecked((int) 0xc0804fc5), unchecked((int) 0xdc61a220), unchecked((int) 0x775a694b), unchecked((int) 0x121c161a),
unchecked((int) 0x93e20aba), unchecked((int) 0xa0c0e52a), unchecked((int) 0x223c43e0), unchecked((int) 0x1b121d17), unchecked((int) 0x090e0b0d),
unchecked((int) 0x8bf2adc7), unchecked((int) 0xb62db9a8), unchecked((int) 0x1e14c8a9), unchecked((int) 0xf1578519), unchecked((int) 0x75af4c07),
unchecked((int) 0x99eebbdd), unchecked((int) 0x7fa3fd60), unchecked((int) 0x01f79f26), unchecked((int) 0x725cbcf5), unchecked((int) 0x6644c53b),
unchecked((int) 0xfb5b347e), unchecked((int) 0x438b7629), unchecked((int) 0x23cbdcc6), unchecked((int) 0xedb668fc), unchecked((int) 0xe4b863f1),
unchecked((int) 0x31d7cadc), unchecked((int) 0x63421085), unchecked((int) 0x97134022), unchecked((int) 0xc6842011), unchecked((int) 0x4a857d24),
unchecked((int) 0xbbd2f83d), unchecked((int) 0xf9ae1132), unchecked((int) 0x29c76da1), unchecked((int) 0x9e1d4b2f), unchecked((int) 0xb2dcf330),
unchecked((int) 0x860dec52), unchecked((int) 0xc177d0e3), unchecked((int) 0xb32b6c16), unchecked((int) 0x70a999b9), unchecked((int) 0x9411fa48),
unchecked((int) 0xe9472264), unchecked((int) 0xfca8c48c), unchecked((int) 0xf0a01a3f), unchecked((int) 0x7d56d82c), unchecked((int) 0x3322ef90),
unchecked((int) 0x4987c74e), unchecked((int) 0x38d9c1d1), unchecked((int) 0xca8cfea2), unchecked((int) 0xd498360b), unchecked((int) 0xf5a6cf81),
unchecked((int) 0x7aa528de), unchecked((int) 0xb7da268e), unchecked((int) 0xad3fa4bf), unchecked((int) 0x3a2ce49d), unchecked((int) 0x78500d92),
unchecked((int) 0x5f6a9bcc), unchecked((int) 0x7e546246), unchecked((int) 0x8df6c213), unchecked((int) 0xd890e8b8), unchecked((int) 0x392e5ef7),
unchecked((int) 0xc382f5af), unchecked((int) 0x5d9fbe80), unchecked((int) 0xd0697c93), unchecked((int) 0xd56fa92d), unchecked((int) 0x25cfb312),
unchecked((int) 0xacc83b99), unchecked((int) 0x1810a77d), unchecked((int) 0x9ce86e63), unchecked((int) 0x3bdb7bbb), unchecked((int) 0x26cd0978),
unchecked((int) 0x596ef418), unchecked((int) 0x9aec01b7), unchecked((int) 0x4f83a89a), unchecked((int) 0x95e6656e), unchecked((int) 0xffaa7ee6),
unchecked((int) 0xbc2108cf), unchecked((int) 0x15efe6e8), unchecked((int) 0xe7bad99b), unchecked((int) 0x6f4ace36), unchecked((int) 0x9fead409),
unchecked((int) 0xb029d67c), unchecked((int) 0xa431afb2), unchecked((int) 0x3f2a3123), unchecked((int) 0xa5c63094), unchecked((int) 0xa235c066),
unchecked((int) 0x4e7437bc), unchecked((int) 0x82fca6ca), unchecked((int) 0x90e0b0d0), unchecked((int) 0xa73315d8), unchecked((int) 0x04f14a98),
unchecked((int) 0xec41f7da), unchecked((int) 0xcd7f0e50), unchecked((int) 0x91172ff6), unchecked((int) 0x4d768dd6), unchecked((int) 0xef434db0),
unchecked((int) 0xaacc544d), unchecked((int) 0x96e4df04), unchecked((int) 0xd19ee3b5), unchecked((int) 0x6a4c1b88), unchecked((int) 0x2cc1b81f),
unchecked((int) 0x65467f51), unchecked((int) 0x5e9d04ea), unchecked((int) 0x8c015d35), unchecked((int) 0x87fa7374), unchecked((int) 0x0bfb2e41),
unchecked((int) 0x67b35a1d), unchecked((int) 0xdb9252d2), unchecked((int) 0x10e93356), unchecked((int) 0xd66d1347), unchecked((int) 0xd79a8c61),
unchecked((int) 0xa1377a0c), unchecked((int) 0xf8598e14), unchecked((int) 0x13eb893c), unchecked((int) 0xa9ceee27), unchecked((int) 0x61b735c9),
unchecked((int) 0x1ce1ede5), unchecked((int) 0x477a3cb1), unchecked((int) 0xd29c59df), unchecked((int) 0xf2553f73), unchecked((int) 0x141879ce),
unchecked((int) 0xc773bf37), unchecked((int) 0xf753eacd), unchecked((int) 0xfd5f5baa), unchecked((int) 0x3ddf146f), unchecked((int) 0x447886db),
unchecked((int) 0xafca81f3), unchecked((int) 0x68b93ec4), unchecked((int) 0x24382c34), unchecked((int) 0xa3c25f40), unchecked((int) 0x1d1672c3),
unchecked((int) 0xe2bc0c25), unchecked((int) 0x3c288b49), unchecked((int) 0x0dff4195), unchecked((int) 0xa8397101), unchecked((int) 0x0c08deb3),
unchecked((int) 0xb4d89ce4), unchecked((int) 0x566490c1), unchecked((int) 0xcb7b6184), unchecked((int) 0x32d570b6), unchecked((int) 0x6c48745c),
unchecked((int) 0xb8d04257)};
private static readonly int[] Tinv3 =
{
unchecked((int) 0x5150a7f4), unchecked((int) 0x7e536541), unchecked((int) 0x1ac3a417), unchecked((int) 0x3a965e27), unchecked((int) 0x3bcb6bab),
unchecked((int) 0x1ff1459d), unchecked((int) 0xacab58fa), unchecked((int) 0x4b9303e3), unchecked((int) 0x2055fa30), unchecked((int) 0xadf66d76),
unchecked((int) 0x889176cc), unchecked((int) 0xf5254c02), unchecked((int) 0x4ffcd7e5), unchecked((int) 0xc5d7cb2a), unchecked((int) 0x26804435),
unchecked((int) 0xb58fa362), unchecked((int) 0xde495ab1), unchecked((int) 0x25671bba), unchecked((int) 0x45980eea), unchecked((int) 0x5de1c0fe),
unchecked((int) 0xc302752f), unchecked((int) 0x8112f04c), unchecked((int) 0x8da39746), unchecked((int) 0x6bc6f9d3), unchecked((int) 0x03e75f8f),
unchecked((int) 0x15959c92), unchecked((int) 0xbfeb7a6d), unchecked((int) 0x95da5952), unchecked((int) 0xd42d83be), unchecked((int) 0x58d32174),
unchecked((int) 0x492969e0), unchecked((int) 0x8e44c8c9), unchecked((int) 0x756a89c2), unchecked((int) 0xf478798e), unchecked((int) 0x996b3e58),
unchecked((int) 0x27dd71b9), unchecked((int) 0xbeb64fe1), unchecked((int) 0xf017ad88), unchecked((int) 0xc966ac20), unchecked((int) 0x7db43ace),
unchecked((int) 0x63184adf), unchecked((int) 0xe582311a), unchecked((int) 0x97603351), unchecked((int) 0x62457f53), unchecked((int) 0xb1e07764),
unchecked((int) 0xbb84ae6b), unchecked((int) 0xfe1ca081), unchecked((int) 0xf9942b08), unchecked((int) 0x70586848), unchecked((int) 0x8f19fd45),
unchecked((int) 0x94876cde), unchecked((int) 0x52b7f87b), unchecked((int) 0xab23d373), unchecked((int) 0x72e2024b), unchecked((int) 0xe3578f1f),
unchecked((int) 0x662aab55), unchecked((int) 0xb20728eb), unchecked((int) 0x2f03c2b5), unchecked((int) 0x869a7bc5), unchecked((int) 0xd3a50837),
unchecked((int) 0x30f28728), unchecked((int) 0x23b2a5bf), unchecked((int) 0x02ba6a03), unchecked((int) 0xed5c8216), unchecked((int) 0x8a2b1ccf),
unchecked((int) 0xa792b479), unchecked((int) 0xf3f0f207), unchecked((int) 0x4ea1e269), unchecked((int) 0x65cdf4da), unchecked((int) 0x06d5be05),
unchecked((int) 0xd11f6234), unchecked((int) 0xc48afea6), unchecked((int) 0x349d532e), unchecked((int) 0xa2a055f3), unchecked((int) 0x0532e18a),
unchecked((int) 0xa475ebf6), unchecked((int) 0x0b39ec83), unchecked((int) 0x40aaef60), unchecked((int) 0x5e069f71), unchecked((int) 0xbd51106e),
unchecked((int) 0x3ef98a21), unchecked((int) 0x963d06dd), unchecked((int) 0xddae053e), unchecked((int) 0x4d46bde6), unchecked((int) 0x91b58d54),
unchecked((int) 0x71055dc4), unchecked((int) 0x046fd406), unchecked((int) 0x60ff1550), unchecked((int) 0x1924fb98), unchecked((int) 0xd697e9bd),
unchecked((int) 0x89cc4340), unchecked((int) 0x67779ed9), unchecked((int) 0xb0bd42e8), unchecked((int) 0x07888b89), unchecked((int) 0xe7385b19),
unchecked((int) 0x79dbeec8), unchecked((int) 0xa1470a7c), unchecked((int) 0x7ce90f42), unchecked((int) 0xf8c91e84), unchecked((int) 0x00000000),
unchecked((int) 0x09838680), unchecked((int) 0x3248ed2b), unchecked((int) 0x1eac7011), unchecked((int) 0x6c4e725a), unchecked((int) 0xfdfbff0e),
unchecked((int) 0x0f563885), unchecked((int) 0x3d1ed5ae), unchecked((int) 0x3627392d), unchecked((int) 0x0a64d90f), unchecked((int) 0x6821a65c),
unchecked((int) 0x9bd1545b), unchecked((int) 0x243a2e36), unchecked((int) 0x0cb1670a), unchecked((int) 0x930fe757), unchecked((int) 0xb4d296ee),
unchecked((int) 0x1b9e919b), unchecked((int) 0x804fc5c0), unchecked((int) 0x61a220dc), unchecked((int) 0x5a694b77), unchecked((int) 0x1c161a12),
unchecked((int) 0xe20aba93), unchecked((int) 0xc0e52aa0), unchecked((int) 0x3c43e022), unchecked((int) 0x121d171b), unchecked((int) 0x0e0b0d09),
unchecked((int) 0xf2adc78b), unchecked((int) 0x2db9a8b6), unchecked((int) 0x14c8a91e), unchecked((int) 0x578519f1), unchecked((int) 0xaf4c0775),
unchecked((int) 0xeebbdd99), unchecked((int) 0xa3fd607f), unchecked((int) 0xf79f2601), unchecked((int) 0x5cbcf572), unchecked((int) 0x44c53b66),
unchecked((int) 0x5b347efb), unchecked((int) 0x8b762943), unchecked((int) 0xcbdcc623), unchecked((int) 0xb668fced), unchecked((int) 0xb863f1e4),
unchecked((int) 0xd7cadc31), unchecked((int) 0x42108563), unchecked((int) 0x13402297), unchecked((int) 0x842011c6), unchecked((int) 0x857d244a),
unchecked((int) 0xd2f83dbb), unchecked((int) 0xae1132f9), unchecked((int) 0xc76da129), unchecked((int) 0x1d4b2f9e), unchecked((int) 0xdcf330b2),
unchecked((int) 0x0dec5286), unchecked((int) 0x77d0e3c1), unchecked((int) 0x2b6c16b3), unchecked((int) 0xa999b970), unchecked((int) 0x11fa4894),
unchecked((int) 0x472264e9), unchecked((int) 0xa8c48cfc), unchecked((int) 0xa01a3ff0), unchecked((int) 0x56d82c7d), unchecked((int) 0x22ef9033),
unchecked((int) 0x87c74e49), unchecked((int) 0xd9c1d138), unchecked((int) 0x8cfea2ca), unchecked((int) 0x98360bd4), unchecked((int) 0xa6cf81f5),
unchecked((int) 0xa528de7a), unchecked((int) 0xda268eb7), unchecked((int) 0x3fa4bfad), unchecked((int) 0x2ce49d3a), unchecked((int) 0x500d9278),
unchecked((int) 0x6a9bcc5f), unchecked((int) 0x5462467e), unchecked((int) 0xf6c2138d), unchecked((int) 0x90e8b8d8), unchecked((int) 0x2e5ef739),
unchecked((int) 0x82f5afc3), unchecked((int) 0x9fbe805d), unchecked((int) 0x697c93d0), unchecked((int) 0x6fa92dd5), unchecked((int) 0xcfb31225),
unchecked((int) 0xc83b99ac), unchecked((int) 0x10a77d18), unchecked((int) 0xe86e639c), unchecked((int) 0xdb7bbb3b), unchecked((int) 0xcd097826),
unchecked((int) 0x6ef41859), unchecked((int) 0xec01b79a), unchecked((int) 0x83a89a4f), unchecked((int) 0xe6656e95), unchecked((int) 0xaa7ee6ff),
unchecked((int) 0x2108cfbc), unchecked((int) 0xefe6e815), unchecked((int) 0xbad99be7), unchecked((int) 0x4ace366f), unchecked((int) 0xead4099f),
unchecked((int) 0x29d67cb0), unchecked((int) 0x31afb2a4), unchecked((int) 0x2a31233f), unchecked((int) 0xc63094a5), unchecked((int) 0x35c066a2),
unchecked((int) 0x7437bc4e), unchecked((int) 0xfca6ca82), unchecked((int) 0xe0b0d090), unchecked((int) 0x3315d8a7), unchecked((int) 0xf14a9804),
unchecked((int) 0x41f7daec), unchecked((int) 0x7f0e50cd), unchecked((int) 0x172ff691), unchecked((int) 0x768dd64d), unchecked((int) 0x434db0ef),
unchecked((int) 0xcc544daa), unchecked((int) 0xe4df0496), unchecked((int) 0x9ee3b5d1), unchecked((int) 0x4c1b886a), unchecked((int) 0xc1b81f2c),
unchecked((int) 0x467f5165), unchecked((int) 0x9d04ea5e), unchecked((int) 0x015d358c), unchecked((int) 0xfa737487), unchecked((int) 0xfb2e410b),
unchecked((int) 0xb35a1d67), unchecked((int) 0x9252d2db), unchecked((int) 0xe9335610), unchecked((int) 0x6d1347d6), unchecked((int) 0x9a8c61d7),
unchecked((int) 0x377a0ca1), unchecked((int) 0x598e14f8), unchecked((int) 0xeb893c13), unchecked((int) 0xceee27a9), unchecked((int) 0xb735c961),
unchecked((int) 0xe1ede51c), unchecked((int) 0x7a3cb147), unchecked((int) 0x9c59dfd2), unchecked((int) 0x553f73f2), unchecked((int) 0x1879ce14),
unchecked((int) 0x73bf37c7), unchecked((int) 0x53eacdf7), unchecked((int) 0x5f5baafd), unchecked((int) 0xdf146f3d), unchecked((int) 0x7886db44),
unchecked((int) 0xca81f3af), unchecked((int) 0xb93ec468), unchecked((int) 0x382c3424), unchecked((int) 0xc25f40a3), unchecked((int) 0x1672c31d),
unchecked((int) 0xbc0c25e2), unchecked((int) 0x288b493c), unchecked((int) 0xff41950d), unchecked((int) 0x397101a8), unchecked((int) 0x08deb30c),
unchecked((int) 0xd89ce4b4), unchecked((int) 0x6490c156), unchecked((int) 0x7b6184cb), unchecked((int) 0xd570b632), unchecked((int) 0x48745c6c),
unchecked((int) 0xd04257b8)};
private int Shift(
int r,
int shift)
{
return ((int) ( ( (uint) r >> shift) |
(uint) (r << (32 - shift))
));
}
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const int m1 = unchecked((int) 0x80808080);
private const int m2 = unchecked((int) 0x7f7f7f7f);
private const int m3 = unchecked((int) 0x0000001b);
private int FFmulX(int x) {
return ( (int) ( ((x & m2) << 1) ^
(( (uint)(x & m1) >> 7) * m3)
) );
}
/*
The following defines provide alternative definitions of FFmulX that might
give improved performance if a fast 32-bit multiply is not available.
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
private static final int m4 = 0x1b1b1b1b;
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
*/
private int Inv_Mcol(int x) {
int f2 = FFmulX(x);
int f4 = FFmulX(f2);
int f8 = FFmulX(f4);
int f9 = x ^ f8;
return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
}
private int SubWord(int x) {
return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
}
/**
* Calculate the necessary round keys
* The number of calculations depends on key size and block size
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
* This code is written assuming those are the only possible values
*/
private int[,] GenerateWorkingKey(
byte[] key,
bool forEncryption)
{
int KC = key.Length / 4; // key length in words
int t;
if ((KC != 4) && (KC != 6) && (KC != 8)) {
throw new ArgumentException("Key length not 128/192/256 bits.");
}
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
int[,] W = new int[ROUNDS+1,4]; // 4 words in a block
//
// copy the key into the round key array
//
t = 0;
for (int i = 0; i < key.Length; t++)
{
W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
i+=4;
}
//
// while not enough round key material calculated
// calculate new values
//
int k = (ROUNDS + 1) << 2;
for (int i = KC; (i < k); i++)
{
int temp = W[(i-1)>>2,(i-1)&3];
if ((i % KC) == 0) {
temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
} else if ((KC > 6) && ((i % KC) == 4)) {
temp = SubWord(temp);
}
W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp;
}
if (!forEncryption) {
for (int j = 1; j < ROUNDS; j++) {
for (int i = 0; i < 4; i++){
W[j,i] = Inv_Mcol(W[j,i]);
}
}
}
return W;
}
private int ROUNDS;
private int[,] WorkingKey;
private int C0, C1, C2, C3;
private bool forEncryption;
private const int BLOCK_SIZE = 16;
/**
* default constructor - 128 bit block size.
*/
public AesFastEngine()
{
}
/**
* initialise an AES cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
this.forEncryption = forEncryption;
}
public string AlgorithmName
{
get { return "AES"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (WorkingKey == null)
{
throw new InvalidOperationException("AES engine not initialised");
}
if ((inOff + (32 / 2)) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + (32 / 2)) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
if (forEncryption)
{
UnPackBlock(input, inOff);
EncryptBlock(WorkingKey);
PackBlock(output, outOff);
}
else
{
UnPackBlock(input, inOff);
DecryptBlock(WorkingKey);
PackBlock(output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
}
private void UnPackBlock(
byte[] bytes,
int off)
{
int index = off;
C0 = (bytes[index++] & 0xff);
C0 |= (bytes[index++] & 0xff) << 8;
C0 |= (bytes[index++] & 0xff) << 16;
C0 |= bytes[index++] << 24;
C1 = (bytes[index++] & 0xff);
C1 |= (bytes[index++] & 0xff) << 8;
C1 |= (bytes[index++] & 0xff) << 16;
C1 |= bytes[index++] << 24;
C2 = (bytes[index++] & 0xff);
C2 |= (bytes[index++] & 0xff) << 8;
C2 |= (bytes[index++] & 0xff) << 16;
C2 |= bytes[index++] << 24;
C3 = (bytes[index++] & 0xff);
C3 |= (bytes[index++] & 0xff) << 8;
C3 |= (bytes[index++] & 0xff) << 16;
C3 |= bytes[index++] << 24;
}
private void PackBlock(
byte[] bytes,
int off)
{
int index = off;
bytes[index++] = (byte)C0;
bytes[index++] = (byte)(C0 >> 8);
bytes[index++] = (byte)(C0 >> 16);
bytes[index++] = (byte)(C0 >> 24);
bytes[index++] = (byte)C1;
bytes[index++] = (byte)(C1 >> 8);
bytes[index++] = (byte)(C1 >> 16);
bytes[index++] = (byte)(C1 >> 24);
bytes[index++] = (byte)C2;
bytes[index++] = (byte)(C2 >> 8);
bytes[index++] = (byte)(C2 >> 16);
bytes[index++] = (byte)(C2 >> 24);
bytes[index++] = (byte)C3;
bytes[index++] = (byte)(C3 >> 8);
bytes[index++] = (byte)(C3 >> 16);
bytes[index++] = (byte)(C3 >> 24);
}
private void EncryptBlock(int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[0,0];
C1 ^= KW[0,1];
C2 ^= KW[0,2];
C3 ^= KW[0,3];
for (r = 1; r < ROUNDS - 1;) {
r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0];
r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1];
r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2];
r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3];
C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r,0];
C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r,1];
C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r,2];
C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++,3];
}
r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0];
r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1];
r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2];
r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
}
private void DecryptBlock(int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[ROUNDS,0];
C1 ^= KW[ROUNDS,1];
C2 ^= KW[ROUNDS,2];
C3 ^= KW[ROUNDS,3];
for (r = ROUNDS-1; r>1;) {
r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0];
r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1];
r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2];
r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--,3];
C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r,0];
C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r,1];
C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r,2];
C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--,3];
}
r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0];
r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1];
r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2];
r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r,3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
}
}
}

View File

@@ -0,0 +1,438 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of the AES (Rijndael), from FIPS-197.
* <p>
* For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
*
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
*
* There are three levels of tradeoff of speed vs memory
* Because java has no preprocessor, they are written as three separate classes from which to choose
*
* The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
* and 4 for decryption.
*
* The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
* adding 12 rotate operations per round to compute the values contained in the other tables from
* the contents of the first
*
* The slowest version uses no static tables at all and computes the values
* in each round.
* </p>
* <p>
* This file contains the slowest performance version with no static tables
* for round precomputation, but it has the smallest foot print.
* </p>
*/
public class AesLightEngine
: IBlockCipher
{
// The S box
private static readonly byte[] S = {
(byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
(byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
(byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
(byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
(byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
(byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
(byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
(byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
(byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
(byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
(byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
(byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
(byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
(byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
(byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
(byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
(byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
(byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
(byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
(byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
(byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
(byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
(byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
(byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
(byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
(byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
(byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
(byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
(byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
(byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
(byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
(byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
};
// The inverse S-box
private static readonly byte[] Si = {
(byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
(byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
(byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
(byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
(byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
(byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
(byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
(byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
(byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
(byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
(byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
(byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
(byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
(byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
(byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
(byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
(byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
(byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
(byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
(byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
(byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
(byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
(byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
(byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
(byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
(byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
(byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
(byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
(byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
(byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
(byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
(byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
};
// vector used in calculating key schedule (powers of x in GF(256))
private static readonly int[] rcon = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
private int Shift(
int r,
int shift)
{
return ((int) ( ( (uint) r >> shift) |
(uint) (r << (32 - shift)) )
);
}
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const int m1 = unchecked((int) 0x80808080);
private const int m2 = unchecked((int) 0x7f7f7f7f);
private const int m3 = unchecked((int) 0x0000001b);
private int FFmulX(int x)
{
return ( (int) ( ((x & m2) << 1) ^
(( (uint)(x & m1) >> 7) * m3)
)
);
}
/*
The following defines provide alternative definitions of FFmulX that might
give improved performance if a fast 32-bit multiply is not available.
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
private static final int m4 = 0x1b1b1b1b;
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
*/
private int Mcol(int x)
{
int f2 = FFmulX(x);
return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
}
private int Inv_Mcol(int x)
{
int f2 = FFmulX(x);
int f4 = FFmulX(f2);
int f8 = FFmulX(f4);
int f9 = x ^ f8;
return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
}
private int SubWord(int x)
{
return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
}
/**
* Calculate the necessary round keys
* The number of calculations depends on key size and block size
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
* This code is written assuming those are the only possible values
*/
private int[,] GenerateWorkingKey(
byte[] key,
bool forEncryption)
{
int KC = key.Length / 4; // key length in words
int t;
if ((KC != 4) && (KC != 6) && (KC != 8)) {
throw new ArgumentException("Key length not 128/192/256 bits.");
}
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
int[,] W = new int[ROUNDS+1,4]; // 4 words in a block
//
// copy the key into the round key array
//
t = 0;
for (int i = 0; i < key.Length; t++)
{
W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
i+=4;
}
//
// while not enough round key material calculated
// calculate new values
//
int k = (ROUNDS + 1) << 2;
for (int i = KC; (i < k); i++)
{
int temp = W[(i-1)>>2,(i-1)&3];
if ((i % KC) == 0) {
temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
} else if ((KC > 6) && ((i % KC) == 4)) {
temp = SubWord(temp);
}
W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp;
}
if (!forEncryption) {
for (int j = 1; j < ROUNDS; j++) {
for (int i = 0; i < 4; i++){
W[j,i] = Inv_Mcol(W[j,i]);
}
}
}
return W;
}
private int ROUNDS;
private int[,] WorkingKey;
private int C0, C1, C2, C3;
private bool forEncryption;
private const int BLOCK_SIZE = 16;
/**
* default constructor - 128 bit block size.
*/
public AesLightEngine()
{
}
/**
* initialise an AES cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
this.forEncryption = forEncryption;
}
public string AlgorithmName
{
get { return "AES"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (WorkingKey == null)
{
throw new InvalidOperationException("AES engine not initialised");
}
if ((inOff + (32 / 2)) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + (32 / 2)) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
if (forEncryption)
{
UnPackBlock(input, inOff);
EncryptBlock(WorkingKey);
PackBlock(output, outOff);
}
else
{
UnPackBlock(input, inOff);
DecryptBlock(WorkingKey);
PackBlock(output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
}
private void UnPackBlock(
byte[] bytes,
int off)
{
int index = off;
C0 = (bytes[index++] & 0xff);
C0 |= (bytes[index++] & 0xff) << 8;
C0 |= (bytes[index++] & 0xff) << 16;
C0 |= bytes[index++] << 24;
C1 = (bytes[index++] & 0xff);
C1 |= (bytes[index++] & 0xff) << 8;
C1 |= (bytes[index++] & 0xff) << 16;
C1 |= bytes[index++] << 24;
C2 = (bytes[index++] & 0xff);
C2 |= (bytes[index++] & 0xff) << 8;
C2 |= (bytes[index++] & 0xff) << 16;
C2 |= bytes[index++] << 24;
C3 = (bytes[index++] & 0xff);
C3 |= (bytes[index++] & 0xff) << 8;
C3 |= (bytes[index++] & 0xff) << 16;
C3 |= bytes[index++] << 24;
}
private void PackBlock(
byte[] bytes,
int off)
{
int index = off;
bytes[index++] = (byte)C0;
bytes[index++] = (byte)(C0 >> 8);
bytes[index++] = (byte)(C0 >> 16);
bytes[index++] = (byte)(C0 >> 24);
bytes[index++] = (byte)C1;
bytes[index++] = (byte)(C1 >> 8);
bytes[index++] = (byte)(C1 >> 16);
bytes[index++] = (byte)(C1 >> 24);
bytes[index++] = (byte)C2;
bytes[index++] = (byte)(C2 >> 8);
bytes[index++] = (byte)(C2 >> 16);
bytes[index++] = (byte)(C2 >> 24);
bytes[index++] = (byte)C3;
bytes[index++] = (byte)(C3 >> 8);
bytes[index++] = (byte)(C3 >> 16);
bytes[index++] = (byte)(C3 >> 24);
}
private void EncryptBlock(int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[0,0];
C1 ^= KW[0,1];
C2 ^= KW[0,2];
C3 ^= KW[0,3];
for (r = 1; r < ROUNDS - 1;) {
r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0];
r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1];
r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2];
r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3];
C0 = Mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r,0];
C1 = Mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r,1];
C2 = Mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r,2];
C3 = Mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++,3];
}
r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0];
r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1];
r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2];
r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3];
// the final round is a simple function of S
C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
}
private void DecryptBlock(int[,] KW)
{
int r, r0, r1, r2, r3;
C0 ^= KW[ROUNDS,0];
C1 ^= KW[ROUNDS,1];
C2 ^= KW[ROUNDS,2];
C3 ^= KW[ROUNDS,3];
for (r = ROUNDS-1; r>1;) {
r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0];
r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1];
r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2];
r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--,3];
C0 = Inv_Mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r,0];
C1 = Inv_Mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r,1];
C2 = Inv_Mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r,2];
C3 = Inv_Mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--,3];
}
r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0];
r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1];
r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2];
r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r,3];
// the final round's table is a simple function of Si
C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>
/// An implementation of the AES Key Wrapper from the NIST Key Wrap Specification.
/// <p/>
/// For further details see: <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
/// </remarks>
public class AesWrapEngine
: Rfc3394WrapEngine
{
public AesWrapEngine()
: base(new AesEngine())
{
}
}
}

View File

@@ -0,0 +1,577 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* A class that provides Blowfish key encryption operations,
* such as encoding data and generating keys.
* All the algorithms herein are from Applied Cryptography
* and implement a simplified cryptography interface.
*/
public sealed class BlowfishEngine
: IBlockCipher
{
private readonly static int[]
KP = {
unchecked((int) 0x243F6A88), unchecked((int) 0x85A308D3), unchecked((int) 0x13198A2E), unchecked((int) 0x03707344),
unchecked((int) 0xA4093822), unchecked((int) 0x299F31D0), unchecked((int) 0x082EFA98), unchecked((int) 0xEC4E6C89),
unchecked((int) 0x452821E6), unchecked((int) 0x38D01377), unchecked((int) 0xBE5466CF), unchecked((int) 0x34E90C6C),
unchecked((int) 0xC0AC29B7), unchecked((int) 0xC97C50DD), unchecked((int) 0x3F84D5B5), unchecked((int) 0xB5470917),
unchecked((int) 0x9216D5D9), unchecked((int) 0x8979FB1B)
},
KS0 = {
unchecked((int) 0xD1310BA6), unchecked((int) 0x98DFB5AC), unchecked((int) 0x2FFD72DB), unchecked((int) 0xD01ADFB7),
unchecked((int) 0xB8E1AFED), unchecked((int) 0x6A267E96), unchecked((int) 0xBA7C9045), unchecked((int) 0xF12C7F99),
unchecked((int) 0x24A19947), unchecked((int) 0xB3916CF7), unchecked((int) 0x0801F2E2), unchecked((int) 0x858EFC16),
unchecked((int) 0x636920D8), unchecked((int) 0x71574E69), unchecked((int) 0xA458FEA3), unchecked((int) 0xF4933D7E),
unchecked((int) 0x0D95748F), unchecked((int) 0x728EB658), unchecked((int) 0x718BCD58), unchecked((int) 0x82154AEE),
unchecked((int) 0x7B54A41D), unchecked((int) 0xC25A59B5), unchecked((int) 0x9C30D539), unchecked((int) 0x2AF26013),
unchecked((int) 0xC5D1B023), unchecked((int) 0x286085F0), unchecked((int) 0xCA417918), unchecked((int) 0xB8DB38EF),
unchecked((int) 0x8E79DCB0), unchecked((int) 0x603A180E), unchecked((int) 0x6C9E0E8B), unchecked((int) 0xB01E8A3E),
unchecked((int) 0xD71577C1), unchecked((int) 0xBD314B27), unchecked((int) 0x78AF2FDA), unchecked((int) 0x55605C60),
unchecked((int) 0xE65525F3), unchecked((int) 0xAA55AB94), unchecked((int) 0x57489862), unchecked((int) 0x63E81440),
unchecked((int) 0x55CA396A), unchecked((int) 0x2AAB10B6), unchecked((int) 0xB4CC5C34), unchecked((int) 0x1141E8CE),
unchecked((int) 0xA15486AF), unchecked((int) 0x7C72E993), unchecked((int) 0xB3EE1411), unchecked((int) 0x636FBC2A),
unchecked((int) 0x2BA9C55D), unchecked((int) 0x741831F6), unchecked((int) 0xCE5C3E16), unchecked((int) 0x9B87931E),
unchecked((int) 0xAFD6BA33), unchecked((int) 0x6C24CF5C), unchecked((int) 0x7A325381), unchecked((int) 0x28958677),
unchecked((int) 0x3B8F4898), unchecked((int) 0x6B4BB9AF), unchecked((int) 0xC4BFE81B), unchecked((int) 0x66282193),
unchecked((int) 0x61D809CC), unchecked((int) 0xFB21A991), unchecked((int) 0x487CAC60), unchecked((int) 0x5DEC8032),
unchecked((int) 0xEF845D5D), unchecked((int) 0xE98575B1), unchecked((int) 0xDC262302), unchecked((int) 0xEB651B88),
unchecked((int) 0x23893E81), unchecked((int) 0xD396ACC5), unchecked((int) 0x0F6D6FF3), unchecked((int) 0x83F44239),
unchecked((int) 0x2E0B4482), unchecked((int) 0xA4842004), unchecked((int) 0x69C8F04A), unchecked((int) 0x9E1F9B5E),
unchecked((int) 0x21C66842), unchecked((int) 0xF6E96C9A), unchecked((int) 0x670C9C61), unchecked((int) 0xABD388F0),
unchecked((int) 0x6A51A0D2), unchecked((int) 0xD8542F68), unchecked((int) 0x960FA728), unchecked((int) 0xAB5133A3),
unchecked((int) 0x6EEF0B6C), unchecked((int) 0x137A3BE4), unchecked((int) 0xBA3BF050), unchecked((int) 0x7EFB2A98),
unchecked((int) 0xA1F1651D), unchecked((int) 0x39AF0176), unchecked((int) 0x66CA593E), unchecked((int) 0x82430E88),
unchecked((int) 0x8CEE8619), unchecked((int) 0x456F9FB4), unchecked((int) 0x7D84A5C3), unchecked((int) 0x3B8B5EBE),
unchecked((int) 0xE06F75D8), unchecked((int) 0x85C12073), unchecked((int) 0x401A449F), unchecked((int) 0x56C16AA6),
unchecked((int) 0x4ED3AA62), unchecked((int) 0x363F7706), unchecked((int) 0x1BFEDF72), unchecked((int) 0x429B023D),
unchecked((int) 0x37D0D724), unchecked((int) 0xD00A1248), unchecked((int) 0xDB0FEAD3), unchecked((int) 0x49F1C09B),
unchecked((int) 0x075372C9), unchecked((int) 0x80991B7B), unchecked((int) 0x25D479D8), unchecked((int) 0xF6E8DEF7),
unchecked((int) 0xE3FE501A), unchecked((int) 0xB6794C3B), unchecked((int) 0x976CE0BD), unchecked((int) 0x04C006BA),
unchecked((int) 0xC1A94FB6), unchecked((int) 0x409F60C4), unchecked((int) 0x5E5C9EC2), unchecked((int) 0x196A2463),
unchecked((int) 0x68FB6FAF), unchecked((int) 0x3E6C53B5), unchecked((int) 0x1339B2EB), unchecked((int) 0x3B52EC6F),
unchecked((int) 0x6DFC511F), unchecked((int) 0x9B30952C), unchecked((int) 0xCC814544), unchecked((int) 0xAF5EBD09),
unchecked((int) 0xBEE3D004), unchecked((int) 0xDE334AFD), unchecked((int) 0x660F2807), unchecked((int) 0x192E4BB3),
unchecked((int) 0xC0CBA857), unchecked((int) 0x45C8740F), unchecked((int) 0xD20B5F39), unchecked((int) 0xB9D3FBDB),
unchecked((int) 0x5579C0BD), unchecked((int) 0x1A60320A), unchecked((int) 0xD6A100C6), unchecked((int) 0x402C7279),
unchecked((int) 0x679F25FE), unchecked((int) 0xFB1FA3CC), unchecked((int) 0x8EA5E9F8), unchecked((int) 0xDB3222F8),
unchecked((int) 0x3C7516DF), unchecked((int) 0xFD616B15), unchecked((int) 0x2F501EC8), unchecked((int) 0xAD0552AB),
unchecked((int) 0x323DB5FA), unchecked((int) 0xFD238760), unchecked((int) 0x53317B48), unchecked((int) 0x3E00DF82),
unchecked((int) 0x9E5C57BB), unchecked((int) 0xCA6F8CA0), unchecked((int) 0x1A87562E), unchecked((int) 0xDF1769DB),
unchecked((int) 0xD542A8F6), unchecked((int) 0x287EFFC3), unchecked((int) 0xAC6732C6), unchecked((int) 0x8C4F5573),
unchecked((int) 0x695B27B0), unchecked((int) 0xBBCA58C8), unchecked((int) 0xE1FFA35D), unchecked((int) 0xB8F011A0),
unchecked((int) 0x10FA3D98), unchecked((int) 0xFD2183B8), unchecked((int) 0x4AFCB56C), unchecked((int) 0x2DD1D35B),
unchecked((int) 0x9A53E479), unchecked((int) 0xB6F84565), unchecked((int) 0xD28E49BC), unchecked((int) 0x4BFB9790),
unchecked((int) 0xE1DDF2DA), unchecked((int) 0xA4CB7E33), unchecked((int) 0x62FB1341), unchecked((int) 0xCEE4C6E8),
unchecked((int) 0xEF20CADA), unchecked((int) 0x36774C01), unchecked((int) 0xD07E9EFE), unchecked((int) 0x2BF11FB4),
unchecked((int) 0x95DBDA4D), unchecked((int) 0xAE909198), unchecked((int) 0xEAAD8E71), unchecked((int) 0x6B93D5A0),
unchecked((int) 0xD08ED1D0), unchecked((int) 0xAFC725E0), unchecked((int) 0x8E3C5B2F), unchecked((int) 0x8E7594B7),
unchecked((int) 0x8FF6E2FB), unchecked((int) 0xF2122B64), unchecked((int) 0x8888B812), unchecked((int) 0x900DF01C),
unchecked((int) 0x4FAD5EA0), unchecked((int) 0x688FC31C), unchecked((int) 0xD1CFF191), unchecked((int) 0xB3A8C1AD),
unchecked((int) 0x2F2F2218), unchecked((int) 0xBE0E1777), unchecked((int) 0xEA752DFE), unchecked((int) 0x8B021FA1),
unchecked((int) 0xE5A0CC0F), unchecked((int) 0xB56F74E8), unchecked((int) 0x18ACF3D6), unchecked((int) 0xCE89E299),
unchecked((int) 0xB4A84FE0), unchecked((int) 0xFD13E0B7), unchecked((int) 0x7CC43B81), unchecked((int) 0xD2ADA8D9),
unchecked((int) 0x165FA266), unchecked((int) 0x80957705), unchecked((int) 0x93CC7314), unchecked((int) 0x211A1477),
unchecked((int) 0xE6AD2065), unchecked((int) 0x77B5FA86), unchecked((int) 0xC75442F5), unchecked((int) 0xFB9D35CF),
unchecked((int) 0xEBCDAF0C), unchecked((int) 0x7B3E89A0), unchecked((int) 0xD6411BD3), unchecked((int) 0xAE1E7E49),
unchecked((int) 0x00250E2D), unchecked((int) 0x2071B35E), unchecked((int) 0x226800BB), unchecked((int) 0x57B8E0AF),
unchecked((int) 0x2464369B), unchecked((int) 0xF009B91E), unchecked((int) 0x5563911D), unchecked((int) 0x59DFA6AA),
unchecked((int) 0x78C14389), unchecked((int) 0xD95A537F), unchecked((int) 0x207D5BA2), unchecked((int) 0x02E5B9C5),
unchecked((int) 0x83260376), unchecked((int) 0x6295CFA9), unchecked((int) 0x11C81968), unchecked((int) 0x4E734A41),
unchecked((int) 0xB3472DCA), unchecked((int) 0x7B14A94A), unchecked((int) 0x1B510052), unchecked((int) 0x9A532915),
unchecked((int) 0xD60F573F), unchecked((int) 0xBC9BC6E4), unchecked((int) 0x2B60A476), unchecked((int) 0x81E67400),
unchecked((int) 0x08BA6FB5), unchecked((int) 0x571BE91F), unchecked((int) 0xF296EC6B), unchecked((int) 0x2A0DD915),
unchecked((int) 0xB6636521), unchecked((int) 0xE7B9F9B6), unchecked((int) 0xFF34052E), unchecked((int) 0xC5855664),
unchecked((int) 0x53B02D5D), unchecked((int) 0xA99F8FA1), unchecked((int) 0x08BA4799), unchecked((int) 0x6E85076A)
},
KS1 = {
unchecked((int) 0x4B7A70E9), unchecked((int) 0xB5B32944), unchecked((int) 0xDB75092E), unchecked((int) 0xC4192623),
unchecked((int) 0xAD6EA6B0), unchecked((int) 0x49A7DF7D), unchecked((int) 0x9CEE60B8), unchecked((int) 0x8FEDB266),
unchecked((int) 0xECAA8C71), unchecked((int) 0x699A17FF), unchecked((int) 0x5664526C), unchecked((int) 0xC2B19EE1),
unchecked((int) 0x193602A5), unchecked((int) 0x75094C29), unchecked((int) 0xA0591340), unchecked((int) 0xE4183A3E),
unchecked((int) 0x3F54989A), unchecked((int) 0x5B429D65), unchecked((int) 0x6B8FE4D6), unchecked((int) 0x99F73FD6),
unchecked((int) 0xA1D29C07), unchecked((int) 0xEFE830F5), unchecked((int) 0x4D2D38E6), unchecked((int) 0xF0255DC1),
unchecked((int) 0x4CDD2086), unchecked((int) 0x8470EB26), unchecked((int) 0x6382E9C6), unchecked((int) 0x021ECC5E),
unchecked((int) 0x09686B3F), unchecked((int) 0x3EBAEFC9), unchecked((int) 0x3C971814), unchecked((int) 0x6B6A70A1),
unchecked((int) 0x687F3584), unchecked((int) 0x52A0E286), unchecked((int) 0xB79C5305), unchecked((int) 0xAA500737),
unchecked((int) 0x3E07841C), unchecked((int) 0x7FDEAE5C), unchecked((int) 0x8E7D44EC), unchecked((int) 0x5716F2B8),
unchecked((int) 0xB03ADA37), unchecked((int) 0xF0500C0D), unchecked((int) 0xF01C1F04), unchecked((int) 0x0200B3FF),
unchecked((int) 0xAE0CF51A), unchecked((int) 0x3CB574B2), unchecked((int) 0x25837A58), unchecked((int) 0xDC0921BD),
unchecked((int) 0xD19113F9), unchecked((int) 0x7CA92FF6), unchecked((int) 0x94324773), unchecked((int) 0x22F54701),
unchecked((int) 0x3AE5E581), unchecked((int) 0x37C2DADC), unchecked((int) 0xC8B57634), unchecked((int) 0x9AF3DDA7),
unchecked((int) 0xA9446146), unchecked((int) 0x0FD0030E), unchecked((int) 0xECC8C73E), unchecked((int) 0xA4751E41),
unchecked((int) 0xE238CD99), unchecked((int) 0x3BEA0E2F), unchecked((int) 0x3280BBA1), unchecked((int) 0x183EB331),
unchecked((int) 0x4E548B38), unchecked((int) 0x4F6DB908), unchecked((int) 0x6F420D03), unchecked((int) 0xF60A04BF),
unchecked((int) 0x2CB81290), unchecked((int) 0x24977C79), unchecked((int) 0x5679B072), unchecked((int) 0xBCAF89AF),
unchecked((int) 0xDE9A771F), unchecked((int) 0xD9930810), unchecked((int) 0xB38BAE12), unchecked((int) 0xDCCF3F2E),
unchecked((int) 0x5512721F), unchecked((int) 0x2E6B7124), unchecked((int) 0x501ADDE6), unchecked((int) 0x9F84CD87),
unchecked((int) 0x7A584718), unchecked((int) 0x7408DA17), unchecked((int) 0xBC9F9ABC), unchecked((int) 0xE94B7D8C),
unchecked((int) 0xEC7AEC3A), unchecked((int) 0xDB851DFA), unchecked((int) 0x63094366), unchecked((int) 0xC464C3D2),
unchecked((int) 0xEF1C1847), unchecked((int) 0x3215D908), unchecked((int) 0xDD433B37), unchecked((int) 0x24C2BA16),
unchecked((int) 0x12A14D43), unchecked((int) 0x2A65C451), unchecked((int) 0x50940002), unchecked((int) 0x133AE4DD),
unchecked((int) 0x71DFF89E), unchecked((int) 0x10314E55), unchecked((int) 0x81AC77D6), unchecked((int) 0x5F11199B),
unchecked((int) 0x043556F1), unchecked((int) 0xD7A3C76B), unchecked((int) 0x3C11183B), unchecked((int) 0x5924A509),
unchecked((int) 0xF28FE6ED), unchecked((int) 0x97F1FBFA), unchecked((int) 0x9EBABF2C), unchecked((int) 0x1E153C6E),
unchecked((int) 0x86E34570), unchecked((int) 0xEAE96FB1), unchecked((int) 0x860E5E0A), unchecked((int) 0x5A3E2AB3),
unchecked((int) 0x771FE71C), unchecked((int) 0x4E3D06FA), unchecked((int) 0x2965DCB9), unchecked((int) 0x99E71D0F),
unchecked((int) 0x803E89D6), unchecked((int) 0x5266C825), unchecked((int) 0x2E4CC978), unchecked((int) 0x9C10B36A),
unchecked((int) 0xC6150EBA), unchecked((int) 0x94E2EA78), unchecked((int) 0xA5FC3C53), unchecked((int) 0x1E0A2DF4),
unchecked((int) 0xF2F74EA7), unchecked((int) 0x361D2B3D), unchecked((int) 0x1939260F), unchecked((int) 0x19C27960),
unchecked((int) 0x5223A708), unchecked((int) 0xF71312B6), unchecked((int) 0xEBADFE6E), unchecked((int) 0xEAC31F66),
unchecked((int) 0xE3BC4595), unchecked((int) 0xA67BC883), unchecked((int) 0xB17F37D1), unchecked((int) 0x018CFF28),
unchecked((int) 0xC332DDEF), unchecked((int) 0xBE6C5AA5), unchecked((int) 0x65582185), unchecked((int) 0x68AB9802),
unchecked((int) 0xEECEA50F), unchecked((int) 0xDB2F953B), unchecked((int) 0x2AEF7DAD), unchecked((int) 0x5B6E2F84),
unchecked((int) 0x1521B628), unchecked((int) 0x29076170), unchecked((int) 0xECDD4775), unchecked((int) 0x619F1510),
unchecked((int) 0x13CCA830), unchecked((int) 0xEB61BD96), unchecked((int) 0x0334FE1E), unchecked((int) 0xAA0363CF),
unchecked((int) 0xB5735C90), unchecked((int) 0x4C70A239), unchecked((int) 0xD59E9E0B), unchecked((int) 0xCBAADE14),
unchecked((int) 0xEECC86BC), unchecked((int) 0x60622CA7), unchecked((int) 0x9CAB5CAB), unchecked((int) 0xB2F3846E),
unchecked((int) 0x648B1EAF), unchecked((int) 0x19BDF0CA), unchecked((int) 0xA02369B9), unchecked((int) 0x655ABB50),
unchecked((int) 0x40685A32), unchecked((int) 0x3C2AB4B3), unchecked((int) 0x319EE9D5), unchecked((int) 0xC021B8F7),
unchecked((int) 0x9B540B19), unchecked((int) 0x875FA099), unchecked((int) 0x95F7997E), unchecked((int) 0x623D7DA8),
unchecked((int) 0xF837889A), unchecked((int) 0x97E32D77), unchecked((int) 0x11ED935F), unchecked((int) 0x16681281),
unchecked((int) 0x0E358829), unchecked((int) 0xC7E61FD6), unchecked((int) 0x96DEDFA1), unchecked((int) 0x7858BA99),
unchecked((int) 0x57F584A5), unchecked((int) 0x1B227263), unchecked((int) 0x9B83C3FF), unchecked((int) 0x1AC24696),
unchecked((int) 0xCDB30AEB), unchecked((int) 0x532E3054), unchecked((int) 0x8FD948E4), unchecked((int) 0x6DBC3128),
unchecked((int) 0x58EBF2EF), unchecked((int) 0x34C6FFEA), unchecked((int) 0xFE28ED61), unchecked((int) 0xEE7C3C73),
unchecked((int) 0x5D4A14D9), unchecked((int) 0xE864B7E3), unchecked((int) 0x42105D14), unchecked((int) 0x203E13E0),
unchecked((int) 0x45EEE2B6), unchecked((int) 0xA3AAABEA), unchecked((int) 0xDB6C4F15), unchecked((int) 0xFACB4FD0),
unchecked((int) 0xC742F442), unchecked((int) 0xEF6ABBB5), unchecked((int) 0x654F3B1D), unchecked((int) 0x41CD2105),
unchecked((int) 0xD81E799E), unchecked((int) 0x86854DC7), unchecked((int) 0xE44B476A), unchecked((int) 0x3D816250),
unchecked((int) 0xCF62A1F2), unchecked((int) 0x5B8D2646), unchecked((int) 0xFC8883A0), unchecked((int) 0xC1C7B6A3),
unchecked((int) 0x7F1524C3), unchecked((int) 0x69CB7492), unchecked((int) 0x47848A0B), unchecked((int) 0x5692B285),
unchecked((int) 0x095BBF00), unchecked((int) 0xAD19489D), unchecked((int) 0x1462B174), unchecked((int) 0x23820E00),
unchecked((int) 0x58428D2A), unchecked((int) 0x0C55F5EA), unchecked((int) 0x1DADF43E), unchecked((int) 0x233F7061),
unchecked((int) 0x3372F092), unchecked((int) 0x8D937E41), unchecked((int) 0xD65FECF1), unchecked((int) 0x6C223BDB),
unchecked((int) 0x7CDE3759), unchecked((int) 0xCBEE7460), unchecked((int) 0x4085F2A7), unchecked((int) 0xCE77326E),
unchecked((int) 0xA6078084), unchecked((int) 0x19F8509E), unchecked((int) 0xE8EFD855), unchecked((int) 0x61D99735),
unchecked((int) 0xA969A7AA), unchecked((int) 0xC50C06C2), unchecked((int) 0x5A04ABFC), unchecked((int) 0x800BCADC),
unchecked((int) 0x9E447A2E), unchecked((int) 0xC3453484), unchecked((int) 0xFDD56705), unchecked((int) 0x0E1E9EC9),
unchecked((int) 0xDB73DBD3), unchecked((int) 0x105588CD), unchecked((int) 0x675FDA79), unchecked((int) 0xE3674340),
unchecked((int) 0xC5C43465), unchecked((int) 0x713E38D8), unchecked((int) 0x3D28F89E), unchecked((int) 0xF16DFF20),
unchecked((int) 0x153E21E7), unchecked((int) 0x8FB03D4A), unchecked((int) 0xE6E39F2B), unchecked((int) 0xDB83ADF7)
},
KS2 = {
unchecked((int) 0xE93D5A68), unchecked((int) 0x948140F7), unchecked((int) 0xF64C261C), unchecked((int) 0x94692934),
unchecked((int) 0x411520F7), unchecked((int) 0x7602D4F7), unchecked((int) 0xBCF46B2E), unchecked((int) 0xD4A20068),
unchecked((int) 0xD4082471), unchecked((int) 0x3320F46A), unchecked((int) 0x43B7D4B7), unchecked((int) 0x500061AF),
unchecked((int) 0x1E39F62E), unchecked((int) 0x97244546), unchecked((int) 0x14214F74), unchecked((int) 0xBF8B8840),
unchecked((int) 0x4D95FC1D), unchecked((int) 0x96B591AF), unchecked((int) 0x70F4DDD3), unchecked((int) 0x66A02F45),
unchecked((int) 0xBFBC09EC), unchecked((int) 0x03BD9785), unchecked((int) 0x7FAC6DD0), unchecked((int) 0x31CB8504),
unchecked((int) 0x96EB27B3), unchecked((int) 0x55FD3941), unchecked((int) 0xDA2547E6), unchecked((int) 0xABCA0A9A),
unchecked((int) 0x28507825), unchecked((int) 0x530429F4), unchecked((int) 0x0A2C86DA), unchecked((int) 0xE9B66DFB),
unchecked((int) 0x68DC1462), unchecked((int) 0xD7486900), unchecked((int) 0x680EC0A4), unchecked((int) 0x27A18DEE),
unchecked((int) 0x4F3FFEA2), unchecked((int) 0xE887AD8C), unchecked((int) 0xB58CE006), unchecked((int) 0x7AF4D6B6),
unchecked((int) 0xAACE1E7C), unchecked((int) 0xD3375FEC), unchecked((int) 0xCE78A399), unchecked((int) 0x406B2A42),
unchecked((int) 0x20FE9E35), unchecked((int) 0xD9F385B9), unchecked((int) 0xEE39D7AB), unchecked((int) 0x3B124E8B),
unchecked((int) 0x1DC9FAF7), unchecked((int) 0x4B6D1856), unchecked((int) 0x26A36631), unchecked((int) 0xEAE397B2),
unchecked((int) 0x3A6EFA74), unchecked((int) 0xDD5B4332), unchecked((int) 0x6841E7F7), unchecked((int) 0xCA7820FB),
unchecked((int) 0xFB0AF54E), unchecked((int) 0xD8FEB397), unchecked((int) 0x454056AC), unchecked((int) 0xBA489527),
unchecked((int) 0x55533A3A), unchecked((int) 0x20838D87), unchecked((int) 0xFE6BA9B7), unchecked((int) 0xD096954B),
unchecked((int) 0x55A867BC), unchecked((int) 0xA1159A58), unchecked((int) 0xCCA92963), unchecked((int) 0x99E1DB33),
unchecked((int) 0xA62A4A56), unchecked((int) 0x3F3125F9), unchecked((int) 0x5EF47E1C), unchecked((int) 0x9029317C),
unchecked((int) 0xFDF8E802), unchecked((int) 0x04272F70), unchecked((int) 0x80BB155C), unchecked((int) 0x05282CE3),
unchecked((int) 0x95C11548), unchecked((int) 0xE4C66D22), unchecked((int) 0x48C1133F), unchecked((int) 0xC70F86DC),
unchecked((int) 0x07F9C9EE), unchecked((int) 0x41041F0F), unchecked((int) 0x404779A4), unchecked((int) 0x5D886E17),
unchecked((int) 0x325F51EB), unchecked((int) 0xD59BC0D1), unchecked((int) 0xF2BCC18F), unchecked((int) 0x41113564),
unchecked((int) 0x257B7834), unchecked((int) 0x602A9C60), unchecked((int) 0xDFF8E8A3), unchecked((int) 0x1F636C1B),
unchecked((int) 0x0E12B4C2), unchecked((int) 0x02E1329E), unchecked((int) 0xAF664FD1), unchecked((int) 0xCAD18115),
unchecked((int) 0x6B2395E0), unchecked((int) 0x333E92E1), unchecked((int) 0x3B240B62), unchecked((int) 0xEEBEB922),
unchecked((int) 0x85B2A20E), unchecked((int) 0xE6BA0D99), unchecked((int) 0xDE720C8C), unchecked((int) 0x2DA2F728),
unchecked((int) 0xD0127845), unchecked((int) 0x95B794FD), unchecked((int) 0x647D0862), unchecked((int) 0xE7CCF5F0),
unchecked((int) 0x5449A36F), unchecked((int) 0x877D48FA), unchecked((int) 0xC39DFD27), unchecked((int) 0xF33E8D1E),
unchecked((int) 0x0A476341), unchecked((int) 0x992EFF74), unchecked((int) 0x3A6F6EAB), unchecked((int) 0xF4F8FD37),
unchecked((int) 0xA812DC60), unchecked((int) 0xA1EBDDF8), unchecked((int) 0x991BE14C), unchecked((int) 0xDB6E6B0D),
unchecked((int) 0xC67B5510), unchecked((int) 0x6D672C37), unchecked((int) 0x2765D43B), unchecked((int) 0xDCD0E804),
unchecked((int) 0xF1290DC7), unchecked((int) 0xCC00FFA3), unchecked((int) 0xB5390F92), unchecked((int) 0x690FED0B),
unchecked((int) 0x667B9FFB), unchecked((int) 0xCEDB7D9C), unchecked((int) 0xA091CF0B), unchecked((int) 0xD9155EA3),
unchecked((int) 0xBB132F88), unchecked((int) 0x515BAD24), unchecked((int) 0x7B9479BF), unchecked((int) 0x763BD6EB),
unchecked((int) 0x37392EB3), unchecked((int) 0xCC115979), unchecked((int) 0x8026E297), unchecked((int) 0xF42E312D),
unchecked((int) 0x6842ADA7), unchecked((int) 0xC66A2B3B), unchecked((int) 0x12754CCC), unchecked((int) 0x782EF11C),
unchecked((int) 0x6A124237), unchecked((int) 0xB79251E7), unchecked((int) 0x06A1BBE6), unchecked((int) 0x4BFB6350),
unchecked((int) 0x1A6B1018), unchecked((int) 0x11CAEDFA), unchecked((int) 0x3D25BDD8), unchecked((int) 0xE2E1C3C9),
unchecked((int) 0x44421659), unchecked((int) 0x0A121386), unchecked((int) 0xD90CEC6E), unchecked((int) 0xD5ABEA2A),
unchecked((int) 0x64AF674E), unchecked((int) 0xDA86A85F), unchecked((int) 0xBEBFE988), unchecked((int) 0x64E4C3FE),
unchecked((int) 0x9DBC8057), unchecked((int) 0xF0F7C086), unchecked((int) 0x60787BF8), unchecked((int) 0x6003604D),
unchecked((int) 0xD1FD8346), unchecked((int) 0xF6381FB0), unchecked((int) 0x7745AE04), unchecked((int) 0xD736FCCC),
unchecked((int) 0x83426B33), unchecked((int) 0xF01EAB71), unchecked((int) 0xB0804187), unchecked((int) 0x3C005E5F),
unchecked((int) 0x77A057BE), unchecked((int) 0xBDE8AE24), unchecked((int) 0x55464299), unchecked((int) 0xBF582E61),
unchecked((int) 0x4E58F48F), unchecked((int) 0xF2DDFDA2), unchecked((int) 0xF474EF38), unchecked((int) 0x8789BDC2),
unchecked((int) 0x5366F9C3), unchecked((int) 0xC8B38E74), unchecked((int) 0xB475F255), unchecked((int) 0x46FCD9B9),
unchecked((int) 0x7AEB2661), unchecked((int) 0x8B1DDF84), unchecked((int) 0x846A0E79), unchecked((int) 0x915F95E2),
unchecked((int) 0x466E598E), unchecked((int) 0x20B45770), unchecked((int) 0x8CD55591), unchecked((int) 0xC902DE4C),
unchecked((int) 0xB90BACE1), unchecked((int) 0xBB8205D0), unchecked((int) 0x11A86248), unchecked((int) 0x7574A99E),
unchecked((int) 0xB77F19B6), unchecked((int) 0xE0A9DC09), unchecked((int) 0x662D09A1), unchecked((int) 0xC4324633),
unchecked((int) 0xE85A1F02), unchecked((int) 0x09F0BE8C), unchecked((int) 0x4A99A025), unchecked((int) 0x1D6EFE10),
unchecked((int) 0x1AB93D1D), unchecked((int) 0x0BA5A4DF), unchecked((int) 0xA186F20F), unchecked((int) 0x2868F169),
unchecked((int) 0xDCB7DA83), unchecked((int) 0x573906FE), unchecked((int) 0xA1E2CE9B), unchecked((int) 0x4FCD7F52),
unchecked((int) 0x50115E01), unchecked((int) 0xA70683FA), unchecked((int) 0xA002B5C4), unchecked((int) 0x0DE6D027),
unchecked((int) 0x9AF88C27), unchecked((int) 0x773F8641), unchecked((int) 0xC3604C06), unchecked((int) 0x61A806B5),
unchecked((int) 0xF0177A28), unchecked((int) 0xC0F586E0), unchecked((int) 0x006058AA), unchecked((int) 0x30DC7D62),
unchecked((int) 0x11E69ED7), unchecked((int) 0x2338EA63), unchecked((int) 0x53C2DD94), unchecked((int) 0xC2C21634),
unchecked((int) 0xBBCBEE56), unchecked((int) 0x90BCB6DE), unchecked((int) 0xEBFC7DA1), unchecked((int) 0xCE591D76),
unchecked((int) 0x6F05E409), unchecked((int) 0x4B7C0188), unchecked((int) 0x39720A3D), unchecked((int) 0x7C927C24),
unchecked((int) 0x86E3725F), unchecked((int) 0x724D9DB9), unchecked((int) 0x1AC15BB4), unchecked((int) 0xD39EB8FC),
unchecked((int) 0xED545578), unchecked((int) 0x08FCA5B5), unchecked((int) 0xD83D7CD3), unchecked((int) 0x4DAD0FC4),
unchecked((int) 0x1E50EF5E), unchecked((int) 0xB161E6F8), unchecked((int) 0xA28514D9), unchecked((int) 0x6C51133C),
unchecked((int) 0x6FD5C7E7), unchecked((int) 0x56E14EC4), unchecked((int) 0x362ABFCE), unchecked((int) 0xDDC6C837),
unchecked((int) 0xD79A3234), unchecked((int) 0x92638212), unchecked((int) 0x670EFA8E), unchecked((int) 0x406000E0)
},
KS3 = {
unchecked((int) 0x3A39CE37), unchecked((int) 0xD3FAF5CF), unchecked((int) 0xABC27737), unchecked((int) 0x5AC52D1B),
unchecked((int) 0x5CB0679E), unchecked((int) 0x4FA33742), unchecked((int) 0xD3822740), unchecked((int) 0x99BC9BBE),
unchecked((int) 0xD5118E9D), unchecked((int) 0xBF0F7315), unchecked((int) 0xD62D1C7E), unchecked((int) 0xC700C47B),
unchecked((int) 0xB78C1B6B), unchecked((int) 0x21A19045), unchecked((int) 0xB26EB1BE), unchecked((int) 0x6A366EB4),
unchecked((int) 0x5748AB2F), unchecked((int) 0xBC946E79), unchecked((int) 0xC6A376D2), unchecked((int) 0x6549C2C8),
unchecked((int) 0x530FF8EE), unchecked((int) 0x468DDE7D), unchecked((int) 0xD5730A1D), unchecked((int) 0x4CD04DC6),
unchecked((int) 0x2939BBDB), unchecked((int) 0xA9BA4650), unchecked((int) 0xAC9526E8), unchecked((int) 0xBE5EE304),
unchecked((int) 0xA1FAD5F0), unchecked((int) 0x6A2D519A), unchecked((int) 0x63EF8CE2), unchecked((int) 0x9A86EE22),
unchecked((int) 0xC089C2B8), unchecked((int) 0x43242EF6), unchecked((int) 0xA51E03AA), unchecked((int) 0x9CF2D0A4),
unchecked((int) 0x83C061BA), unchecked((int) 0x9BE96A4D), unchecked((int) 0x8FE51550), unchecked((int) 0xBA645BD6),
unchecked((int) 0x2826A2F9), unchecked((int) 0xA73A3AE1), unchecked((int) 0x4BA99586), unchecked((int) 0xEF5562E9),
unchecked((int) 0xC72FEFD3), unchecked((int) 0xF752F7DA), unchecked((int) 0x3F046F69), unchecked((int) 0x77FA0A59),
unchecked((int) 0x80E4A915), unchecked((int) 0x87B08601), unchecked((int) 0x9B09E6AD), unchecked((int) 0x3B3EE593),
unchecked((int) 0xE990FD5A), unchecked((int) 0x9E34D797), unchecked((int) 0x2CF0B7D9), unchecked((int) 0x022B8B51),
unchecked((int) 0x96D5AC3A), unchecked((int) 0x017DA67D), unchecked((int) 0xD1CF3ED6), unchecked((int) 0x7C7D2D28),
unchecked((int) 0x1F9F25CF), unchecked((int) 0xADF2B89B), unchecked((int) 0x5AD6B472), unchecked((int) 0x5A88F54C),
unchecked((int) 0xE029AC71), unchecked((int) 0xE019A5E6), unchecked((int) 0x47B0ACFD), unchecked((int) 0xED93FA9B),
unchecked((int) 0xE8D3C48D), unchecked((int) 0x283B57CC), unchecked((int) 0xF8D56629), unchecked((int) 0x79132E28),
unchecked((int) 0x785F0191), unchecked((int) 0xED756055), unchecked((int) 0xF7960E44), unchecked((int) 0xE3D35E8C),
unchecked((int) 0x15056DD4), unchecked((int) 0x88F46DBA), unchecked((int) 0x03A16125), unchecked((int) 0x0564F0BD),
unchecked((int) 0xC3EB9E15), unchecked((int) 0x3C9057A2), unchecked((int) 0x97271AEC), unchecked((int) 0xA93A072A),
unchecked((int) 0x1B3F6D9B), unchecked((int) 0x1E6321F5), unchecked((int) 0xF59C66FB), unchecked((int) 0x26DCF319),
unchecked((int) 0x7533D928), unchecked((int) 0xB155FDF5), unchecked((int) 0x03563482), unchecked((int) 0x8ABA3CBB),
unchecked((int) 0x28517711), unchecked((int) 0xC20AD9F8), unchecked((int) 0xABCC5167), unchecked((int) 0xCCAD925F),
unchecked((int) 0x4DE81751), unchecked((int) 0x3830DC8E), unchecked((int) 0x379D5862), unchecked((int) 0x9320F991),
unchecked((int) 0xEA7A90C2), unchecked((int) 0xFB3E7BCE), unchecked((int) 0x5121CE64), unchecked((int) 0x774FBE32),
unchecked((int) 0xA8B6E37E), unchecked((int) 0xC3293D46), unchecked((int) 0x48DE5369), unchecked((int) 0x6413E680),
unchecked((int) 0xA2AE0810), unchecked((int) 0xDD6DB224), unchecked((int) 0x69852DFD), unchecked((int) 0x09072166),
unchecked((int) 0xB39A460A), unchecked((int) 0x6445C0DD), unchecked((int) 0x586CDECF), unchecked((int) 0x1C20C8AE),
unchecked((int) 0x5BBEF7DD), unchecked((int) 0x1B588D40), unchecked((int) 0xCCD2017F), unchecked((int) 0x6BB4E3BB),
unchecked((int) 0xDDA26A7E), unchecked((int) 0x3A59FF45), unchecked((int) 0x3E350A44), unchecked((int) 0xBCB4CDD5),
unchecked((int) 0x72EACEA8), unchecked((int) 0xFA6484BB), unchecked((int) 0x8D6612AE), unchecked((int) 0xBF3C6F47),
unchecked((int) 0xD29BE463), unchecked((int) 0x542F5D9E), unchecked((int) 0xAEC2771B), unchecked((int) 0xF64E6370),
unchecked((int) 0x740E0D8D), unchecked((int) 0xE75B1357), unchecked((int) 0xF8721671), unchecked((int) 0xAF537D5D),
unchecked((int) 0x4040CB08), unchecked((int) 0x4EB4E2CC), unchecked((int) 0x34D2466A), unchecked((int) 0x0115AF84),
unchecked((int) 0xE1B00428), unchecked((int) 0x95983A1D), unchecked((int) 0x06B89FB4), unchecked((int) 0xCE6EA048),
unchecked((int) 0x6F3F3B82), unchecked((int) 0x3520AB82), unchecked((int) 0x011A1D4B), unchecked((int) 0x277227F8),
unchecked((int) 0x611560B1), unchecked((int) 0xE7933FDC), unchecked((int) 0xBB3A792B), unchecked((int) 0x344525BD),
unchecked((int) 0xA08839E1), unchecked((int) 0x51CE794B), unchecked((int) 0x2F32C9B7), unchecked((int) 0xA01FBAC9),
unchecked((int) 0xE01CC87E), unchecked((int) 0xBCC7D1F6), unchecked((int) 0xCF0111C3), unchecked((int) 0xA1E8AAC7),
unchecked((int) 0x1A908749), unchecked((int) 0xD44FBD9A), unchecked((int) 0xD0DADECB), unchecked((int) 0xD50ADA38),
unchecked((int) 0x0339C32A), unchecked((int) 0xC6913667), unchecked((int) 0x8DF9317C), unchecked((int) 0xE0B12B4F),
unchecked((int) 0xF79E59B7), unchecked((int) 0x43F5BB3A), unchecked((int) 0xF2D519FF), unchecked((int) 0x27D9459C),
unchecked((int) 0xBF97222C), unchecked((int) 0x15E6FC2A), unchecked((int) 0x0F91FC71), unchecked((int) 0x9B941525),
unchecked((int) 0xFAE59361), unchecked((int) 0xCEB69CEB), unchecked((int) 0xC2A86459), unchecked((int) 0x12BAA8D1),
unchecked((int) 0xB6C1075E), unchecked((int) 0xE3056A0C), unchecked((int) 0x10D25065), unchecked((int) 0xCB03A442),
unchecked((int) 0xE0EC6E0E), unchecked((int) 0x1698DB3B), unchecked((int) 0x4C98A0BE), unchecked((int) 0x3278E964),
unchecked((int) 0x9F1F9532), unchecked((int) 0xE0D392DF), unchecked((int) 0xD3A0342B), unchecked((int) 0x8971F21E),
unchecked((int) 0x1B0A7441), unchecked((int) 0x4BA3348C), unchecked((int) 0xC5BE7120), unchecked((int) 0xC37632D8),
unchecked((int) 0xDF359F8D), unchecked((int) 0x9B992F2E), unchecked((int) 0xE60B6F47), unchecked((int) 0x0FE3F11D),
unchecked((int) 0xE54CDA54), unchecked((int) 0x1EDAD891), unchecked((int) 0xCE6279CF), unchecked((int) 0xCD3E7E6F),
unchecked((int) 0x1618B166), unchecked((int) 0xFD2C1D05), unchecked((int) 0x848FD2C5), unchecked((int) 0xF6FB2299),
unchecked((int) 0xF523F357), unchecked((int) 0xA6327623), unchecked((int) 0x93A83531), unchecked((int) 0x56CCCD02),
unchecked((int) 0xACF08162), unchecked((int) 0x5A75EBB5), unchecked((int) 0x6E163697), unchecked((int) 0x88D273CC),
unchecked((int) 0xDE966292), unchecked((int) 0x81B949D0), unchecked((int) 0x4C50901B), unchecked((int) 0x71C65614),
unchecked((int) 0xE6C6C7BD), unchecked((int) 0x327A140A), unchecked((int) 0x45E1D006), unchecked((int) 0xC3F27B9A),
unchecked((int) 0xC9AA53FD), unchecked((int) 0x62A80F00), unchecked((int) 0xBB25BFE2), unchecked((int) 0x35BDD2F6),
unchecked((int) 0x71126905), unchecked((int) 0xB2040222), unchecked((int) 0xB6CBCF7C), unchecked((int) 0xCD769C2B),
unchecked((int) 0x53113EC0), unchecked((int) 0x1640E3D3), unchecked((int) 0x38ABBD60), unchecked((int) 0x2547ADF0),
unchecked((int) 0xBA38209C), unchecked((int) 0xF746CE76), unchecked((int) 0x77AFA1C5), unchecked((int) 0x20756060),
unchecked((int) 0x85CBFE4E), unchecked((int) 0x8AE88DD8), unchecked((int) 0x7AAAF9B0), unchecked((int) 0x4CF9AA7E),
unchecked((int) 0x1948C25C), unchecked((int) 0x02FB8A8C), unchecked((int) 0x01C36AE4), unchecked((int) 0xD6EBE1F9),
unchecked((int) 0x90D4F869), unchecked((int) 0xA65CDEA0), unchecked((int) 0x3F09252D), unchecked((int) 0xC208E69F),
unchecked((int) 0xB74E6132), unchecked((int) 0xCE77E25B), unchecked((int) 0x578FDFE3), unchecked((int) 0x3AC372E6)
};
//====================================
// Useful constants
//====================================
private static readonly int ROUNDS = 16;
private const int BLOCK_SIZE = 8; // bytes = 64 bits
private static readonly int SBOX_SK = 256;
private static readonly int P_SZ = ROUNDS+2;
private readonly int[] S0, S1, S2, S3; // the s-boxes
private readonly int[] P; // the p-array
private bool encrypting;
private byte[] workingKey;
public BlowfishEngine()
{
S0 = new int[SBOX_SK];
S1 = new int[SBOX_SK];
S2 = new int[SBOX_SK];
S3 = new int[SBOX_SK];
P = new int[P_SZ];
}
/**
* initialise a Blowfish cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to Blowfish init - " + parameters.GetType().ToString());
this.encrypting = forEncryption;
this.workingKey = ((KeyParameter)parameters).GetKey();
SetKey(this.workingKey);
}
public string AlgorithmName
{
get { return "Blowfish"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("Blowfish not initialised");
}
if ((inOff + BLOCK_SIZE) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + BLOCK_SIZE) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
//==================================
// Private Implementation
//==================================
private int F(int x)
{
return (( (S0[((uint) x >> 24)] + S1[((uint) x >> 16) & 0xff])
^ S2[((uint) x >> 8) & 0xff]) + S3[x & 0xff]);
}
/**
* apply the encryption cycle to each value pair in the table.
*/
private void ProcessTable(
int xl,
int xr,
int[] table)
{
int size = table.Length;
for (int s = 0; s < size; s += 2)
{
xl ^= P[0];
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
table[s] = xr;
table[s + 1] = xl;
xr = xl; // end of cycle swap
xl = table[s];
}
}
private void SetKey(byte[] key)
{
/*
* - comments are from _Applied Crypto_, Schneier, p338
* please be careful comparing the two, AC numbers the
* arrays from 1, the enclosed code from 0.
*
* (1)
* Initialise the S-boxes and the P-array, with a fixed string
* This string contains the hexadecimal digits of pi (3.141...)
*/
Array.Copy(KS0, 0, S0, 0, SBOX_SK);
Array.Copy(KS1, 0, S1, 0, SBOX_SK);
Array.Copy(KS2, 0, S2, 0, SBOX_SK);
Array.Copy(KS3, 0, S3, 0, SBOX_SK);
Array.Copy(KP, 0, P, 0, P_SZ);
/*
* (2)
* Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
* second 32-bits of the key, and so on for all bits of the key
* (up to P[17]). Repeatedly cycle through the key bits until the
* entire P-array has been XOR-ed with the key bits
*/
int keyLength = key.Length;
int keyIndex = 0;
for (int i=0; i < P_SZ; i++)
{
// Get the 32 bits of the key, in 4 * 8 bit chunks
int data = unchecked((int) 0x0000000);
for (int j=0; j < 4; j++)
{
// create a 32 bit block
data = (data << 8) | (key[keyIndex++] & 0xff);
// wrap when we Get to the end of the key
if (keyIndex >= keyLength)
{
keyIndex = 0;
}
}
// XOR the newly created 32 bit chunk onto the P-array
P[i] ^= data;
}
/*
* (3)
* Encrypt the all-zero string with the Blowfish algorithm, using
* the subkeys described in (1) and (2)
*
* (4)
* Replace P1 and P2 with the output of step (3)
*
* (5)
* Encrypt the output of step(3) using the Blowfish algorithm,
* with the modified subkeys.
*
* (6)
* Replace P3 and P4 with the output of step (5)
*
* (7)
* Continue the process, replacing all elements of the P-array
* and then all four S-boxes in order, with the output of the
* continuously changing Blowfish algorithm
*/
ProcessTable(0, 0, P);
ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0);
ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
/**
* Encrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
private void EncryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int xl = BytesTo32bits(src, srcIndex);
int xr = BytesTo32bits(src, srcIndex+4);
xl ^= P[0];
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}
/**
* Decrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
private void DecryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int xl = BytesTo32bits(src, srcIndex);
int xr = BytesTo32bits(src, srcIndex + 4);
xl ^= P[ROUNDS + 1];
for (int i = ROUNDS; i > 0 ; i -= 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}
xr ^= P[0];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex+4);
}
private int BytesTo32bits(byte[] b, int i)
{
return ((b[i] & 0xff) << 24) |
((b[i+1] & 0xff) << 16) |
((b[i+2] & 0xff) << 8) |
((b[i+3] & 0xff));
}
private void Bits32ToBytes(int inData, byte[] b, int offset)
{
b[offset + 3] = (byte)inData;
b[offset + 2] = (byte)(inData >> 8);
b[offset + 1] = (byte)(inData >> 16);
b[offset] = (byte)(inData >> 24);
}
}
}

View File

@@ -0,0 +1,579 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Camellia - based on RFC 3713.
*/
public class CamelliaEngine
: IBlockCipher
{
private bool initialised;
private bool _keyIs128;
private const int BLOCK_SIZE = 16;
private const long MASK8 = 0xff;
private const long MASK32 = 0xffffffffL;
private const long SIGMA1 = unchecked((long) 0xA09E667F3BCC908BL);
private const long SIGMA2 = unchecked((long) 0xB67AE8584CAA73B2L);
private const long SIGMA3 = unchecked((long) 0xC6EF372FE94F82BEL);
private const long SIGMA4 = unchecked((long) 0x54FF53A5F1D36F1CL);
private const long SIGMA5 = unchecked((long) 0x10E527FADE682D1DL);
private const long SIGMA6 = unchecked((long) 0xB05688C2B3E6C1FDL);
private long _kw1, _kw2, _kw3, _kw4;
private long _k1, _k2, _k3, _k4, _k5, _k6, _k7, _k8, _k9, _k10, _k11, _k12,
_k13, _k14, _k15, _k16, _k17, _k18, _k19, _k20, _k21, _k22, _k23, _k24;
private long _ke1, _ke2, _ke3, _ke4, _ke5, _ke6;
private readonly byte[] SBOX1 = {
(byte)112, (byte)130, (byte)44, (byte)236, (byte)179 , (byte)39, (byte)192, (byte)229, (byte)228, (byte)133 , (byte)87 , (byte)53, (byte)234 , (byte)12, (byte)174 , (byte)65,
(byte)35, (byte)239, (byte)107, (byte)147 , (byte)69 , (byte)25, (byte)165 , (byte)33, (byte)237 , (byte)14 , (byte)79 , (byte)78 , (byte)29, (byte)101, (byte)146, (byte)189,
(byte)134, (byte)184, (byte)175, (byte)143, (byte)124, (byte)235 , (byte)31, (byte)206 , (byte)62 , (byte)48, (byte)220 , (byte)95 , (byte)94, (byte)197 , (byte)11 , (byte)26,
(byte)166, (byte)225, (byte)57, (byte)202, (byte)213 , (byte)71 , (byte)93 , (byte)61, (byte)217 , (byte)1 , (byte)90, (byte)214 , (byte)81 , (byte)86, (byte)108 , (byte)77,
(byte)139, (byte)13, (byte)154, (byte)102, (byte)251, (byte)204, (byte)176 , (byte)45, (byte)116 , (byte)18 , (byte)43 , (byte)32, (byte)240, (byte)177, (byte)132, (byte)153,
(byte)223, (byte)76, (byte)203, (byte)194 , (byte)52, (byte)126, (byte)118 , (byte)5, (byte)109, (byte)183, (byte)169 , (byte)49, (byte)209 , (byte)23 , (byte)4, (byte)215,
(byte)20, (byte)88, (byte)58, (byte)97, (byte)222 , (byte)27 , (byte)17 , (byte)28 , (byte)50 , (byte)15, (byte)156 , (byte)22 , (byte)83 , (byte)24, (byte)242 , (byte)34,
(byte)254, (byte)68, (byte)207, (byte)178, (byte)195, (byte)181, (byte)122, (byte)145 , (byte)36 , (byte)8, (byte)232, (byte)168 , (byte)96, (byte)252, (byte)105 , (byte)80,
(byte)170, (byte)208, (byte)160, (byte)125, (byte)161, (byte)137 , (byte)98, (byte)151 , (byte)84 , (byte)91 , (byte)30, (byte)149, (byte)224, (byte)255, (byte)100, (byte)210,
(byte)16, (byte)196, (byte)0, (byte)72, (byte)163, (byte)247, (byte)117, (byte)219, (byte)138 , (byte)3, (byte)230, (byte)218 , (byte)9 , (byte)63, (byte)221, (byte)148,
(byte)135, (byte)92, (byte)131, (byte)2, (byte)205 , (byte)74, (byte)144 , (byte)51, (byte)115, (byte)103, (byte)246, (byte)243, (byte)157, (byte)127, (byte)191, (byte)226,
(byte)82, (byte)155, (byte)216 , (byte)38, (byte)200 , (byte)55, (byte)198 , (byte)59, (byte)129, (byte)150, (byte)111 , (byte)75 , (byte)19, (byte)190 , (byte)99 , (byte)46,
(byte)233, (byte)121, (byte)167, (byte)140, (byte)159, (byte)110, (byte)188, (byte)142 , (byte)41, (byte)245, (byte)249, (byte)182 , (byte)47, (byte)253, (byte)180 , (byte)89,
(byte)120, (byte)152, (byte)6, (byte)106, (byte)231 , (byte)70, (byte)113, (byte)186, (byte)212 , (byte)37, (byte)171 , (byte)66, (byte)136, (byte)162, (byte)141, (byte)250,
(byte)114, (byte)7, (byte)185 , (byte)85, (byte)248, (byte)238, (byte)172 , (byte)10 , (byte)54 , (byte)73 , (byte)42, (byte)104 , (byte)60 , (byte)56, (byte)241, (byte)164,
(byte)64, (byte)40, (byte)211, (byte)123, (byte)187, (byte)201 , (byte)67, (byte)193 , (byte)21, (byte)227, (byte)173, (byte)244, (byte)119, (byte)199, (byte)128, (byte)158
};
private readonly byte[] SBOX2 = new byte[256];
private readonly byte[] SBOX3 = new byte[256];
private readonly byte[] SBOX4 = new byte[256];
public CamelliaEngine()
{
for (int x = 0; x != 256; x++)
{
SBOX2[x] = lRot8(SBOX1[x], 1);
SBOX3[x] = lRot8(SBOX1[x], 7);
SBOX4[x] = SBOX1[lRot8((byte)x, 1) & 0xff];
}
}
private void setKey(
bool forEncryption,
byte[] key)
{
long klA, klB;
long krA, krB;
switch (key.Length)
{
case 16:
_keyIs128 = true;
klA = bytesToWord(key, 0);
klB = bytesToWord(key, 8);
krA = 0;
krB = 0;
break;
case 24:
klA = bytesToWord(key, 0);
klB = bytesToWord(key, 8);
krA = bytesToWord(key, 16);
krB = ~bytesToWord(key, 16);
_keyIs128 = false;
break;
case 32:
klA = bytesToWord(key, 0);
klB = bytesToWord(key, 8);
krA = bytesToWord(key, 16);
krB = bytesToWord(key, 24);
_keyIs128 = false;
break;
default:
throw new ArgumentException("only a key sizes of 128/192/256 are acceptable.");
}
long d1 = klA ^ krA;
long d2 = klB ^ krB;
d2 = d2 ^ f(d1, SIGMA1);
d1 = d1 ^ f(d2, SIGMA2);
d1 = d1 ^ klA;
d2 = d2 ^ klB;
d2 = d2 ^ f(d1, SIGMA3);
d1 = d1 ^ f(d2, SIGMA4);
long kaA = d1;
long kaB = d2;
if (_keyIs128)
{
if (forEncryption)
{
_kw1 = klA;
_kw2 = klB;
_kw3 = lRot128high(kaA, kaB, 111);
_kw4 = lRot128low(kaA, kaB, 111);
_k1 = kaA;
_k2 = kaB;
_k3 = lRot128high(klA, klB, 15);
_k4 = lRot128low(klA, klB, 15);
_k5 = lRot128high(kaA, kaB, 15);
_k6 = lRot128low(kaA, kaB, 15);
_k7 = lRot128high(klA, klB, 45);
_k8 = lRot128low(klA, klB, 45);
_k9 = lRot128high(kaA, kaB, 45);
_k10 = lRot128low(klA, klB, 60);
_k11 = lRot128high(kaA, kaB, 60);
_k12 = lRot128low(kaA, kaB, 60);
_k13 = lRot128high(klA, klB, 94);
_k14 = lRot128low(klA, klB, 94);
_k15 = lRot128high(kaA, kaB, 94);
_k16 = lRot128low(kaA, kaB, 94);
_k17 = lRot128high(klA, klB, 111);
_k18 = lRot128low(klA, klB, 111);
_ke1 = lRot128high(kaA, kaB, 30);
_ke2 = lRot128low(kaA, kaB, 30);
_ke3 = lRot128high(klA, klB, 77);
_ke4 = lRot128low(klA, klB, 77);
}
else
{
_kw3 = klA;
_kw4 = klB;
_kw1 = lRot128high(kaA, kaB, 111);
_kw2 = lRot128low(kaA, kaB, 111);
_k18 = kaA;
_k17 = kaB;
_k16 = lRot128high(klA, klB, 15);
_k15 = lRot128low(klA, klB, 15);
_k14 = lRot128high(kaA, kaB, 15);
_k13 = lRot128low(kaA, kaB, 15);
_k12 = lRot128high(klA, klB, 45);
_k11 = lRot128low(klA, klB, 45);
_k10 = lRot128high(kaA, kaB, 45);
_k9 = lRot128low(klA, klB, 60);
_k8 = lRot128high(kaA, kaB, 60);
_k7 = lRot128low(kaA, kaB, 60);
_k6 = lRot128high(klA, klB, 94);
_k5 = lRot128low(klA, klB, 94);
_k4 = lRot128high(kaA, kaB, 94);
_k3 = lRot128low(kaA, kaB, 94);
_k2 = lRot128high(klA, klB, 111);
_k1 = lRot128low(klA, klB, 111);
_ke4 = lRot128high(kaA, kaB, 30);
_ke3 = lRot128low(kaA, kaB, 30);
_ke2 = lRot128high(klA, klB, 77);
_ke1 = lRot128low(klA, klB, 77);
}
}
else
{
d1 = kaA ^ krA;
d2 = kaB ^ krB;
d2 = d2 ^ f(d1, SIGMA5);
d1 = d1 ^ f(d2, SIGMA6);
long kbA = d1;
long kbB = d2;
if (forEncryption)
{
_kw1 = klA;
_kw2 = klB;
_k1 = kbA;
_k2 = kbB;
_k3 = lRot128high(krA, krB, 15);
_k4 = lRot128low(krA, krB, 15);
_k5 = lRot128high(kaA, kaB, 15);
_k6 = lRot128low(kaA, kaB, 15);
_ke1 = lRot128high(krA, krB, 30);
_ke2 = lRot128low(krA, krB, 30);
_k7 = lRot128high(kbA, kbB, 30);
_k8 = lRot128low(kbA, kbB, 30);
_k9 = lRot128high(klA, klB, 45);
_k10 = lRot128low(klA, klB, 45);
_k11 = lRot128high(kaA, kaB, 45);
_k12 = lRot128low(kaA, kaB, 45);
_ke3 = lRot128high(klA, klB, 60);
_ke4 = lRot128low(klA, klB, 60);
_k13 = lRot128high(krA, krB, 60);
_k14 = lRot128low(krA, krB, 60);
_k15 = lRot128high(kbA, kbB, 60);
_k16 = lRot128low(kbA, kbB, 60);
_k17 = lRot128high(klA, klB, 77);
_k18 = lRot128low(klA, klB, 77);
_ke5 = lRot128high(kaA, kaB, 77);
_ke6 = lRot128low(kaA, kaB, 77);
_k19 = lRot128high(krA, krB, 94);
_k20 = lRot128low(krA, krB, 94);
_k21 = lRot128high(kaA, kaB, 94);
_k22 = lRot128low(kaA, kaB, 94);
_k23 = lRot128high(klA, klB, 111);
_k24 = lRot128low(klA, klB, 111);
_kw3 = lRot128high(kbA, kbB, 111);
_kw4 = lRot128low(kbA, kbB, 111);
}
else
{
_kw3 = klA;
_kw4 = klB;
_kw1 = lRot128high(kbA, kbB, 111);
_kw2 = lRot128low(kbA, kbB, 111);
_k24 = kbA;
_k23 = kbB;
_k22 = lRot128high(krA, krB, 15);
_k21 = lRot128low(krA, krB, 15);
_k20 = lRot128high(kaA, kaB, 15);
_k19 = lRot128low(kaA, kaB, 15);
_k18 = lRot128high(kbA, kbB, 30);
_k17 = lRot128low(kbA, kbB, 30);
_k16 = lRot128high(klA, klB, 45);
_k15 = lRot128low(klA, klB, 45);
_k14 = lRot128high(kaA, kaB, 45);
_k13 = lRot128low(kaA, kaB, 45);
_k12 = lRot128high(krA, krB, 60);
_k11 = lRot128low(krA, krB, 60);
_k10 = lRot128high(kbA, kbB, 60);
_k9 = lRot128low(kbA, kbB, 60);
_k8 = lRot128high(klA, klB, 77);
_k7 = lRot128low(klA, klB, 77);
_k6 = lRot128high(krA, krB, 94);
_k5 = lRot128low(krA, krB, 94);
_k4 = lRot128high(kaA, kaB, 94);
_k3 = lRot128low(kaA, kaB, 94);
_k2 = lRot128high(klA, klB, 111);
_k1 = lRot128low(klA, klB, 111);
_ke6 = lRot128high(krA, krB, 30);
_ke5 = lRot128low(krA, krB, 30);
_ke4 = lRot128high(klA, klB, 60);
_ke3 = lRot128low(klA, klB, 60);
_ke2 = lRot128high(kaA, kaB, 77);
_ke1 = lRot128low(kaA, kaB, 77);
}
}
}
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("only simple KeyParameter expected.");
setKey(forEncryption, ((KeyParameter)parameters).GetKey());
initialised = true;
}
public string AlgorithmName
{
get { return "Camellia"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (!initialised)
throw new InvalidOperationException("Camellia engine not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (_keyIs128)
{
return processBlock128(input, inOff, output, outOff);
}
else
{
return processBlock192or256(input, inOff, output, outOff);
}
}
public void Reset()
{
// nothing
}
private byte lRot8(
byte value,
int rotation)
{
// return (byte)((value << rotation) | ((value & 0xff) >>> (8 - rotation)));
return (byte)((value << rotation) | ((value & 0xff) >> (8 - rotation)));
}
private int lRot32(
int value,
int rotation)
{
uint uv = (uint) value;
// return (value << rotation) | (value >>> (32 - rotation));
return (int)((uv << rotation) | (uv >> (32 - rotation)));
}
private long lRot128high(
long a,
long b,
int rotation)
{
ulong ua = (ulong) a, ub = (ulong) b;
if (rotation < 64)
{
// a = (a << rotation) | (b >>> (64 - rotation));
ua = (ua << rotation) | (ub >> (64 - rotation));
}
else if (rotation == 64)
{
ua = ub;
}
else
{
// a = (b << (rotation - 64)) | (a >>> (64 - (rotation - 64)));
ua = (ub << (rotation - 64)) | (ua >> (64 - (rotation - 64)));
}
// return a;
return (long) ua;
}
private long lRot128low(
long a,
long b,
int rotation)
{
ulong ua = (ulong) a, ub = (ulong) b;
if (rotation < 64)
{
// b = (b << rotation) | (a >>> (64 - rotation));
ub = (ub << rotation) | (ua >> (64 - rotation));
}
else if (rotation == 64)
{
ub = ua;
}
else
{
// b = (a << (rotation - 64)) | (b >>> (64 - (rotation - 64)));
ub = (ua << (rotation - 64)) | (ub >> (64 - (rotation - 64)));
}
// return b;
return (long) ub;
}
private long fl(
long input,
long ke)
{
int x1 = (int)(input >> 32);
int x2 = (int)input;
int k1 = (int)(ke >> 32);
int k2 = (int)ke;
x2 = x2 ^ lRot32((x1 & k1), 1);
x1 = x1 ^ (x2 | k2);
return ((long)x1 << 32) | (x2 & MASK32);
}
private long flInv(
long input,
long ke)
{
int y1 = (int)(input >> 32);
int y2 = (int)input;
int k1 = (int)(ke >> 32);
int k2 = (int)ke;
y1 = y1 ^ (y2 | k2);
y2 = y2 ^ lRot32((y1 & k1), 1);
return ((long)y1 << 32) | (y2 & MASK32);
}
private long f(
long input,
long ke)
{
long x;
int a, b;
int t1, t2, t3, t4, t5, t6, t7, t8;
int y1, y2, y3, y4, y5, y6, y7, y8;
x = input ^ ke;
a = (int)(x >> 32);
b = (int)x;
t1 = SBOX1[(a >> 24) & 0xff];
t2 = SBOX2[(a >> 16) & 0xff];
t3 = SBOX3[(a >> 8) & 0xff];
t4 = SBOX4[a & 0xff];
t5 = SBOX2[(b >> 24) & 0xff];
t6 = SBOX3[(b >> 16) & 0xff];
t7 = SBOX4[(b >> 8) & 0xff];
t8 = SBOX1[b & 0xff];
y1 = (t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8);
y2 = (t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8);
y3 = (t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8);
y4 = (t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7);
y5 = (t1 ^ t2 ^ t6 ^ t7 ^ t8);
y6 = (t2 ^ t3 ^ t5 ^ t7 ^ t8);
y7 = (t3 ^ t4 ^ t5 ^ t6 ^ t8);
y8 = (t1 ^ t4 ^ t5 ^ t6 ^ t7);
return ((long)y1 << 56) | (((long)y2 & MASK8) << 48) | (((long)y3 & MASK8) << 40)
| (((long)y4 & MASK8) << 32) | (((long)y5 & MASK8) << 24) | (((long)y6 & MASK8) << 16)
| (((long)y7 & MASK8) << 8) | ((long)y8 & MASK8);
}
private long bytesToWord(
byte[] src,
int srcOff)
{
long word = 0;
for (int i = 0; i < 8; i++)
{
word = (word << 8) + (src[i + srcOff] & 0xff);
}
return word;
}
private void wordToBytes(
long word,
byte[] dst,
int dstOff)
{
ulong uw = (ulong) word;
for (int i = 0; i < 8; i++)
{
// dst[(7 - i) + dstOff] = (byte)word;
dst[(7 - i) + dstOff] = (byte)uw;
// word >>>= 8;
uw >>= 8;
}
}
private int processBlock128(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
long d1 = bytesToWord(inBytes, inOff);
long d2 = bytesToWord(inBytes, inOff + 8);
d1 = d1 ^ _kw1; // Prewhitening
d2 = d2 ^ _kw2;
d2 = d2 ^ f(d1, _k1); // Round 1
d1 = d1 ^ f(d2, _k2); // Round 2
d2 = d2 ^ f(d1, _k3); // Round 3
d1 = d1 ^ f(d2, _k4); // Round 4
d2 = d2 ^ f(d1, _k5); // Round 5
d1 = d1 ^ f(d2, _k6); // Round 6
d1 = fl (d1, _ke1); // FL
d2 = flInv(d2, _ke2); // FLINV
d2 = d2 ^ f(d1, _k7); // Round 7
d1 = d1 ^ f(d2, _k8); // Round 8
d2 = d2 ^ f(d1, _k9); // Round 9
d1 = d1 ^ f(d2, _k10); // Round 10
d2 = d2 ^ f(d1, _k11); // Round 11
d1 = d1 ^ f(d2, _k12); // Round 12
d1 = fl (d1, _ke3); // FL
d2 = flInv(d2, _ke4); // FLINV
d2 = d2 ^ f(d1, _k13); // Round 13
d1 = d1 ^ f(d2, _k14); // Round 14
d2 = d2 ^ f(d1, _k15); // Round 15
d1 = d1 ^ f(d2, _k16); // Round 16
d2 = d2 ^ f(d1, _k17); // Round 17
d1 = d1 ^ f(d2, _k18); // Round 18
d2 = d2 ^ _kw3; // Postwhitening
d1 = d1 ^ _kw4;
wordToBytes(d2, outBytes, outOff);
wordToBytes(d1, outBytes, outOff + 8);
return BLOCK_SIZE;
}
private int processBlock192or256(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
long d1 = bytesToWord(inBytes, inOff);
long d2 = bytesToWord(inBytes, inOff + 8);
d1 = d1 ^ _kw1; // Prewhitening
d2 = d2 ^ _kw2;
d2 = d2 ^ f(d1, _k1); // Round 1
d1 = d1 ^ f(d2, _k2); // Round 2
d2 = d2 ^ f(d1, _k3); // Round 3
d1 = d1 ^ f(d2, _k4); // Round 4
d2 = d2 ^ f(d1, _k5); // Round 5
d1 = d1 ^ f(d2, _k6); // Round 6
d1 = fl (d1, _ke1); // FL
d2 = flInv(d2, _ke2); // FLINV
d2 = d2 ^ f(d1, _k7); // Round 7
d1 = d1 ^ f(d2, _k8); // Round 8
d2 = d2 ^ f(d1, _k9); // Round 9
d1 = d1 ^ f(d2, _k10); // Round 10
d2 = d2 ^ f(d1, _k11); // Round 11
d1 = d1 ^ f(d2, _k12); // Round 12
d1 = fl (d1, _ke3); // FL
d2 = flInv(d2, _ke4); // FLINV
d2 = d2 ^ f(d1, _k13); // Round 13
d1 = d1 ^ f(d2, _k14); // Round 14
d2 = d2 ^ f(d1, _k15); // Round 15
d1 = d1 ^ f(d2, _k16); // Round 16
d2 = d2 ^ f(d1, _k17); // Round 17
d1 = d1 ^ f(d2, _k18); // Round 18
d1 = fl (d1, _ke5); // FL
d2 = flInv(d2, _ke6); // FLINV
d2 = d2 ^ f(d1, _k19); // Round 19
d1 = d1 ^ f(d2, _k20); // Round 20
d2 = d2 ^ f(d1, _k21); // Round 21
d1 = d1 ^ f(d2, _k22); // Round 22
d2 = d2 ^ f(d1, _k23); // Round 23
d1 = d1 ^ f(d2, _k24); // Round 24
d2 = d2 ^ _kw3; // Postwhitening
d1 = d1 ^ _kw4;
wordToBytes(d2, outBytes, outOff);
wordToBytes(d1, outBytes, outOff + 8);
return BLOCK_SIZE;
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>
/// An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394.
/// <p/>
/// For further details see: <a href="http://www.ietf.org/rfc/rfc3657.txt">http://www.ietf.org/rfc/rfc3657.txt</a>.
/// </remarks>
public class CamelliaWrapEngine
: Rfc3394WrapEngine
{
public CamelliaWrapEngine()
: base(new CamelliaEngine())
{
}
}
}

View File

@@ -0,0 +1,829 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* A class that provides CAST key encryption operations,
* such as encoding data and generating keys.
*
* All the algorithms herein are from the Internet RFC's
*
* RFC2144 - Cast5 (64bit block, 40-128bit key)
* RFC2612 - CAST6 (128bit block, 128-256bit key)
*
* and implement a simplified cryptography interface.
*/
public class Cast5Engine
: IBlockCipher
{
internal const int M32 = unchecked((int) 0xffffffff);
internal static readonly int[]
S1 = {
unchecked((int) 0x30fb40d4), unchecked((int) 0x9fa0ff0b), unchecked((int) 0x6beccd2f), unchecked((int) 0x3f258c7a), unchecked((int) 0x1e213f2f), unchecked((int) 0x9c004dd3), unchecked((int) 0x6003e540), unchecked((int) 0xcf9fc949),
unchecked((int) 0xbfd4af27), unchecked((int) 0x88bbbdb5), unchecked((int) 0xe2034090), unchecked((int) 0x98d09675), unchecked((int) 0x6e63a0e0), unchecked((int) 0x15c361d2), unchecked((int) 0xc2e7661d), unchecked((int) 0x22d4ff8e),
unchecked((int) 0x28683b6f), unchecked((int) 0xc07fd059), unchecked((int) 0xff2379c8), unchecked((int) 0x775f50e2), unchecked((int) 0x43c340d3), unchecked((int) 0xdf2f8656), unchecked((int) 0x887ca41a), unchecked((int) 0xa2d2bd2d),
unchecked((int) 0xa1c9e0d6), unchecked((int) 0x346c4819), unchecked((int) 0x61b76d87), unchecked((int) 0x22540f2f), unchecked((int) 0x2abe32e1), unchecked((int) 0xaa54166b), unchecked((int) 0x22568e3a), unchecked((int) 0xa2d341d0),
unchecked((int) 0x66db40c8), unchecked((int) 0xa784392f), unchecked((int) 0x004dff2f), unchecked((int) 0x2db9d2de), unchecked((int) 0x97943fac), unchecked((int) 0x4a97c1d8), unchecked((int) 0x527644b7), unchecked((int) 0xb5f437a7),
unchecked((int) 0xb82cbaef), unchecked((int) 0xd751d159), unchecked((int) 0x6ff7f0ed), unchecked((int) 0x5a097a1f), unchecked((int) 0x827b68d0), unchecked((int) 0x90ecf52e), unchecked((int) 0x22b0c054), unchecked((int) 0xbc8e5935),
unchecked((int) 0x4b6d2f7f), unchecked((int) 0x50bb64a2), unchecked((int) 0xd2664910), unchecked((int) 0xbee5812d), unchecked((int) 0xb7332290), unchecked((int) 0xe93b159f), unchecked((int) 0xb48ee411), unchecked((int) 0x4bff345d),
unchecked((int) 0xfd45c240), unchecked((int) 0xad31973f), unchecked((int) 0xc4f6d02e), unchecked((int) 0x55fc8165), unchecked((int) 0xd5b1caad), unchecked((int) 0xa1ac2dae), unchecked((int) 0xa2d4b76d), unchecked((int) 0xc19b0c50),
unchecked((int) 0x882240f2), unchecked((int) 0x0c6e4f38), unchecked((int) 0xa4e4bfd7), unchecked((int) 0x4f5ba272), unchecked((int) 0x564c1d2f), unchecked((int) 0xc59c5319), unchecked((int) 0xb949e354), unchecked((int) 0xb04669fe),
unchecked((int) 0xb1b6ab8a), unchecked((int) 0xc71358dd), unchecked((int) 0x6385c545), unchecked((int) 0x110f935d), unchecked((int) 0x57538ad5), unchecked((int) 0x6a390493), unchecked((int) 0xe63d37e0), unchecked((int) 0x2a54f6b3),
unchecked((int) 0x3a787d5f), unchecked((int) 0x6276a0b5), unchecked((int) 0x19a6fcdf), unchecked((int) 0x7a42206a), unchecked((int) 0x29f9d4d5), unchecked((int) 0xf61b1891), unchecked((int) 0xbb72275e), unchecked((int) 0xaa508167),
unchecked((int) 0x38901091), unchecked((int) 0xc6b505eb), unchecked((int) 0x84c7cb8c), unchecked((int) 0x2ad75a0f), unchecked((int) 0x874a1427), unchecked((int) 0xa2d1936b), unchecked((int) 0x2ad286af), unchecked((int) 0xaa56d291),
unchecked((int) 0xd7894360), unchecked((int) 0x425c750d), unchecked((int) 0x93b39e26), unchecked((int) 0x187184c9), unchecked((int) 0x6c00b32d), unchecked((int) 0x73e2bb14), unchecked((int) 0xa0bebc3c), unchecked((int) 0x54623779),
unchecked((int) 0x64459eab), unchecked((int) 0x3f328b82), unchecked((int) 0x7718cf82), unchecked((int) 0x59a2cea6), unchecked((int) 0x04ee002e), unchecked((int) 0x89fe78e6), unchecked((int) 0x3fab0950), unchecked((int) 0x325ff6c2),
unchecked((int) 0x81383f05), unchecked((int) 0x6963c5c8), unchecked((int) 0x76cb5ad6), unchecked((int) 0xd49974c9), unchecked((int) 0xca180dcf), unchecked((int) 0x380782d5), unchecked((int) 0xc7fa5cf6), unchecked((int) 0x8ac31511),
unchecked((int) 0x35e79e13), unchecked((int) 0x47da91d0), unchecked((int) 0xf40f9086), unchecked((int) 0xa7e2419e), unchecked((int) 0x31366241), unchecked((int) 0x051ef495), unchecked((int) 0xaa573b04), unchecked((int) 0x4a805d8d),
unchecked((int) 0x548300d0), unchecked((int) 0x00322a3c), unchecked((int) 0xbf64cddf), unchecked((int) 0xba57a68e), unchecked((int) 0x75c6372b), unchecked((int) 0x50afd341), unchecked((int) 0xa7c13275), unchecked((int) 0x915a0bf5),
unchecked((int) 0x6b54bfab), unchecked((int) 0x2b0b1426), unchecked((int) 0xab4cc9d7), unchecked((int) 0x449ccd82), unchecked((int) 0xf7fbf265), unchecked((int) 0xab85c5f3), unchecked((int) 0x1b55db94), unchecked((int) 0xaad4e324),
unchecked((int) 0xcfa4bd3f), unchecked((int) 0x2deaa3e2), unchecked((int) 0x9e204d02), unchecked((int) 0xc8bd25ac), unchecked((int) 0xeadf55b3), unchecked((int) 0xd5bd9e98), unchecked((int) 0xe31231b2), unchecked((int) 0x2ad5ad6c),
unchecked((int) 0x954329de), unchecked((int) 0xadbe4528), unchecked((int) 0xd8710f69), unchecked((int) 0xaa51c90f), unchecked((int) 0xaa786bf6), unchecked((int) 0x22513f1e), unchecked((int) 0xaa51a79b), unchecked((int) 0x2ad344cc),
unchecked((int) 0x7b5a41f0), unchecked((int) 0xd37cfbad), unchecked((int) 0x1b069505), unchecked((int) 0x41ece491), unchecked((int) 0xb4c332e6), unchecked((int) 0x032268d4), unchecked((int) 0xc9600acc), unchecked((int) 0xce387e6d),
unchecked((int) 0xbf6bb16c), unchecked((int) 0x6a70fb78), unchecked((int) 0x0d03d9c9), unchecked((int) 0xd4df39de), unchecked((int) 0xe01063da), unchecked((int) 0x4736f464), unchecked((int) 0x5ad328d8), unchecked((int) 0xb347cc96),
unchecked((int) 0x75bb0fc3), unchecked((int) 0x98511bfb), unchecked((int) 0x4ffbcc35), unchecked((int) 0xb58bcf6a), unchecked((int) 0xe11f0abc), unchecked((int) 0xbfc5fe4a), unchecked((int) 0xa70aec10), unchecked((int) 0xac39570a),
unchecked((int) 0x3f04442f), unchecked((int) 0x6188b153), unchecked((int) 0xe0397a2e), unchecked((int) 0x5727cb79), unchecked((int) 0x9ceb418f), unchecked((int) 0x1cacd68d), unchecked((int) 0x2ad37c96), unchecked((int) 0x0175cb9d),
unchecked((int) 0xc69dff09), unchecked((int) 0xc75b65f0), unchecked((int) 0xd9db40d8), unchecked((int) 0xec0e7779), unchecked((int) 0x4744ead4), unchecked((int) 0xb11c3274), unchecked((int) 0xdd24cb9e), unchecked((int) 0x7e1c54bd),
unchecked((int) 0xf01144f9), unchecked((int) 0xd2240eb1), unchecked((int) 0x9675b3fd), unchecked((int) 0xa3ac3755), unchecked((int) 0xd47c27af), unchecked((int) 0x51c85f4d), unchecked((int) 0x56907596), unchecked((int) 0xa5bb15e6),
unchecked((int) 0x580304f0), unchecked((int) 0xca042cf1), unchecked((int) 0x011a37ea), unchecked((int) 0x8dbfaadb), unchecked((int) 0x35ba3e4a), unchecked((int) 0x3526ffa0), unchecked((int) 0xc37b4d09), unchecked((int) 0xbc306ed9),
unchecked((int) 0x98a52666), unchecked((int) 0x5648f725), unchecked((int) 0xff5e569d), unchecked((int) 0x0ced63d0), unchecked((int) 0x7c63b2cf), unchecked((int) 0x700b45e1), unchecked((int) 0xd5ea50f1), unchecked((int) 0x85a92872),
unchecked((int) 0xaf1fbda7), unchecked((int) 0xd4234870), unchecked((int) 0xa7870bf3), unchecked((int) 0x2d3b4d79), unchecked((int) 0x42e04198), unchecked((int) 0x0cd0ede7), unchecked((int) 0x26470db8), unchecked((int) 0xf881814c),
unchecked((int) 0x474d6ad7), unchecked((int) 0x7c0c5e5c), unchecked((int) 0xd1231959), unchecked((int) 0x381b7298), unchecked((int) 0xf5d2f4db), unchecked((int) 0xab838653), unchecked((int) 0x6e2f1e23), unchecked((int) 0x83719c9e),
unchecked((int) 0xbd91e046), unchecked((int) 0x9a56456e), unchecked((int) 0xdc39200c), unchecked((int) 0x20c8c571), unchecked((int) 0x962bda1c), unchecked((int) 0xe1e696ff), unchecked((int) 0xb141ab08), unchecked((int) 0x7cca89b9),
unchecked((int) 0x1a69e783), unchecked((int) 0x02cc4843), unchecked((int) 0xa2f7c579), unchecked((int) 0x429ef47d), unchecked((int) 0x427b169c), unchecked((int) 0x5ac9f049), unchecked((int) 0xdd8f0f00), unchecked((int) 0x5c8165bf)
},
S2 =
{
unchecked((int) 0x1f201094), unchecked((int) 0xef0ba75b), unchecked((int) 0x69e3cf7e), unchecked((int) 0x393f4380), unchecked((int) 0xfe61cf7a), unchecked((int) 0xeec5207a), unchecked((int) 0x55889c94), unchecked((int) 0x72fc0651),
unchecked((int) 0xada7ef79), unchecked((int) 0x4e1d7235), unchecked((int) 0xd55a63ce), unchecked((int) 0xde0436ba), unchecked((int) 0x99c430ef), unchecked((int) 0x5f0c0794), unchecked((int) 0x18dcdb7d), unchecked((int) 0xa1d6eff3),
unchecked((int) 0xa0b52f7b), unchecked((int) 0x59e83605), unchecked((int) 0xee15b094), unchecked((int) 0xe9ffd909), unchecked((int) 0xdc440086), unchecked((int) 0xef944459), unchecked((int) 0xba83ccb3), unchecked((int) 0xe0c3cdfb),
unchecked((int) 0xd1da4181), unchecked((int) 0x3b092ab1), unchecked((int) 0xf997f1c1), unchecked((int) 0xa5e6cf7b), unchecked((int) 0x01420ddb), unchecked((int) 0xe4e7ef5b), unchecked((int) 0x25a1ff41), unchecked((int) 0xe180f806),
unchecked((int) 0x1fc41080), unchecked((int) 0x179bee7a), unchecked((int) 0xd37ac6a9), unchecked((int) 0xfe5830a4), unchecked((int) 0x98de8b7f), unchecked((int) 0x77e83f4e), unchecked((int) 0x79929269), unchecked((int) 0x24fa9f7b),
unchecked((int) 0xe113c85b), unchecked((int) 0xacc40083), unchecked((int) 0xd7503525), unchecked((int) 0xf7ea615f), unchecked((int) 0x62143154), unchecked((int) 0x0d554b63), unchecked((int) 0x5d681121), unchecked((int) 0xc866c359),
unchecked((int) 0x3d63cf73), unchecked((int) 0xcee234c0), unchecked((int) 0xd4d87e87), unchecked((int) 0x5c672b21), unchecked((int) 0x071f6181), unchecked((int) 0x39f7627f), unchecked((int) 0x361e3084), unchecked((int) 0xe4eb573b),
unchecked((int) 0x602f64a4), unchecked((int) 0xd63acd9c), unchecked((int) 0x1bbc4635), unchecked((int) 0x9e81032d), unchecked((int) 0x2701f50c), unchecked((int) 0x99847ab4), unchecked((int) 0xa0e3df79), unchecked((int) 0xba6cf38c),
unchecked((int) 0x10843094), unchecked((int) 0x2537a95e), unchecked((int) 0xf46f6ffe), unchecked((int) 0xa1ff3b1f), unchecked((int) 0x208cfb6a), unchecked((int) 0x8f458c74), unchecked((int) 0xd9e0a227), unchecked((int) 0x4ec73a34),
unchecked((int) 0xfc884f69), unchecked((int) 0x3e4de8df), unchecked((int) 0xef0e0088), unchecked((int) 0x3559648d), unchecked((int) 0x8a45388c), unchecked((int) 0x1d804366), unchecked((int) 0x721d9bfd), unchecked((int) 0xa58684bb),
unchecked((int) 0xe8256333), unchecked((int) 0x844e8212), unchecked((int) 0x128d8098), unchecked((int) 0xfed33fb4), unchecked((int) 0xce280ae1), unchecked((int) 0x27e19ba5), unchecked((int) 0xd5a6c252), unchecked((int) 0xe49754bd),
unchecked((int) 0xc5d655dd), unchecked((int) 0xeb667064), unchecked((int) 0x77840b4d), unchecked((int) 0xa1b6a801), unchecked((int) 0x84db26a9), unchecked((int) 0xe0b56714), unchecked((int) 0x21f043b7), unchecked((int) 0xe5d05860),
unchecked((int) 0x54f03084), unchecked((int) 0x066ff472), unchecked((int) 0xa31aa153), unchecked((int) 0xdadc4755), unchecked((int) 0xb5625dbf), unchecked((int) 0x68561be6), unchecked((int) 0x83ca6b94), unchecked((int) 0x2d6ed23b),
unchecked((int) 0xeccf01db), unchecked((int) 0xa6d3d0ba), unchecked((int) 0xb6803d5c), unchecked((int) 0xaf77a709), unchecked((int) 0x33b4a34c), unchecked((int) 0x397bc8d6), unchecked((int) 0x5ee22b95), unchecked((int) 0x5f0e5304),
unchecked((int) 0x81ed6f61), unchecked((int) 0x20e74364), unchecked((int) 0xb45e1378), unchecked((int) 0xde18639b), unchecked((int) 0x881ca122), unchecked((int) 0xb96726d1), unchecked((int) 0x8049a7e8), unchecked((int) 0x22b7da7b),
unchecked((int) 0x5e552d25), unchecked((int) 0x5272d237), unchecked((int) 0x79d2951c), unchecked((int) 0xc60d894c), unchecked((int) 0x488cb402), unchecked((int) 0x1ba4fe5b), unchecked((int) 0xa4b09f6b), unchecked((int) 0x1ca815cf),
unchecked((int) 0xa20c3005), unchecked((int) 0x8871df63), unchecked((int) 0xb9de2fcb), unchecked((int) 0x0cc6c9e9), unchecked((int) 0x0beeff53), unchecked((int) 0xe3214517), unchecked((int) 0xb4542835), unchecked((int) 0x9f63293c),
unchecked((int) 0xee41e729), unchecked((int) 0x6e1d2d7c), unchecked((int) 0x50045286), unchecked((int) 0x1e6685f3), unchecked((int) 0xf33401c6), unchecked((int) 0x30a22c95), unchecked((int) 0x31a70850), unchecked((int) 0x60930f13),
unchecked((int) 0x73f98417), unchecked((int) 0xa1269859), unchecked((int) 0xec645c44), unchecked((int) 0x52c877a9), unchecked((int) 0xcdff33a6), unchecked((int) 0xa02b1741), unchecked((int) 0x7cbad9a2), unchecked((int) 0x2180036f),
unchecked((int) 0x50d99c08), unchecked((int) 0xcb3f4861), unchecked((int) 0xc26bd765), unchecked((int) 0x64a3f6ab), unchecked((int) 0x80342676), unchecked((int) 0x25a75e7b), unchecked((int) 0xe4e6d1fc), unchecked((int) 0x20c710e6),
unchecked((int) 0xcdf0b680), unchecked((int) 0x17844d3b), unchecked((int) 0x31eef84d), unchecked((int) 0x7e0824e4), unchecked((int) 0x2ccb49eb), unchecked((int) 0x846a3bae), unchecked((int) 0x8ff77888), unchecked((int) 0xee5d60f6),
unchecked((int) 0x7af75673), unchecked((int) 0x2fdd5cdb), unchecked((int) 0xa11631c1), unchecked((int) 0x30f66f43), unchecked((int) 0xb3faec54), unchecked((int) 0x157fd7fa), unchecked((int) 0xef8579cc), unchecked((int) 0xd152de58),
unchecked((int) 0xdb2ffd5e), unchecked((int) 0x8f32ce19), unchecked((int) 0x306af97a), unchecked((int) 0x02f03ef8), unchecked((int) 0x99319ad5), unchecked((int) 0xc242fa0f), unchecked((int) 0xa7e3ebb0), unchecked((int) 0xc68e4906),
unchecked((int) 0xb8da230c), unchecked((int) 0x80823028), unchecked((int) 0xdcdef3c8), unchecked((int) 0xd35fb171), unchecked((int) 0x088a1bc8), unchecked((int) 0xbec0c560), unchecked((int) 0x61a3c9e8), unchecked((int) 0xbca8f54d),
unchecked((int) 0xc72feffa), unchecked((int) 0x22822e99), unchecked((int) 0x82c570b4), unchecked((int) 0xd8d94e89), unchecked((int) 0x8b1c34bc), unchecked((int) 0x301e16e6), unchecked((int) 0x273be979), unchecked((int) 0xb0ffeaa6),
unchecked((int) 0x61d9b8c6), unchecked((int) 0x00b24869), unchecked((int) 0xb7ffce3f), unchecked((int) 0x08dc283b), unchecked((int) 0x43daf65a), unchecked((int) 0xf7e19798), unchecked((int) 0x7619b72f), unchecked((int) 0x8f1c9ba4),
unchecked((int) 0xdc8637a0), unchecked((int) 0x16a7d3b1), unchecked((int) 0x9fc393b7), unchecked((int) 0xa7136eeb), unchecked((int) 0xc6bcc63e), unchecked((int) 0x1a513742), unchecked((int) 0xef6828bc), unchecked((int) 0x520365d6),
unchecked((int) 0x2d6a77ab), unchecked((int) 0x3527ed4b), unchecked((int) 0x821fd216), unchecked((int) 0x095c6e2e), unchecked((int) 0xdb92f2fb), unchecked((int) 0x5eea29cb), unchecked((int) 0x145892f5), unchecked((int) 0x91584f7f),
unchecked((int) 0x5483697b), unchecked((int) 0x2667a8cc), unchecked((int) 0x85196048), unchecked((int) 0x8c4bacea), unchecked((int) 0x833860d4), unchecked((int) 0x0d23e0f9), unchecked((int) 0x6c387e8a), unchecked((int) 0x0ae6d249),
unchecked((int) 0xb284600c), unchecked((int) 0xd835731d), unchecked((int) 0xdcb1c647), unchecked((int) 0xac4c56ea), unchecked((int) 0x3ebd81b3), unchecked((int) 0x230eabb0), unchecked((int) 0x6438bc87), unchecked((int) 0xf0b5b1fa),
unchecked((int) 0x8f5ea2b3), unchecked((int) 0xfc184642), unchecked((int) 0x0a036b7a), unchecked((int) 0x4fb089bd), unchecked((int) 0x649da589), unchecked((int) 0xa345415e), unchecked((int) 0x5c038323), unchecked((int) 0x3e5d3bb9),
unchecked((int) 0x43d79572), unchecked((int) 0x7e6dd07c), unchecked((int) 0x06dfdf1e), unchecked((int) 0x6c6cc4ef), unchecked((int) 0x7160a539), unchecked((int) 0x73bfbe70), unchecked((int) 0x83877605), unchecked((int) 0x4523ecf1)
},
S3 =
{
unchecked((int) 0x8defc240), unchecked((int) 0x25fa5d9f), unchecked((int) 0xeb903dbf), unchecked((int) 0xe810c907), unchecked((int) 0x47607fff), unchecked((int) 0x369fe44b), unchecked((int) 0x8c1fc644), unchecked((int) 0xaececa90),
unchecked((int) 0xbeb1f9bf), unchecked((int) 0xeefbcaea), unchecked((int) 0xe8cf1950), unchecked((int) 0x51df07ae), unchecked((int) 0x920e8806), unchecked((int) 0xf0ad0548), unchecked((int) 0xe13c8d83), unchecked((int) 0x927010d5),
unchecked((int) 0x11107d9f), unchecked((int) 0x07647db9), unchecked((int) 0xb2e3e4d4), unchecked((int) 0x3d4f285e), unchecked((int) 0xb9afa820), unchecked((int) 0xfade82e0), unchecked((int) 0xa067268b), unchecked((int) 0x8272792e),
unchecked((int) 0x553fb2c0), unchecked((int) 0x489ae22b), unchecked((int) 0xd4ef9794), unchecked((int) 0x125e3fbc), unchecked((int) 0x21fffcee), unchecked((int) 0x825b1bfd), unchecked((int) 0x9255c5ed), unchecked((int) 0x1257a240),
unchecked((int) 0x4e1a8302), unchecked((int) 0xbae07fff), unchecked((int) 0x528246e7), unchecked((int) 0x8e57140e), unchecked((int) 0x3373f7bf), unchecked((int) 0x8c9f8188), unchecked((int) 0xa6fc4ee8), unchecked((int) 0xc982b5a5),
unchecked((int) 0xa8c01db7), unchecked((int) 0x579fc264), unchecked((int) 0x67094f31), unchecked((int) 0xf2bd3f5f), unchecked((int) 0x40fff7c1), unchecked((int) 0x1fb78dfc), unchecked((int) 0x8e6bd2c1), unchecked((int) 0x437be59b),
unchecked((int) 0x99b03dbf), unchecked((int) 0xb5dbc64b), unchecked((int) 0x638dc0e6), unchecked((int) 0x55819d99), unchecked((int) 0xa197c81c), unchecked((int) 0x4a012d6e), unchecked((int) 0xc5884a28), unchecked((int) 0xccc36f71),
unchecked((int) 0xb843c213), unchecked((int) 0x6c0743f1), unchecked((int) 0x8309893c), unchecked((int) 0x0feddd5f), unchecked((int) 0x2f7fe850), unchecked((int) 0xd7c07f7e), unchecked((int) 0x02507fbf), unchecked((int) 0x5afb9a04),
unchecked((int) 0xa747d2d0), unchecked((int) 0x1651192e), unchecked((int) 0xaf70bf3e), unchecked((int) 0x58c31380), unchecked((int) 0x5f98302e), unchecked((int) 0x727cc3c4), unchecked((int) 0x0a0fb402), unchecked((int) 0x0f7fef82),
unchecked((int) 0x8c96fdad), unchecked((int) 0x5d2c2aae), unchecked((int) 0x8ee99a49), unchecked((int) 0x50da88b8), unchecked((int) 0x8427f4a0), unchecked((int) 0x1eac5790), unchecked((int) 0x796fb449), unchecked((int) 0x8252dc15),
unchecked((int) 0xefbd7d9b), unchecked((int) 0xa672597d), unchecked((int) 0xada840d8), unchecked((int) 0x45f54504), unchecked((int) 0xfa5d7403), unchecked((int) 0xe83ec305), unchecked((int) 0x4f91751a), unchecked((int) 0x925669c2),
unchecked((int) 0x23efe941), unchecked((int) 0xa903f12e), unchecked((int) 0x60270df2), unchecked((int) 0x0276e4b6), unchecked((int) 0x94fd6574), unchecked((int) 0x927985b2), unchecked((int) 0x8276dbcb), unchecked((int) 0x02778176),
unchecked((int) 0xf8af918d), unchecked((int) 0x4e48f79e), unchecked((int) 0x8f616ddf), unchecked((int) 0xe29d840e), unchecked((int) 0x842f7d83), unchecked((int) 0x340ce5c8), unchecked((int) 0x96bbb682), unchecked((int) 0x93b4b148),
unchecked((int) 0xef303cab), unchecked((int) 0x984faf28), unchecked((int) 0x779faf9b), unchecked((int) 0x92dc560d), unchecked((int) 0x224d1e20), unchecked((int) 0x8437aa88), unchecked((int) 0x7d29dc96), unchecked((int) 0x2756d3dc),
unchecked((int) 0x8b907cee), unchecked((int) 0xb51fd240), unchecked((int) 0xe7c07ce3), unchecked((int) 0xe566b4a1), unchecked((int) 0xc3e9615e), unchecked((int) 0x3cf8209d), unchecked((int) 0x6094d1e3), unchecked((int) 0xcd9ca341),
unchecked((int) 0x5c76460e), unchecked((int) 0x00ea983b), unchecked((int) 0xd4d67881), unchecked((int) 0xfd47572c), unchecked((int) 0xf76cedd9), unchecked((int) 0xbda8229c), unchecked((int) 0x127dadaa), unchecked((int) 0x438a074e),
unchecked((int) 0x1f97c090), unchecked((int) 0x081bdb8a), unchecked((int) 0x93a07ebe), unchecked((int) 0xb938ca15), unchecked((int) 0x97b03cff), unchecked((int) 0x3dc2c0f8), unchecked((int) 0x8d1ab2ec), unchecked((int) 0x64380e51),
unchecked((int) 0x68cc7bfb), unchecked((int) 0xd90f2788), unchecked((int) 0x12490181), unchecked((int) 0x5de5ffd4), unchecked((int) 0xdd7ef86a), unchecked((int) 0x76a2e214), unchecked((int) 0xb9a40368), unchecked((int) 0x925d958f),
unchecked((int) 0x4b39fffa), unchecked((int) 0xba39aee9), unchecked((int) 0xa4ffd30b), unchecked((int) 0xfaf7933b), unchecked((int) 0x6d498623), unchecked((int) 0x193cbcfa), unchecked((int) 0x27627545), unchecked((int) 0x825cf47a),
unchecked((int) 0x61bd8ba0), unchecked((int) 0xd11e42d1), unchecked((int) 0xcead04f4), unchecked((int) 0x127ea392), unchecked((int) 0x10428db7), unchecked((int) 0x8272a972), unchecked((int) 0x9270c4a8), unchecked((int) 0x127de50b),
unchecked((int) 0x285ba1c8), unchecked((int) 0x3c62f44f), unchecked((int) 0x35c0eaa5), unchecked((int) 0xe805d231), unchecked((int) 0x428929fb), unchecked((int) 0xb4fcdf82), unchecked((int) 0x4fb66a53), unchecked((int) 0x0e7dc15b),
unchecked((int) 0x1f081fab), unchecked((int) 0x108618ae), unchecked((int) 0xfcfd086d), unchecked((int) 0xf9ff2889), unchecked((int) 0x694bcc11), unchecked((int) 0x236a5cae), unchecked((int) 0x12deca4d), unchecked((int) 0x2c3f8cc5),
unchecked((int) 0xd2d02dfe), unchecked((int) 0xf8ef5896), unchecked((int) 0xe4cf52da), unchecked((int) 0x95155b67), unchecked((int) 0x494a488c), unchecked((int) 0xb9b6a80c), unchecked((int) 0x5c8f82bc), unchecked((int) 0x89d36b45),
unchecked((int) 0x3a609437), unchecked((int) 0xec00c9a9), unchecked((int) 0x44715253), unchecked((int) 0x0a874b49), unchecked((int) 0xd773bc40), unchecked((int) 0x7c34671c), unchecked((int) 0x02717ef6), unchecked((int) 0x4feb5536),
unchecked((int) 0xa2d02fff), unchecked((int) 0xd2bf60c4), unchecked((int) 0xd43f03c0), unchecked((int) 0x50b4ef6d), unchecked((int) 0x07478cd1), unchecked((int) 0x006e1888), unchecked((int) 0xa2e53f55), unchecked((int) 0xb9e6d4bc),
unchecked((int) 0xa2048016), unchecked((int) 0x97573833), unchecked((int) 0xd7207d67), unchecked((int) 0xde0f8f3d), unchecked((int) 0x72f87b33), unchecked((int) 0xabcc4f33), unchecked((int) 0x7688c55d), unchecked((int) 0x7b00a6b0),
unchecked((int) 0x947b0001), unchecked((int) 0x570075d2), unchecked((int) 0xf9bb88f8), unchecked((int) 0x8942019e), unchecked((int) 0x4264a5ff), unchecked((int) 0x856302e0), unchecked((int) 0x72dbd92b), unchecked((int) 0xee971b69),
unchecked((int) 0x6ea22fde), unchecked((int) 0x5f08ae2b), unchecked((int) 0xaf7a616d), unchecked((int) 0xe5c98767), unchecked((int) 0xcf1febd2), unchecked((int) 0x61efc8c2), unchecked((int) 0xf1ac2571), unchecked((int) 0xcc8239c2),
unchecked((int) 0x67214cb8), unchecked((int) 0xb1e583d1), unchecked((int) 0xb7dc3e62), unchecked((int) 0x7f10bdce), unchecked((int) 0xf90a5c38), unchecked((int) 0x0ff0443d), unchecked((int) 0x606e6dc6), unchecked((int) 0x60543a49),
unchecked((int) 0x5727c148), unchecked((int) 0x2be98a1d), unchecked((int) 0x8ab41738), unchecked((int) 0x20e1be24), unchecked((int) 0xaf96da0f), unchecked((int) 0x68458425), unchecked((int) 0x99833be5), unchecked((int) 0x600d457d),
unchecked((int) 0x282f9350), unchecked((int) 0x8334b362), unchecked((int) 0xd91d1120), unchecked((int) 0x2b6d8da0), unchecked((int) 0x642b1e31), unchecked((int) 0x9c305a00), unchecked((int) 0x52bce688), unchecked((int) 0x1b03588a),
unchecked((int) 0xf7baefd5), unchecked((int) 0x4142ed9c), unchecked((int) 0xa4315c11), unchecked((int) 0x83323ec5), unchecked((int) 0xdfef4636), unchecked((int) 0xa133c501), unchecked((int) 0xe9d3531c), unchecked((int) 0xee353783)
},
S4 =
{
unchecked((int) 0x9db30420), unchecked((int) 0x1fb6e9de), unchecked((int) 0xa7be7bef), unchecked((int) 0xd273a298), unchecked((int) 0x4a4f7bdb), unchecked((int) 0x64ad8c57), unchecked((int) 0x85510443), unchecked((int) 0xfa020ed1),
unchecked((int) 0x7e287aff), unchecked((int) 0xe60fb663), unchecked((int) 0x095f35a1), unchecked((int) 0x79ebf120), unchecked((int) 0xfd059d43), unchecked((int) 0x6497b7b1), unchecked((int) 0xf3641f63), unchecked((int) 0x241e4adf),
unchecked((int) 0x28147f5f), unchecked((int) 0x4fa2b8cd), unchecked((int) 0xc9430040), unchecked((int) 0x0cc32220), unchecked((int) 0xfdd30b30), unchecked((int) 0xc0a5374f), unchecked((int) 0x1d2d00d9), unchecked((int) 0x24147b15),
unchecked((int) 0xee4d111a), unchecked((int) 0x0fca5167), unchecked((int) 0x71ff904c), unchecked((int) 0x2d195ffe), unchecked((int) 0x1a05645f), unchecked((int) 0x0c13fefe), unchecked((int) 0x081b08ca), unchecked((int) 0x05170121),
unchecked((int) 0x80530100), unchecked((int) 0xe83e5efe), unchecked((int) 0xac9af4f8), unchecked((int) 0x7fe72701), unchecked((int) 0xd2b8ee5f), unchecked((int) 0x06df4261), unchecked((int) 0xbb9e9b8a), unchecked((int) 0x7293ea25),
unchecked((int) 0xce84ffdf), unchecked((int) 0xf5718801), unchecked((int) 0x3dd64b04), unchecked((int) 0xa26f263b), unchecked((int) 0x7ed48400), unchecked((int) 0x547eebe6), unchecked((int) 0x446d4ca0), unchecked((int) 0x6cf3d6f5),
unchecked((int) 0x2649abdf), unchecked((int) 0xaea0c7f5), unchecked((int) 0x36338cc1), unchecked((int) 0x503f7e93), unchecked((int) 0xd3772061), unchecked((int) 0x11b638e1), unchecked((int) 0x72500e03), unchecked((int) 0xf80eb2bb),
unchecked((int) 0xabe0502e), unchecked((int) 0xec8d77de), unchecked((int) 0x57971e81), unchecked((int) 0xe14f6746), unchecked((int) 0xc9335400), unchecked((int) 0x6920318f), unchecked((int) 0x081dbb99), unchecked((int) 0xffc304a5),
unchecked((int) 0x4d351805), unchecked((int) 0x7f3d5ce3), unchecked((int) 0xa6c866c6), unchecked((int) 0x5d5bcca9), unchecked((int) 0xdaec6fea), unchecked((int) 0x9f926f91), unchecked((int) 0x9f46222f), unchecked((int) 0x3991467d),
unchecked((int) 0xa5bf6d8e), unchecked((int) 0x1143c44f), unchecked((int) 0x43958302), unchecked((int) 0xd0214eeb), unchecked((int) 0x022083b8), unchecked((int) 0x3fb6180c), unchecked((int) 0x18f8931e), unchecked((int) 0x281658e6),
unchecked((int) 0x26486e3e), unchecked((int) 0x8bd78a70), unchecked((int) 0x7477e4c1), unchecked((int) 0xb506e07c), unchecked((int) 0xf32d0a25), unchecked((int) 0x79098b02), unchecked((int) 0xe4eabb81), unchecked((int) 0x28123b23),
unchecked((int) 0x69dead38), unchecked((int) 0x1574ca16), unchecked((int) 0xdf871b62), unchecked((int) 0x211c40b7), unchecked((int) 0xa51a9ef9), unchecked((int) 0x0014377b), unchecked((int) 0x041e8ac8), unchecked((int) 0x09114003),
unchecked((int) 0xbd59e4d2), unchecked((int) 0xe3d156d5), unchecked((int) 0x4fe876d5), unchecked((int) 0x2f91a340), unchecked((int) 0x557be8de), unchecked((int) 0x00eae4a7), unchecked((int) 0x0ce5c2ec), unchecked((int) 0x4db4bba6),
unchecked((int) 0xe756bdff), unchecked((int) 0xdd3369ac), unchecked((int) 0xec17b035), unchecked((int) 0x06572327), unchecked((int) 0x99afc8b0), unchecked((int) 0x56c8c391), unchecked((int) 0x6b65811c), unchecked((int) 0x5e146119),
unchecked((int) 0x6e85cb75), unchecked((int) 0xbe07c002), unchecked((int) 0xc2325577), unchecked((int) 0x893ff4ec), unchecked((int) 0x5bbfc92d), unchecked((int) 0xd0ec3b25), unchecked((int) 0xb7801ab7), unchecked((int) 0x8d6d3b24),
unchecked((int) 0x20c763ef), unchecked((int) 0xc366a5fc), unchecked((int) 0x9c382880), unchecked((int) 0x0ace3205), unchecked((int) 0xaac9548a), unchecked((int) 0xeca1d7c7), unchecked((int) 0x041afa32), unchecked((int) 0x1d16625a),
unchecked((int) 0x6701902c), unchecked((int) 0x9b757a54), unchecked((int) 0x31d477f7), unchecked((int) 0x9126b031), unchecked((int) 0x36cc6fdb), unchecked((int) 0xc70b8b46), unchecked((int) 0xd9e66a48), unchecked((int) 0x56e55a79),
unchecked((int) 0x026a4ceb), unchecked((int) 0x52437eff), unchecked((int) 0x2f8f76b4), unchecked((int) 0x0df980a5), unchecked((int) 0x8674cde3), unchecked((int) 0xedda04eb), unchecked((int) 0x17a9be04), unchecked((int) 0x2c18f4df),
unchecked((int) 0xb7747f9d), unchecked((int) 0xab2af7b4), unchecked((int) 0xefc34d20), unchecked((int) 0x2e096b7c), unchecked((int) 0x1741a254), unchecked((int) 0xe5b6a035), unchecked((int) 0x213d42f6), unchecked((int) 0x2c1c7c26),
unchecked((int) 0x61c2f50f), unchecked((int) 0x6552daf9), unchecked((int) 0xd2c231f8), unchecked((int) 0x25130f69), unchecked((int) 0xd8167fa2), unchecked((int) 0x0418f2c8), unchecked((int) 0x001a96a6), unchecked((int) 0x0d1526ab),
unchecked((int) 0x63315c21), unchecked((int) 0x5e0a72ec), unchecked((int) 0x49bafefd), unchecked((int) 0x187908d9), unchecked((int) 0x8d0dbd86), unchecked((int) 0x311170a7), unchecked((int) 0x3e9b640c), unchecked((int) 0xcc3e10d7),
unchecked((int) 0xd5cad3b6), unchecked((int) 0x0caec388), unchecked((int) 0xf73001e1), unchecked((int) 0x6c728aff), unchecked((int) 0x71eae2a1), unchecked((int) 0x1f9af36e), unchecked((int) 0xcfcbd12f), unchecked((int) 0xc1de8417),
unchecked((int) 0xac07be6b), unchecked((int) 0xcb44a1d8), unchecked((int) 0x8b9b0f56), unchecked((int) 0x013988c3), unchecked((int) 0xb1c52fca), unchecked((int) 0xb4be31cd), unchecked((int) 0xd8782806), unchecked((int) 0x12a3a4e2),
unchecked((int) 0x6f7de532), unchecked((int) 0x58fd7eb6), unchecked((int) 0xd01ee900), unchecked((int) 0x24adffc2), unchecked((int) 0xf4990fc5), unchecked((int) 0x9711aac5), unchecked((int) 0x001d7b95), unchecked((int) 0x82e5e7d2),
unchecked((int) 0x109873f6), unchecked((int) 0x00613096), unchecked((int) 0xc32d9521), unchecked((int) 0xada121ff), unchecked((int) 0x29908415), unchecked((int) 0x7fbb977f), unchecked((int) 0xaf9eb3db), unchecked((int) 0x29c9ed2a),
unchecked((int) 0x5ce2a465), unchecked((int) 0xa730f32c), unchecked((int) 0xd0aa3fe8), unchecked((int) 0x8a5cc091), unchecked((int) 0xd49e2ce7), unchecked((int) 0x0ce454a9), unchecked((int) 0xd60acd86), unchecked((int) 0x015f1919),
unchecked((int) 0x77079103), unchecked((int) 0xdea03af6), unchecked((int) 0x78a8565e), unchecked((int) 0xdee356df), unchecked((int) 0x21f05cbe), unchecked((int) 0x8b75e387), unchecked((int) 0xb3c50651), unchecked((int) 0xb8a5c3ef),
unchecked((int) 0xd8eeb6d2), unchecked((int) 0xe523be77), unchecked((int) 0xc2154529), unchecked((int) 0x2f69efdf), unchecked((int) 0xafe67afb), unchecked((int) 0xf470c4b2), unchecked((int) 0xf3e0eb5b), unchecked((int) 0xd6cc9876),
unchecked((int) 0x39e4460c), unchecked((int) 0x1fda8538), unchecked((int) 0x1987832f), unchecked((int) 0xca007367), unchecked((int) 0xa99144f8), unchecked((int) 0x296b299e), unchecked((int) 0x492fc295), unchecked((int) 0x9266beab),
unchecked((int) 0xb5676e69), unchecked((int) 0x9bd3ddda), unchecked((int) 0xdf7e052f), unchecked((int) 0xdb25701c), unchecked((int) 0x1b5e51ee), unchecked((int) 0xf65324e6), unchecked((int) 0x6afce36c), unchecked((int) 0x0316cc04),
unchecked((int) 0x8644213e), unchecked((int) 0xb7dc59d0), unchecked((int) 0x7965291f), unchecked((int) 0xccd6fd43), unchecked((int) 0x41823979), unchecked((int) 0x932bcdf6), unchecked((int) 0xb657c34d), unchecked((int) 0x4edfd282),
unchecked((int) 0x7ae5290c), unchecked((int) 0x3cb9536b), unchecked((int) 0x851e20fe), unchecked((int) 0x9833557e), unchecked((int) 0x13ecf0b0), unchecked((int) 0xd3ffb372), unchecked((int) 0x3f85c5c1), unchecked((int) 0x0aef7ed2)
},
S5 =
{
unchecked((int) 0x7ec90c04), unchecked((int) 0x2c6e74b9), unchecked((int) 0x9b0e66df), unchecked((int) 0xa6337911), unchecked((int) 0xb86a7fff), unchecked((int) 0x1dd358f5), unchecked((int) 0x44dd9d44), unchecked((int) 0x1731167f),
unchecked((int) 0x08fbf1fa), unchecked((int) 0xe7f511cc), unchecked((int) 0xd2051b00), unchecked((int) 0x735aba00), unchecked((int) 0x2ab722d8), unchecked((int) 0x386381cb), unchecked((int) 0xacf6243a), unchecked((int) 0x69befd7a),
unchecked((int) 0xe6a2e77f), unchecked((int) 0xf0c720cd), unchecked((int) 0xc4494816), unchecked((int) 0xccf5c180), unchecked((int) 0x38851640), unchecked((int) 0x15b0a848), unchecked((int) 0xe68b18cb), unchecked((int) 0x4caadeff),
unchecked((int) 0x5f480a01), unchecked((int) 0x0412b2aa), unchecked((int) 0x259814fc), unchecked((int) 0x41d0efe2), unchecked((int) 0x4e40b48d), unchecked((int) 0x248eb6fb), unchecked((int) 0x8dba1cfe), unchecked((int) 0x41a99b02),
unchecked((int) 0x1a550a04), unchecked((int) 0xba8f65cb), unchecked((int) 0x7251f4e7), unchecked((int) 0x95a51725), unchecked((int) 0xc106ecd7), unchecked((int) 0x97a5980a), unchecked((int) 0xc539b9aa), unchecked((int) 0x4d79fe6a),
unchecked((int) 0xf2f3f763), unchecked((int) 0x68af8040), unchecked((int) 0xed0c9e56), unchecked((int) 0x11b4958b), unchecked((int) 0xe1eb5a88), unchecked((int) 0x8709e6b0), unchecked((int) 0xd7e07156), unchecked((int) 0x4e29fea7),
unchecked((int) 0x6366e52d), unchecked((int) 0x02d1c000), unchecked((int) 0xc4ac8e05), unchecked((int) 0x9377f571), unchecked((int) 0x0c05372a), unchecked((int) 0x578535f2), unchecked((int) 0x2261be02), unchecked((int) 0xd642a0c9),
unchecked((int) 0xdf13a280), unchecked((int) 0x74b55bd2), unchecked((int) 0x682199c0), unchecked((int) 0xd421e5ec), unchecked((int) 0x53fb3ce8), unchecked((int) 0xc8adedb3), unchecked((int) 0x28a87fc9), unchecked((int) 0x3d959981),
unchecked((int) 0x5c1ff900), unchecked((int) 0xfe38d399), unchecked((int) 0x0c4eff0b), unchecked((int) 0x062407ea), unchecked((int) 0xaa2f4fb1), unchecked((int) 0x4fb96976), unchecked((int) 0x90c79505), unchecked((int) 0xb0a8a774),
unchecked((int) 0xef55a1ff), unchecked((int) 0xe59ca2c2), unchecked((int) 0xa6b62d27), unchecked((int) 0xe66a4263), unchecked((int) 0xdf65001f), unchecked((int) 0x0ec50966), unchecked((int) 0xdfdd55bc), unchecked((int) 0x29de0655),
unchecked((int) 0x911e739a), unchecked((int) 0x17af8975), unchecked((int) 0x32c7911c), unchecked((int) 0x89f89468), unchecked((int) 0x0d01e980), unchecked((int) 0x524755f4), unchecked((int) 0x03b63cc9), unchecked((int) 0x0cc844b2),
unchecked((int) 0xbcf3f0aa), unchecked((int) 0x87ac36e9), unchecked((int) 0xe53a7426), unchecked((int) 0x01b3d82b), unchecked((int) 0x1a9e7449), unchecked((int) 0x64ee2d7e), unchecked((int) 0xcddbb1da), unchecked((int) 0x01c94910),
unchecked((int) 0xb868bf80), unchecked((int) 0x0d26f3fd), unchecked((int) 0x9342ede7), unchecked((int) 0x04a5c284), unchecked((int) 0x636737b6), unchecked((int) 0x50f5b616), unchecked((int) 0xf24766e3), unchecked((int) 0x8eca36c1),
unchecked((int) 0x136e05db), unchecked((int) 0xfef18391), unchecked((int) 0xfb887a37), unchecked((int) 0xd6e7f7d4), unchecked((int) 0xc7fb7dc9), unchecked((int) 0x3063fcdf), unchecked((int) 0xb6f589de), unchecked((int) 0xec2941da),
unchecked((int) 0x26e46695), unchecked((int) 0xb7566419), unchecked((int) 0xf654efc5), unchecked((int) 0xd08d58b7), unchecked((int) 0x48925401), unchecked((int) 0xc1bacb7f), unchecked((int) 0xe5ff550f), unchecked((int) 0xb6083049),
unchecked((int) 0x5bb5d0e8), unchecked((int) 0x87d72e5a), unchecked((int) 0xab6a6ee1), unchecked((int) 0x223a66ce), unchecked((int) 0xc62bf3cd), unchecked((int) 0x9e0885f9), unchecked((int) 0x68cb3e47), unchecked((int) 0x086c010f),
unchecked((int) 0xa21de820), unchecked((int) 0xd18b69de), unchecked((int) 0xf3f65777), unchecked((int) 0xfa02c3f6), unchecked((int) 0x407edac3), unchecked((int) 0xcbb3d550), unchecked((int) 0x1793084d), unchecked((int) 0xb0d70eba),
unchecked((int) 0x0ab378d5), unchecked((int) 0xd951fb0c), unchecked((int) 0xded7da56), unchecked((int) 0x4124bbe4), unchecked((int) 0x94ca0b56), unchecked((int) 0x0f5755d1), unchecked((int) 0xe0e1e56e), unchecked((int) 0x6184b5be),
unchecked((int) 0x580a249f), unchecked((int) 0x94f74bc0), unchecked((int) 0xe327888e), unchecked((int) 0x9f7b5561), unchecked((int) 0xc3dc0280), unchecked((int) 0x05687715), unchecked((int) 0x646c6bd7), unchecked((int) 0x44904db3),
unchecked((int) 0x66b4f0a3), unchecked((int) 0xc0f1648a), unchecked((int) 0x697ed5af), unchecked((int) 0x49e92ff6), unchecked((int) 0x309e374f), unchecked((int) 0x2cb6356a), unchecked((int) 0x85808573), unchecked((int) 0x4991f840),
unchecked((int) 0x76f0ae02), unchecked((int) 0x083be84d), unchecked((int) 0x28421c9a), unchecked((int) 0x44489406), unchecked((int) 0x736e4cb8), unchecked((int) 0xc1092910), unchecked((int) 0x8bc95fc6), unchecked((int) 0x7d869cf4),
unchecked((int) 0x134f616f), unchecked((int) 0x2e77118d), unchecked((int) 0xb31b2be1), unchecked((int) 0xaa90b472), unchecked((int) 0x3ca5d717), unchecked((int) 0x7d161bba), unchecked((int) 0x9cad9010), unchecked((int) 0xaf462ba2),
unchecked((int) 0x9fe459d2), unchecked((int) 0x45d34559), unchecked((int) 0xd9f2da13), unchecked((int) 0xdbc65487), unchecked((int) 0xf3e4f94e), unchecked((int) 0x176d486f), unchecked((int) 0x097c13ea), unchecked((int) 0x631da5c7),
unchecked((int) 0x445f7382), unchecked((int) 0x175683f4), unchecked((int) 0xcdc66a97), unchecked((int) 0x70be0288), unchecked((int) 0xb3cdcf72), unchecked((int) 0x6e5dd2f3), unchecked((int) 0x20936079), unchecked((int) 0x459b80a5),
unchecked((int) 0xbe60e2db), unchecked((int) 0xa9c23101), unchecked((int) 0xeba5315c), unchecked((int) 0x224e42f2), unchecked((int) 0x1c5c1572), unchecked((int) 0xf6721b2c), unchecked((int) 0x1ad2fff3), unchecked((int) 0x8c25404e),
unchecked((int) 0x324ed72f), unchecked((int) 0x4067b7fd), unchecked((int) 0x0523138e), unchecked((int) 0x5ca3bc78), unchecked((int) 0xdc0fd66e), unchecked((int) 0x75922283), unchecked((int) 0x784d6b17), unchecked((int) 0x58ebb16e),
unchecked((int) 0x44094f85), unchecked((int) 0x3f481d87), unchecked((int) 0xfcfeae7b), unchecked((int) 0x77b5ff76), unchecked((int) 0x8c2302bf), unchecked((int) 0xaaf47556), unchecked((int) 0x5f46b02a), unchecked((int) 0x2b092801),
unchecked((int) 0x3d38f5f7), unchecked((int) 0x0ca81f36), unchecked((int) 0x52af4a8a), unchecked((int) 0x66d5e7c0), unchecked((int) 0xdf3b0874), unchecked((int) 0x95055110), unchecked((int) 0x1b5ad7a8), unchecked((int) 0xf61ed5ad),
unchecked((int) 0x6cf6e479), unchecked((int) 0x20758184), unchecked((int) 0xd0cefa65), unchecked((int) 0x88f7be58), unchecked((int) 0x4a046826), unchecked((int) 0x0ff6f8f3), unchecked((int) 0xa09c7f70), unchecked((int) 0x5346aba0),
unchecked((int) 0x5ce96c28), unchecked((int) 0xe176eda3), unchecked((int) 0x6bac307f), unchecked((int) 0x376829d2), unchecked((int) 0x85360fa9), unchecked((int) 0x17e3fe2a), unchecked((int) 0x24b79767), unchecked((int) 0xf5a96b20),
unchecked((int) 0xd6cd2595), unchecked((int) 0x68ff1ebf), unchecked((int) 0x7555442c), unchecked((int) 0xf19f06be), unchecked((int) 0xf9e0659a), unchecked((int) 0xeeb9491d), unchecked((int) 0x34010718), unchecked((int) 0xbb30cab8),
unchecked((int) 0xe822fe15), unchecked((int) 0x88570983), unchecked((int) 0x750e6249), unchecked((int) 0xda627e55), unchecked((int) 0x5e76ffa8), unchecked((int) 0xb1534546), unchecked((int) 0x6d47de08), unchecked((int) 0xefe9e7d4)
},
S6 =
{
unchecked((int) 0xf6fa8f9d), unchecked((int) 0x2cac6ce1), unchecked((int) 0x4ca34867), unchecked((int) 0xe2337f7c), unchecked((int) 0x95db08e7), unchecked((int) 0x016843b4), unchecked((int) 0xeced5cbc), unchecked((int) 0x325553ac),
unchecked((int) 0xbf9f0960), unchecked((int) 0xdfa1e2ed), unchecked((int) 0x83f0579d), unchecked((int) 0x63ed86b9), unchecked((int) 0x1ab6a6b8), unchecked((int) 0xde5ebe39), unchecked((int) 0xf38ff732), unchecked((int) 0x8989b138),
unchecked((int) 0x33f14961), unchecked((int) 0xc01937bd), unchecked((int) 0xf506c6da), unchecked((int) 0xe4625e7e), unchecked((int) 0xa308ea99), unchecked((int) 0x4e23e33c), unchecked((int) 0x79cbd7cc), unchecked((int) 0x48a14367),
unchecked((int) 0xa3149619), unchecked((int) 0xfec94bd5), unchecked((int) 0xa114174a), unchecked((int) 0xeaa01866), unchecked((int) 0xa084db2d), unchecked((int) 0x09a8486f), unchecked((int) 0xa888614a), unchecked((int) 0x2900af98),
unchecked((int) 0x01665991), unchecked((int) 0xe1992863), unchecked((int) 0xc8f30c60), unchecked((int) 0x2e78ef3c), unchecked((int) 0xd0d51932), unchecked((int) 0xcf0fec14), unchecked((int) 0xf7ca07d2), unchecked((int) 0xd0a82072),
unchecked((int) 0xfd41197e), unchecked((int) 0x9305a6b0), unchecked((int) 0xe86be3da), unchecked((int) 0x74bed3cd), unchecked((int) 0x372da53c), unchecked((int) 0x4c7f4448), unchecked((int) 0xdab5d440), unchecked((int) 0x6dba0ec3),
unchecked((int) 0x083919a7), unchecked((int) 0x9fbaeed9), unchecked((int) 0x49dbcfb0), unchecked((int) 0x4e670c53), unchecked((int) 0x5c3d9c01), unchecked((int) 0x64bdb941), unchecked((int) 0x2c0e636a), unchecked((int) 0xba7dd9cd),
unchecked((int) 0xea6f7388), unchecked((int) 0xe70bc762), unchecked((int) 0x35f29adb), unchecked((int) 0x5c4cdd8d), unchecked((int) 0xf0d48d8c), unchecked((int) 0xb88153e2), unchecked((int) 0x08a19866), unchecked((int) 0x1ae2eac8),
unchecked((int) 0x284caf89), unchecked((int) 0xaa928223), unchecked((int) 0x9334be53), unchecked((int) 0x3b3a21bf), unchecked((int) 0x16434be3), unchecked((int) 0x9aea3906), unchecked((int) 0xefe8c36e), unchecked((int) 0xf890cdd9),
unchecked((int) 0x80226dae), unchecked((int) 0xc340a4a3), unchecked((int) 0xdf7e9c09), unchecked((int) 0xa694a807), unchecked((int) 0x5b7c5ecc), unchecked((int) 0x221db3a6), unchecked((int) 0x9a69a02f), unchecked((int) 0x68818a54),
unchecked((int) 0xceb2296f), unchecked((int) 0x53c0843a), unchecked((int) 0xfe893655), unchecked((int) 0x25bfe68a), unchecked((int) 0xb4628abc), unchecked((int) 0xcf222ebf), unchecked((int) 0x25ac6f48), unchecked((int) 0xa9a99387),
unchecked((int) 0x53bddb65), unchecked((int) 0xe76ffbe7), unchecked((int) 0xe967fd78), unchecked((int) 0x0ba93563), unchecked((int) 0x8e342bc1), unchecked((int) 0xe8a11be9), unchecked((int) 0x4980740d), unchecked((int) 0xc8087dfc),
unchecked((int) 0x8de4bf99), unchecked((int) 0xa11101a0), unchecked((int) 0x7fd37975), unchecked((int) 0xda5a26c0), unchecked((int) 0xe81f994f), unchecked((int) 0x9528cd89), unchecked((int) 0xfd339fed), unchecked((int) 0xb87834bf),
unchecked((int) 0x5f04456d), unchecked((int) 0x22258698), unchecked((int) 0xc9c4c83b), unchecked((int) 0x2dc156be), unchecked((int) 0x4f628daa), unchecked((int) 0x57f55ec5), unchecked((int) 0xe2220abe), unchecked((int) 0xd2916ebf),
unchecked((int) 0x4ec75b95), unchecked((int) 0x24f2c3c0), unchecked((int) 0x42d15d99), unchecked((int) 0xcd0d7fa0), unchecked((int) 0x7b6e27ff), unchecked((int) 0xa8dc8af0), unchecked((int) 0x7345c106), unchecked((int) 0xf41e232f),
unchecked((int) 0x35162386), unchecked((int) 0xe6ea8926), unchecked((int) 0x3333b094), unchecked((int) 0x157ec6f2), unchecked((int) 0x372b74af), unchecked((int) 0x692573e4), unchecked((int) 0xe9a9d848), unchecked((int) 0xf3160289),
unchecked((int) 0x3a62ef1d), unchecked((int) 0xa787e238), unchecked((int) 0xf3a5f676), unchecked((int) 0x74364853), unchecked((int) 0x20951063), unchecked((int) 0x4576698d), unchecked((int) 0xb6fad407), unchecked((int) 0x592af950),
unchecked((int) 0x36f73523), unchecked((int) 0x4cfb6e87), unchecked((int) 0x7da4cec0), unchecked((int) 0x6c152daa), unchecked((int) 0xcb0396a8), unchecked((int) 0xc50dfe5d), unchecked((int) 0xfcd707ab), unchecked((int) 0x0921c42f),
unchecked((int) 0x89dff0bb), unchecked((int) 0x5fe2be78), unchecked((int) 0x448f4f33), unchecked((int) 0x754613c9), unchecked((int) 0x2b05d08d), unchecked((int) 0x48b9d585), unchecked((int) 0xdc049441), unchecked((int) 0xc8098f9b),
unchecked((int) 0x7dede786), unchecked((int) 0xc39a3373), unchecked((int) 0x42410005), unchecked((int) 0x6a091751), unchecked((int) 0x0ef3c8a6), unchecked((int) 0x890072d6), unchecked((int) 0x28207682), unchecked((int) 0xa9a9f7be),
unchecked((int) 0xbf32679d), unchecked((int) 0xd45b5b75), unchecked((int) 0xb353fd00), unchecked((int) 0xcbb0e358), unchecked((int) 0x830f220a), unchecked((int) 0x1f8fb214), unchecked((int) 0xd372cf08), unchecked((int) 0xcc3c4a13),
unchecked((int) 0x8cf63166), unchecked((int) 0x061c87be), unchecked((int) 0x88c98f88), unchecked((int) 0x6062e397), unchecked((int) 0x47cf8e7a), unchecked((int) 0xb6c85283), unchecked((int) 0x3cc2acfb), unchecked((int) 0x3fc06976),
unchecked((int) 0x4e8f0252), unchecked((int) 0x64d8314d), unchecked((int) 0xda3870e3), unchecked((int) 0x1e665459), unchecked((int) 0xc10908f0), unchecked((int) 0x513021a5), unchecked((int) 0x6c5b68b7), unchecked((int) 0x822f8aa0),
unchecked((int) 0x3007cd3e), unchecked((int) 0x74719eef), unchecked((int) 0xdc872681), unchecked((int) 0x073340d4), unchecked((int) 0x7e432fd9), unchecked((int) 0x0c5ec241), unchecked((int) 0x8809286c), unchecked((int) 0xf592d891),
unchecked((int) 0x08a930f6), unchecked((int) 0x957ef305), unchecked((int) 0xb7fbffbd), unchecked((int) 0xc266e96f), unchecked((int) 0x6fe4ac98), unchecked((int) 0xb173ecc0), unchecked((int) 0xbc60b42a), unchecked((int) 0x953498da),
unchecked((int) 0xfba1ae12), unchecked((int) 0x2d4bd736), unchecked((int) 0x0f25faab), unchecked((int) 0xa4f3fceb), unchecked((int) 0xe2969123), unchecked((int) 0x257f0c3d), unchecked((int) 0x9348af49), unchecked((int) 0x361400bc),
unchecked((int) 0xe8816f4a), unchecked((int) 0x3814f200), unchecked((int) 0xa3f94043), unchecked((int) 0x9c7a54c2), unchecked((int) 0xbc704f57), unchecked((int) 0xda41e7f9), unchecked((int) 0xc25ad33a), unchecked((int) 0x54f4a084),
unchecked((int) 0xb17f5505), unchecked((int) 0x59357cbe), unchecked((int) 0xedbd15c8), unchecked((int) 0x7f97c5ab), unchecked((int) 0xba5ac7b5), unchecked((int) 0xb6f6deaf), unchecked((int) 0x3a479c3a), unchecked((int) 0x5302da25),
unchecked((int) 0x653d7e6a), unchecked((int) 0x54268d49), unchecked((int) 0x51a477ea), unchecked((int) 0x5017d55b), unchecked((int) 0xd7d25d88), unchecked((int) 0x44136c76), unchecked((int) 0x0404a8c8), unchecked((int) 0xb8e5a121),
unchecked((int) 0xb81a928a), unchecked((int) 0x60ed5869), unchecked((int) 0x97c55b96), unchecked((int) 0xeaec991b), unchecked((int) 0x29935913), unchecked((int) 0x01fdb7f1), unchecked((int) 0x088e8dfa), unchecked((int) 0x9ab6f6f5),
unchecked((int) 0x3b4cbf9f), unchecked((int) 0x4a5de3ab), unchecked((int) 0xe6051d35), unchecked((int) 0xa0e1d855), unchecked((int) 0xd36b4cf1), unchecked((int) 0xf544edeb), unchecked((int) 0xb0e93524), unchecked((int) 0xbebb8fbd),
unchecked((int) 0xa2d762cf), unchecked((int) 0x49c92f54), unchecked((int) 0x38b5f331), unchecked((int) 0x7128a454), unchecked((int) 0x48392905), unchecked((int) 0xa65b1db8), unchecked((int) 0x851c97bd), unchecked((int) 0xd675cf2f)
},
S7 =
{
unchecked((int) 0x85e04019), unchecked((int) 0x332bf567), unchecked((int) 0x662dbfff), unchecked((int) 0xcfc65693), unchecked((int) 0x2a8d7f6f), unchecked((int) 0xab9bc912), unchecked((int) 0xde6008a1), unchecked((int) 0x2028da1f),
unchecked((int) 0x0227bce7), unchecked((int) 0x4d642916), unchecked((int) 0x18fac300), unchecked((int) 0x50f18b82), unchecked((int) 0x2cb2cb11), unchecked((int) 0xb232e75c), unchecked((int) 0x4b3695f2), unchecked((int) 0xb28707de),
unchecked((int) 0xa05fbcf6), unchecked((int) 0xcd4181e9), unchecked((int) 0xe150210c), unchecked((int) 0xe24ef1bd), unchecked((int) 0xb168c381), unchecked((int) 0xfde4e789), unchecked((int) 0x5c79b0d8), unchecked((int) 0x1e8bfd43),
unchecked((int) 0x4d495001), unchecked((int) 0x38be4341), unchecked((int) 0x913cee1d), unchecked((int) 0x92a79c3f), unchecked((int) 0x089766be), unchecked((int) 0xbaeeadf4), unchecked((int) 0x1286becf), unchecked((int) 0xb6eacb19),
unchecked((int) 0x2660c200), unchecked((int) 0x7565bde4), unchecked((int) 0x64241f7a), unchecked((int) 0x8248dca9), unchecked((int) 0xc3b3ad66), unchecked((int) 0x28136086), unchecked((int) 0x0bd8dfa8), unchecked((int) 0x356d1cf2),
unchecked((int) 0x107789be), unchecked((int) 0xb3b2e9ce), unchecked((int) 0x0502aa8f), unchecked((int) 0x0bc0351e), unchecked((int) 0x166bf52a), unchecked((int) 0xeb12ff82), unchecked((int) 0xe3486911), unchecked((int) 0xd34d7516),
unchecked((int) 0x4e7b3aff), unchecked((int) 0x5f43671b), unchecked((int) 0x9cf6e037), unchecked((int) 0x4981ac83), unchecked((int) 0x334266ce), unchecked((int) 0x8c9341b7), unchecked((int) 0xd0d854c0), unchecked((int) 0xcb3a6c88),
unchecked((int) 0x47bc2829), unchecked((int) 0x4725ba37), unchecked((int) 0xa66ad22b), unchecked((int) 0x7ad61f1e), unchecked((int) 0x0c5cbafa), unchecked((int) 0x4437f107), unchecked((int) 0xb6e79962), unchecked((int) 0x42d2d816),
unchecked((int) 0x0a961288), unchecked((int) 0xe1a5c06e), unchecked((int) 0x13749e67), unchecked((int) 0x72fc081a), unchecked((int) 0xb1d139f7), unchecked((int) 0xf9583745), unchecked((int) 0xcf19df58), unchecked((int) 0xbec3f756),
unchecked((int) 0xc06eba30), unchecked((int) 0x07211b24), unchecked((int) 0x45c28829), unchecked((int) 0xc95e317f), unchecked((int) 0xbc8ec511), unchecked((int) 0x38bc46e9), unchecked((int) 0xc6e6fa14), unchecked((int) 0xbae8584a),
unchecked((int) 0xad4ebc46), unchecked((int) 0x468f508b), unchecked((int) 0x7829435f), unchecked((int) 0xf124183b), unchecked((int) 0x821dba9f), unchecked((int) 0xaff60ff4), unchecked((int) 0xea2c4e6d), unchecked((int) 0x16e39264),
unchecked((int) 0x92544a8b), unchecked((int) 0x009b4fc3), unchecked((int) 0xaba68ced), unchecked((int) 0x9ac96f78), unchecked((int) 0x06a5b79a), unchecked((int) 0xb2856e6e), unchecked((int) 0x1aec3ca9), unchecked((int) 0xbe838688),
unchecked((int) 0x0e0804e9), unchecked((int) 0x55f1be56), unchecked((int) 0xe7e5363b), unchecked((int) 0xb3a1f25d), unchecked((int) 0xf7debb85), unchecked((int) 0x61fe033c), unchecked((int) 0x16746233), unchecked((int) 0x3c034c28),
unchecked((int) 0xda6d0c74), unchecked((int) 0x79aac56c), unchecked((int) 0x3ce4e1ad), unchecked((int) 0x51f0c802), unchecked((int) 0x98f8f35a), unchecked((int) 0x1626a49f), unchecked((int) 0xeed82b29), unchecked((int) 0x1d382fe3),
unchecked((int) 0x0c4fb99a), unchecked((int) 0xbb325778), unchecked((int) 0x3ec6d97b), unchecked((int) 0x6e77a6a9), unchecked((int) 0xcb658b5c), unchecked((int) 0xd45230c7), unchecked((int) 0x2bd1408b), unchecked((int) 0x60c03eb7),
unchecked((int) 0xb9068d78), unchecked((int) 0xa33754f4), unchecked((int) 0xf430c87d), unchecked((int) 0xc8a71302), unchecked((int) 0xb96d8c32), unchecked((int) 0xebd4e7be), unchecked((int) 0xbe8b9d2d), unchecked((int) 0x7979fb06),
unchecked((int) 0xe7225308), unchecked((int) 0x8b75cf77), unchecked((int) 0x11ef8da4), unchecked((int) 0xe083c858), unchecked((int) 0x8d6b786f), unchecked((int) 0x5a6317a6), unchecked((int) 0xfa5cf7a0), unchecked((int) 0x5dda0033),
unchecked((int) 0xf28ebfb0), unchecked((int) 0xf5b9c310), unchecked((int) 0xa0eac280), unchecked((int) 0x08b9767a), unchecked((int) 0xa3d9d2b0), unchecked((int) 0x79d34217), unchecked((int) 0x021a718d), unchecked((int) 0x9ac6336a),
unchecked((int) 0x2711fd60), unchecked((int) 0x438050e3), unchecked((int) 0x069908a8), unchecked((int) 0x3d7fedc4), unchecked((int) 0x826d2bef), unchecked((int) 0x4eeb8476), unchecked((int) 0x488dcf25), unchecked((int) 0x36c9d566),
unchecked((int) 0x28e74e41), unchecked((int) 0xc2610aca), unchecked((int) 0x3d49a9cf), unchecked((int) 0xbae3b9df), unchecked((int) 0xb65f8de6), unchecked((int) 0x92aeaf64), unchecked((int) 0x3ac7d5e6), unchecked((int) 0x9ea80509),
unchecked((int) 0xf22b017d), unchecked((int) 0xa4173f70), unchecked((int) 0xdd1e16c3), unchecked((int) 0x15e0d7f9), unchecked((int) 0x50b1b887), unchecked((int) 0x2b9f4fd5), unchecked((int) 0x625aba82), unchecked((int) 0x6a017962),
unchecked((int) 0x2ec01b9c), unchecked((int) 0x15488aa9), unchecked((int) 0xd716e740), unchecked((int) 0x40055a2c), unchecked((int) 0x93d29a22), unchecked((int) 0xe32dbf9a), unchecked((int) 0x058745b9), unchecked((int) 0x3453dc1e),
unchecked((int) 0xd699296e), unchecked((int) 0x496cff6f), unchecked((int) 0x1c9f4986), unchecked((int) 0xdfe2ed07), unchecked((int) 0xb87242d1), unchecked((int) 0x19de7eae), unchecked((int) 0x053e561a), unchecked((int) 0x15ad6f8c),
unchecked((int) 0x66626c1c), unchecked((int) 0x7154c24c), unchecked((int) 0xea082b2a), unchecked((int) 0x93eb2939), unchecked((int) 0x17dcb0f0), unchecked((int) 0x58d4f2ae), unchecked((int) 0x9ea294fb), unchecked((int) 0x52cf564c),
unchecked((int) 0x9883fe66), unchecked((int) 0x2ec40581), unchecked((int) 0x763953c3), unchecked((int) 0x01d6692e), unchecked((int) 0xd3a0c108), unchecked((int) 0xa1e7160e), unchecked((int) 0xe4f2dfa6), unchecked((int) 0x693ed285),
unchecked((int) 0x74904698), unchecked((int) 0x4c2b0edd), unchecked((int) 0x4f757656), unchecked((int) 0x5d393378), unchecked((int) 0xa132234f), unchecked((int) 0x3d321c5d), unchecked((int) 0xc3f5e194), unchecked((int) 0x4b269301),
unchecked((int) 0xc79f022f), unchecked((int) 0x3c997e7e), unchecked((int) 0x5e4f9504), unchecked((int) 0x3ffafbbd), unchecked((int) 0x76f7ad0e), unchecked((int) 0x296693f4), unchecked((int) 0x3d1fce6f), unchecked((int) 0xc61e45be),
unchecked((int) 0xd3b5ab34), unchecked((int) 0xf72bf9b7), unchecked((int) 0x1b0434c0), unchecked((int) 0x4e72b567), unchecked((int) 0x5592a33d), unchecked((int) 0xb5229301), unchecked((int) 0xcfd2a87f), unchecked((int) 0x60aeb767),
unchecked((int) 0x1814386b), unchecked((int) 0x30bcc33d), unchecked((int) 0x38a0c07d), unchecked((int) 0xfd1606f2), unchecked((int) 0xc363519b), unchecked((int) 0x589dd390), unchecked((int) 0x5479f8e6), unchecked((int) 0x1cb8d647),
unchecked((int) 0x97fd61a9), unchecked((int) 0xea7759f4), unchecked((int) 0x2d57539d), unchecked((int) 0x569a58cf), unchecked((int) 0xe84e63ad), unchecked((int) 0x462e1b78), unchecked((int) 0x6580f87e), unchecked((int) 0xf3817914),
unchecked((int) 0x91da55f4), unchecked((int) 0x40a230f3), unchecked((int) 0xd1988f35), unchecked((int) 0xb6e318d2), unchecked((int) 0x3ffa50bc), unchecked((int) 0x3d40f021), unchecked((int) 0xc3c0bdae), unchecked((int) 0x4958c24c),
unchecked((int) 0x518f36b2), unchecked((int) 0x84b1d370), unchecked((int) 0x0fedce83), unchecked((int) 0x878ddada), unchecked((int) 0xf2a279c7), unchecked((int) 0x94e01be8), unchecked((int) 0x90716f4b), unchecked((int) 0x954b8aa3)
},
S8 =
{
unchecked((int) 0xe216300d), unchecked((int) 0xbbddfffc), unchecked((int) 0xa7ebdabd), unchecked((int) 0x35648095), unchecked((int) 0x7789f8b7), unchecked((int) 0xe6c1121b), unchecked((int) 0x0e241600), unchecked((int) 0x052ce8b5),
unchecked((int) 0x11a9cfb0), unchecked((int) 0xe5952f11), unchecked((int) 0xece7990a), unchecked((int) 0x9386d174), unchecked((int) 0x2a42931c), unchecked((int) 0x76e38111), unchecked((int) 0xb12def3a), unchecked((int) 0x37ddddfc),
unchecked((int) 0xde9adeb1), unchecked((int) 0x0a0cc32c), unchecked((int) 0xbe197029), unchecked((int) 0x84a00940), unchecked((int) 0xbb243a0f), unchecked((int) 0xb4d137cf), unchecked((int) 0xb44e79f0), unchecked((int) 0x049eedfd),
unchecked((int) 0x0b15a15d), unchecked((int) 0x480d3168), unchecked((int) 0x8bbbde5a), unchecked((int) 0x669ded42), unchecked((int) 0xc7ece831), unchecked((int) 0x3f8f95e7), unchecked((int) 0x72df191b), unchecked((int) 0x7580330d),
unchecked((int) 0x94074251), unchecked((int) 0x5c7dcdfa), unchecked((int) 0xabbe6d63), unchecked((int) 0xaa402164), unchecked((int) 0xb301d40a), unchecked((int) 0x02e7d1ca), unchecked((int) 0x53571dae), unchecked((int) 0x7a3182a2),
unchecked((int) 0x12a8ddec), unchecked((int) 0xfdaa335d), unchecked((int) 0x176f43e8), unchecked((int) 0x71fb46d4), unchecked((int) 0x38129022), unchecked((int) 0xce949ad4), unchecked((int) 0xb84769ad), unchecked((int) 0x965bd862),
unchecked((int) 0x82f3d055), unchecked((int) 0x66fb9767), unchecked((int) 0x15b80b4e), unchecked((int) 0x1d5b47a0), unchecked((int) 0x4cfde06f), unchecked((int) 0xc28ec4b8), unchecked((int) 0x57e8726e), unchecked((int) 0x647a78fc),
unchecked((int) 0x99865d44), unchecked((int) 0x608bd593), unchecked((int) 0x6c200e03), unchecked((int) 0x39dc5ff6), unchecked((int) 0x5d0b00a3), unchecked((int) 0xae63aff2), unchecked((int) 0x7e8bd632), unchecked((int) 0x70108c0c),
unchecked((int) 0xbbd35049), unchecked((int) 0x2998df04), unchecked((int) 0x980cf42a), unchecked((int) 0x9b6df491), unchecked((int) 0x9e7edd53), unchecked((int) 0x06918548), unchecked((int) 0x58cb7e07), unchecked((int) 0x3b74ef2e),
unchecked((int) 0x522fffb1), unchecked((int) 0xd24708cc), unchecked((int) 0x1c7e27cd), unchecked((int) 0xa4eb215b), unchecked((int) 0x3cf1d2e2), unchecked((int) 0x19b47a38), unchecked((int) 0x424f7618), unchecked((int) 0x35856039),
unchecked((int) 0x9d17dee7), unchecked((int) 0x27eb35e6), unchecked((int) 0xc9aff67b), unchecked((int) 0x36baf5b8), unchecked((int) 0x09c467cd), unchecked((int) 0xc18910b1), unchecked((int) 0xe11dbf7b), unchecked((int) 0x06cd1af8),
unchecked((int) 0x7170c608), unchecked((int) 0x2d5e3354), unchecked((int) 0xd4de495a), unchecked((int) 0x64c6d006), unchecked((int) 0xbcc0c62c), unchecked((int) 0x3dd00db3), unchecked((int) 0x708f8f34), unchecked((int) 0x77d51b42),
unchecked((int) 0x264f620f), unchecked((int) 0x24b8d2bf), unchecked((int) 0x15c1b79e), unchecked((int) 0x46a52564), unchecked((int) 0xf8d7e54e), unchecked((int) 0x3e378160), unchecked((int) 0x7895cda5), unchecked((int) 0x859c15a5),
unchecked((int) 0xe6459788), unchecked((int) 0xc37bc75f), unchecked((int) 0xdb07ba0c), unchecked((int) 0x0676a3ab), unchecked((int) 0x7f229b1e), unchecked((int) 0x31842e7b), unchecked((int) 0x24259fd7), unchecked((int) 0xf8bef472),
unchecked((int) 0x835ffcb8), unchecked((int) 0x6df4c1f2), unchecked((int) 0x96f5b195), unchecked((int) 0xfd0af0fc), unchecked((int) 0xb0fe134c), unchecked((int) 0xe2506d3d), unchecked((int) 0x4f9b12ea), unchecked((int) 0xf215f225),
unchecked((int) 0xa223736f), unchecked((int) 0x9fb4c428), unchecked((int) 0x25d04979), unchecked((int) 0x34c713f8), unchecked((int) 0xc4618187), unchecked((int) 0xea7a6e98), unchecked((int) 0x7cd16efc), unchecked((int) 0x1436876c),
unchecked((int) 0xf1544107), unchecked((int) 0xbedeee14), unchecked((int) 0x56e9af27), unchecked((int) 0xa04aa441), unchecked((int) 0x3cf7c899), unchecked((int) 0x92ecbae6), unchecked((int) 0xdd67016d), unchecked((int) 0x151682eb),
unchecked((int) 0xa842eedf), unchecked((int) 0xfdba60b4), unchecked((int) 0xf1907b75), unchecked((int) 0x20e3030f), unchecked((int) 0x24d8c29e), unchecked((int) 0xe139673b), unchecked((int) 0xefa63fb8), unchecked((int) 0x71873054),
unchecked((int) 0xb6f2cf3b), unchecked((int) 0x9f326442), unchecked((int) 0xcb15a4cc), unchecked((int) 0xb01a4504), unchecked((int) 0xf1e47d8d), unchecked((int) 0x844a1be5), unchecked((int) 0xbae7dfdc), unchecked((int) 0x42cbda70),
unchecked((int) 0xcd7dae0a), unchecked((int) 0x57e85b7a), unchecked((int) 0xd53f5af6), unchecked((int) 0x20cf4d8c), unchecked((int) 0xcea4d428), unchecked((int) 0x79d130a4), unchecked((int) 0x3486ebfb), unchecked((int) 0x33d3cddc),
unchecked((int) 0x77853b53), unchecked((int) 0x37effcb5), unchecked((int) 0xc5068778), unchecked((int) 0xe580b3e6), unchecked((int) 0x4e68b8f4), unchecked((int) 0xc5c8b37e), unchecked((int) 0x0d809ea2), unchecked((int) 0x398feb7c),
unchecked((int) 0x132a4f94), unchecked((int) 0x43b7950e), unchecked((int) 0x2fee7d1c), unchecked((int) 0x223613bd), unchecked((int) 0xdd06caa2), unchecked((int) 0x37df932b), unchecked((int) 0xc4248289), unchecked((int) 0xacf3ebc3),
unchecked((int) 0x5715f6b7), unchecked((int) 0xef3478dd), unchecked((int) 0xf267616f), unchecked((int) 0xc148cbe4), unchecked((int) 0x9052815e), unchecked((int) 0x5e410fab), unchecked((int) 0xb48a2465), unchecked((int) 0x2eda7fa4),
unchecked((int) 0xe87b40e4), unchecked((int) 0xe98ea084), unchecked((int) 0x5889e9e1), unchecked((int) 0xefd390fc), unchecked((int) 0xdd07d35b), unchecked((int) 0xdb485694), unchecked((int) 0x38d7e5b2), unchecked((int) 0x57720101),
unchecked((int) 0x730edebc), unchecked((int) 0x5b643113), unchecked((int) 0x94917e4f), unchecked((int) 0x503c2fba), unchecked((int) 0x646f1282), unchecked((int) 0x7523d24a), unchecked((int) 0xe0779695), unchecked((int) 0xf9c17a8f),
unchecked((int) 0x7a5b2121), unchecked((int) 0xd187b896), unchecked((int) 0x29263a4d), unchecked((int) 0xba510cdf), unchecked((int) 0x81f47c9f), unchecked((int) 0xad1163ed), unchecked((int) 0xea7b5965), unchecked((int) 0x1a00726e),
unchecked((int) 0x11403092), unchecked((int) 0x00da6d77), unchecked((int) 0x4a0cdd61), unchecked((int) 0xad1f4603), unchecked((int) 0x605bdfb0), unchecked((int) 0x9eedc364), unchecked((int) 0x22ebe6a8), unchecked((int) 0xcee7d28a),
unchecked((int) 0xa0e736a0), unchecked((int) 0x5564a6b9), unchecked((int) 0x10853209), unchecked((int) 0xc7eb8f37), unchecked((int) 0x2de705ca), unchecked((int) 0x8951570f), unchecked((int) 0xdf09822b), unchecked((int) 0xbd691a6c),
unchecked((int) 0xaa12e4f2), unchecked((int) 0x87451c0f), unchecked((int) 0xe0f6a27a), unchecked((int) 0x3ada4819), unchecked((int) 0x4cf1764f), unchecked((int) 0x0d771c2b), unchecked((int) 0x67cdb156), unchecked((int) 0x350d8384),
unchecked((int) 0x5938fa0f), unchecked((int) 0x42399ef3), unchecked((int) 0x36997b07), unchecked((int) 0x0e84093d), unchecked((int) 0x4aa93e61), unchecked((int) 0x8360d87b), unchecked((int) 0x1fa98b0c), unchecked((int) 0x1149382c),
unchecked((int) 0xe97625a5), unchecked((int) 0x0614d1b7), unchecked((int) 0x0e25244b), unchecked((int) 0x0c768347), unchecked((int) 0x589e8d82), unchecked((int) 0x0d2059d1), unchecked((int) 0xa466bb1e), unchecked((int) 0xf8da0a82),
unchecked((int) 0x04f19130), unchecked((int) 0xba6e4ec0), unchecked((int) 0x99265164), unchecked((int) 0x1ee7230d), unchecked((int) 0x50b2ad80), unchecked((int) 0xeaee6801), unchecked((int) 0x8db2a283), unchecked((int) 0xea8bf59e)
};
//====================================
// Useful constants
//====================================
internal static readonly int MAX_ROUNDS = 16;
internal static readonly int RED_ROUNDS = 12;
private const int BLOCK_SIZE = 8; // bytes = 64 bits
private int [] _Kr = new int[17]; // the rotating round key
private int [] _Km = new int[17]; // the masking round key
private bool _encrypting;
private byte[] _workingKey;
private int _rounds = MAX_ROUNDS;
public Cast5Engine()
{
}
/**
* initialise a CAST cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + parameters.GetType().ToString());
_encrypting = forEncryption;
_workingKey = ((KeyParameter)parameters).GetKey();
SetKey(_workingKey);
}
public virtual string AlgorithmName
{
get { return "CAST5"; }
}
public virtual bool IsPartialBlockOkay
{
get { return false; }
}
public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
int blockSize = GetBlockSize();
if (_workingKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + blockSize) > input.Length)
throw new DataLengthException("Input buffer too short");
if ((outOff + blockSize) > output.Length)
throw new DataLengthException("Output buffer too short");
if (_encrypting)
{
return EncryptBlock(input, inOff, output, outOff);
}
else
{
return DecryptBlock(input, inOff, output, outOff);
}
}
public virtual void Reset()
{
}
public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
//==================================
// Private Implementation
//==================================
/*
* Creates the subkeys using the same nomenclature
* as described in RFC2144.
*
* See section 2.4
*/
internal virtual void SetKey(byte[] key)
{
/*
* Determine the key size here, if required
*
* if keysize <= 80bits, use 12 rounds instead of 16
* if keysize < 128bits, pad with 0
*
* Typical key sizes => 40, 64, 80, 128
*/
if (key.Length < 11)
{
_rounds = RED_ROUNDS;
}
int [] z = new int[16];
int [] x = new int[16];
int z03, z47, z8B, zCF;
int x03, x47, x8B, xCF;
/* copy the key into x */
for (int i=0; i< key.Length; i++)
{
x[i] = (int)(key[i] & 0xff);
}
/*
* This will look different because the selection of
* bytes from the input key I've already chosen the
* correct int.
*/
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
_Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
_Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
_Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
_Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
_Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
_Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
_Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
_Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
_Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
_Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
_Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
_Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Kr[ 1]=(S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f;
_Kr[ 2]=(S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f;
_Kr[ 3]=(S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f;
_Kr[ 4]=(S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f;
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Kr[ 5]=(S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f;
_Kr[ 6]=(S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f;
_Kr[ 7]=(S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f;
_Kr[ 8]=(S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f;
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Kr[ 9]=(S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f;
_Kr[10]=(S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f;
_Kr[11]=(S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f;
_Kr[12]=(S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f;
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Kr[13]=(S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f;
_Kr[14]=(S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f;
_Kr[15]=(S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f;
_Kr[16]=(S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f;
}
/**
* 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 virtual int EncryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int [] result = new int[2];
// process the input block
// batch the units up into a 32 bit chunk and go for it
// the array is in bytes, the increment is 8x8 bits = 64
int L0 = BytesTo32bits(src, srcIndex);
int R0 = BytesTo32bits(src, srcIndex + 4);
CAST_Encipher(L0, R0, result);
// now stuff them into the destination block
Bits32ToBytes(result[0], dst, dstIndex);
Bits32ToBytes(result[1], dst, dstIndex + 4);
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 virtual int DecryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int [] result = new int[2];
// process the input block
// batch the units up into a 32 bit chunk and go for it
// the array is in bytes, the increment is 8x8 bits = 64
int L16 = BytesTo32bits(src, srcIndex);
int R16 = BytesTo32bits(src, srcIndex+4);
CAST_Decipher(L16, R16, result);
// now stuff them into the destination block
Bits32ToBytes(result[0], dst, dstIndex);
Bits32ToBytes(result[1], dst, dstIndex+4);
return BLOCK_SIZE;
}
/**
* The first of the three processing functions for the
* encryption and decryption.
*
* @param D the input to be processed
* @param Kmi the mask to be used from Km[n]
* @param Kri the rotation value to be used
*
*/
internal static int F1(int D, int Kmi, int Kri)
{
int I = Kmi + D;
I = I << Kri | (int) ((uint) I >> (32-Kri));
return ((S1[((uint) I >>24)&0xff]^S2[((uint)I>>16)&0xff])-S3[((uint)I>> 8)&0xff])+
S4[(I )&0xff];
}
/**
* The second of the three processing functions for the
* encryption and decryption.
*
* @param D the input to be processed
* @param Kmi the mask to be used from Km[n]
* @param Kri the rotation value to be used
*
*/
internal static int F2(int D, int Kmi, int Kri)
{
int I = Kmi ^ D;
I = I << Kri | (int) ((uint)I >> (32-Kri));
return ((S1[((uint)I>>24)&0xff]-S2[((uint)I>>16)&0xff])+S3[((uint)I>> 8)&0xff])^
S4[(I )&0xff];
}
/**
* The third of the three processing functions for the
* encryption and decryption.
*
* @param D the input to be processed
* @param Kmi the mask to be used from Km[n]
* @param Kri the rotation value to be used
*
*/
internal static int F3(int D, int Kmi, int Kri)
{
int I = Kmi - D;
I = I << Kri | (int) ((uint)I >> (32-Kri));
return ((S1[((uint)I>>24)&0xff]+S2[((uint)I>>16)&0xff])^S3[((uint)I>> 8)&0xff])-
S4[(I )&0xff];
}
/**
* Does the 16 rounds to encrypt the block.
*
* @param L0 the LH-32bits of the plaintext block
* @param R0 the RH-32bits of the plaintext block
*/
internal void CAST_Encipher(int L0, int R0, int [] result)
{
int Lp = L0; // the previous value, equiv to L[i-1]
int Rp = R0; // equivalent to R[i-1]
/*
* numbering consistent with paper to make
* checking and validating easier
*/
int Li = L0, Ri = R0;
for (int i = 1; i<=_rounds ; i++)
{
Lp = Li;
Rp = Ri;
Li = Rp;
switch (i)
{
case 1:
case 4:
case 7:
case 10:
case 13:
case 16:
Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
break;
case 2:
case 5:
case 8:
case 11:
case 14:
Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
break;
case 3:
case 6:
case 9:
case 12:
case 15:
Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
break;
}
}
result[0] = Ri;
result[1] = Li;
return;
}
internal void CAST_Decipher(int L16, int R16, int [] result)
{
int Lp = L16; // the previous value, equiv to L[i-1]
int Rp = R16; // equivalent to R[i-1]
/*
* numbering consistent with paper to make
* checking and validating easier
*/
int Li = L16, Ri = R16;
for (int i = _rounds; i > 0; i--)
{
Lp = Li;
Rp = Ri;
Li = Rp;
switch (i)
{
case 1:
case 4:
case 7:
case 10:
case 13:
case 16:
Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
break;
case 2:
case 5:
case 8:
case 11:
case 14:
Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
break;
case 3:
case 6:
case 9:
case 12:
case 15:
Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
break;
}
}
result[0] = Ri;
result[1] = Li;
return;
}
internal static void Bits32ToInts(int inData, int[] b, int offset)
{
b[offset + 3] = (inData & 0xff);
b[offset + 2] = (int) (((uint) inData >> 8) & 0xff);
b[offset + 1] = (int) (((uint)inData >> 16) & 0xff);
b[offset] = (int) (((uint)inData >> 24) & 0xff);
}
internal static int IntsTo32bits(int[] b, int i)
{
int rv = 0;
rv = ((b[i] & 0xff) << 24) |
((b[i+1] & 0xff) << 16) |
((b[i+2] & 0xff) << 8) |
((b[i+3] & 0xff));
return rv;
}
internal static void Bits32ToBytes(int inData, byte[] b, int offset)
{
b[offset + 3] = (byte)inData;
b[offset + 2] = (byte)((uint)inData >> 8);
b[offset + 1] = (byte)((uint)inData >> 16);
b[offset] = (byte)((uint)inData >> 24);
}
internal static int BytesTo32bits(byte[] b, int i)
{
return ((b[i] & 0xff) << 24) |
((b[i+1] & 0xff) << 16) |
((b[i+2] & 0xff) << 8) |
((b[i+3] & 0xff));
}
}
}

View File

@@ -0,0 +1,277 @@
using System;
namespace 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 int []_Km = new int[ROUNDS*4]; // the masking round key(s)
/*
* Key setup
*/
private int []_Tr = new int[24 * 8];
private int []_Tm = new int[24 * 8];
private int[] _workingKey = new int[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)
{
int Cm = 0x5a827999;
int 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] = BytesTo32bits(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] = _workingKey[0] & 0x1f;
_Kr[i*4 + 1] = _workingKey[2] & 0x1f;
_Kr[i*4 + 2] = _workingKey[4] & 0x1f;
_Kr[i*4 + 3] = _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)
{
int[] result = new int[4];
// process the input block
// batch the units up into 4x32 bit chunks and go for it
int A = BytesTo32bits(src, srcIndex);
int B = BytesTo32bits(src, srcIndex + 4);
int C = BytesTo32bits(src, srcIndex + 8);
int D = BytesTo32bits(src, srcIndex + 12);
CAST_Encipher(A, B, C, D, result);
// now stuff them into the destination block
Bits32ToBytes(result[0], dst, dstIndex);
Bits32ToBytes(result[1], dst, dstIndex + 4);
Bits32ToBytes(result[2], dst, dstIndex + 8);
Bits32ToBytes(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)
{
int[] result = new int[4];
// process the input block
// batch the units up into 4x32 bit chunks and go for it
int A = BytesTo32bits(src, srcIndex);
int B = BytesTo32bits(src, srcIndex + 4);
int C = BytesTo32bits(src, srcIndex + 8);
int D = BytesTo32bits(src, srcIndex + 12);
CAST_Decipher(A, B, C, D, result);
// now stuff them into the destination block
Bits32ToBytes(result[0], dst, dstIndex);
Bits32ToBytes(result[1], dst, dstIndex + 4);
Bits32ToBytes(result[2], dst, dstIndex + 8);
Bits32ToBytes(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(
int A,
int B,
int C,
int D,
int[] 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(
int A,
int B,
int C,
int D,
int[] 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;
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
public class DesEdeEngine
: DesEngine
{
private int[] workingKey1, workingKey2, workingKey3;
private bool forEncryption;
/**
* initialise a DESede cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public override void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString());
}
byte[] keyMaster = ((KeyParameter)parameters).GetKey();
byte[] key1 = new byte[8], key2 = new byte[8], key3 = new byte[8];
this.forEncryption = forEncryption;
if (keyMaster.Length == 24)
{
Array.Copy(keyMaster, 0, key1, 0, key1.Length);
Array.Copy(keyMaster, 8, key2, 0, key2.Length);
Array.Copy(keyMaster, 16, key3, 0, key3.Length);
workingKey1 = GenerateWorkingKey(forEncryption, key1);
workingKey2 = GenerateWorkingKey(!forEncryption, key2);
workingKey3 = GenerateWorkingKey(forEncryption, key3);
}
else // 16 byte key
{
Array.Copy(keyMaster, 0, key1, 0, key1.Length);
Array.Copy(keyMaster, 8, key2, 0, key2.Length);
workingKey1 = GenerateWorkingKey(forEncryption, key1);
workingKey2 = GenerateWorkingKey(!forEncryption, key2);
workingKey3 = workingKey1;
}
}
public override string AlgorithmName
{
get { return "DESede"; }
}
public override int GetBlockSize()
{
return BLOCK_SIZE;
}
public override int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey1 == null)
throw new InvalidOperationException("DESede engine not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (forEncryption)
{
DesFunc(workingKey1, input, inOff, output, outOff);
DesFunc(workingKey2, output, outOff, output, outOff);
DesFunc(workingKey3, output, outOff, output, outOff);
}
else
{
DesFunc(workingKey3, input, inOff, output, outOff);
DesFunc(workingKey2, output, outOff, output, outOff);
DesFunc(workingKey1, output, outOff, output, outOff);
}
return BLOCK_SIZE;
}
public override void Reset()
{
}
}
}

View File

@@ -0,0 +1,299 @@
using System;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Wrap keys according to
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt">
* draft-ietf-smime-key-wrap-01.txt</a>.
* <p>
* Note:
* <ul>
* <li>this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.</li>
* <li>if you are using this to wrap triple-des keys you need to set the
* parity bits on the key and, if it's a two-key triple-des key, pad it
* yourself.</li>
* </ul>
* </p>
*/
public class DesEdeWrapEngine
: IWrapper
{
/** Field engine */
private CbcBlockCipher engine;
/** Field param */
private KeyParameter param;
/** Field paramPlusIV */
private ParametersWithIV paramPlusIV;
/** Field iv */
private byte[] iv;
/** Field forWrapping */
private bool forWrapping;
/** Field IV2 */
private static readonly byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
(byte) 0x2c, (byte) 0x79, (byte) 0xe8,
(byte) 0x21, (byte) 0x05 };
//
// checksum digest
//
private readonly IDigest sha1 = new Sha1Digest();
private readonly byte[] digest = new byte[20];
/**
* Method init
*
* @param forWrapping
* @param param
*/
public void Init(
bool forWrapping,
ICipherParameters parameters)
{
this.forWrapping = forWrapping;
this.engine = new CbcBlockCipher(new DesEdeEngine());
SecureRandom sr;
if (parameters is ParametersWithRandom)
{
ParametersWithRandom pr = (ParametersWithRandom) parameters;
parameters = pr.Parameters;
sr = pr.Random;
}
else
{
sr = new SecureRandom();
}
if (parameters is KeyParameter)
{
this.param = (KeyParameter) parameters;
if (this.forWrapping)
{
// Hm, we have no IV but we want to wrap ?!?
// well, then we have to create our own IV.
this.iv = new byte[8];
sr.NextBytes(iv);
this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
}
}
else if (parameters is ParametersWithIV)
{
if (!forWrapping)
throw new ArgumentException("You should not supply an IV for unwrapping");
this.paramPlusIV = (ParametersWithIV) parameters;
this.iv = this.paramPlusIV.GetIV();
this.param = (KeyParameter) this.paramPlusIV.Parameters;
if (this.iv.Length != 8)
throw new ArgumentException("IV is not 8 octets", "parameters");
}
}
/**
* Method GetAlgorithmName
*
* @return
*/
public string AlgorithmName
{
get { return "DESede"; }
}
/**
* Method wrap
*
* @param in
* @param inOff
* @param inLen
* @return
*/
public byte[] Wrap(
byte[] input,
int inOff,
int length)
{
if (!forWrapping)
{
throw new InvalidOperationException("Not initialized for wrapping");
}
byte[] keyToBeWrapped = new byte[length];
Array.Copy(input, inOff, keyToBeWrapped, 0, length);
// Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
// Let WKCKS = WK || CKS where || is concatenation.
byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
// Encrypt WKCKS in CBC mode using KEK as the key and IV as the
// initialization vector. Call the results TEMP1.
byte [] TEMP1 = new byte[WKCKS.Length];
Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
int extraBytes = WKCKS.Length % engine.GetBlockSize();
if (extraBytes != 0) {
throw new InvalidOperationException("Not multiple of block length");
}
engine.Init(true, paramPlusIV);
for (int i = 0; i < noOfBlocks; i++) {
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
}
// Left TEMP2 = IV || TEMP1.
byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
// Reverse the order of the octets in TEMP2 and call the result TEMP3.
byte[] TEMP3 = new byte[TEMP2.Length];
for (int i = 0; i < TEMP2.Length; i++) {
TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
}
// Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
// of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
// result. It is 40 octets long if a 168 bit key is being wrapped.
ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
this.engine.Init(true, param2);
for (int i = 0; i < noOfBlocks + 1; i++) {
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
}
return TEMP3;
}
/**
* Method unwrap
*
* @param in
* @param inOff
* @param inLen
* @return
* @throws InvalidCipherTextException
*/
public byte[] Unwrap(
byte[] input,
int inOff,
int length)
{
if (forWrapping)
{
throw new InvalidOperationException("Not set for unwrapping");
}
if (input == null)
{
throw new InvalidCipherTextException("Null pointer as ciphertext");
}
if (length % engine.GetBlockSize() != 0)
{
throw new InvalidCipherTextException(
"Ciphertext not multiple of " + engine.GetBlockSize());
}
/*
// Check if the length of the cipher text is reasonable given the key
// type. It must be 40 bytes for a 168 bit key and either 32, 40, or
// 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
// or inconsistent with the algorithm for which the key is intended,
// return error.
//
// we do not accept 168 bit keys. it has to be 192 bit.
int lengthA = (estimatedKeyLengthInBit / 8) + 16;
int lengthB = estimatedKeyLengthInBit % 8;
if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
throw new XMLSecurityException("empty");
}
*/
// Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
// and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
this.engine.Init(false, param2);
byte [] TEMP3 = new byte[length];
Array.Copy(input, inOff, TEMP3, 0, length);
for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++) {
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
}
// Reverse the order of the octets in TEMP3 and call the result TEMP2.
byte[] TEMP2 = new byte[TEMP3.Length];
for (int i = 0; i < TEMP3.Length; i++) {
TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
}
// Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
this.iv = new byte[8];
byte[] TEMP1 = new byte[TEMP2.Length - 8];
Array.Copy(TEMP2, 0, this.iv, 0, 8);
Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
// Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
// found in the previous step. Call the result WKCKS.
this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
this.engine.Init(false, this.paramPlusIV);
byte[] WKCKS = new byte[TEMP1.Length];
Array.Copy(TEMP1, 0, WKCKS, 0, TEMP1.Length);
for (int i = 0; i < (WKCKS.Length / engine.GetBlockSize()); i++) {
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(WKCKS, currentBytePos, WKCKS, currentBytePos);
}
// Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
// those octets before the CKS.
byte[] result = new byte[WKCKS.Length - 8];
byte[] CKStoBeVerified = new byte[8];
Array.Copy(WKCKS, 0, result, 0, WKCKS.Length - 8);
Array.Copy(WKCKS, WKCKS.Length - 8, CKStoBeVerified, 0, 8);
// Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
// with the CKS extracted in the above step. If they are not equal, return error.
if (!CheckCmsKeyChecksum(result, CKStoBeVerified)) {
throw new InvalidCipherTextException(
"Checksum inside ciphertext is corrupted");
}
// WK is the wrapped key, now extracted for use in data decryption.
return result;
}
/**
* Some key wrap algorithms make use of the Key Checksum defined
* in CMS [CMS-Algorithms]. This is used to provide an integrity
* check value for the key being wrapped. The algorithm is
*
* - Compute the 20 octet SHA-1 hash on the key being wrapped.
* - Use the first 8 octets of this hash as the checksum value.
*
* @param key
* @return
* @throws Exception
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private byte[] CalculateCmsKeyChecksum(
byte[] key)
{
byte[] result = new byte[8];
sha1.BlockUpdate(key, 0, key.Length);
sha1.DoFinal(digest, 0);
Array.Copy(digest, 0, result, 0, 8);
return result;
}
/**
* @param key
* @param checksum
* @return
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private bool CheckCmsKeyChecksum(
byte[] key,
byte[] checksum)
{
return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum);
}
}
}

View File

@@ -0,0 +1,493 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>A class that provides a basic DES engine.</remarks>
public class DesEngine
: IBlockCipher
{
internal const int BLOCK_SIZE = 8;
private int[] workingKey;
public virtual int[] GetWorkingKey()
{
return workingKey;
}
/**
* initialise a DES cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to DES init - " + parameters.GetType().ToString());
workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
}
public virtual string AlgorithmName
{
get { return "DES"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public virtual int GetBlockSize()
{
return BLOCK_SIZE;
}
public virtual int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("DES engine not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
DesFunc(workingKey, input, inOff, output, outOff);
return BLOCK_SIZE;
}
public virtual void Reset()
{
}
/**
* what follows is mainly taken from "Applied Cryptography", by
* Bruce Schneier, however it also bears great resemblance to Richard
* Outerbridge's D3DES...
*/
private static readonly short[] Df_Key =
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
};
private static readonly short[] bytebit =
{
128, 64, 32, 16, 8, 4, 2, 1
};
private static readonly int[] bigbyte =
{
0x800000, 0x400000, 0x200000, 0x100000,
0x80000, 0x40000, 0x20000, 0x10000,
0x8000, 0x4000, 0x2000, 0x1000,
0x800, 0x400, 0x200, 0x100,
0x80, 0x40, 0x20, 0x10,
0x8, 0x4, 0x2, 0x1
};
/*
* Use the key schedule specified in the Standard (ANSI X3.92-1981).
*/
private static readonly byte[] pc1 =
{
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
private static readonly byte[] totrot =
{
1, 2, 4, 6, 8, 10, 12, 14,
15, 17, 19, 21, 23, 25, 27, 28
};
private static readonly byte[] pc2 =
{
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
};
private static readonly int[] SP1 =
{
unchecked((int) 0x01010400), unchecked((int) 0x00000000), unchecked((int) 0x00010000), unchecked((int) 0x01010404),
unchecked((int) 0x01010004), unchecked((int) 0x00010404), unchecked((int) 0x00000004), unchecked((int) 0x00010000),
unchecked((int) 0x00000400), unchecked((int) 0x01010400), unchecked((int) 0x01010404), unchecked((int) 0x00000400),
unchecked((int) 0x01000404), unchecked((int) 0x01010004), unchecked((int) 0x01000000), unchecked((int) 0x00000004),
unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00010400),
unchecked((int) 0x00010400), unchecked((int) 0x01010000), unchecked((int) 0x01010000), unchecked((int) 0x01000404),
unchecked((int) 0x00010004), unchecked((int) 0x01000004), unchecked((int) 0x01000004), unchecked((int) 0x00010004),
unchecked((int) 0x00000000), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01000000),
unchecked((int) 0x00010000), unchecked((int) 0x01010404), unchecked((int) 0x00000004), unchecked((int) 0x01010000),
unchecked((int) 0x01010400), unchecked((int) 0x01000000), unchecked((int) 0x01000000), unchecked((int) 0x00000400),
unchecked((int) 0x01010004), unchecked((int) 0x00010000), unchecked((int) 0x00010400), unchecked((int) 0x01000004),
unchecked((int) 0x00000400), unchecked((int) 0x00000004), unchecked((int) 0x01000404), unchecked((int) 0x00010404),
unchecked((int) 0x01010404), unchecked((int) 0x00010004), unchecked((int) 0x01010000), unchecked((int) 0x01000404),
unchecked((int) 0x01000004), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01010400),
unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00000000),
unchecked((int) 0x00010004), unchecked((int) 0x00010400), unchecked((int) 0x00000000), unchecked((int) 0x01010004)
};
private static readonly int[] SP2 =
{
unchecked((int) 0x80108020), unchecked((int) 0x80008000), unchecked((int) 0x00008000), unchecked((int) 0x00108020),
unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020), unchecked((int) 0x80008020),
unchecked((int) 0x80000020), unchecked((int) 0x80108020), unchecked((int) 0x80108000), unchecked((int) 0x80000000),
unchecked((int) 0x80008000), unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020),
unchecked((int) 0x00108000), unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x00000000),
unchecked((int) 0x80000000), unchecked((int) 0x00008000), unchecked((int) 0x00108020), unchecked((int) 0x80100000),
unchecked((int) 0x00100020), unchecked((int) 0x80000020), unchecked((int) 0x00000000), unchecked((int) 0x00108000),
unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x80100000), unchecked((int) 0x00008020),
unchecked((int) 0x00000000), unchecked((int) 0x00108020), unchecked((int) 0x80100020), unchecked((int) 0x00100000),
unchecked((int) 0x80008020), unchecked((int) 0x80100000), unchecked((int) 0x80108000), unchecked((int) 0x00008000),
unchecked((int) 0x80100000), unchecked((int) 0x80008000), unchecked((int) 0x00000020), unchecked((int) 0x80108020),
unchecked((int) 0x00108020), unchecked((int) 0x00000020), unchecked((int) 0x00008000), unchecked((int) 0x80000000),
unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x00100000), unchecked((int) 0x80000020),
unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x80000020), unchecked((int) 0x00100020),
unchecked((int) 0x00108000), unchecked((int) 0x00000000), unchecked((int) 0x80008000), unchecked((int) 0x00008020),
unchecked((int) 0x80000000), unchecked((int) 0x80100020), unchecked((int) 0x80108020), unchecked((int) 0x00108000)
};
private static readonly int[] SP3 =
{
unchecked((int) 0x00000208), unchecked((int) 0x08020200), unchecked((int) 0x00000000), unchecked((int) 0x08020008),
unchecked((int) 0x08000200), unchecked((int) 0x00000000), unchecked((int) 0x00020208), unchecked((int) 0x08000200),
unchecked((int) 0x00020008), unchecked((int) 0x08000008), unchecked((int) 0x08000008), unchecked((int) 0x00020000),
unchecked((int) 0x08020208), unchecked((int) 0x00020008), unchecked((int) 0x08020000), unchecked((int) 0x00000208),
unchecked((int) 0x08000000), unchecked((int) 0x00000008), unchecked((int) 0x08020200), unchecked((int) 0x00000200),
unchecked((int) 0x00020200), unchecked((int) 0x08020000), unchecked((int) 0x08020008), unchecked((int) 0x00020208),
unchecked((int) 0x08000208), unchecked((int) 0x00020200), unchecked((int) 0x00020000), unchecked((int) 0x08000208),
unchecked((int) 0x00000008), unchecked((int) 0x08020208), unchecked((int) 0x00000200), unchecked((int) 0x08000000),
unchecked((int) 0x08020200), unchecked((int) 0x08000000), unchecked((int) 0x00020008), unchecked((int) 0x00000208),
unchecked((int) 0x00020000), unchecked((int) 0x08020200), unchecked((int) 0x08000200), unchecked((int) 0x00000000),
unchecked((int) 0x00000200), unchecked((int) 0x00020008), unchecked((int) 0x08020208), unchecked((int) 0x08000200),
unchecked((int) 0x08000008), unchecked((int) 0x00000200), unchecked((int) 0x00000000), unchecked((int) 0x08020008),
unchecked((int) 0x08000208), unchecked((int) 0x00020000), unchecked((int) 0x08000000), unchecked((int) 0x08020208),
unchecked((int) 0x00000008), unchecked((int) 0x00020208), unchecked((int) 0x00020200), unchecked((int) 0x08000008),
unchecked((int) 0x08020000), unchecked((int) 0x08000208), unchecked((int) 0x00000208), unchecked((int) 0x08020000),
unchecked((int) 0x00020208), unchecked((int) 0x00000008), unchecked((int) 0x08020008), unchecked((int) 0x00020200)
};
private static readonly int[] SP4 =
{
unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080),
unchecked((int) 0x00802080), unchecked((int) 0x00800081), unchecked((int) 0x00800001), unchecked((int) 0x00002001),
unchecked((int) 0x00000000), unchecked((int) 0x00802000), unchecked((int) 0x00802000), unchecked((int) 0x00802081),
unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00800080), unchecked((int) 0x00800001),
unchecked((int) 0x00000001), unchecked((int) 0x00002000), unchecked((int) 0x00800000), unchecked((int) 0x00802001),
unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002001), unchecked((int) 0x00002080),
unchecked((int) 0x00800081), unchecked((int) 0x00000001), unchecked((int) 0x00002080), unchecked((int) 0x00800080),
unchecked((int) 0x00002000), unchecked((int) 0x00802080), unchecked((int) 0x00802081), unchecked((int) 0x00000081),
unchecked((int) 0x00800080), unchecked((int) 0x00800001), unchecked((int) 0x00802000), unchecked((int) 0x00802081),
unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x00802000),
unchecked((int) 0x00002080), unchecked((int) 0x00800080), unchecked((int) 0x00800081), unchecked((int) 0x00000001),
unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080),
unchecked((int) 0x00802081), unchecked((int) 0x00000081), unchecked((int) 0x00000001), unchecked((int) 0x00002000),
unchecked((int) 0x00800001), unchecked((int) 0x00002001), unchecked((int) 0x00802080), unchecked((int) 0x00800081),
unchecked((int) 0x00002001), unchecked((int) 0x00002080), unchecked((int) 0x00800000), unchecked((int) 0x00802001),
unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002000), unchecked((int) 0x00802080)
};
private static readonly int[] SP5 =
{
unchecked((int) 0x00000100), unchecked((int) 0x02080100), unchecked((int) 0x02080000), unchecked((int) 0x42000100),
unchecked((int) 0x00080000), unchecked((int) 0x00000100), unchecked((int) 0x40000000), unchecked((int) 0x02080000),
unchecked((int) 0x40080100), unchecked((int) 0x00080000), unchecked((int) 0x02000100), unchecked((int) 0x40080100),
unchecked((int) 0x42000100), unchecked((int) 0x42080000), unchecked((int) 0x00080100), unchecked((int) 0x40000000),
unchecked((int) 0x02000000), unchecked((int) 0x40080000), unchecked((int) 0x40080000), unchecked((int) 0x00000000),
unchecked((int) 0x40000100), unchecked((int) 0x42080100), unchecked((int) 0x42080100), unchecked((int) 0x02000100),
unchecked((int) 0x42080000), unchecked((int) 0x40000100), unchecked((int) 0x00000000), unchecked((int) 0x42000000),
unchecked((int) 0x02080100), unchecked((int) 0x02000000), unchecked((int) 0x42000000), unchecked((int) 0x00080100),
unchecked((int) 0x00080000), unchecked((int) 0x42000100), unchecked((int) 0x00000100), unchecked((int) 0x02000000),
unchecked((int) 0x40000000), unchecked((int) 0x02080000), unchecked((int) 0x42000100), unchecked((int) 0x40080100),
unchecked((int) 0x02000100), unchecked((int) 0x40000000), unchecked((int) 0x42080000), unchecked((int) 0x02080100),
unchecked((int) 0x40080100), unchecked((int) 0x00000100), unchecked((int) 0x02000000), unchecked((int) 0x42080000),
unchecked((int) 0x42080100), unchecked((int) 0x00080100), unchecked((int) 0x42000000), unchecked((int) 0x42080100),
unchecked((int) 0x02080000), unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x42000000),
unchecked((int) 0x00080100), unchecked((int) 0x02000100), unchecked((int) 0x40000100), unchecked((int) 0x00080000),
unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x02080100), unchecked((int) 0x40000100)
};
private static readonly int[] SP6 =
{
unchecked((int) 0x20000010), unchecked((int) 0x20400000), unchecked((int) 0x00004000), unchecked((int) 0x20404010),
unchecked((int) 0x20400000), unchecked((int) 0x00000010), unchecked((int) 0x20404010), unchecked((int) 0x00400000),
unchecked((int) 0x20004000), unchecked((int) 0x00404010), unchecked((int) 0x00400000), unchecked((int) 0x20000010),
unchecked((int) 0x00400010), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010),
unchecked((int) 0x00000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00004000),
unchecked((int) 0x00404000), unchecked((int) 0x20004010), unchecked((int) 0x00000010), unchecked((int) 0x20400010),
unchecked((int) 0x20400010), unchecked((int) 0x00000000), unchecked((int) 0x00404010), unchecked((int) 0x20404000),
unchecked((int) 0x00004010), unchecked((int) 0x00404000), unchecked((int) 0x20404000), unchecked((int) 0x20000000),
unchecked((int) 0x20004000), unchecked((int) 0x00000010), unchecked((int) 0x20400010), unchecked((int) 0x00404000),
unchecked((int) 0x20404010), unchecked((int) 0x00400000), unchecked((int) 0x00004010), unchecked((int) 0x20000010),
unchecked((int) 0x00400000), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010),
unchecked((int) 0x20000010), unchecked((int) 0x20404010), unchecked((int) 0x00404000), unchecked((int) 0x20400000),
unchecked((int) 0x00404010), unchecked((int) 0x20404000), unchecked((int) 0x00000000), unchecked((int) 0x20400010),
unchecked((int) 0x00000010), unchecked((int) 0x00004000), unchecked((int) 0x20400000), unchecked((int) 0x00404010),
unchecked((int) 0x00004000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00000000),
unchecked((int) 0x20404000), unchecked((int) 0x20000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010)
};
private static readonly int[] SP7 =
{
unchecked((int) 0x00200000), unchecked((int) 0x04200002), unchecked((int) 0x04000802), unchecked((int) 0x00000000),
unchecked((int) 0x00000800), unchecked((int) 0x04000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800),
unchecked((int) 0x04200802), unchecked((int) 0x00200000), unchecked((int) 0x00000000), unchecked((int) 0x04000002),
unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x04200002), unchecked((int) 0x00000802),
unchecked((int) 0x04000800), unchecked((int) 0x00200802), unchecked((int) 0x00200002), unchecked((int) 0x04000800),
unchecked((int) 0x04000002), unchecked((int) 0x04200000), unchecked((int) 0x04200800), unchecked((int) 0x00200002),
unchecked((int) 0x04200000), unchecked((int) 0x00000800), unchecked((int) 0x00000802), unchecked((int) 0x04200802),
unchecked((int) 0x00200800), unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x00200800),
unchecked((int) 0x04000000), unchecked((int) 0x00200800), unchecked((int) 0x00200000), unchecked((int) 0x04000802),
unchecked((int) 0x04000802), unchecked((int) 0x04200002), unchecked((int) 0x04200002), unchecked((int) 0x00000002),
unchecked((int) 0x00200002), unchecked((int) 0x04000000), unchecked((int) 0x04000800), unchecked((int) 0x00200000),
unchecked((int) 0x04200800), unchecked((int) 0x00000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800),
unchecked((int) 0x00000802), unchecked((int) 0x04000002), unchecked((int) 0x04200802), unchecked((int) 0x04200000),
unchecked((int) 0x00200800), unchecked((int) 0x00000000), unchecked((int) 0x00000002), unchecked((int) 0x04200802),
unchecked((int) 0x00000000), unchecked((int) 0x00200802), unchecked((int) 0x04200000), unchecked((int) 0x00000800),
unchecked((int) 0x04000002), unchecked((int) 0x04000800), unchecked((int) 0x00000800), unchecked((int) 0x00200002)
};
private static readonly int[] SP8 =
{
unchecked((int) 0x10001040), unchecked((int) 0x00001000), unchecked((int) 0x00040000), unchecked((int) 0x10041040),
unchecked((int) 0x10000000), unchecked((int) 0x10001040), unchecked((int) 0x00000040), unchecked((int) 0x10000000),
unchecked((int) 0x00040040), unchecked((int) 0x10040000), unchecked((int) 0x10041040), unchecked((int) 0x00041000),
unchecked((int) 0x10041000), unchecked((int) 0x00041040), unchecked((int) 0x00001000), unchecked((int) 0x00000040),
unchecked((int) 0x10040000), unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00001040),
unchecked((int) 0x00041000), unchecked((int) 0x00040040), unchecked((int) 0x10040040), unchecked((int) 0x10041000),
unchecked((int) 0x00001040), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x10040040),
unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00041040), unchecked((int) 0x00040000),
unchecked((int) 0x00041040), unchecked((int) 0x00040000), unchecked((int) 0x10041000), unchecked((int) 0x00001000),
unchecked((int) 0x00000040), unchecked((int) 0x10040040), unchecked((int) 0x00001000), unchecked((int) 0x00041040),
unchecked((int) 0x10001000), unchecked((int) 0x00000040), unchecked((int) 0x10000040), unchecked((int) 0x10040000),
unchecked((int) 0x10040040), unchecked((int) 0x10000000), unchecked((int) 0x00040000), unchecked((int) 0x10001040),
unchecked((int) 0x00000000), unchecked((int) 0x10041040), unchecked((int) 0x00040040), unchecked((int) 0x10000040),
unchecked((int) 0x10040000), unchecked((int) 0x10001000), unchecked((int) 0x10001040), unchecked((int) 0x00000000),
unchecked((int) 0x10041040), unchecked((int) 0x00041000), unchecked((int) 0x00041000), unchecked((int) 0x00001040),
unchecked((int) 0x00001040), unchecked((int) 0x00040040), unchecked((int) 0x10000000), unchecked((int) 0x10041000)
};
/**
* Generate an integer based working key based on our secret key
* and what we processing we are planning to do.
*
* Acknowledgements for this routine go to James Gillogly and Phil Karn.
* (whoever, and wherever they are!).
*/
protected static int[] GenerateWorkingKey(
bool encrypting,
byte[] key)
{
int[] newKey = new int[32];
bool[] pc1m = new bool[56];
bool[] pcr = new bool[56];
for (int j = 0; j < 56; j++ )
{
int l = pc1[j];
pc1m[j] = ((key[(uint) l >> 3] & bytebit[l & 07]) != 0);
}
for (int i = 0; i < 16; i++)
{
int l, m, n;
if (encrypting)
{
m = i << 1;
}
else
{
m = (15 - i) << 1;
}
n = m + 1;
newKey[m] = newKey[n] = 0;
for (int j = 0; j < 28; j++)
{
l = j + totrot[i];
if ( l < 28 )
{
pcr[j] = pc1m[l];
}
else
{
pcr[j] = pc1m[l - 28];
}
}
for (int j = 28; j < 56; j++)
{
l = j + totrot[i];
if (l < 56 )
{
pcr[j] = pc1m[l];
}
else
{
pcr[j] = pc1m[l - 28];
}
}
for (int j = 0; j < 24; j++)
{
if (pcr[pc2[j]])
{
newKey[m] |= bigbyte[j];
}
if (pcr[pc2[j + 24]])
{
newKey[n] |= bigbyte[j];
}
}
}
//
// store the processed key
//
for (int i = 0; i != 32; i += 2)
{
int i1, i2;
i1 = newKey[i];
i2 = newKey[i + 1];
newKey[i] = (int) ( (uint) ((i1 & 0x00fc0000) << 6) |
(uint) ((i1 & 0x00000fc0) << 10) |
((uint) (i2 & 0x00fc0000) >> 10) |
((uint) (i2 & 0x00000fc0) >> 6));
newKey[i + 1] = (int) ( (uint) ((i1 & 0x0003f000) << 12) |
(uint) ((i1 & 0x0000003f) << 16) |
((uint) (i2 & 0x0003f000) >> 4) |
(uint) (i2 & 0x0000003f));
}
return newKey;
}
/**
* the DES engine.
*/
internal static void DesFunc(
int[] wKey,
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int work, right, left;
left = (input[inOff + 0] & 0xff) << 24;
left |= (input[inOff + 1] & 0xff) << 16;
left |= (input[inOff + 2] & 0xff) << 8;
left |= (input[inOff + 3] & 0xff);
right = (input[inOff + 4] & 0xff) << 24;
right |= (input[inOff + 5] & 0xff) << 16;
right |= (input[inOff + 6] & 0xff) << 8;
right |= (input[inOff + 7] & 0xff);
work = (int) (((uint) left >> 4) ^ right) & unchecked((int) 0x0f0f0f0f);
right ^= work;
left ^= (work << 4);
work = (int) (((uint) left >> 16) ^ right) & unchecked((int) 0x0000ffff);
right ^= work;
left ^= (work << 16);
work = (int) (((uint) right >> 2) ^ left) & unchecked((int) 0x33333333);
left ^= work;
right ^= (work << 2);
work = (int) (((uint) right >> 8) ^ left) & unchecked((int) 0x00ff00ff);
left ^= work;
right ^= (work << 8);
right = (int) ( (uint) (right << 1) |
( ((uint) right >> 31) & 1 )
) &
unchecked((int) 0xffffffff);
work = (left ^ right) & unchecked((int) 0xaaaaaaaa);
left ^= work;
right ^= work;
left = (int) ( (uint) (left << 1) |
( ((uint) left >> 31) & 1)) &
unchecked((int) 0xffffffff);
for (int round = 0; round < 8; round++)
{
int fval;
work = (int) ((uint) (right << 28) | ((uint) right >> 4));
work ^= wKey[round * 4 + 0];
fval = SP7[ work & 0x3f];
fval |= SP5[((uint) work >> 8) & 0x3f];
fval |= SP3[((uint) work >> 16) & 0x3f];
fval |= SP1[((uint) work >> 24) & 0x3f];
work = right ^ wKey[round * 4 + 1];
fval |= SP8[ work & 0x3f];
fval |= SP6[((uint) work >> 8) & 0x3f];
fval |= SP4[((uint) work >> 16) & 0x3f];
fval |= SP2[((uint) work >> 24) & 0x3f];
left ^= fval;
work = (int) ((uint) (left << 28) | ((uint) left >> 4));
work ^= wKey[round * 4 + 2];
fval = SP7[ work & 0x3f];
fval |= SP5[((uint) work >> 8) & 0x3f];
fval |= SP3[((uint) work >> 16) & 0x3f];
fval |= SP1[((uint) work >> 24) & 0x3f];
work = left ^ wKey[round * 4 + 3];
fval |= SP8[ work & 0x3f];
fval |= SP6[((uint) work >> 8) & 0x3f];
fval |= SP4[((uint) work >> 16) & 0x3f];
fval |= SP2[((uint) work >> 24) & 0x3f];
right ^= fval;
}
right = (int) ((uint) (right << 31) | ((uint) right >> 1));
work = (left ^ right) & unchecked((int) 0xaaaaaaaa);
left ^= work;
right ^= work;
left = (int) ((uint) (left << 31) | ((uint) left >> 1));
work = (int) ((((uint) left >> 8) ^ right) & 0x00ff00ff);
right ^= work;
left ^= (work << 8);
work = (int) ((((uint) left >> 2) ^ right) & 0x33333333);
right ^= work;
left ^= (work << 2);
work = (int) ((((uint) right >> 16) ^ left) & 0x0000ffff);
left ^= work;
right ^= (work << 16);
work = (int) ((((uint) right >> 4) ^ left) & 0x0f0f0f0f);
left ^= work;
right ^= (work << 4);
outBytes[outOff + 0] = (byte)(((uint) right >> 24) & 0xff);
outBytes[outOff + 1] = (byte)(((uint) right >> 16) & 0xff);
outBytes[outOff + 2] = (byte)(((uint) right >> 8) & 0xff);
outBytes[outOff + 3] = (byte)( right & 0xff);
outBytes[outOff + 4] = (byte)(((uint) left >> 24) & 0xff);
outBytes[outOff + 5] = (byte)(((uint) left >> 16) & 0xff);
outBytes[outOff + 6] = (byte)(((uint) left >> 8) & 0xff);
outBytes[outOff + 7] = (byte)( left & 0xff);
}
}
}

View File

@@ -0,0 +1,178 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* this does your basic ElGamal algorithm.
*/
public class ElGamalEngine
: IAsymmetricBlockCipher
{
private ElGamalKeyParameters key;
private SecureRandom random;
private bool forEncryption;
private int bitSize;
public string AlgorithmName
{
get { return "ElGamal"; }
}
/**
* initialise the ElGamal engine.
*
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary ElGamal key parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (parameters is ParametersWithRandom)
{
ParametersWithRandom p = (ParametersWithRandom) parameters;
this.key = (ElGamalKeyParameters) p.Parameters;
this.random = p.Random;
}
else
{
this.key = (ElGamalKeyParameters) parameters;
this.random = new SecureRandom();
}
this.forEncryption = forEncryption;
this.bitSize = key.Parameters.P.BitLength;
if (forEncryption)
{
if (!(key is ElGamalPublicKeyParameters))
{
throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption.");
}
}
else
{
if (!(key is ElGamalPrivateKeyParameters))
{
throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption.");
}
}
}
/**
* Return the maximum size for an input block to this engine.
* For ElGamal this is always one byte less than the size of P on
* encryption, and twice the length as the size of P on decryption.
*
* @return maximum size for an input block.
*/
public int GetInputBlockSize()
{
if (forEncryption)
{
return (bitSize - 1) / 8;
}
return 2 * ((bitSize + 7) / 8);
}
/**
* Return the maximum size for an output block to this engine.
* For ElGamal this is always one byte less than the size of P on
* decryption, and twice the length as the size of P on encryption.
*
* @return maximum size for an output block.
*/
public int GetOutputBlockSize()
{
if (forEncryption)
{
return 2 * ((bitSize + 7) / 8);
}
return (bitSize - 1) / 8;
}
/**
* Process a single block using the basic ElGamal algorithm.
*
* @param in the input array.
* @param inOff the offset into the input buffer where the data starts.
* @param length the length of the data to be processed.
* @return the result of the ElGamal process.
* @exception DataLengthException the input block is too large.
*/
public byte[] ProcessBlock(
byte[] input,
int inOff,
int length)
{
if (key == null)
throw new InvalidOperationException("ElGamal engine not initialised");
int maxLength = forEncryption
? (bitSize - 1 + 7) / 8
: GetInputBlockSize();
if (length > maxLength)
throw new DataLengthException("input too large for ElGamal cipher.\n");
BigInteger p = key.Parameters.P;
byte[] output;
if (key is ElGamalPrivateKeyParameters) // decryption
{
int halfLength = length / 2;
BigInteger gamma = new BigInteger(1, input, inOff, halfLength);
BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength);
ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key;
// a shortcut, which generally relies on p being prime amongst other things.
// if a problem with this shows up, check the p and g values!
BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p);
output = m.ToByteArrayUnsigned();
}
else // encryption
{
BigInteger tmp = new BigInteger(1, input, inOff, length);
if (tmp.BitLength >= p.BitLength)
throw new DataLengthException("input too large for ElGamal cipher.\n");
ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key;
BigInteger pSub2 = p.Subtract(BigInteger.Two);
// TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated
BigInteger k;
do
{
k = new BigInteger(p.BitLength, random);
}
while (k.SignValue == 0 || k.CompareTo(pSub2) > 0);
BigInteger g = key.Parameters.G;
BigInteger gamma = g.ModPow(k, p);
BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p);
output = new byte[this.GetOutputBlockSize()];
// TODO Add methods to allow writing BigInteger to existing byte array?
byte[] out1 = gamma.ToByteArrayUnsigned();
byte[] out2 = phi.ToByteArrayUnsigned();
out1.CopyTo(output, output.Length / 2 - out1.Length);
out2.CopyTo(output, output.Length - out2.Length);
}
return output;
}
}
}

View File

@@ -0,0 +1,364 @@
using System;
using System.Collections;
using System.Globalization;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* implementation of GOST 28147-89
*/
public class Gost28147Engine
: IBlockCipher
{
private const int BlockSize = 8;
private int[] workingKey = null;
private bool forEncryption;
// these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
// This is default S-box!
private readonly byte[] S = {
0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
};
/*
* class content S-box parameters for encrypting
* getting from, see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
* http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-02.txt
*/
private static readonly byte[] ESbox_Test = {
0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6,
0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5,
0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB,
0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8,
0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4,
0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4,
0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD,
0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8
};
private static readonly byte[] ESbox_A = {
0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
};
private static readonly byte[] ESbox_B = {
0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF,
0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE,
0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4,
0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8,
0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3,
0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5,
0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE,
0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC
};
private static readonly byte[] ESbox_C = {
0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3,
0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3,
0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB,
0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4,
0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7,
0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD,
0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7,
0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8
};
private static readonly byte[] ESbox_D = {
0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3,
0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1,
0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2,
0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8,
0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1,
0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6,
0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7,
0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE
};
//S-box for digest
private static readonly byte[] DSbox_Test = {
0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
};
private static readonly byte[] DSbox_A = {
0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF,
0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8,
0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD,
0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3,
0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5,
0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3,
0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB,
0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC
};
//
// pre-defined sbox table
//
private static readonly Hashtable sBoxes = new Hashtable();
static Gost28147Engine()
{
sBoxes.Add("E-TEST", ESbox_Test);
sBoxes.Add("E-A", ESbox_A);
sBoxes.Add("E-B", ESbox_B);
sBoxes.Add("E-C", ESbox_C);
sBoxes.Add("E-D", ESbox_D);
sBoxes.Add("D-TEST", DSbox_Test);
sBoxes.Add("D-A", DSbox_A);
}
/**
* standard constructor.
*/
public Gost28147Engine()
{
}
/**
* initialise an Gost28147 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (parameters is ParametersWithSBox)
{
ParametersWithSBox param = (ParametersWithSBox)parameters;
//
// Set the S-Box
//
Array.Copy(param.GetSBox(), 0, this.S, 0, param.GetSBox().Length);
//
// set key if there is one
//
if (param.Parameters != null)
{
workingKey = generateWorkingKey(forEncryption,
((KeyParameter)param.Parameters).GetKey());
}
}
else if (parameters is KeyParameter)
{
workingKey = generateWorkingKey(forEncryption,
((KeyParameter)parameters).GetKey());
}
else
{
throw new ArgumentException("invalid parameter passed to Gost28147 init - " + parameters.GetType().Name);
}
}
public string AlgorithmName
{
get { return "Gost28147"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BlockSize;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("Gost28147 engine not initialised");
}
if ((inOff + BlockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + BlockSize) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
Gost28147Func(workingKey, input, inOff, output, outOff);
return BlockSize;
}
public void Reset()
{
}
private int[] generateWorkingKey(
bool forEncryption,
byte[] userKey)
{
this.forEncryption = forEncryption;
if (userKey.Length != 32)
{
throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
}
int[] key = new int[8];
for(int i=0; i!=8; i++)
{
key[i] = bytesToint(userKey,i*4);
}
return key;
}
private int Gost28147_mainStep(int n1, int key)
{
int cm = (key + n1); // CM1
// S-box replacing
int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
// return om << 11 | om >>> (32-11); // 11-leftshift
int omLeft = om << 11;
int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
return omLeft | omRight;
}
private void Gost28147Func(
int[] workingKey,
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
int N1, N2, tmp; //tmp -> for saving N1
N1 = bytesToint(inBytes, inOff);
N2 = bytesToint(inBytes, inOff + 4);
if (this.forEncryption)
{
for(int k = 0; k < 3; k++) // 1-24 steps
{
for(int j = 0; j < 8; j++)
{
tmp = N1;
int step = Gost28147_mainStep(N1, workingKey[j]);
N1 = N2 ^ step; // CM2
N2 = tmp;
}
}
for(int j = 7; j > 0; j--) // 25-31 steps
{
tmp = N1;
N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
N2 = tmp;
}
}
else //decrypt
{
for(int j = 0; j < 8; j++) // 1-8 steps
{
tmp = N1;
N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
N2 = tmp;
}
for(int k = 0; k < 3; k++) //9-31 steps
{
for(int j = 7; j >= 0; j--)
{
if ((k == 2) && (j==0))
{
break; // break 32 step
}
tmp = N1;
N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
N2 = tmp;
}
}
}
N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1)
intTobytes(N1, outBytes, outOff);
intTobytes(N2, outBytes, outOff + 4);
}
//array of bytes to type int
private static int bytesToint(
byte[] inBytes,
int inOff)
{
return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
}
//int to array of bytes
private static void intTobytes(
int num,
byte[] outBytes,
int outOff)
{
outBytes[outOff + 3] = (byte)(num >> 24);
outBytes[outOff + 2] = (byte)(num >> 16);
outBytes[outOff + 1] = (byte)(num >> 8);
outBytes[outOff] = (byte)num;
}
/**
* Return the S-Box associated with SBoxName
* @param sBoxName name of the S-Box
* @return byte array representing the S-Box
*/
public static byte[] GetSBox(
string sBoxName)
{
byte[] namedSBox = (byte[])sBoxes[sBoxName.ToUpper(CultureInfo.InvariantCulture)];
if (namedSBox == null)
{
throw new ArgumentException("Unknown S-Box - possible types: "
+ "\"E-Test\", \"E-A\", \"E-B\", \"E-C\", \"E-D\", \"D-Test\", \"D-A\".");
}
return (byte[]) namedSBox.Clone();
}
}
}

View File

@@ -0,0 +1,241 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* HC-128 is a software-efficient stream cipher created by Hongjun Wu. It
* generates keystream from a 128-bit secret key and a 128-bit initialization
* vector.
* <p>
* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
* </p><p>
* It is a third phase candidate in the eStream contest, and is patent-free.
* No attacks are known as of today (April 2007). See
*
* http://www.ecrypt.eu.org/stream/hcp3.html
* </p>
*/
public class HC128Engine
: IStreamCipher
{
private uint[] p = new uint[512];
private uint[] q = new uint[512];
private uint cnt = 0;
private static uint F1(uint x)
{
return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
}
private static uint F2(uint x)
{
return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
}
private uint G1(uint x, uint y, uint z)
{
return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8);
}
private uint G2(uint x, uint y, uint z)
{
return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8);
}
private static uint RotateLeft(uint x, int bits)
{
return (x << bits) | (x >> -bits);
}
private static uint RotateRight(uint x, int bits)
{
return (x >> bits) | (x << -bits);
}
private uint H1(uint x)
{
return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256];
}
private uint H2(uint x)
{
return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256];
}
private static uint Mod1024(uint x)
{
return x & 0x3FF;
}
private static uint Mod512(uint x)
{
return x & 0x1FF;
}
private static uint Dim(uint x, uint y)
{
return Mod512(x - y);
}
private uint Step()
{
uint j = Mod512(cnt);
uint ret;
if (cnt < 512)
{
p[j] += G1(p[Dim(j, 3)], p[Dim(j, 10)], p[Dim(j, 511)]);
ret = H1(p[Dim(j, 12)]) ^ p[j];
}
else
{
q[j] += G2(q[Dim(j, 3)], q[Dim(j, 10)], q[Dim(j, 511)]);
ret = H2(q[Dim(j, 12)]) ^ q[j];
}
cnt = Mod1024(cnt + 1);
return ret;
}
private byte[] key, iv;
private bool initialised;
private void Init()
{
if (key.Length != 16)
throw new ArgumentException("The key must be 128 bit long");
cnt = 0;
uint[] w = new uint[1280];
for (int i = 0; i < 16; i++)
{
w[i >> 3] |= ((uint)key[i] << (i & 0x7));
}
Array.Copy(w, 0, w, 4, 4);
for (int i = 0; i < iv.Length && i < 16; i++)
{
w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7));
}
Array.Copy(w, 8, w, 12, 4);
for (uint i = 16; i < 1280; i++)
{
w[i] = F2(w[i - 2]) + w[i - 7] + F1(w[i - 15]) + w[i - 16] + i;
}
Array.Copy(w, 256, p, 0, 512);
Array.Copy(w, 768, q, 0, 512);
for (int i = 0; i < 512; i++)
{
p[i] = Step();
}
for (int i = 0; i < 512; i++)
{
q[i] = Step();
}
cnt = 0;
}
public string AlgorithmName
{
get { return "HC-128"; }
}
/**
* Initialise a HC-128 cipher.
*
* @param forEncryption whether or not we are for encryption. Irrelevant, as
* encryption and decryption are the same.
* @param params the parameters required to set up the cipher.
* @throws ArgumentException if the params argument is
* inappropriate (ie. the key is not 128 bit long).
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
ICipherParameters keyParam = parameters;
if (parameters is ParametersWithIV)
{
iv = ((ParametersWithIV)parameters).GetIV();
keyParam = ((ParametersWithIV)parameters).Parameters;
}
else
{
iv = new byte[0];
}
if (keyParam is KeyParameter)
{
key = ((KeyParameter)keyParam).GetKey();
Init();
}
else
{
throw new ArgumentException(
"Invalid parameter passed to HC128 init - " + parameters.GetType().Name,
"parameters");
}
initialised = true;
}
private byte[] buf = new byte[4];
private int idx = 0;
private byte GetByte()
{
if (idx == 0)
{
uint step = Step();
buf[3] = (byte)step;
step >>= 8;
buf[2] = (byte)step;
step >>= 8;
buf[1] = (byte)step;
step >>= 8;
buf[0] = (byte)step;
}
byte ret = buf[idx];
idx = idx + 1 & 0x3;
return ret;
}
public void ProcessBytes(
byte[] input,
int inOff,
int len,
byte[] output,
int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + len) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + len) > output.Length)
throw new DataLengthException("output buffer too short");
for (int i = 0; i < len; i++)
{
output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
}
}
public void Reset()
{
idx = 0;
Init();
}
public byte ReturnByte(byte input)
{
return (byte)(input ^ GetByte());
}
}
}

View File

@@ -0,0 +1,207 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* HC-256 is a software-efficient stream cipher created by Hongjun Wu. It
* generates keystream from a 256-bit secret key and a 256-bit initialization
* vector.
* <p>
* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
* </p><p>
* Its brother, HC-128, is a third phase candidate in the eStream contest.
* The algorithm is patent-free. No attacks are known as of today (April 2007).
* See
*
* http://www.ecrypt.eu.org/stream/hcp3.html
* </p>
*/
public class HC256Engine
: IStreamCipher
{
private uint[] p = new uint[1024];
private uint[] q = new uint[1024];
private uint cnt = 0;
private uint Step()
{
uint j = cnt & 0x3FF;
uint ret;
if (cnt < 1024)
{
uint x = p[(j - 3 & 0x3FF)];
uint y = p[(j - 1023 & 0x3FF)];
p[j] += p[(j - 10 & 0x3FF)]
+ (RotateRight(x, 10) ^ RotateRight(y, 23))
+ q[((x ^ y) & 0x3FF)];
x = p[(j - 12 & 0x3FF)];
ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
+ q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
^ p[j];
}
else
{
uint x = q[(j - 3 & 0x3FF)];
uint y = q[(j - 1023 & 0x3FF)];
q[j] += q[(j - 10 & 0x3FF)]
+ (RotateRight(x, 10) ^ RotateRight(y, 23))
+ p[((x ^ y) & 0x3FF)];
x = q[(j - 12 & 0x3FF)];
ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
+ p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
^ q[j];
}
cnt = cnt + 1 & 0x7FF;
return ret;
}
private byte[] key, iv;
private bool initialised;
private void Init()
{
if (key.Length != 32)
throw new ArgumentException("The key must be 256 bit long");
cnt = 0;
uint[] w = new uint[2560];
for (int i = 0; i < 32; i++)
{
w[i >> 3] |= ((uint)key[i] << (i & 0x7));
}
for (int i = 0; i < iv.Length && i < 32; i++)
{
w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7));
}
for (uint i = 16; i < 2560; i++)
{
uint x = w[i - 2];
uint y = w[i - 15];
w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10))
+ w[i - 7]
+ (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3))
+ w[i - 16] + i;
}
Array.Copy(w, 512, p, 0, 1024);
Array.Copy(w, 1536, q, 0, 1024);
for (int i = 0; i < 4096; i++)
{
Step();
}
cnt = 0;
}
public string AlgorithmName
{
get { return "HC-256"; }
}
/**
* Initialise a HC-256 cipher.
*
* @param forEncryption whether or not we are for encryption. Irrelevant, as
* encryption and decryption are the same.
* @param params the parameters required to set up the cipher.
* @throws ArgumentException if the params argument is
* inappropriate (ie. the key is not 256 bit long).
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
ICipherParameters keyParam = parameters;
if (parameters is ParametersWithIV)
{
iv = ((ParametersWithIV)parameters).GetIV();
keyParam = ((ParametersWithIV)parameters).Parameters;
}
else
{
iv = new byte[0];
}
if (keyParam is KeyParameter)
{
key = ((KeyParameter)keyParam).GetKey();
Init();
}
else
{
throw new ArgumentException(
"Invalid parameter passed to HC256 init - " + parameters.GetType().Name,
"parameters");
}
initialised = true;
}
private byte[] buf = new byte[4];
private int idx = 0;
private byte GetByte()
{
if (idx == 0)
{
uint step = Step();
buf[3] = (byte)step;
step >>= 8;
buf[2] = (byte)step;
step >>= 8;
buf[1] = (byte)step;
step >>= 8;
buf[0] = (byte)step;
}
byte ret = buf[idx];
idx = idx + 1 & 0x3;
return ret;
}
public void ProcessBytes(
byte[] input,
int inOff,
int len,
byte[] output,
int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + len) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + len) > output.Length)
throw new DataLengthException("output buffer too short");
for (int i = 0; i < len; i++)
{
output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
}
}
public void Reset()
{
idx = 0;
Init();
}
public byte ReturnByte(byte input)
{
return (byte)(input ^ GetByte());
}
private static uint RotateRight(uint x, int bits)
{
return (x >> bits) | (x << -bits);
}
}
}

View File

@@ -0,0 +1,252 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
* see: http://www.burtleburtle.net/bob/rand/isaacafa.html
*/
public class IsaacEngine
: IStreamCipher
{
// Constants
private static readonly int sizeL = 8,
stateArraySize = sizeL<<5; // 256
// Cipher's internal state
private uint[] engineState = null, // mm
results = null; // randrsl
private uint a = 0, b = 0, c = 0;
// Engine state
private int index = 0;
private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes
workingKey = null;
private bool initialised = false;
/**
* initialise an ISAAC cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception ArgumentException if the params argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException(
"invalid parameter passed to ISAAC Init - " + parameters.GetType().Name,
"parameters");
/*
* ISAAC encryption and decryption is completely
* symmetrical, so the 'forEncryption' is
* irrelevant.
*/
KeyParameter p = (KeyParameter) parameters;
setKey(p.GetKey());
}
public byte ReturnByte(
byte input)
{
if (index == 0)
{
isaac();
keyStream = intToByteLittle(results);
}
byte output = (byte)(keyStream[index]^input);
index = (index + 1) & 1023;
return output;
}
public void ProcessBytes(
byte[] input,
int inOff,
int len,
byte[] output,
int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + len) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + len) > output.Length)
throw new DataLengthException("output buffer too short");
for (int i = 0; i < len; i++)
{
if (index == 0)
{
isaac();
keyStream = intToByteLittle(results);
}
output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]);
index = (index + 1) & 1023;
}
}
public string AlgorithmName
{
get { return "ISAAC"; }
}
public void Reset()
{
setKey(workingKey);
}
// Private implementation
private void setKey(
byte[] keyBytes)
{
workingKey = keyBytes;
if (engineState == null)
{
engineState = new uint[stateArraySize];
}
if (results == null)
{
results = new uint[stateArraySize];
}
int i, j, k;
// Reset state
for (i = 0; i < stateArraySize; i++)
{
engineState[i] = results[i] = 0;
}
a = b = c = 0;
// Reset index counter for output
index = 0;
// Convert the key bytes to ints and put them into results[] for initialization
byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)];
Array.Copy(keyBytes, 0, t, 0, keyBytes.Length);
for (i = 0; i < t.Length; i+=4)
{
results[i>>2] = byteToIntLittle(t, i);
}
// It has begun?
uint[] abcdefgh = new uint[sizeL];
for (i = 0; i < sizeL; i++)
{
abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
}
for (i = 0; i < 4; i++)
{
mix(abcdefgh);
}
for (i = 0; i < 2; i++)
{
for (j = 0; j < stateArraySize; j+=sizeL)
{
for (k = 0; k < sizeL; k++)
{
abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
}
mix(abcdefgh);
for (k = 0; k < sizeL; k++)
{
engineState[j+k] = abcdefgh[k];
}
}
}
isaac();
initialised = true;
}
private void isaac()
{
uint x, y;
b += ++c;
for (int i = 0; i < stateArraySize; i++)
{
x = engineState[i];
switch (i & 3)
{
case 0: a ^= (a << 13); break;
case 1: a ^= (a >> 6); break;
case 2: a ^= (a << 2); break;
case 3: a ^= (a >> 16); break;
}
a += engineState[(i+128) & 0xFF];
engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b;
results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x;
}
}
private void mix(uint[] x)
{
// x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
// x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3];
// x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
// x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5];
// x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
// x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7];
// x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
// x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1];
x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
x[1]^=x[2]>> 2; x[4]+=x[1]; x[2]+=x[3];
x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5];
x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
x[5]^=x[6]>> 4; x[0]+=x[5]; x[6]+=x[7];
x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
x[7]^=x[0]>> 9; x[2]+=x[7]; x[0]+=x[1];
}
private uint byteToIntLittle(
byte[] x,
int offset)
{
uint result = (byte) x[offset + 3];
result = (result << 8) | x[offset + 2];
result = (result << 8) | x[offset + 1];
result = (result << 8) | x[offset + 0];
return result;
}
private byte[] intToByteLittle(
uint x)
{
byte[] output = new byte[4];
output[3] = (byte)x;
output[2] = (byte)(x >> 8);
output[1] = (byte)(x >> 16);
output[0] = (byte)(x >> 24);
return output;
}
private byte[] intToByteLittle(
uint[] x)
{
byte[] output = new byte[4*x.Length];
for (int i = 0, j = 0; i < x.Length; i++,j+=4)
{
Array.Copy(intToByteLittle(x[i]), 0, output, j, 4);
}
return output;
}
}
}

View File

@@ -0,0 +1,333 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
* <p>
* This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
* implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
* end of the mulinv function!).
* </p>
* <p>
* It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
* </p>
* <p>
* Note: This algorithm is patented in the USA, Japan, and Europe including
* at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
* and the United Kingdom. Non-commercial use is free, however any commercial
* products are liable for royalties. Please see
* <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for
* further details. This announcement has been included at the request of
* the patent holders.
* </p>
*/
public class IdeaEngine
: IBlockCipher
{
private const int BLOCK_SIZE = 8;
private int[] workingKey;
/**
* standard constructor.
*/
public IdeaEngine()
{
}
/**
* initialise an IDEA cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString());
workingKey = GenerateWorkingKey(forEncryption,
((KeyParameter)parameters).GetKey());
}
public string AlgorithmName
{
get { return "IDEA"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("IDEA engine not initialised");
}
if ((inOff + BLOCK_SIZE) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + BLOCK_SIZE) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
IdeaFunc(workingKey, input, inOff, output, outOff);
return BLOCK_SIZE;
}
public void Reset()
{
}
private static readonly int MASK = 0xffff;
private static readonly int BASE = 0x10001;
private int BytesToWord(
byte[] input,
int inOff)
{
return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff);
}
private void WordToBytes(
int word,
byte[] outBytes,
int outOff)
{
outBytes[outOff] = (byte)((uint) word >> 8);
outBytes[outOff + 1] = (byte)word;
}
/**
* return x = x * y where the multiplication is done modulo
* 65537 (0x10001) (as defined in the IDEA specification) and
* a zero input is taken to be 65536 (0x10000).
*
* @param x the x value
* @param y the y value
* @return x = x * y
*/
private int Mul(
int x,
int y)
{
if (x == 0)
{
x = (BASE - y);
}
else if (y == 0)
{
x = (BASE - x);
}
else
{
int p = x * y;
y = p & MASK;
x = (int) ((uint) p >> 16);
x = y - x + ((y < x) ? 1 : 0);
}
return x & MASK;
}
private void IdeaFunc(
int[] workingKey,
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int x0, x1, x2, x3, t0, t1;
int keyOff = 0;
x0 = BytesToWord(input, inOff);
x1 = BytesToWord(input, inOff + 2);
x2 = BytesToWord(input, inOff + 4);
x3 = BytesToWord(input, inOff + 6);
for (int round = 0; round < 8; round++)
{
x0 = Mul(x0, workingKey[keyOff++]);
x1 += workingKey[keyOff++];
x1 &= MASK;
x2 += workingKey[keyOff++];
x2 &= MASK;
x3 = Mul(x3, workingKey[keyOff++]);
t0 = x1;
t1 = x2;
x2 ^= x0;
x1 ^= x3;
x2 = Mul(x2, workingKey[keyOff++]);
x1 += x2;
x1 &= MASK;
x1 = Mul(x1, workingKey[keyOff++]);
x2 += x1;
x2 &= MASK;
x0 ^= x1;
x3 ^= x2;
x1 ^= t1;
x2 ^= t0;
}
WordToBytes(Mul(x0, workingKey[keyOff++]), outBytes, outOff);
WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2); /* NB: Order */
WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
}
/**
* The following function is used to expand the user key to the encryption
* subkey. The first 16 bytes are the user key, and the rest of the subkey
* is calculated by rotating the previous 16 bytes by 25 bits to the left,
* and so on until the subkey is completed.
*/
private int[] ExpandKey(
byte[] uKey)
{
int[] key = new int[52];
if (uKey.Length < 16)
{
byte[] tmp = new byte[16];
Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length);
uKey = tmp;
}
for (int i = 0; i < 8; i++)
{
key[i] = BytesToWord(uKey, i * 2);
}
for (int i = 8; i < 52; i++)
{
if ((i & 7) < 6)
{
key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK;
}
else if ((i & 7) == 6)
{
key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK;
}
else
{
key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK;
}
}
return key;
}
/**
* This function computes multiplicative inverse using Euclid's Greatest
* Common Divisor algorithm. Zero and one are self inverse.
* <p>
* i.e. x * MulInv(x) == 1 (modulo BASE)
* </p>
*/
private int MulInv(
int x)
{
int t0, t1, q, y;
if (x < 2)
{
return x;
}
t0 = 1;
t1 = BASE / x;
y = BASE % x;
while (y != 1)
{
q = x / y;
x = x % y;
t0 = (t0 + (t1 * q)) & MASK;
if (x == 1)
{
return t0;
}
q = y / x;
y = y % x;
t1 = (t1 + (t0 * q)) & MASK;
}
return (1 - t1) & MASK;
}
/**
* Return the additive inverse of x.
* <p>
* i.e. x + AddInv(x) == 0
* </p>
*/
int AddInv(
int x)
{
return (0 - x) & MASK;
}
/**
* The function to invert the encryption subkey to the decryption subkey.
* It also involves the multiplicative inverse and the additive inverse functions.
*/
private int[] InvertKey(
int[] inKey)
{
int t1, t2, t3, t4;
int p = 52; /* We work backwards */
int[] key = new int[52];
int inOff = 0;
t1 = MulInv(inKey[inOff++]);
t2 = AddInv(inKey[inOff++]);
t3 = AddInv(inKey[inOff++]);
t4 = MulInv(inKey[inOff++]);
key[--p] = t4;
key[--p] = t3;
key[--p] = t2;
key[--p] = t1;
for (int round = 1; round < 8; round++)
{
t1 = inKey[inOff++];
t2 = inKey[inOff++];
key[--p] = t2;
key[--p] = t1;
t1 = MulInv(inKey[inOff++]);
t2 = AddInv(inKey[inOff++]);
t3 = AddInv(inKey[inOff++]);
t4 = MulInv(inKey[inOff++]);
key[--p] = t4;
key[--p] = t2; /* NB: Order */
key[--p] = t3;
key[--p] = t1;
}
t1 = inKey[inOff++];
t2 = inKey[inOff++];
key[--p] = t2;
key[--p] = t1;
t1 = MulInv(inKey[inOff++]);
t2 = AddInv(inKey[inOff++]);
t3 = AddInv(inKey[inOff++]);
t4 = MulInv(inKey[inOff]);
key[--p] = t4;
key[--p] = t3;
key[--p] = t2;
key[--p] = t1;
return key;
}
private int[] GenerateWorkingKey(
bool forEncryption,
byte[] userKey)
{
if (forEncryption)
{
return ExpandKey(userKey);
}
else
{
return InvertKey(ExpandKey(userKey));
}
}
}
}

View File

@@ -0,0 +1,236 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* support class for constructing intergrated encryption ciphers
* for doing basic message exchanges on top of key agreement ciphers
*/
public class IesEngine
{
private readonly IBasicAgreement agree;
private readonly IDerivationFunction kdf;
private readonly IMac mac;
private readonly BufferedBlockCipher cipher;
private readonly byte[] macBuf;
private bool forEncryption;
private ICipherParameters privParam, pubParam;
private IesParameters param;
/**
* set up for use with stream mode, where the key derivation function
* is used to provide a stream of bytes to xor with the message.
*
* @param agree the key agreement used as the basis for the encryption
* @param kdf the key derivation function used for byte generation
* @param mac the message authentication code generator for the message
*/
public IesEngine(
IBasicAgreement agree,
IDerivationFunction kdf,
IMac mac)
{
this.agree = agree;
this.kdf = kdf;
this.mac = mac;
this.macBuf = new byte[mac.GetMacSize()];
// this.cipher = null;
}
/**
* set up for use in conjunction with a block cipher to handle the
* message.
*
* @param agree the key agreement used as the basis for the encryption
* @param kdf the key derivation function used for byte generation
* @param mac the message authentication code generator for the message
* @param cipher the cipher to used for encrypting the message
*/
public IesEngine(
IBasicAgreement agree,
IDerivationFunction kdf,
IMac mac,
BufferedBlockCipher cipher)
{
this.agree = agree;
this.kdf = kdf;
this.mac = mac;
this.macBuf = new byte[mac.GetMacSize()];
this.cipher = cipher;
}
/**
* Initialise the encryptor.
*
* @param forEncryption whether or not this is encryption/decryption.
* @param privParam our private key parameters
* @param pubParam the recipient's/sender's public key parameters
* @param param encoding and derivation parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters privParameters,
ICipherParameters pubParameters,
ICipherParameters iesParameters)
{
this.forEncryption = forEncryption;
this.privParam = privParameters;
this.pubParam = pubParameters;
this.param = (IesParameters)iesParameters;
}
private byte[] DecryptBlock(
byte[] in_enc,
int inOff,
int inLen,
byte[] z)
{
byte[] M = null;
KeyParameter macKey = null;
KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
int macKeySize = param.MacKeySize;
kdf.Init(kParam);
inLen -= mac.GetMacSize();
if (cipher == null) // stream mode
{
byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
M = new byte[inLen];
for (int i = 0; i != inLen; i++)
{
M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]);
}
macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
}
else
{
int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
M = cipher.DoFinal(in_enc, inOff, inLen);
macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
}
byte[] macIV = param.GetEncodingV();
mac.Init(macKey);
mac.BlockUpdate(in_enc, inOff, inLen);
mac.BlockUpdate(macIV, 0, macIV.Length);
mac.DoFinal(macBuf, 0);
inOff += inLen;
for (int t = 0; t < macBuf.Length; t++)
{
if (macBuf[t] != in_enc[inOff + t])
{
throw (new InvalidCipherTextException("IMac codes failed to equal."));
}
}
return M;
}
private byte[] EncryptBlock(
byte[] input,
int inOff,
int inLen,
byte[] z)
{
byte[] C = null;
KeyParameter macKey = null;
KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
int c_text_length = 0;
int macKeySize = param.MacKeySize;
if (cipher == null) // stream mode
{
byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
C = new byte[inLen + mac.GetMacSize()];
c_text_length = inLen;
for (int i = 0; i != inLen; i++)
{
C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
}
macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
}
else
{
int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
c_text_length = cipher.GetOutputSize(inLen);
byte[] tmp = new byte[c_text_length];
int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
len += cipher.DoFinal(tmp, len);
C = new byte[len + mac.GetMacSize()];
c_text_length = len;
Array.Copy(tmp, 0, C, 0, len);
macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
}
byte[] macIV = param.GetEncodingV();
mac.Init(macKey);
mac.BlockUpdate(C, 0, c_text_length);
mac.BlockUpdate(macIV, 0, macIV.Length);
//
// return the message and it's MAC
//
mac.DoFinal(C, c_text_length);
return C;
}
private byte[] GenerateKdfBytes(
KdfParameters kParam,
int length)
{
byte[] buf = new byte[length];
kdf.Init(kParam);
kdf.GenerateBytes(buf, 0, buf.Length);
return buf;
}
public byte[] ProcessBlock(
byte[] input,
int inOff,
int inLen)
{
agree.Init(privParam);
BigInteger z = agree.CalculateAgreement(pubParam);
// TODO Check that this is right (...Unsigned? Check length?)
byte[] zBytes = z.ToByteArray();
return forEncryption
? EncryptBlock(input, inOff, inLen, zBytes)
: DecryptBlock(input, inOff, inLen, zBytes);
}
}
}

View File

@@ -0,0 +1,432 @@
using System;
using System.Collections;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* NaccacheStern Engine. For details on this cipher, please see
* http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
*/
public class NaccacheSternEngine
: IAsymmetricBlockCipher
{
private bool forEncryption;
private NaccacheSternKeyParameters key;
private ArrayList[] lookup = null;
private bool debug = false;
public string AlgorithmName
{
get { return "NaccacheStern"; }
}
/**
* Initializes this algorithm. Must be called before all other Functions.
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
* org.bouncycastle.crypto.CipherParameters)
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
key = (NaccacheSternKeyParameters)parameters;
// construct lookup table for faster decryption if necessary
if (!this.forEncryption)
{
if (debug)
{
Console.WriteLine("Constructing lookup Array");
}
NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
ArrayList primes = priv.SmallPrimes;
lookup = new ArrayList[primes.Count];
for (int i = 0; i < primes.Count; i++)
{
BigInteger actualPrime = (BigInteger) primes[i];
int actualPrimeValue = actualPrime.IntValue;
lookup[i] = new ArrayList(actualPrimeValue);
lookup[i].Add(BigInteger.One);
if (debug)
{
Console.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue);
}
BigInteger accJ = BigInteger.Zero;
for (int j = 1; j < actualPrimeValue; j++)
{
// BigInteger bigJ = BigInteger.ValueOf(j);
// accJ = priv.PhiN.Multiply(bigJ);
accJ = accJ.Add(priv.PhiN);
BigInteger comp = accJ.Divide(actualPrime);
lookup[i].Add(priv.G.ModPow(comp, priv.Modulus));
}
}
}
}
public bool Debug
{
set { this.debug = value; }
}
/**
* Returns the input block size of this algorithm.
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
*/
public int GetInputBlockSize()
{
if (forEncryption)
{
// We can only encrypt values up to lowerSigmaBound
return (key.LowerSigmaBound + 7) / 8 - 1;
}
else
{
// We pad to modulus-size bytes for easier decryption.
// return key.Modulus.ToByteArray().Length;
return key.Modulus.BitLength / 8 + 1;
}
}
/**
* Returns the output block size of this algorithm.
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
*/
public int GetOutputBlockSize()
{
if (forEncryption)
{
// encrypted Data is always padded up to modulus size
// return key.Modulus.ToByteArray().Length;
return key.Modulus.BitLength / 8 + 1;
}
else
{
// decrypted Data has upper limit lowerSigmaBound
return (key.LowerSigmaBound + 7) / 8 - 1;
}
}
/**
* Process a single Block using the Naccache-Stern algorithm.
*
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
* int, int)
*/
public byte[] ProcessBlock(
byte[] inBytes,
int inOff,
int length)
{
if (key == null)
throw new InvalidOperationException("NaccacheStern engine not initialised");
if (length > (GetInputBlockSize() + 1))
throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
if (!forEncryption)
{
// At decryption make sure that we receive padded data blocks
if (length < GetInputBlockSize())
{
throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
}
}
// transform input into BigInteger
BigInteger input = new BigInteger(1, inBytes, inOff, length);
if (debug)
{
Console.WriteLine("input as BigInteger: " + input);
}
byte[] output;
if (forEncryption)
{
output = Encrypt(input);
}
else
{
ArrayList plain = new ArrayList();
NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
ArrayList primes = priv.SmallPrimes;
// Get Chinese Remainders of CipherText
for (int i = 0; i < primes.Count; i++)
{
BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus);
ArrayList al = lookup[i];
if (lookup[i].Count != ((BigInteger)primes[i]).IntValue)
{
if (debug)
{
Console.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count);
}
throw new InvalidCipherTextException("Error in lookup Array for "
+ ((BigInteger)primes[i]).IntValue
+ ": Size mismatch. Expected ArrayList with length "
+ ((BigInteger)primes[i]).IntValue + " but found ArrayList of length "
+ lookup[i].Count);
}
int lookedup = al.IndexOf(exp);
if (lookedup == -1)
{
if (debug)
{
Console.WriteLine("Actual prime is " + primes[i]);
Console.WriteLine("Decrypted value is " + exp);
Console.WriteLine("LookupList for " + primes[i] + " with size " + lookup[i].Count
+ " is: ");
for (int j = 0; j < lookup[i].Count; j++)
{
Console.WriteLine(lookup[i][j]);
}
}
throw new InvalidCipherTextException("Lookup failed");
}
plain.Add(BigInteger.ValueOf(lookedup));
}
BigInteger test = chineseRemainder(plain, primes);
// Should not be used as an oracle, so reencrypt output to see
// if it corresponds to input
// this breaks probabilisic encryption, so disable it. Anyway, we do
// use the first n primes for key generation, so it is pretty easy
// to guess them. But as stated in the paper, this is not a security
// breach. So we can just work with the correct sigma.
// if (debug) {
// Console.WriteLine("Decryption is " + test);
// }
// if ((key.G.ModPow(test, key.Modulus)).Equals(input)) {
// output = test.ToByteArray();
// } else {
// if(debug){
// Console.WriteLine("Engine seems to be used as an oracle,
// returning null");
// }
// output = null;
// }
output = test.ToByteArray();
}
return output;
}
/**
* Encrypts a BigInteger aka Plaintext with the public key.
*
* @param plain
* The BigInteger to encrypt
* @return The byte[] representation of the encrypted BigInteger (i.e.
* crypted.toByteArray())
*/
public byte[] Encrypt(
BigInteger plain)
{
// Always return modulus size values 0-padded at the beginning
// 0-padding at the beginning is correctly parsed by BigInteger :)
// byte[] output = key.Modulus.ToByteArray();
// Array.Clear(output, 0, output.Length);
byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray();
Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
if (debug)
{
Console.WriteLine("Encrypted value is: " + new BigInteger(output));
}
return output;
}
/**
* Adds the contents of two encrypted blocks mod sigma
*
* @param block1
* the first encrypted block
* @param block2
* the second encrypted block
* @return encrypt((block1 + block2) mod sigma)
* @throws InvalidCipherTextException
*/
public byte[] AddCryptedBlocks(
byte[] block1,
byte[] block2)
{
// check for correct blocksize
if (forEncryption)
{
if ((block1.Length > GetOutputBlockSize())
|| (block2.Length > GetOutputBlockSize()))
{
throw new InvalidCipherTextException(
"BlockLength too large for simple addition.\n");
}
}
else
{
if ((block1.Length > GetInputBlockSize())
|| (block2.Length > GetInputBlockSize()))
{
throw new InvalidCipherTextException(
"BlockLength too large for simple addition.\n");
}
}
// calculate resulting block
BigInteger m1Crypt = new BigInteger(1, block1);
BigInteger m2Crypt = new BigInteger(1, block2);
BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt);
m1m2Crypt = m1m2Crypt.Mod(key.Modulus);
if (debug)
{
Console.WriteLine("c(m1) as BigInteger:....... " + m1Crypt);
Console.WriteLine("c(m2) as BigInteger:....... " + m2Crypt);
Console.WriteLine("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt);
}
//byte[] output = key.Modulus.ToByteArray();
//Array.Clear(output, 0, output.Length);
byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray();
Array.Copy(m1m2CryptBytes, 0, output,
output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length);
return output;
}
/**
* Convenience Method for data exchange with the cipher.
*
* Determines blocksize and splits data to blocksize.
*
* @param data the data to be processed
* @return the data after it went through the NaccacheSternEngine.
* @throws InvalidCipherTextException
*/
public byte[] ProcessData(
byte[] data)
{
if (debug)
{
Console.WriteLine();
}
if (data.Length > GetInputBlockSize())
{
int inBlocksize = GetInputBlockSize();
int outBlocksize = GetOutputBlockSize();
if (debug)
{
Console.WriteLine("Input blocksize is: " + inBlocksize + " bytes");
Console.WriteLine("Output blocksize is: " + outBlocksize + " bytes");
Console.WriteLine("Data has length:.... " + data.Length + " bytes");
}
int datapos = 0;
int retpos = 0;
byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize];
while (datapos < data.Length)
{
byte[] tmp;
if (datapos + inBlocksize < data.Length)
{
tmp = ProcessBlock(data, datapos, inBlocksize);
datapos += inBlocksize;
}
else
{
tmp = ProcessBlock(data, datapos, data.Length - datapos);
datapos += data.Length - datapos;
}
if (debug)
{
Console.WriteLine("new datapos is " + datapos);
}
if (tmp != null)
{
tmp.CopyTo(retval, retpos);
retpos += tmp.Length;
}
else
{
if (debug)
{
Console.WriteLine("cipher returned null");
}
throw new InvalidCipherTextException("cipher returned null");
}
}
byte[] ret = new byte[retpos];
Array.Copy(retval, 0, ret, 0, retpos);
if (debug)
{
Console.WriteLine("returning " + ret.Length + " bytes");
}
return ret;
}
else
{
if (debug)
{
Console.WriteLine("data size is less then input block size, processing directly");
}
return ProcessBlock(data, 0, data.Length);
}
}
/**
* Computes the integer x that is expressed through the given primes and the
* congruences with the chinese remainder theorem (CRT).
*
* @param congruences
* the congruences c_i
* @param primes
* the primes p_i
* @return an integer x for that x % p_i == c_i
*/
private static BigInteger chineseRemainder(ArrayList congruences, ArrayList primes)
{
BigInteger retval = BigInteger.Zero;
BigInteger all = BigInteger.One;
for (int i = 0; i < primes.Count; i++)
{
all = all.Multiply((BigInteger)primes[i]);
}
for (int i = 0; i < primes.Count; i++)
{
BigInteger a = (BigInteger)primes[i];
BigInteger b = all.Divide(a);
BigInteger b_ = b.ModInverse(a);
BigInteger tmp = b.Multiply(b_);
tmp = tmp.Multiply((BigInteger)congruences[i]);
retval = retval.Add(tmp);
}
return retval.Mod(all);
}
}
}

View File

@@ -0,0 +1,256 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* A Noekeon engine, using direct-key mode.
*/
public class NoekeonEngine
: IBlockCipher
{
private const int GenericSize = 16; // Block and key size, as well as the amount of rounds.
private static readonly uint[] nullVector =
{
0x00, 0x00, 0x00, 0x00 // Used in decryption
};
private static readonly uint[] roundConstants =
{
0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a,
0xd4
};
private uint[] state = new uint[4], // a
subKeys = new uint[4], // k
decryptKeys = new uint[4];
private bool _initialised, _forEncryption;
/**
* Create an instance of the Noekeon encryption algorithm
* and set some defaults
*/
public NoekeonEngine()
{
_initialised = false;
}
public string AlgorithmName
{
get { return "Noekeon"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return GenericSize;
}
/**
* initialise
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception ArgumentException if the params argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters");
_forEncryption = forEncryption;
_initialised = true;
KeyParameter p = (KeyParameter) parameters;
setKey(p.GetKey());
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + GenericSize) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + GenericSize) > output.Length)
throw new DataLengthException("output buffer too short");
return _forEncryption
? encryptBlock(input, inOff, output, outOff)
: decryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
// TODO This should do something in case the encryption is aborted
}
/**
* Re-key the cipher.
*
* @param key the key to be used
*/
private void setKey(byte[] key)
{
subKeys[0] = bytesToIntBig(key, 0);
subKeys[1] = bytesToIntBig(key, 4);
subKeys[2] = bytesToIntBig(key, 8);
subKeys[3] = bytesToIntBig(key, 12);
}
private int encryptBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
state[0] = bytesToIntBig(input, inOff);
state[1] = bytesToIntBig(input, inOff+4);
state[2] = bytesToIntBig(input, inOff+8);
state[3] = bytesToIntBig(input, inOff+12);
int i;
for (i = 0; i < GenericSize; i++)
{
state[0] ^= roundConstants[i];
theta(state, subKeys);
pi1(state);
gamma(state);
pi2(state);
}
state[0] ^= roundConstants[i];
theta(state, subKeys);
intToBytesBig(state[0], output, outOff);
intToBytesBig(state[1], output, outOff+4);
intToBytesBig(state[2], output, outOff+8);
intToBytesBig(state[3], output, outOff+12);
return GenericSize;
}
private int decryptBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
state[0] = bytesToIntBig(input, inOff);
state[1] = bytesToIntBig(input, inOff+4);
state[2] = bytesToIntBig(input, inOff+8);
state[3] = bytesToIntBig(input, inOff+12);
Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length);
theta(decryptKeys, nullVector);
int i;
for (i = GenericSize; i > 0; i--)
{
theta(state, decryptKeys);
state[0] ^= roundConstants[i];
pi1(state);
gamma(state);
pi2(state);
}
theta(state, decryptKeys);
state[0] ^= roundConstants[i];
intToBytesBig(state[0], output, outOff);
intToBytesBig(state[1], output, outOff+4);
intToBytesBig(state[2], output, outOff+8);
intToBytesBig(state[3], output, outOff+12);
return GenericSize;
}
private void gamma(uint[] a)
{
a[1] ^= ~a[3] & ~a[2];
a[0] ^= a[2] & a[1];
uint tmp = a[3];
a[3] = a[0];
a[0] = tmp;
a[2] ^= a[0]^a[1]^a[3];
a[1] ^= ~a[3] & ~a[2];
a[0] ^= a[2] & a[1];
}
private void theta(uint[] a, uint[] k)
{
uint tmp;
tmp = a[0]^a[2];
tmp ^= rotl(tmp,8)^rotl(tmp,24);
a[1] ^= tmp;
a[3] ^= tmp;
for (int i = 0; i < 4; i++)
{
a[i] ^= k[i];
}
tmp = a[1]^a[3];
tmp ^= rotl(tmp,8)^rotl(tmp,24);
a[0] ^= tmp;
a[2] ^= tmp;
}
private void pi1(uint[] a)
{
a[1] = rotl(a[1], 1);
a[2] = rotl(a[2], 5);
a[3] = rotl(a[3], 2);
}
private void pi2(uint[] a)
{
a[1] = rotl(a[1], 31);
a[2] = rotl(a[2], 27);
a[3] = rotl(a[3], 30);
}
// Helpers
private uint bytesToIntBig(byte[] input, int off)
{
int result = ((input[off++]) << 24) |
((input[off++] & 0xff) << 16) |
((input[off++] & 0xff) << 8) |
(input[off ] & 0xff);
return (uint) result;
}
private void intToBytesBig(uint x, byte[] output, int off)
{
output[off++] = (byte)(x >> 24);
output[off++] = (byte)(x >> 16);
output[off++] = (byte)(x >> 8);
output[off ] = (byte)x;
}
private uint rotl(uint x, int y)
{
return (x << y) | (x >> (32-y));
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
* Provided for the sake of completeness.
*/
public class NullEngine
: IBlockCipher
{
private bool initialised;
private const int BlockSize = 1;
public NullEngine()
{
}
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
// we don't mind any parameters that may come in
initialised = true;
}
public string AlgorithmName
{
get { return "Null"; }
}
public bool IsPartialBlockOkay
{
get { return true; }
}
public int GetBlockSize()
{
return BlockSize;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (!initialised)
throw new InvalidOperationException("Null engine not initialised");
if ((inOff + BlockSize) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BlockSize) > output.Length)
throw new DataLengthException("output buffer too short");
for (int i = 0; i < BlockSize; ++i)
{
output[outOff + i] = input[inOff + i];
}
return BlockSize;
}
public void Reset()
{
// nothing needs to be done
}
}
}

View File

@@ -0,0 +1,312 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of RC2 as described in RFC 2268
* "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
*/
public class RC2Engine
: IBlockCipher
{
//
// the values we use for key expansion (based on the digits of PI)
//
private static readonly byte[] piTable =
{
(byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed,
(byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d,
(byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e,
(byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2,
(byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13,
(byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32,
(byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb,
(byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82,
(byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c,
(byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc,
(byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1,
(byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26,
(byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57,
(byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3,
(byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7,
(byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7,
(byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7,
(byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a,
(byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74,
(byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec,
(byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc,
(byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39,
(byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a,
(byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31,
(byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae,
(byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9,
(byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c,
(byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9,
(byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0,
(byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e,
(byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77,
(byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad
};
private const int BLOCK_SIZE = 8;
private int[] workingKey;
private bool encrypting;
private int[] GenerateWorkingKey(
byte[] key,
int bits)
{
int x;
int[] xKey = new int[128];
for (int i = 0; i != key.Length; i++)
{
xKey[i] = key[i] & 0xff;
}
// Phase 1: Expand input key to 128 bytes
int len = key.Length;
if (len < 128)
{
int index = 0;
x = xKey[len - 1];
do
{
x = piTable[(x + xKey[index++]) & 255] & 0xff;
xKey[len++] = x;
}
while (len < 128);
}
// Phase 2 - reduce effective key size to "bits"
len = (bits + 7) >> 3;
x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
xKey[128 - len] = x;
for (int i = 128 - len - 1; i >= 0; i--)
{
x = piTable[x ^ xKey[i + len]] & 0xff;
xKey[i] = x;
}
// Phase 3 - copy to newKey in little-endian order
int[] newKey = new int[64];
for (int i = 0; i != newKey.Length; i++)
{
newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
}
return newKey;
}
/**
* initialise a RC2 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.encrypting = forEncryption;
if (parameters is RC2Parameters)
{
RC2Parameters param = (RC2Parameters) parameters;
workingKey = GenerateWorkingKey(param.GetKey(), param.EffectiveKeyBits);
}
else if (parameters is KeyParameter)
{
KeyParameter param = (KeyParameter) parameters;
byte[] key = param.GetKey();
workingKey = GenerateWorkingKey(key, key.Length * 8);
}
else
{
throw new ArgumentException("invalid parameter passed to RC2 init - " + parameters.GetType().Name);
}
}
public void Reset()
{
}
public string AlgorithmName
{
get { return "RC2"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("RC2 engine not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return BLOCK_SIZE;
}
/**
* return the result rotating the 16 bit number in x left by y
*/
private int RotateWordLeft(
int x,
int y)
{
x &= 0xffff;
return (x << y) | (x >> (16 - y));
}
private void EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int x76, x54, x32, x10;
x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff);
for (int i = 0; i <= 16; i += 4)
{
x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
x10 += workingKey[x76 & 63];
x32 += workingKey[x10 & 63];
x54 += workingKey[x32 & 63];
x76 += workingKey[x54 & 63];
for (int i = 20; i <= 40; i += 4)
{
x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
x10 += workingKey[x76 & 63];
x32 += workingKey[x10 & 63];
x54 += workingKey[x32 & 63];
x76 += workingKey[x54 & 63];
for (int i = 44; i < 64; i += 4)
{
x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
outBytes[outOff + 0] = (byte)x10;
outBytes[outOff + 1] = (byte)(x10 >> 8);
outBytes[outOff + 2] = (byte)x32;
outBytes[outOff + 3] = (byte)(x32 >> 8);
outBytes[outOff + 4] = (byte)x54;
outBytes[outOff + 5] = (byte)(x54 >> 8);
outBytes[outOff + 6] = (byte)x76;
outBytes[outOff + 7] = (byte)(x76 >> 8);
}
private void DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int x76, x54, x32, x10;
x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff);
for (int i = 60; i >= 44; i -= 4)
{
x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
}
x76 -= workingKey[x54 & 63];
x54 -= workingKey[x32 & 63];
x32 -= workingKey[x10 & 63];
x10 -= workingKey[x76 & 63];
for (int i = 40; i >= 20; i -= 4)
{
x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
}
x76 -= workingKey[x54 & 63];
x54 -= workingKey[x32 & 63];
x32 -= workingKey[x10 & 63];
x10 -= workingKey[x76 & 63];
for (int i = 16; i >= 0; i -= 4)
{
x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
}
outBytes[outOff + 0] = (byte)x10;
outBytes[outOff + 1] = (byte)(x10 >> 8);
outBytes[outOff + 2] = (byte)x32;
outBytes[outOff + 3] = (byte)(x32 >> 8);
outBytes[outOff + 4] = (byte)x54;
outBytes[outOff + 5] = (byte)(x54 >> 8);
outBytes[outOff + 6] = (byte)x76;
outBytes[outOff + 7] = (byte)(x76 >> 8);
}
}
}

View File

@@ -0,0 +1,372 @@
using System;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Wrap keys according to RFC 3217 - RC2 mechanism
*/
public class RC2WrapEngine
: IWrapper
{
/** Field engine */
private CbcBlockCipher engine;
/** Field param */
private ICipherParameters parameters;
/** Field paramPlusIV */
private ParametersWithIV paramPlusIV;
/** Field iv */
private byte[] iv;
/** Field forWrapping */
private bool forWrapping;
private SecureRandom sr;
/** Field IV2 */
private static readonly byte[] IV2 =
{
(byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
(byte) 0x2c, (byte) 0x79, (byte) 0xe8,
(byte) 0x21, (byte) 0x05
};
//
// checksum digest
//
IDigest sha1 = new Sha1Digest();
byte[] digest = new byte[20];
/**
* Method init
*
* @param forWrapping
* @param param
*/
public void Init(
bool forWrapping,
ICipherParameters parameters)
{
this.forWrapping = forWrapping;
this.engine = new CbcBlockCipher(new RC2Engine());
if (parameters is ParametersWithRandom)
{
ParametersWithRandom pWithR = (ParametersWithRandom)parameters;
sr = pWithR.Random;
parameters = pWithR.Parameters;
}
else
{
sr = new SecureRandom();
}
if (parameters is ParametersWithIV)
{
if (!forWrapping)
throw new ArgumentException("You should not supply an IV for unwrapping");
this.paramPlusIV = (ParametersWithIV)parameters;
this.iv = this.paramPlusIV.GetIV();
this.parameters = this.paramPlusIV.Parameters;
if (this.iv.Length != 8)
throw new ArgumentException("IV is not 8 octets");
}
else
{
this.parameters = parameters;
if (this.forWrapping)
{
// Hm, we have no IV but we want to wrap ?!?
// well, then we have to create our own IV.
this.iv = new byte[8];
sr.NextBytes(iv);
this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
}
}
}
/**
* Method GetAlgorithmName
*
* @return
*/
public string AlgorithmName
{
get { return "RC2"; }
}
/**
* Method wrap
*
* @param in
* @param inOff
* @param inLen
* @return
*/
public byte[] Wrap(
byte[] input,
int inOff,
int length)
{
if (!forWrapping)
{
throw new InvalidOperationException("Not initialized for wrapping");
}
int len = length + 1;
if ((len % 8) != 0)
{
len += 8 - (len % 8);
}
byte [] keyToBeWrapped = new byte[len];
keyToBeWrapped[0] = (byte)length;
Array.Copy(input, inOff, keyToBeWrapped, 1, length);
byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
if (pad.Length > 0)
{
sr.NextBytes(pad);
Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
}
// Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
// Let WKCKS = WK || CKS where || is concatenation.
byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
// Encrypt WKCKS in CBC mode using KEK as the key and IV as the
// initialization vector. Call the results TEMP1.
byte [] TEMP1 = new byte[WKCKS.Length];
Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
int extraBytes = WKCKS.Length % engine.GetBlockSize();
if (extraBytes != 0)
{
throw new InvalidOperationException("Not multiple of block length");
}
engine.Init(true, paramPlusIV);
for (int i = 0; i < noOfBlocks; i++)
{
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
}
// Left TEMP2 = IV || TEMP1.
byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
// Reverse the order of the octets in TEMP2 and call the result TEMP3.
byte[] TEMP3 = new byte[TEMP2.Length];
for (int i = 0; i < TEMP2.Length; i++)
{
TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
}
// Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
// of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
// result. It is 40 octets long if a 168 bit key is being wrapped.
ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
this.engine.Init(true, param2);
for (int i = 0; i < noOfBlocks + 1; i++)
{
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
}
return TEMP3;
}
/**
* Method unwrap
*
* @param in
* @param inOff
* @param inLen
* @return
* @throws InvalidCipherTextException
*/
public byte[] Unwrap(
byte[] input,
int inOff,
int length)
{
if (forWrapping)
{
throw new InvalidOperationException("Not set for unwrapping");
}
if (input == null)
{
throw new InvalidCipherTextException("Null pointer as ciphertext");
}
if (length % engine.GetBlockSize() != 0)
{
throw new InvalidCipherTextException("Ciphertext not multiple of "
+ engine.GetBlockSize());
}
/*
// Check if the length of the cipher text is reasonable given the key
// type. It must be 40 bytes for a 168 bit key and either 32, 40, or
// 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
// or inconsistent with the algorithm for which the key is intended,
// return error.
//
// we do not accept 168 bit keys. it has to be 192 bit.
int lengthA = (estimatedKeyLengthInBit / 8) + 16;
int lengthB = estimatedKeyLengthInBit % 8;
if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
throw new XMLSecurityException("empty");
}
*/
// Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
// and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
this.engine.Init(false, param2);
byte [] TEMP3 = new byte[length];
Array.Copy(input, inOff, TEMP3, 0, length);
for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
{
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
}
// Reverse the order of the octets in TEMP3 and call the result TEMP2.
byte[] TEMP2 = new byte[TEMP3.Length];
for (int i = 0; i < TEMP3.Length; i++)
{
TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
}
// Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
this.iv = new byte[8];
byte[] TEMP1 = new byte[TEMP2.Length - 8];
Array.Copy(TEMP2, 0, this.iv, 0, 8);
Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
// Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
// found in the previous step. Call the result WKCKS.
this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
this.engine.Init(false, this.paramPlusIV);
byte[] LCEKPADICV = new byte[TEMP1.Length];
Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
{
int currentBytePos = i * engine.GetBlockSize();
engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
}
// Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
// those octets before the CKS.
byte[] result = new byte[LCEKPADICV.Length - 8];
byte[] CKStoBeVerified = new byte[8];
Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
// Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
// with the CKS extracted in the above step. If they are not equal, return error.
if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
{
throw new InvalidCipherTextException(
"Checksum inside ciphertext is corrupted");
}
if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
{
throw new InvalidCipherTextException(
"too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
}
// CEK is the wrapped key, now extracted for use in data decryption.
byte[] CEK = new byte[result[0]];
Array.Copy(result, 1, CEK, 0, CEK.Length);
return CEK;
}
/**
* Some key wrap algorithms make use of the Key Checksum defined
* in CMS [CMS-Algorithms]. This is used to provide an integrity
* check value for the key being wrapped. The algorithm is
*
* - Compute the 20 octet SHA-1 hash on the key being wrapped.
* - Use the first 8 octets of this hash as the checksum value.
*
* @param key
* @return
* @throws Exception
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private byte[] CalculateCmsKeyChecksum(
byte[] key)
{
byte[] result = new byte[8];
sha1.BlockUpdate(key, 0, key.Length);
sha1.DoFinal(digest, 0);
Array.Copy(digest, 0, result, 0, 8);
return result;
}
/**
* @param key
* @param checksum
* @return
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private bool CheckCmsKeyChecksum(
byte[] key,
byte[] checksum)
{
return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum);
}
}
}

View File

@@ -0,0 +1,147 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
public class RC4Engine
: IStreamCipher
{
private readonly static int STATE_LENGTH = 256;
/*
* variables to hold the state of the RC4 engine
* during encryption and decryption
*/
private byte[] engineState;
private int x;
private int y;
private byte[] workingKey;
/**
* initialise a RC4 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (parameters is KeyParameter)
{
/*
* RC4 encryption and decryption is completely
* symmetrical, so the 'forEncryption' is
* irrelevant.
*/
workingKey = ((KeyParameter)parameters).GetKey();
SetKey(workingKey);
return;
}
throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
}
public string AlgorithmName
{
get { return "RC4"; }
}
public byte ReturnByte(
byte input)
{
x = (x + 1) & 0xff;
y = (engineState[x] + y) & 0xff;
// swap
byte tmp = engineState[x];
engineState[x] = engineState[y];
engineState[y] = tmp;
// xor
return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
public void ProcessBytes(
byte[] input,
int inOff,
int length,
byte[] output,
int outOff
)
{
if ((inOff + length) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + length) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
for (int i = 0; i < length ; i++)
{
x = (x + 1) & 0xff;
y = (engineState[x] + y) & 0xff;
// swap
byte tmp = engineState[x];
engineState[x] = engineState[y];
engineState[y] = tmp;
// xor
output[i+outOff] = (byte)(input[i + inOff]
^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
}
public void Reset()
{
SetKey(workingKey);
}
// Private implementation
private void SetKey(
byte[] keyBytes)
{
workingKey = keyBytes;
// System.out.println("the key length is ; "+ workingKey.Length);
x = 0;
y = 0;
if (engineState == null)
{
engineState = new byte[STATE_LENGTH];
}
// reset the state of the engine
for (int i=0; i < STATE_LENGTH; i++)
{
engineState[i] = (byte)i;
}
int i1 = 0;
int i2 = 0;
for (int i=0; i < STATE_LENGTH; i++)
{
i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
// do the byte-swap inline
byte tmp = engineState[i];
engineState[i] = engineState[i2];
engineState[i2] = tmp;
i1 = (i1+1) % keyBytes.Length;
}
}
}
}

View File

@@ -0,0 +1,294 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* The specification for RC5 came from the <code>RC5 Encryption Algorithm</code>
* publication in RSA CryptoBytes, Spring of 1995.
* <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>.
* <p>
* This implementation has a word size of 32 bits.</p>
*/
public class RC532Engine
: IBlockCipher
{
/*
* the number of rounds to perform
*/
private int _noRounds;
/*
* the expanded key array of size 2*(rounds + 1)
*/
private int [] _S;
/*
* our "magic constants" for 32 32
*
* Pw = Odd((e-2) * 2^wordsize)
* Qw = Odd((o-2) * 2^wordsize)
*
* where e is the base of natural logarithms (2.718281828...)
* and o is the golden ratio (1.61803398...)
*/
private static readonly int P32 = unchecked((int) 0xb7e15163);
private static readonly int Q32 = unchecked((int) 0x9e3779b9);
private bool forEncryption;
/**
* Create an instance of the RC5 encryption algorithm
* and set some defaults
*/
public RC532Engine()
{
_noRounds = 12; // the default
// _S = null;
}
public string AlgorithmName
{
get { return "RC5-32"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return 2 * 4;
}
/**
* initialise a RC5-32 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (typeof(RC5Parameters).IsInstanceOfType(parameters))
{
RC5Parameters p = (RC5Parameters)parameters;
_noRounds = p.Rounds;
SetKey(p.GetKey());
}
else if (typeof(KeyParameter).IsInstanceOfType(parameters))
{
KeyParameter p = (KeyParameter)parameters;
SetKey(p.GetKey());
}
else
{
throw new ArgumentException("invalid parameter passed to RC532 init - " + parameters.GetType().ToString());
}
this.forEncryption = forEncryption;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
return (forEncryption)
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
}
/**
* Re-key the cipher.
*
* @param key the key to be used
*/
private void SetKey(
byte[] key)
{
//
// KEY EXPANSION:
//
// There are 3 phases to the key expansion.
//
// Phase 1:
// Copy the secret key K[0...b-1] into an array L[0..c-1] of
// c = ceil(b/u), where u = 32/8 in little-endian order.
// In other words, we fill up L using u consecutive key bytes
// of K. Any unfilled byte positions in L are zeroed. In the
// case that b = c = 0, set c = 1 and L[0] = 0.
//
int[] L = new int[(key.Length + (4 - 1)) / 4];
for (int i = 0; i != key.Length; i++)
{
L[i / 4] += (key[i] & 0xff) << (8 * (i % 4));
}
//
// Phase 2:
// Initialize S to a particular fixed pseudo-random bit pattern
// using an arithmetic progression modulo 2^wordsize determined
// by the magic numbers, Pw & Qw.
//
_S = new int[2*(_noRounds + 1)];
_S[0] = P32;
for (int i=1; i < _S.Length; i++)
{
_S[i] = (_S[i-1] + Q32);
}
//
// Phase 3:
// Mix in the user's secret key in 3 passes over the arrays S & L.
// The max of the arrays sizes is used as the loop control
//
int iter;
if (L.Length > _S.Length)
{
iter = 3 * L.Length;
}
else
{
iter = 3 * _S.Length;
}
int A = 0, B = 0;
int ii = 0, jj = 0;
for (int k = 0; k < iter; k++)
{
A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
/**
* Encrypt the given block starting at the given offset and place
* the result in the provided buffer starting at the given offset.
*
* @param in in byte buffer containing data to encrypt
* @param inOff offset into src buffer
* @param out out buffer where encrypted data is written
* @param outOff offset into out buffer
*/
private int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int A = BytesToWord(input, inOff) + _S[0];
int B = BytesToWord(input, inOff + 4) + _S[1];
for (int i = 1; i <= _noRounds; i++)
{
A = RotateLeft(A ^ B, B) + _S[2*i];
B = RotateLeft(B ^ A, A) + _S[2*i+1];
}
WordToBytes(A, outBytes, outOff);
WordToBytes(B, outBytes, outOff + 4);
return 2 * 4;
}
private int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int A = BytesToWord(input, inOff);
int B = BytesToWord(input, inOff + 4);
for (int i = _noRounds; i >= 1; i--)
{
B = RotateRight(B - _S[2*i+1], A) ^ A;
A = RotateRight(A - _S[2*i], B) ^ B;
}
WordToBytes(A - _S[0], outBytes, outOff);
WordToBytes(B - _S[1], outBytes, outOff + 4);
return 2 * 4;
}
//////////////////////////////////////////////////////////////
//
// PRIVATE Helper Methods
//
//////////////////////////////////////////////////////////////
/**
* Perform a left "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(32)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % 32
*/
private int RotateLeft(int x, int y) {
return ((int) ( (uint) (x << (y & (32-1))) |
((uint) x >> (32 - (y & (32-1)))) )
);
}
/**
* Perform a right "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(32)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % 32
*/
private int RotateRight(int x, int y) {
return ((int) ( ((uint) x >> (y & (32-1))) |
(uint) (x << (32 - (y & (32-1)))) )
);
}
private int BytesToWord(
byte[] src,
int srcOff)
{
return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
| ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
}
private void WordToBytes(
int word,
byte[] dst,
int dstOff)
{
dst[dstOff] = (byte)word;
dst[dstOff + 1] = (byte)(word >> 8);
dst[dstOff + 2] = (byte)(word >> 16);
dst[dstOff + 3] = (byte)(word >> 24);
}
}
}

View File

@@ -0,0 +1,295 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* The specification for RC5 came from the <code>RC5 Encryption Algorithm</code>
* publication in RSA CryptoBytes, Spring of 1995.
* <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>.
* <p>
* This implementation is set to work with a 64 bit word size.</p>
*/
public class RC564Engine
: IBlockCipher
{
private static readonly int wordSize = 64;
private static readonly int bytesPerWord = wordSize / 8;
/*
* the number of rounds to perform
*/
private int _noRounds;
/*
* the expanded key array of size 2*(rounds + 1)
*/
private long [] _S;
/*
* our "magic constants" for wordSize 62
*
* Pw = Odd((e-2) * 2^wordsize)
* Qw = Odd((o-2) * 2^wordsize)
*
* where e is the base of natural logarithms (2.718281828...)
* and o is the golden ratio (1.61803398...)
*/
private static readonly long P64 = unchecked( (long) 0xb7e151628aed2a6bL);
private static readonly long Q64 = unchecked( (long) 0x9e3779b97f4a7c15L);
private bool forEncryption;
/**
* Create an instance of the RC5 encryption algorithm
* and set some defaults
*/
public RC564Engine()
{
_noRounds = 12;
// _S = null;
}
public string AlgorithmName
{
get { return "RC5-64"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return 2 * bytesPerWord;
}
/**
* initialise a RC5-64 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
{
throw new ArgumentException("invalid parameter passed to RC564 init - " + parameters.GetType().ToString());
}
RC5Parameters p = (RC5Parameters)parameters;
this.forEncryption = forEncryption;
_noRounds = p.Rounds;
SetKey(p.GetKey());
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
return (forEncryption) ? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
}
/**
* Re-key the cipher.
*
* @param key the key to be used
*/
private void SetKey(
byte[] key)
{
//
// KEY EXPANSION:
//
// There are 3 phases to the key expansion.
//
// Phase 1:
// Copy the secret key K[0...b-1] into an array L[0..c-1] of
// c = ceil(b/u), where u = wordSize/8 in little-endian order.
// In other words, we fill up L using u consecutive key bytes
// of K. Any unfilled byte positions in L are zeroed. In the
// case that b = c = 0, set c = 1 and L[0] = 0.
//
long[] L = new long[(key.Length + (bytesPerWord - 1)) / bytesPerWord];
for (int i = 0; i != key.Length; i++)
{
L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord));
}
//
// Phase 2:
// Initialize S to a particular fixed pseudo-random bit pattern
// using an arithmetic progression modulo 2^wordsize determined
// by the magic numbers, Pw & Qw.
//
_S = new long[2*(_noRounds + 1)];
_S[0] = P64;
for (int i=1; i < _S.Length; i++)
{
_S[i] = (_S[i-1] + Q64);
}
//
// Phase 3:
// Mix in the user's secret key in 3 passes over the arrays S & L.
// The max of the arrays sizes is used as the loop control
//
int iter;
if (L.Length > _S.Length)
{
iter = 3 * L.Length;
}
else
{
iter = 3 * _S.Length;
}
long A = 0, B = 0;
int ii = 0, jj = 0;
for (int k = 0; k < iter; k++)
{
A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
/**
* Encrypt the given block starting at the given offset and place
* the result in the provided buffer starting at the given offset.
*
* @param in in byte buffer containing data to encrypt
* @param inOff offset into src buffer
* @param out out buffer where encrypted data is written
* @param outOff offset into out buffer
*/
private int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
long A = BytesToWord(input, inOff) + _S[0];
long B = BytesToWord(input, inOff + bytesPerWord) + _S[1];
for (int i = 1; i <= _noRounds; i++)
{
A = RotateLeft(A ^ B, B) + _S[2*i];
B = RotateLeft(B ^ A, A) + _S[2*i+1];
}
WordToBytes(A, outBytes, outOff);
WordToBytes(B, outBytes, outOff + bytesPerWord);
return 2 * bytesPerWord;
}
private int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
long A = BytesToWord(input, inOff);
long B = BytesToWord(input, inOff + bytesPerWord);
for (int i = _noRounds; i >= 1; i--)
{
B = RotateRight(B - _S[2*i+1], A) ^ A;
A = RotateRight(A - _S[2*i], B) ^ B;
}
WordToBytes(A - _S[0], outBytes, outOff);
WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord);
return 2 * bytesPerWord;
}
//////////////////////////////////////////////////////////////
//
// PRIVATE Helper Methods
//
//////////////////////////////////////////////////////////////
/**
* Perform a left "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % wordSize
*/
private long RotateLeft(long x, long y) {
return ((long) ( (ulong) (x << (int) (y & (wordSize-1))) |
((ulong) x >> (int) (wordSize - (y & (wordSize-1)))))
);
}
/**
* Perform a right "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % wordSize
*/
private long RotateRight(long x, long y) {
return ((long) ( ((ulong) x >> (int) (y & (wordSize-1))) |
(ulong) (x << (int) (wordSize - (y & (wordSize-1)))))
);
}
private long BytesToWord(
byte[] src,
int srcOff)
{
long word = 0;
for (int i = bytesPerWord - 1; i >= 0; i--)
{
word = (word << 8) + (src[i + srcOff] & 0xff);
}
return word;
}
private void WordToBytes(
long word,
byte[] dst,
int dstOff)
{
for (int i = 0; i < bytesPerWord; i++)
{
dst[i + dstOff] = (byte)word;
word = (long) ((ulong) word >> 8);
}
}
}
}

View File

@@ -0,0 +1,362 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* An RC6 engine.
*/
public class RC6Engine
: IBlockCipher
{
private static readonly int wordSize = 32;
private static readonly int bytesPerWord = wordSize / 8;
/*
* the number of rounds to perform
*/
private static readonly int _noRounds = 20;
/*
* the expanded key array of size 2*(rounds + 1)
*/
private int [] _S;
/*
* our "magic constants" for wordSize 32
*
* Pw = Odd((e-2) * 2^wordsize)
* Qw = Odd((o-2) * 2^wordsize)
*
* where e is the base of natural logarithms (2.718281828...)
* and o is the golden ratio (1.61803398...)
*/
private static readonly int P32 = unchecked((int) 0xb7e15163);
private static readonly int Q32 = unchecked((int) 0x9e3779b9);
private static readonly int LGW = 5; // log2(32)
private bool forEncryption;
/**
* Create an instance of the RC6 encryption algorithm
* and set some defaults
*/
public RC6Engine()
{
// _S = null;
}
public string AlgorithmName
{
get { return "RC6"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return 4 * bytesPerWord;
}
/**
* initialise a RC5-32 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to RC6 init - " + parameters.GetType().ToString());
this.forEncryption = forEncryption;
KeyParameter p = (KeyParameter)parameters;
SetKey(p.GetKey());
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
int blockSize = GetBlockSize();
if (_S == null)
throw new InvalidOperationException("RC6 engine not initialised");
if ((inOff + blockSize) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + blockSize) > output.Length)
throw new DataLengthException("output buffer too short");
return (forEncryption)
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
}
/**
* Re-key the cipher.
*
* @param inKey the key to be used
*/
private void SetKey(
byte[] key)
{
//
// KEY EXPANSION:
//
// There are 3 phases to the key expansion.
//
// Phase 1:
// Copy the secret key K[0...b-1] into an array L[0..c-1] of
// c = ceil(b/u), where u = wordSize/8 in little-endian order.
// In other words, we fill up L using u consecutive key bytes
// of K. Any unfilled byte positions in L are zeroed. In the
// case that b = c = 0, set c = 1 and L[0] = 0.
//
// compute number of dwords
int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord;
if (c == 0)
{
c = 1;
}
int[] L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord];
// load all key bytes into array of key dwords
for (int i = key.Length - 1; i >= 0; i--)
{
L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff);
}
//
// Phase 2:
// Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords.
// Initialize S to a particular fixed pseudo-random bit pattern
// using an arithmetic progression modulo 2^wordsize determined
// by the magic numbers, Pw & Qw.
//
_S = new int[2+2*_noRounds+2];
_S[0] = P32;
for (int i=1; i < _S.Length; i++)
{
_S[i] = (_S[i-1] + Q32);
}
//
// Phase 3:
// Mix in the user's secret key in 3 passes over the arrays S & L.
// The max of the arrays sizes is used as the loop control
//
int iter;
if (L.Length > _S.Length)
{
iter = 3 * L.Length;
}
else
{
iter = 3 * _S.Length;
}
int A = 0;
int B = 0;
int ii = 0, jj = 0;
for (int k = 0; k < iter; k++)
{
A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
private int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
// load A,B,C and D registers from in.
int A = BytesToWord(input, inOff);
int B = BytesToWord(input, inOff + bytesPerWord);
int C = BytesToWord(input, inOff + bytesPerWord*2);
int D = BytesToWord(input, inOff + bytesPerWord*3);
// Do pseudo-round #0: pre-whitening of B and D
B += _S[0];
D += _S[1];
// perform round #1,#2 ... #ROUNDS of encryption
for (int i = 1; i <= _noRounds; i++)
{
int t = 0,u = 0;
t = B*(2*B+1);
t = RotateLeft(t,5);
u = D*(2*D+1);
u = RotateLeft(u,5);
A ^= t;
A = RotateLeft(A,u);
A += _S[2*i];
C ^= u;
C = RotateLeft(C,t);
C += _S[2*i+1];
int temp = A;
A = B;
B = C;
C = D;
D = temp;
}
// do pseudo-round #(ROUNDS+1) : post-whitening of A and C
A += _S[2*_noRounds+2];
C += _S[2*_noRounds+3];
// store A, B, C and D registers to out
WordToBytes(A, outBytes, outOff);
WordToBytes(B, outBytes, outOff + bytesPerWord);
WordToBytes(C, outBytes, outOff + bytesPerWord*2);
WordToBytes(D, outBytes, outOff + bytesPerWord*3);
return 4 * bytesPerWord;
}
private int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
// load A,B,C and D registers from out.
int A = BytesToWord(input, inOff);
int B = BytesToWord(input, inOff + bytesPerWord);
int C = BytesToWord(input, inOff + bytesPerWord*2);
int D = BytesToWord(input, inOff + bytesPerWord*3);
// Undo pseudo-round #(ROUNDS+1) : post whitening of A and C
C -= _S[2*_noRounds+3];
A -= _S[2*_noRounds+2];
// Undo round #ROUNDS, .., #2,#1 of encryption
for (int i = _noRounds; i >= 1; i--)
{
int t=0,u = 0;
int temp = D;
D = C;
C = B;
B = A;
A = temp;
t = B*(2*B+1);
t = RotateLeft(t, LGW);
u = D*(2*D+1);
u = RotateLeft(u, LGW);
C -= _S[2*i+1];
C = RotateRight(C,t);
C ^= u;
A -= _S[2*i];
A = RotateRight(A,u);
A ^= t;
}
// Undo pseudo-round #0: pre-whitening of B and D
D -= _S[1];
B -= _S[0];
WordToBytes(A, outBytes, outOff);
WordToBytes(B, outBytes, outOff + bytesPerWord);
WordToBytes(C, outBytes, outOff + bytesPerWord*2);
WordToBytes(D, outBytes, outOff + bytesPerWord*3);
return 4 * bytesPerWord;
}
//////////////////////////////////////////////////////////////
//
// PRIVATE Helper Methods
//
//////////////////////////////////////////////////////////////
/**
* Perform a left "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % wordSize
*/
private int RotateLeft(int x, int y)
{
return ((int)((uint)(x << (y & (wordSize-1)))
| ((uint) x >> (wordSize - (y & (wordSize-1))))));
}
/**
* Perform a right "spin" of the word. The rotation of the given
* word <em>x</em> is rotated left by <em>y</em> bits.
* Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
* are used to determine the rotation amount. Here it is
* assumed that the wordsize used is a power of 2.
*
* @param x word to rotate
* @param y number of bits to rotate % wordSize
*/
private int RotateRight(int x, int y)
{
return ((int)(((uint) x >> (y & (wordSize-1)))
| (uint)(x << (wordSize - (y & (wordSize-1))))));
}
private int BytesToWord(
byte[] src,
int srcOff)
{
int word = 0;
for (int i = bytesPerWord - 1; i >= 0; i--)
{
word = (word << 8) + (src[i + srcOff] & 0xff);
}
return word;
}
private void WordToBytes(
int word,
byte[] dst,
int dstOff)
{
for (int i = 0; i < bytesPerWord; i++)
{
dst[i + dstOff] = (byte)word;
word = (int) ((uint) word >> 8);
}
}
}
}

View File

@@ -0,0 +1,166 @@
using System;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of the RFC 3211 Key Wrap
* Specification.
*/
public class Rfc3211WrapEngine
: IWrapper
{
private CbcBlockCipher engine;
private ParametersWithIV param;
private bool forWrapping;
private SecureRandom rand;
public Rfc3211WrapEngine(
IBlockCipher engine)
{
this.engine = new CbcBlockCipher(engine);
}
public void Init(
bool forWrapping,
ICipherParameters param)
{
this.forWrapping = forWrapping;
if (param is ParametersWithRandom)
{
ParametersWithRandom p = (ParametersWithRandom) param;
this.rand = p.Random;
this.param = (ParametersWithIV) p.Parameters;
}
else
{
if (forWrapping)
{
rand = new SecureRandom();
}
this.param = (ParametersWithIV) param;
}
}
public string AlgorithmName
{
get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
}
public byte[] Wrap(
byte[] inBytes,
int inOff,
int inLen)
{
if (!forWrapping)
{
throw new InvalidOperationException("not set for wrapping");
}
engine.Init(true, param);
int blockSize = engine.GetBlockSize();
byte[] cekBlock;
if (inLen + 4 < blockSize * 2)
{
cekBlock = new byte[blockSize * 2];
}
else
{
cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
}
cekBlock[0] = (byte)inLen;
cekBlock[1] = (byte)~inBytes[inOff];
cekBlock[2] = (byte)~inBytes[inOff + 1];
cekBlock[3] = (byte)~inBytes[inOff + 2];
Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
for (int i = 0; i < cekBlock.Length; i += blockSize)
{
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
for (int i = 0; i < cekBlock.Length; i += blockSize)
{
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
return cekBlock;
}
public byte[] Unwrap(
byte[] inBytes,
int inOff,
int inLen)
{
if (forWrapping)
{
throw new InvalidOperationException("not set for unwrapping");
}
int blockSize = engine.GetBlockSize();
if (inLen < 2 * blockSize)
{
throw new InvalidCipherTextException("input too short");
}
byte[] cekBlock = new byte[inLen];
byte[] iv = new byte[blockSize];
Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
Array.Copy(inBytes, inOff, iv, 0, iv.Length);
engine.Init(false, new ParametersWithIV(param.Parameters, iv));
for (int i = blockSize; i < cekBlock.Length; i += blockSize)
{
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
engine.Init(false, new ParametersWithIV(param.Parameters, iv));
engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
engine.Init(false, param);
for (int i = 0; i < cekBlock.Length; i += blockSize)
{
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
{
throw new InvalidCipherTextException("wrapped key corrupted");
}
byte[] key = new byte[cekBlock[0] & 0xff];
Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
for (int i = 0; i != 3; i++)
{
byte check = (byte)~cekBlock[1 + i];
if (check != key[i])
{
throw new InvalidCipherTextException("wrapped key fails checksum");
}
}
return key;
}
}
}

View File

@@ -0,0 +1,181 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>
/// An implementation of the AES Key Wrapper from the NIST Key Wrap
/// Specification as described in RFC 3394.
/// <p/>
/// For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
/// and <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
/// </remarks>
public class Rfc3394WrapEngine
: IWrapper
{
private readonly IBlockCipher engine;
private KeyParameter param;
private bool forWrapping;
private byte[] iv =
{
0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6
};
public Rfc3394WrapEngine(
IBlockCipher engine)
{
this.engine = engine;
}
public void Init(
bool forWrapping,
ICipherParameters parameters)
{
this.forWrapping = forWrapping;
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
if (parameters is KeyParameter)
{
this.param = (KeyParameter) parameters;
}
else if (parameters is ParametersWithIV)
{
ParametersWithIV pIV = (ParametersWithIV) parameters;
byte[] iv = pIV.GetIV();
if (iv.Length != 8)
throw new ArgumentException("IV length not equal to 8", "parameters");
this.iv = iv;
this.param = (KeyParameter) pIV.Parameters;
}
else
{
// TODO Throw an exception for bad parameters?
}
}
public string AlgorithmName
{
get { return engine.AlgorithmName; }
}
public byte[] Wrap(
byte[] input,
int inOff,
int inLen)
{
if (!forWrapping)
{
throw new InvalidOperationException("not set for wrapping");
}
int n = inLen / 8;
if ((n * 8) != inLen)
{
throw new DataLengthException("wrap data must be a multiple of 8 bytes");
}
byte[] block = new byte[inLen + iv.Length];
byte[] buf = new byte[8 + iv.Length];
Array.Copy(iv, 0, block, 0, iv.Length);
Array.Copy(input, 0, block, iv.Length, inLen);
engine.Init(true, param);
for (int j = 0; j != 6; j++)
{
for (int i = 1; i <= n; i++)
{
Array.Copy(block, 0, buf, 0, iv.Length);
Array.Copy(block, 8 * i, buf, iv.Length, 8);
engine.ProcessBlock(buf, 0, buf, 0);
int t = n * j + i;
for (int k = 1; t != 0; k++)
{
byte v = (byte)t;
buf[iv.Length - k] ^= v;
t = (int) ((uint)t >> 8);
}
Array.Copy(buf, 0, block, 0, 8);
Array.Copy(buf, 8, block, 8 * i, 8);
}
}
return block;
}
public byte[] Unwrap(
byte[] input,
int inOff,
int inLen)
{
if (forWrapping)
{
throw new InvalidOperationException("not set for unwrapping");
}
int n = inLen / 8;
if ((n * 8) != inLen)
{
throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
}
byte[] block = new byte[inLen - iv.Length];
byte[] a = new byte[iv.Length];
byte[] buf = new byte[8 + iv.Length];
Array.Copy(input, 0, a, 0, iv.Length);
Array.Copy(input, iv.Length, block, 0, inLen - iv.Length);
engine.Init(false, param);
n = n - 1;
for (int j = 5; j >= 0; j--)
{
for (int i = n; i >= 1; i--)
{
Array.Copy(a, 0, buf, 0, iv.Length);
Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8);
int t = n * j + i;
for (int k = 1; t != 0; k++)
{
byte v = (byte)t;
buf[iv.Length - k] ^= v;
t = (int) ((uint)t >> 8);
}
engine.ProcessBlock(buf, 0, buf, 0);
Array.Copy(buf, 0, a, 0, 8);
Array.Copy(buf, 8, block, 8 * (i - 1), 8);
}
}
for (int i = 0; i != iv.Length; i++)
{
if (a[i] != iv[i])
{
throw new InvalidCipherTextException("checksum failed");
}
}
return block;
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* this does your basic RSA algorithm with blinding
*/
public class RsaBlindedEngine
: IAsymmetricBlockCipher
{
private readonly RsaCoreEngine core = new RsaCoreEngine();
private RsaKeyParameters key;
private SecureRandom random;
public string AlgorithmName
{
get { return "RSA"; }
}
/**
* initialise the RSA engine.
*
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters param)
{
core.Init(forEncryption, param);
if (param is ParametersWithRandom)
{
ParametersWithRandom rParam = (ParametersWithRandom)param;
key = (RsaKeyParameters)rParam.Parameters;
random = rParam.Random;
}
else
{
key = (RsaKeyParameters)param;
random = new SecureRandom();
}
}
/**
* Return the maximum size for an input block to this engine.
* For RSA this is always one byte less than the key size on
* encryption, and the same length as the key size on decryption.
*
* @return maximum size for an input block.
*/
public int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
/**
* Return the maximum size for an output block to this engine.
* For RSA this is always one byte less than the key size on
* decryption, and the same length as the key size on encryption.
*
* @return maximum size for an output block.
*/
public int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
/**
* Process a single block using the basic RSA algorithm.
*
* @param inBuf the input array.
* @param inOff the offset into the input buffer where the data starts.
* @param inLen the length of the data to be processed.
* @return the result of the RSA process.
* @exception DataLengthException the input block is too large.
*/
public byte[] ProcessBlock(
byte[] inBuf,
int inOff,
int inLen)
{
if (key == null)
throw new InvalidOperationException("RSA engine not initialised");
BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
BigInteger result;
if (key is RsaPrivateCrtKeyParameters)
{
RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
if (k.PublicExponent != null) // can't do blinding without a public exponent
{
BigInteger m = k.Modulus;
BigInteger r = calculateR(m);
BigInteger blindedInput = r.ModPow(k.PublicExponent, m).Multiply(input).Mod(m);
BigInteger blindedResult = core.ProcessBlock(blindedInput);
result = blindedResult.Multiply(r.ModInverse(m)).Mod(m);
}
else
{
result = core.ProcessBlock(input);
}
}
else
{
result = core.ProcessBlock(input);
}
return core.ConvertOutput(result);
}
/*
* calculate a random mess-with-their-heads value.
*/
private BigInteger calculateR(
BigInteger m)
{
int max = m.BitLength - 1; // must be less than m.BitLength
int min = max / 2;
int length = ((random.NextInt() & 0xff) * ((max - min) / 0xff)) + min;
BigInteger factor = new BigInteger(length, random);
while (factor.SignValue == 0)
{
factor = new BigInteger(length, random);
}
return factor;
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* This does your basic RSA Chaum's blinding and unblinding as outlined in
* "Handbook of Applied Cryptography", page 475. You need to use this if you are
* trying to get another party to generate signatures without them being aware
* of the message they are signing.
*/
public class RsaBlindingEngine
: IAsymmetricBlockCipher
{
private readonly RsaCoreEngine core = new RsaCoreEngine();
private RsaKeyParameters key;
private BigInteger blindingFactor;
private bool forEncryption;
public string AlgorithmName
{
get { return "RSA"; }
}
/**
* Initialise the blinding engine.
*
* @param forEncryption true if we are encrypting (blinding), false otherwise.
* @param param the necessary RSA key parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters param)
{
RsaBlindingParameters p;
if (param is ParametersWithRandom)
{
ParametersWithRandom rParam = (ParametersWithRandom)param;
p = (RsaBlindingParameters)rParam.Parameters;
}
else
{
p = (RsaBlindingParameters)param;
}
core.Init(forEncryption, p.PublicKey);
this.forEncryption = forEncryption;
this.key = p.PublicKey;
this.blindingFactor = p.BlindingFactor;
}
/**
* Return the maximum size for an input block to this engine.
* For RSA this is always one byte less than the key size on
* encryption, and the same length as the key size on decryption.
*
* @return maximum size for an input block.
*/
public int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
/**
* Return the maximum size for an output block to this engine.
* For RSA this is always one byte less than the key size on
* decryption, and the same length as the key size on encryption.
*
* @return maximum size for an output block.
*/
public int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
/**
* Process a single block using the RSA blinding algorithm.
*
* @param in the input array.
* @param inOff the offset into the input buffer where the data starts.
* @param inLen the length of the data to be processed.
* @return the result of the RSA process.
* @throws DataLengthException the input block is too large.
*/
public byte[] ProcessBlock(
byte[] inBuf,
int inOff,
int inLen)
{
BigInteger msg = core.ConvertInput(inBuf, inOff, inLen);
if (forEncryption)
{
msg = BlindMessage(msg);
}
else
{
msg = UnblindMessage(msg);
}
return core.ConvertOutput(msg);
}
/*
* Blind message with the blind factor.
*/
private BigInteger BlindMessage(
BigInteger msg)
{
BigInteger blindMsg = blindingFactor;
blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus));
blindMsg = blindMsg.Mod(key.Modulus);
return blindMsg;
}
/*
* Unblind the message blinded with the blind factor.
*/
private BigInteger UnblindMessage(
BigInteger blindedMsg)
{
BigInteger m = key.Modulus;
BigInteger msg = blindedMsg;
BigInteger blindFactorInverse = blindingFactor.ModInverse(m);
msg = msg.Multiply(blindFactorInverse);
msg = msg.Mod(m);
return msg;
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* this does your basic RSA algorithm.
*/
class RsaCoreEngine
{
private RsaKeyParameters key;
private bool forEncryption;
private int bitSize;
/**
* initialise the RSA engine.
*
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (parameters is ParametersWithRandom)
{
parameters = ((ParametersWithRandom) parameters).Parameters;
}
if (!(parameters is RsaKeyParameters))
throw new InvalidKeyException("Not an RSA key");
this.key = (RsaKeyParameters) parameters;
this.forEncryption = forEncryption;
this.bitSize = key.Modulus.BitLength;
}
/**
* Return the maximum size for an input block to this engine.
* For RSA this is always one byte less than the key size on
* encryption, and the same length as the key size on decryption.
*
* @return maximum size for an input block.
*/
public int GetInputBlockSize()
{
if (forEncryption)
{
return (bitSize - 1) / 8;
}
return (bitSize + 7) / 8;
}
/**
* Return the maximum size for an output block to this engine.
* For RSA this is always one byte less than the key size on
* decryption, and the same length as the key size on encryption.
*
* @return maximum size for an output block.
*/
public int GetOutputBlockSize()
{
if (forEncryption)
{
return (bitSize + 7) / 8;
}
return (bitSize - 1) / 8;
}
public BigInteger ConvertInput(
byte[] inBuf,
int inOff,
int inLen)
{
int maxLength = (bitSize + 7) / 8;
if (inLen > maxLength)
throw new DataLengthException("input too large for RSA cipher.");
BigInteger input = new BigInteger(1, inBuf, inOff, inLen);
if (input.CompareTo(key.Modulus) >= 0)
throw new DataLengthException("input too large for RSA cipher.");
return input;
}
public byte[] ConvertOutput(
BigInteger result)
{
byte[] output = result.ToByteArrayUnsigned();
if (forEncryption)
{
int outSize = GetOutputBlockSize();
// TODO To avoid this, create version of BigInteger.ToByteArray that
// writes to an existing array
if (output.Length < outSize) // have ended up with less bytes than normal, lengthen
{
byte[] tmp = new byte[outSize];
output.CopyTo(tmp, tmp.Length - output.Length);
output = tmp;
}
}
return output;
}
public BigInteger ProcessBlock(
BigInteger input)
{
if (key is RsaPrivateCrtKeyParameters)
{
//
// we have the extra factors, use the Chinese Remainder Theorem - the author
// wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
// advice regarding the expression of this.
//
RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
BigInteger p = crtKey.P;;
BigInteger q = crtKey.Q;
BigInteger dP = crtKey.DP;
BigInteger dQ = crtKey.DQ;
BigInteger qInv = crtKey.QInv;
BigInteger mP, mQ, h, m;
// mP = ((input Mod p) ^ dP)) Mod p
mP = (input.Remainder(p)).ModPow(dP, p);
// mQ = ((input Mod q) ^ dQ)) Mod q
mQ = (input.Remainder(q)).ModPow(dQ, q);
// h = qInv * (mP - mQ) Mod p
h = mP.Subtract(mQ);
h = h.Multiply(qInv);
h = h.Mod(p); // Mod (in Java) returns the positive residual
// m = h * q + mQ
m = h.Multiply(q);
m = m.Add(mQ);
return m;
}
return input.ModPow(key.Exponent, key.Modulus);
}
}
}

View File

@@ -0,0 +1,740 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* an implementation of Rijndael, based on the documentation and reference implementation
* by Paulo Barreto, Vincent Rijmen, for v2.0 August '99.
* <p>
* Note: this implementation is based on information prior to readonly NIST publication.
* </p>
*/
public class RijndaelEngine
: IBlockCipher
{
private static readonly int MAXROUNDS = 14;
private static readonly int MAXKC = (256/4);
private static readonly byte[] Logtable = {
(byte)0, (byte)0, (byte)25, (byte)1, (byte)50, (byte)2, (byte)26, (byte)198,
(byte)75, (byte)199, (byte)27, (byte)104, (byte)51, (byte)238, (byte)223, (byte)3,
(byte)100, (byte)4, (byte)224, (byte)14, (byte)52, (byte)141, (byte)129, (byte)239,
(byte)76, (byte)113, (byte)8, (byte)200, (byte)248, (byte)105, (byte)28, (byte)193,
(byte)125, (byte)194, (byte)29, (byte)181, (byte)249, (byte)185, (byte)39, (byte)106,
(byte)77, (byte)228, (byte)166, (byte)114, (byte)154, (byte)201, (byte)9, (byte)120,
(byte)101, (byte)47, (byte)138, (byte)5, (byte)33, (byte)15, (byte)225, (byte)36,
(byte)18, (byte)240, (byte)130, (byte)69, (byte)53, (byte)147, (byte)218, (byte)142,
(byte)150, (byte)143, (byte)219, (byte)189, (byte)54, (byte)208, (byte)206, (byte)148,
(byte)19, (byte)92, (byte)210, (byte)241, (byte)64, (byte)70, (byte)131, (byte)56,
(byte)102, (byte)221, (byte)253, (byte)48, (byte)191, (byte)6, (byte)139, (byte)98,
(byte)179, (byte)37, (byte)226, (byte)152, (byte)34, (byte)136, (byte)145, (byte)16,
(byte)126, (byte)110, (byte)72, (byte)195, (byte)163, (byte)182, (byte)30, (byte)66,
(byte)58, (byte)107, (byte)40, (byte)84, (byte)250, (byte)133, (byte)61, (byte)186,
(byte)43, (byte)121, (byte)10, (byte)21, (byte)155, (byte)159, (byte)94, (byte)202,
(byte)78, (byte)212, (byte)172, (byte)229, (byte)243, (byte)115, (byte)167, (byte)87,
(byte)175, (byte)88, (byte)168, (byte)80, (byte)244, (byte)234, (byte)214, (byte)116,
(byte)79, (byte)174, (byte)233, (byte)213, (byte)231, (byte)230, (byte)173, (byte)232,
(byte)44, (byte)215, (byte)117, (byte)122, (byte)235, (byte)22, (byte)11, (byte)245,
(byte)89, (byte)203, (byte)95, (byte)176, (byte)156, (byte)169, (byte)81, (byte)160,
(byte)127, (byte)12, (byte)246, (byte)111, (byte)23, (byte)196, (byte)73, (byte)236,
(byte)216, (byte)67, (byte)31, (byte)45, (byte)164, (byte)118, (byte)123, (byte)183,
(byte)204, (byte)187, (byte)62, (byte)90, (byte)251, (byte)96, (byte)177, (byte)134,
(byte)59, (byte)82, (byte)161, (byte)108, (byte)170, (byte)85, (byte)41, (byte)157,
(byte)151, (byte)178, (byte)135, (byte)144, (byte)97, (byte)190, (byte)220, (byte)252,
(byte)188, (byte)149, (byte)207, (byte)205, (byte)55, (byte)63, (byte)91, (byte)209,
(byte)83, (byte)57, (byte)132, (byte)60, (byte)65, (byte)162, (byte)109, (byte)71,
(byte)20, (byte)42, (byte)158, (byte)93, (byte)86, (byte)242, (byte)211, (byte)171,
(byte)68, (byte)17, (byte)146, (byte)217, (byte)35, (byte)32, (byte)46, (byte)137,
(byte)180, (byte)124, (byte)184, (byte)38, (byte)119, (byte)153, (byte)227, (byte)165,
(byte)103, (byte)74, (byte)237, (byte)222, (byte)197, (byte)49, (byte)254, (byte)24,
(byte)13, (byte)99, (byte)140, (byte)128, (byte)192, (byte)247, (byte)112, (byte)7
};
private static readonly byte[] Alogtable = {
(byte)0, (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
(byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
(byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
(byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
(byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
(byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
(byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
(byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
(byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
(byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
(byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
(byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
(byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
(byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
(byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
(byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
(byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
(byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
(byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
(byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
(byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
(byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
(byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
(byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
(byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
(byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
(byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
(byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
(byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
(byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
(byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
(byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
};
private static readonly byte[] S = {
(byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
(byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
(byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
(byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
(byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
(byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
(byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
(byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
(byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
(byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
(byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
(byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
(byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
(byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
(byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
(byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
};
private static readonly byte[] Si = {
(byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
(byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
(byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
(byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
(byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
(byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
(byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
(byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
(byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
(byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
(byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
(byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
(byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
(byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
(byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
(byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
};
private static readonly int[] rcon = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
static readonly byte[][] shifts0 = new byte [][]
{
new byte [] { 0, 8, 16, 24 },
new byte [] { 0, 8, 16, 24 },
new byte [] { 0, 8, 16, 24 },
new byte [] { 0, 8, 16, 32 },
new byte [] { 0, 8, 24, 32 }
};
static readonly byte[][] shifts1 =
{
new byte [] { 0, 24, 16, 8 },
new byte [] { 0, 32, 24, 16 },
new byte [] { 0, 40, 32, 24 },
new byte [] { 0, 48, 40, 24 },
new byte [] { 0, 56, 40, 32 }
};
/**
* multiply two elements of GF(2^m)
* needed for MixColumn and InvMixColumn
*/
private byte Mul0x2(
int b)
{
if (b != 0)
{
return Alogtable[25 + (Logtable[b] & 0xff)];
}
else
{
return 0;
}
}
private byte Mul0x3(
int b)
{
if (b != 0)
{
return Alogtable[1 + (Logtable[b] & 0xff)];
}
else
{
return 0;
}
}
private byte Mul0x9(
int b)
{
if (b >= 0)
{
return Alogtable[199 + b];
}
else
{
return 0;
}
}
private byte Mul0xb(
int b)
{
if (b >= 0)
{
return Alogtable[104 + b];
}
else
{
return 0;
}
}
private byte Mul0xd(
int b)
{
if (b >= 0)
{
return Alogtable[238 + b];
}
else
{
return 0;
}
}
private byte Mul0xe(
int b)
{
if (b >= 0)
{
return Alogtable[223 + b];
}
else
{
return 0;
}
}
/**
* xor corresponding text input and round key input bytes
*/
private void KeyAddition(
long[] rk)
{
A0 ^= rk[0];
A1 ^= rk[1];
A2 ^= rk[2];
A3 ^= rk[3];
}
private long Shift(
long r,
int shift)
{
//return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK;
ulong temp = (ulong) r >> shift;
// NB: This corrects for Mono Bug #79087 (fixed in 1.1.17)
if (shift > 31)
{
temp &= 0xFFFFFFFFUL;
}
return ((long) temp | (r << (BC - shift))) & BC_MASK;
}
/**
* Row 0 remains unchanged
* The other three rows are shifted a variable amount
*/
private void ShiftRow(
byte[] shiftsSC)
{
A1 = Shift(A1, shiftsSC[1]);
A2 = Shift(A2, shiftsSC[2]);
A3 = Shift(A3, shiftsSC[3]);
}
private long ApplyS(
long r,
byte[] box)
{
long res = 0;
for (int j = 0; j < BC; j += 8)
{
res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j;
}
return res;
}
/**
* Replace every byte of the input by the byte at that place
* in the nonlinear S-box
*/
private void Substitution(
byte[] box)
{
A0 = ApplyS(A0, box);
A1 = ApplyS(A1, box);
A2 = ApplyS(A2, box);
A3 = ApplyS(A3, box);
}
/**
* Mix the bytes of every column in a linear way
*/
private void MixColumn()
{
long r0, r1, r2, r3;
r0 = r1 = r2 = r3 = 0;
for (int j = 0; j < BC; j += 8)
{
int a0 = (int)((A0 >> j) & 0xff);
int a1 = (int)((A1 >> j) & 0xff);
int a2 = (int)((A2 >> j) & 0xff);
int a3 = (int)((A3 >> j) & 0xff);
r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j;
r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j;
r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j;
r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j;
}
A0 = r0;
A1 = r1;
A2 = r2;
A3 = r3;
}
/**
* Mix the bytes of every column in a linear way
* This is the opposite operation of Mixcolumn
*/
private void InvMixColumn()
{
long r0, r1, r2, r3;
r0 = r1 = r2 = r3 = 0;
for (int j = 0; j < BC; j += 8)
{
int a0 = (int)((A0 >> j) & 0xff);
int a1 = (int)((A1 >> j) & 0xff);
int a2 = (int)((A2 >> j) & 0xff);
int a3 = (int)((A3 >> j) & 0xff);
//
// pre-lookup the log table
//
a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1;
a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1;
a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1;
a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1;
r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j;
r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j;
r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j;
r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j;
}
A0 = r0;
A1 = r1;
A2 = r2;
A3 = r3;
}
/**
* Calculate the necessary round keys
* The number of calculations depends on keyBits and blockBits
*/
private long[][] GenerateWorkingKey(
byte[] key)
{
int KC;
int t, rconpointer = 0;
int keyBits = key.Length * 8;
byte[,] tk = new byte[4,MAXKC];
//long[,] W = new long[MAXROUNDS+1,4];
long[][] W = new long[MAXROUNDS+1][];
for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4];
switch (keyBits)
{
case 128:
KC = 4;
break;
case 160:
KC = 5;
break;
case 192:
KC = 6;
break;
case 224:
KC = 7;
break;
case 256:
KC = 8;
break;
default :
throw new ArgumentException("Key length not 128/160/192/224/256 bits.");
}
if (keyBits >= blockBits)
{
ROUNDS = KC + 6;
}
else
{
ROUNDS = (BC / 8) + 6;
}
//
// copy the key into the processing area
//
int index = 0;
for (int i = 0; i < key.Length; i++)
{
tk[i % 4,i / 4] = key[index++];
}
t = 0;
//
// copy values into round key array
//
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
{
for (int i = 0; i < 4; i++)
{
W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC);
}
}
//
// while not enough round key material calculated
// calculate new values
//
while (t < (ROUNDS+1)*(BC/8))
{
for (int i = 0; i < 4; i++)
{
tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff];
}
tk[0,0] ^= (byte) rcon[rconpointer++];
if (KC <= 6)
{
for (int j = 1; j < KC; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
}
else
{
for (int j = 1; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
for (int i = 0; i < 4; i++)
{
tk[i,4] ^= S[tk[i,3] & 0xff];
}
for (int j = 5; j < KC; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
}
//
// copy values into round key array
//
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
{
for (int i = 0; i < 4; i++)
{
W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC));
}
}
}
return W;
}
private int BC;
private long BC_MASK;
private int ROUNDS;
private int blockBits;
private long[][] workingKey;
private long A0, A1, A2, A3;
private bool forEncryption;
private byte[] shifts0SC;
private byte[] shifts1SC;
/**
* default constructor - 128 bit block size.
*/
public RijndaelEngine() : this(128) {}
/**
* basic constructor - set the cipher up for a given blocksize
*
* @param blocksize the blocksize in bits, must be 128, 192, or 256.
*/
public RijndaelEngine(
int blockBits)
{
switch (blockBits)
{
case 128:
BC = 32;
BC_MASK = 0xffffffffL;
shifts0SC = shifts0[0];
shifts1SC = shifts1[0];
break;
case 160:
BC = 40;
BC_MASK = 0xffffffffffL;
shifts0SC = shifts0[1];
shifts1SC = shifts1[1];
break;
case 192:
BC = 48;
BC_MASK = 0xffffffffffffL;
shifts0SC = shifts0[2];
shifts1SC = shifts1[2];
break;
case 224:
BC = 56;
BC_MASK = 0xffffffffffffffL;
shifts0SC = shifts0[3];
shifts1SC = shifts1[3];
break;
case 256:
BC = 64;
BC_MASK = unchecked( (long)0xffffffffffffffffL);
shifts0SC = shifts0[4];
shifts1SC = shifts1[4];
break;
default:
throw new ArgumentException("unknown blocksize to Rijndael");
}
this.blockBits = blockBits;
}
/**
* initialise a Rijndael cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (typeof(KeyParameter).IsInstanceOfType(parameters))
{
workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
this.forEncryption = forEncryption;
return;
}
throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
}
public string AlgorithmName
{
get { return "Rijndael"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BC / 2;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("Rijndael engine not initialised");
}
if ((inOff + (BC / 2)) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + (BC / 2)) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
UnPackBlock(input, inOff);
if (forEncryption)
{
EncryptBlock(workingKey);
}
else
{
DecryptBlock(workingKey);
}
PackBlock(output, outOff);
return BC / 2;
}
public void Reset()
{
}
private void UnPackBlock(
byte[] bytes,
int off)
{
int index = off;
A0 = (long)(bytes[index++] & 0xff);
A1 = (long)(bytes[index++] & 0xff);
A2 = (long)(bytes[index++] & 0xff);
A3 = (long)(bytes[index++] & 0xff);
for (int j = 8; j != BC; j += 8)
{
A0 |= (long)(bytes[index++] & 0xff) << j;
A1 |= (long)(bytes[index++] & 0xff) << j;
A2 |= (long)(bytes[index++] & 0xff) << j;
A3 |= (long)(bytes[index++] & 0xff) << j;
}
}
private void PackBlock(
byte[] bytes,
int off)
{
int index = off;
for (int j = 0; j != BC; j += 8)
{
bytes[index++] = (byte)(A0 >> j);
bytes[index++] = (byte)(A1 >> j);
bytes[index++] = (byte)(A2 >> j);
bytes[index++] = (byte)(A3 >> j);
}
}
private void EncryptBlock(
long[][] rk)
{
int r;
//
// begin with a key addition
//
KeyAddition(rk[0]);
//
// ROUNDS-1 ordinary rounds
//
for (r = 1; r < ROUNDS; r++)
{
Substitution(S);
ShiftRow(shifts0SC);
MixColumn();
KeyAddition(rk[r]);
}
//
// Last round is special: there is no MixColumn
//
Substitution(S);
ShiftRow(shifts0SC);
KeyAddition(rk[ROUNDS]);
}
private void DecryptBlock(
long[][] rk)
{
int r;
// To decrypt: apply the inverse operations of the encrypt routine,
// in opposite order
//
// (KeyAddition is an involution: it 's equal to its inverse)
// (the inverse of Substitution with table S is Substitution with the inverse table of S)
// (the inverse of Shiftrow is Shiftrow over a suitable distance)
//
// First the special round:
// without InvMixColumn
// with extra KeyAddition
//
KeyAddition(rk[ROUNDS]);
Substitution(Si);
ShiftRow(shifts1SC);
//
// ROUNDS-1 ordinary rounds
//
for (r = ROUNDS-1; r > 0; r--)
{
KeyAddition(rk[r]);
InvMixColumn();
Substitution(Si);
ShiftRow(shifts1SC);
}
//
// End with the extra key addition
//
KeyAddition(rk[0]);
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* this does your basic RSA algorithm.
*/
public class RsaEngine
: IAsymmetricBlockCipher
{
private RsaCoreEngine core;
public string AlgorithmName
{
get { return "RSA"; }
}
/**
* initialise the RSA engine.
*
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (core == null)
core = new RsaCoreEngine();
core.Init(forEncryption, parameters);
}
/**
* Return the maximum size for an input block to this engine.
* For RSA this is always one byte less than the key size on
* encryption, and the same length as the key size on decryption.
*
* @return maximum size for an input block.
*/
public int GetInputBlockSize()
{
return core.GetInputBlockSize();
}
/**
* Return the maximum size for an output block to this engine.
* For RSA this is always one byte less than the key size on
* decryption, and the same length as the key size on encryption.
*
* @return maximum size for an output block.
*/
public int GetOutputBlockSize()
{
return core.GetOutputBlockSize();
}
/**
* Process a single block using the basic RSA algorithm.
*
* @param inBuf the input array.
* @param inOff the offset into the input buffer where the data starts.
* @param inLen the length of the data to be processed.
* @return the result of the RSA process.
* @exception DataLengthException the input block is too large.
*/
public byte[] ProcessBlock(
byte[] inBuf,
int inOff,
int inLen)
{
if (core == null)
throw new InvalidOperationException("RSA engine not initialised");
return core.ConvertOutput(core.ProcessBlock(core.ConvertInput(inBuf, inOff, inLen)));
}
}
}

View File

@@ -0,0 +1,361 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Implementation of the SEED algorithm as described in RFC 4009
*/
public class SeedEngine
: IBlockCipher
{
private const int BlockSize = 16;
private static readonly uint[] SS0 =
{
0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038,
0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330,
0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
};
private static readonly uint[] SS1 =
{
0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171,
0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
};
private static readonly uint[] SS2 =
{
0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808,
0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303,
0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
};
private static readonly uint[] SS3 =
{
0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031,
0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
};
private static readonly uint[] KC =
{
0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc,
0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf,
0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1,
0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b
};
private int[] wKey;
private bool forEncryption;
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
}
public string AlgorithmName
{
get { return "SEED"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BlockSize;
}
public int ProcessBlock(
byte[] inBuf,
int inOff,
byte[] outBuf,
int outOff)
{
if (wKey == null)
throw new InvalidOperationException("SEED engine not initialised");
if (inOff + BlockSize > inBuf.Length)
throw new DataLengthException("input buffer too short");
if (outOff + BlockSize > outBuf.Length)
throw new DataLengthException("output buffer too short");
long l = bytesToLong(inBuf, inOff + 0);
long r = bytesToLong(inBuf, inOff + 8);
if (forEncryption)
{
for (int i = 0; i < 16; i++)
{
long nl = r;
r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
l = nl;
}
}
else
{
for (int i = 15; i >= 0; i--)
{
long nl = r;
r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
l = nl;
}
}
longToBytes(outBuf, outOff + 0, r);
longToBytes(outBuf, outOff + 8, l);
return BlockSize;
}
public void Reset()
{
}
private int[] createWorkingKey(
byte[] inKey)
{
int[] key = new int[32];
long lower = bytesToLong(inKey, 0);
long upper = bytesToLong(inKey, 8);
int key0 = extractW0(lower);
int key1 = extractW1(lower);
int key2 = extractW0(upper);
int key3 = extractW1(upper);
for (int i = 0; i < 16; i++)
{
key[2 * i] = G(key0 + key2 - (int)KC[i]);
key[2 * i + 1] = G(key1 - key3 + (int)KC[i]);
if (i % 2 == 0)
{
lower = rotateRight8(lower);
key0 = extractW0(lower);
key1 = extractW1(lower);
}
else
{
upper = rotateLeft8(upper);
key2 = extractW0(upper);
key3 = extractW1(upper);
}
}
return key;
}
private int extractW1(
long lVal)
{
return (int)lVal;
}
private int extractW0(
long lVal)
{
return (int)(lVal >> 32);
}
private long rotateLeft8(
long x)
{
return (x << 8) | ((long)((ulong) x >> 56));
}
private long rotateRight8(
long x)
{
return ((long)((ulong) x >> 8)) | (x << 56);
}
private long bytesToLong(
byte[] src,
int srcOff)
{
long word = 0;
for (int i = 0; i <= 7; i++)
{
word = (word << 8) + (src[i + srcOff] & 0xff);
}
return word;
}
private void longToBytes(
byte[] dest,
int destOff,
long value)
{
for (int i = 0; i < 8; i++)
{
dest[i + destOff] = (byte)(value >> ((7 - i) * 8));
}
}
private int G(
int x)
{
return (int)(SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]);
}
private long F(
int ki0,
int ki1,
long r)
{
int r0 = (int)(r >> 32);
int r1 = (int)r;
int rd1 = phaseCalc2(r0, ki0, r1, ki1);
int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1);
return ((long)rd0 << 32) | (rd1 & 0xffffffffL);
}
private int phaseCalc1(
int r0,
int ki0,
int r1,
int ki1)
{
return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0));
}
private int phaseCalc2(
int r0,
int ki0,
int r1,
int ki1)
{
return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1)));
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Org.BouncyCastle.Crypto.Engines
{
/// <remarks>
/// An implementation of the SEED key wrapper based on RFC 4010/RFC 3394.
/// <p/>
/// For further details see: <a href="http://www.ietf.org/rfc/rfc4010.txt">http://www.ietf.org/rfc/rfc4010.txt</a>.
/// </remarks>
public class SeedWrapEngine
: Rfc3394WrapEngine
{
public SeedWrapEngine()
: base(new SeedEngine())
{
}
}
}

View File

@@ -0,0 +1,363 @@
using System;
using System.Text;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
*/
public class Salsa20Engine
: IStreamCipher
{
/** Constants */
private const int stateSize = 16; // 16, 32 bit ints = 64 bytes
private readonly static byte[]
sigma = Encoding.ASCII.GetBytes("expand 32-byte k"),
tau = Encoding.ASCII.GetBytes("expand 16-byte k");
/*
* variables to hold the state of the engine
* during encryption and decryption
*/
private int index = 0;
private int[] engineState = new int[stateSize]; // state
private int[] x = new int[stateSize] ; // internal buffer
private byte[] keyStream = new byte[stateSize * 4], // expanded state, 64 bytes
workingKey = null,
workingIV = null;
private bool initialised = false;
/*
* internal counter
*/
private int cW0, cW1, cW2;
/**
* initialise a Salsa20 cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception ArgumentException if the params argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
/*
* Salsa20 encryption and decryption is completely
* symmetrical, so the 'forEncryption' is
* irrelevant. (Like 90% of stream ciphers)
*/
ParametersWithIV ivParams = parameters as ParametersWithIV;
if (ivParams == null)
throw new ArgumentException("Salsa20 Init requires an IV", "parameters");
byte[] iv = ivParams.GetIV();
if (iv == null || iv.Length != 8)
throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV");
KeyParameter key = ivParams.Parameters as KeyParameter;
if (key == null)
throw new ArgumentException("Salsa20 Init requires a key", "parameters");
workingKey = key.GetKey();
workingIV = iv;
setKey(workingKey, workingIV);
}
public string AlgorithmName
{
get { return "Salsa20"; }
}
public byte ReturnByte(
byte input)
{
if (limitExceeded())
{
throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV");
}
if (index == 0)
{
salsa20WordToByte(engineState, keyStream);
engineState[8]++;
if (engineState[8] == 0)
{
engineState[9]++;
}
}
byte output = (byte)(keyStream[index]^input);
index = (index + 1) & 63;
return output;
}
public void ProcessBytes(
byte[] inBytes,
int inOff,
int len,
byte[] outBytes,
int outOff)
{
if (!initialised)
{
throw new InvalidOperationException(AlgorithmName + " not initialised");
}
if ((inOff + len) > inBytes.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + len) > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
if (limitExceeded(len))
{
throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
}
for (int i = 0; i < len; i++)
{
if (index == 0)
{
salsa20WordToByte(engineState, keyStream);
engineState[8]++;
if (engineState[8] == 0)
{
engineState[9]++;
}
}
outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]);
index = (index + 1) & 63;
}
}
public void Reset()
{
setKey(workingKey, workingIV);
}
// Private implementation
private void setKey(byte[] keyBytes, byte[] ivBytes)
{
workingKey = keyBytes;
workingIV = ivBytes;
index = 0;
resetCounter();
int offset = 0;
byte[] constants;
// Key
engineState[1] = byteToIntLittle(workingKey, 0);
engineState[2] = byteToIntLittle(workingKey, 4);
engineState[3] = byteToIntLittle(workingKey, 8);
engineState[4] = byteToIntLittle(workingKey, 12);
if (workingKey.Length == 32)
{
constants = sigma;
offset = 16;
}
else
{
constants = tau;
}
engineState[11] = byteToIntLittle(workingKey, offset);
engineState[12] = byteToIntLittle(workingKey, offset+4);
engineState[13] = byteToIntLittle(workingKey, offset+8);
engineState[14] = byteToIntLittle(workingKey, offset+12);
engineState[0 ] = byteToIntLittle(constants, 0);
engineState[5 ] = byteToIntLittle(constants, 4);
engineState[10] = byteToIntLittle(constants, 8);
engineState[15] = byteToIntLittle(constants, 12);
// IV
engineState[6] = byteToIntLittle(workingIV, 0);
engineState[7] = byteToIntLittle(workingIV, 4);
engineState[8] = engineState[9] = 0;
initialised = true;
}
/**
* Salsa20 function
*
* @param input input data
*
* @return keystream
*/
private void salsa20WordToByte(
int[] input,
byte[] output)
{
Array.Copy(input, 0, x, 0, input.Length);
for (int i = 0; i < 10; i++)
{
x[ 4] ^= rotl((x[ 0]+x[12]), 7);
x[ 8] ^= rotl((x[ 4]+x[ 0]), 9);
x[12] ^= rotl((x[ 8]+x[ 4]),13);
x[ 0] ^= rotl((x[12]+x[ 8]),18);
x[ 9] ^= rotl((x[ 5]+x[ 1]), 7);
x[13] ^= rotl((x[ 9]+x[ 5]), 9);
x[ 1] ^= rotl((x[13]+x[ 9]),13);
x[ 5] ^= rotl((x[ 1]+x[13]),18);
x[14] ^= rotl((x[10]+x[ 6]), 7);
x[ 2] ^= rotl((x[14]+x[10]), 9);
x[ 6] ^= rotl((x[ 2]+x[14]),13);
x[10] ^= rotl((x[ 6]+x[ 2]),18);
x[ 3] ^= rotl((x[15]+x[11]), 7);
x[ 7] ^= rotl((x[ 3]+x[15]), 9);
x[11] ^= rotl((x[ 7]+x[ 3]),13);
x[15] ^= rotl((x[11]+x[ 7]),18);
x[ 1] ^= rotl((x[ 0]+x[ 3]), 7);
x[ 2] ^= rotl((x[ 1]+x[ 0]), 9);
x[ 3] ^= rotl((x[ 2]+x[ 1]),13);
x[ 0] ^= rotl((x[ 3]+x[ 2]),18);
x[ 6] ^= rotl((x[ 5]+x[ 4]), 7);
x[ 7] ^= rotl((x[ 6]+x[ 5]), 9);
x[ 4] ^= rotl((x[ 7]+x[ 6]),13);
x[ 5] ^= rotl((x[ 4]+x[ 7]),18);
x[11] ^= rotl((x[10]+x[ 9]), 7);
x[ 8] ^= rotl((x[11]+x[10]), 9);
x[ 9] ^= rotl((x[ 8]+x[11]),13);
x[10] ^= rotl((x[ 9]+x[ 8]),18);
x[12] ^= rotl((x[15]+x[14]), 7);
x[13] ^= rotl((x[12]+x[15]), 9);
x[14] ^= rotl((x[13]+x[12]),13);
x[15] ^= rotl((x[14]+x[13]),18);
}
int offset = 0;
for (int i = 0; i < stateSize; i++)
{
intToByteLittle(x[i] + input[i], output, offset);
offset += 4;
}
for (int i = stateSize; i < x.Length; i++)
{
intToByteLittle(x[i], output, offset);
offset += 4;
}
}
/**
* 32 bit word to 4 byte array in little endian order
*
* @param x value to 'unpack'
*
* @return value of x expressed as a byte[] array in little endian order
*/
private byte[] intToByteLittle(
int x,
byte[] bs,
int off)
{
bs[off] = (byte)x;
bs[off + 1] = (byte)(x >> 8);
bs[off + 2] = (byte)(x >> 16);
bs[off + 3] = (byte)(x >> 24);
return bs;
}
/**
* Rotate left
*
* @param x value to rotate
* @param y amount to rotate x
*
* @return rotated x
*/
private int rotl(
int x,
int y)
{
return (x << y) | ((int)((uint) x >> -y));
}
/**
* Pack byte[] array into an int in little endian order
*
* @param x byte array to 'pack'
* @param offset only x[offset]..x[offset+3] will be packed
*
* @return x[offset]..x[offset+3] 'packed' into an int in little-endian order
*/
private int byteToIntLittle(
byte[] x,
int offset)
{
return ((x[offset] & 255)) |
((x[offset + 1] & 255) << 8) |
((x[offset + 2] & 255) << 16) |
(x[offset + 3] << 24);
}
private void resetCounter()
{
cW0 = 0;
cW1 = 0;
cW2 = 0;
}
private bool limitExceeded()
{
cW0++;
if (cW0 == 0)
{
cW1++;
if (cW1 == 0)
{
cW2++;
return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
}
}
return false;
}
/*
* this relies on the fact len will always be positive.
*/
private bool limitExceeded(
int len)
{
if (cW0 >= 0)
{
cW0 += len;
}
else
{
cW0 += len;
if (cW0 >= 0)
{
cW1++;
if (cW1 == 0)
{
cW2++;
return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
}
}
}
return false;
}
}
}

View File

@@ -0,0 +1,779 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* Serpent is a 128-bit 32-round block cipher with variable key lengths,
* including 128, 192 and 256 bit keys conjectured to be at least as
* secure as three-key triple-DES.
* <p>
* Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
* candidate algorithm for the NIST AES Quest.>
* </p>
* <p>
* For full details see the <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
* </p>
*/
public class SerpentEngine
: IBlockCipher
{
private const int BLOCK_SIZE = 16;
static readonly int ROUNDS = 32;
static readonly int PHI = unchecked((int)0x9E3779B9); // (Sqrt(5) - 1) * 2**31
private bool encrypting;
private int[] wKey;
private int X0, X1, X2, X3; // registers
/**
* initialise a Serpent cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to Serpent init - " + parameters.GetType().ToString());
this.encrypting = forEncryption;
this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
}
public string AlgorithmName
{
get { return "Serpent"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out the array the output data will be copied into.
* @param outOff the offset into the out array the output will start at.
* @exception DataLengthException if there isn't enough data in in, or
* space in out.
* @exception InvalidOperationException if the cipher isn't initialised.
* @return the number of bytes processed and produced.
*/
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (wKey == null)
throw new InvalidOperationException("Serpent not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
}
/**
* Expand a user-supplied key material into a session key.
*
* @param key The user-key bytes (multiples of 4) to use.
* @exception ArgumentException
*/
private int[] MakeWorkingKey(
byte[] key)
{
//
// pad key to 256 bits
//
int[] kPad = new int[16];
int off = 0;
int length = 0;
for (off = key.Length - 4; off > 0; off -= 4)
{
kPad[length++] = BytesToWord(key, off);
}
if (off == 0)
{
kPad[length++] = BytesToWord(key, 0);
if (length < 8)
{
kPad[length] = 1;
}
}
else
{
throw new ArgumentException("key must be a multiple of 4 bytes");
}
//
// expand the padded key up to 33 x 128 bits of key material
//
int amount = (ROUNDS + 1) * 4;
int[] w = new int[amount];
//
// compute w0 to w7 from w-8 to w-1
//
for (int i = 8; i < 16; i++)
{
kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
}
Array.Copy(kPad, 8, w, 0, 8);
//
// compute w8 to w136
//
for (int i = 8; i < amount; i++)
{
w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
}
//
// create the working keys by processing w with the Sbox and IP
//
Sb3(w[0], w[1], w[2], w[3]);
w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
Sb2(w[4], w[5], w[6], w[7]);
w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
Sb1(w[8], w[9], w[10], w[11]);
w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
Sb0(w[12], w[13], w[14], w[15]);
w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
Sb7(w[16], w[17], w[18], w[19]);
w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
Sb6(w[20], w[21], w[22], w[23]);
w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
Sb5(w[24], w[25], w[26], w[27]);
w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
Sb4(w[28], w[29], w[30], w[31]);
w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
Sb3(w[32], w[33], w[34], w[35]);
w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
Sb2(w[36], w[37], w[38], w[39]);
w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
Sb1(w[40], w[41], w[42], w[43]);
w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
Sb0(w[44], w[45], w[46], w[47]);
w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
Sb7(w[48], w[49], w[50], w[51]);
w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
Sb6(w[52], w[53], w[54], w[55]);
w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
Sb5(w[56], w[57], w[58], w[59]);
w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
Sb4(w[60], w[61], w[62], w[63]);
w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
Sb3(w[64], w[65], w[66], w[67]);
w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
Sb2(w[68], w[69], w[70], w[71]);
w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
Sb1(w[72], w[73], w[74], w[75]);
w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
Sb0(w[76], w[77], w[78], w[79]);
w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
Sb7(w[80], w[81], w[82], w[83]);
w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
Sb6(w[84], w[85], w[86], w[87]);
w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
Sb5(w[88], w[89], w[90], w[91]);
w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
Sb4(w[92], w[93], w[94], w[95]);
w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
Sb3(w[96], w[97], w[98], w[99]);
w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
Sb2(w[100], w[101], w[102], w[103]);
w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
Sb1(w[104], w[105], w[106], w[107]);
w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
Sb0(w[108], w[109], w[110], w[111]);
w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
Sb7(w[112], w[113], w[114], w[115]);
w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
Sb6(w[116], w[117], w[118], w[119]);
w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
Sb5(w[120], w[121], w[122], w[123]);
w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
Sb4(w[124], w[125], w[126], w[127]);
w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
Sb3(w[128], w[129], w[130], w[131]);
w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
return w;
}
private int RotateLeft(
int x,
int bits)
{
return ((x << bits) | (int) ((uint)x >> (32 - bits)));
}
private int RotateRight(
int x,
int bits)
{
return ( (int)((uint)x >> bits) | (x << (32 - bits)));
}
private int BytesToWord(
byte[] src,
int srcOff)
{
return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) |
((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff)));
}
private void WordToBytes(
int word,
byte[] dst,
int dstOff)
{
dst[dstOff + 3] = (byte)(word);
dst[dstOff + 2] = (byte)((uint)word >> 8);
dst[dstOff + 1] = (byte)((uint)word >> 16);
dst[dstOff] = (byte)((uint)word >> 24);
}
/**
* Encrypt one block of plaintext.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out the array the output data will be copied into.
* @param outOff the offset into the out array the output will start at.
*/
private void EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
X3 = BytesToWord(input, inOff);
X2 = BytesToWord(input, inOff + 4);
X1 = BytesToWord(input, inOff + 8);
X0 = BytesToWord(input, inOff + 12);
Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
WordToBytes(wKey[131] ^ X3, outBytes, outOff);
WordToBytes(wKey[130] ^ X2, outBytes, outOff + 4);
WordToBytes(wKey[129] ^ X1, outBytes, outOff + 8);
WordToBytes(wKey[128] ^ X0, outBytes, outOff + 12);
}
/**
* Decrypt one block of ciphertext.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out the array the output data will be copied into.
* @param outOff the offset into the out array the output will start at.
*/
private void DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
X3 = wKey[131] ^ BytesToWord(input, inOff);
X2 = wKey[130] ^ BytesToWord(input, inOff + 4);
X1 = wKey[129] ^ BytesToWord(input, inOff + 8);
X0 = wKey[128] ^ BytesToWord(input, inOff + 12);
Ib7(X0, X1, X2, X3);
X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
InverseLT(); Ib6(X0, X1, X2, X3);
X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
InverseLT(); Ib5(X0, X1, X2, X3);
X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
InverseLT(); Ib4(X0, X1, X2, X3);
X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
InverseLT(); Ib3(X0, X1, X2, X3);
X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
InverseLT(); Ib2(X0, X1, X2, X3);
X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
InverseLT(); Ib1(X0, X1, X2, X3);
X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
InverseLT(); Ib0(X0, X1, X2, X3);
X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
InverseLT(); Ib7(X0, X1, X2, X3);
X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
InverseLT(); Ib6(X0, X1, X2, X3);
X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
InverseLT(); Ib5(X0, X1, X2, X3);
X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
InverseLT(); Ib4(X0, X1, X2, X3);
X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
InverseLT(); Ib3(X0, X1, X2, X3);
X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
InverseLT(); Ib2(X0, X1, X2, X3);
X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
InverseLT(); Ib1(X0, X1, X2, X3);
X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
InverseLT(); Ib0(X0, X1, X2, X3);
X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
InverseLT(); Ib7(X0, X1, X2, X3);
X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
InverseLT(); Ib6(X0, X1, X2, X3);
X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
InverseLT(); Ib5(X0, X1, X2, X3);
X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
InverseLT(); Ib4(X0, X1, X2, X3);
X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
InverseLT(); Ib3(X0, X1, X2, X3);
X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
InverseLT(); Ib2(X0, X1, X2, X3);
X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
InverseLT(); Ib1(X0, X1, X2, X3);
X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
InverseLT(); Ib0(X0, X1, X2, X3);
X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
InverseLT(); Ib7(X0, X1, X2, X3);
X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
InverseLT(); Ib6(X0, X1, X2, X3);
X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
InverseLT(); Ib5(X0, X1, X2, X3);
X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
InverseLT(); Ib4(X0, X1, X2, X3);
X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
InverseLT(); Ib3(X0, X1, X2, X3);
X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
InverseLT(); Ib2(X0, X1, X2, X3);
X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
InverseLT(); Ib1(X0, X1, X2, X3);
X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
InverseLT(); Ib0(X0, X1, X2, X3);
WordToBytes(X3 ^ wKey[3], outBytes, outOff);
WordToBytes(X2 ^ wKey[2], outBytes, outOff + 4);
WordToBytes(X1 ^ wKey[1], outBytes, outOff + 8);
WordToBytes(X0 ^ wKey[0], outBytes, outOff + 12);
}
/*
* The sboxes below are based on the work of Brian Gladman and
* Sam Simpson, whose original notice appears below.
* <p>
* For further details see:
* http://fp.gladman.plus.com/cryptography_technology/serpent/
* </p>
*/
/* Partially optimised Serpent S Box bool functions derived */
/* using a recursive descent analyser but without a full search */
/* of all subtrees. This set of S boxes is the result of work */
/* by Sam Simpson and Brian Gladman using the spare time on a */
/* cluster of high capacity servers to search for S boxes with */
/* this customised search engine. There are now an average of */
/* 15.375 terms per S box. */
/* */
/* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */
/* and Sam Simpson (s.simpson@mia.co.uk) */
/* 17th December 1998 */
/* */
/* We hereby give permission for information in this file to be */
/* used freely subject only to acknowledgement of its origin. */
/**
* S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
*/
private void Sb0(int a, int b, int c, int d)
{
int t1 = a ^ d;
int t3 = c ^ t1;
int t4 = b ^ t3;
X3 = (a & d) ^ t4;
int t7 = a ^ (b & t1);
X2 = t4 ^ (c | t7);
int t12 = X3 & (t3 ^ t7);
X1 = (~t3) ^ t12;
X0 = t12 ^ (~t7);
}
/**
* InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
*/
private void Ib0(int a, int b, int c, int d)
{
int t1 = ~a;
int t2 = a ^ b;
int t4 = d ^ (t1 | t2);
int t5 = c ^ t4;
X2 = t2 ^ t5;
int t8 = t1 ^ (d & t2);
X1 = t4 ^ (X2 & t8);
X3 = (a & t4) ^ (t5 | X1);
X0 = X3 ^ (t5 ^ t8);
}
/**
* S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
*/
private void Sb1(int a, int b, int c, int d)
{
int t2 = b ^ (~a);
int t5 = c ^ (a | t2);
X2 = d ^ t5;
int t7 = b ^ (d | t2);
int t8 = t2 ^ X2;
X3 = t8 ^ (t5 & t7);
int t11 = t5 ^ t7;
X1 = X3 ^ t11;
X0 = t5 ^ (t8 & t11);
}
/**
* InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
*/
private void Ib1(int a, int b, int c, int d)
{
int t1 = b ^ d;
int t3 = a ^ (b & t1);
int t4 = t1 ^ t3;
X3 = c ^ t4;
int t7 = b ^ (t1 & t3);
int t8 = X3 | t7;
X1 = t3 ^ t8;
int t10 = ~X1;
int t11 = X3 ^ t7;
X0 = t10 ^ t11;
X2 = t4 ^ (t10 | t11);
}
/**
* S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
*/
private void Sb2(int a, int b, int c, int d)
{
int t1 = ~a;
int t2 = b ^ d;
int t3 = c & t1;
X0 = t2 ^ t3;
int t5 = c ^ t1;
int t6 = c ^ X0;
int t7 = b & t6;
X3 = t5 ^ t7;
X2 = a ^ ((d | t7) & (X0 | t5));
X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
}
/**
* InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
*/
private void Ib2(int a, int b, int c, int d)
{
int t1 = b ^ d;
int t2 = ~t1;
int t3 = a ^ c;
int t4 = c ^ t1;
int t5 = b & t4;
X0 = t3 ^ t5;
int t7 = a | t2;
int t8 = d ^ t7;
int t9 = t3 | t8;
X3 = t1 ^ t9;
int t11 = ~t4;
int t12 = X0 | X3;
X1 = t11 ^ t12;
X2 = (d & t11) ^ (t3 ^ t12);
}
/**
* S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
*/
private void Sb3(int a, int b, int c, int d)
{
int t1 = a ^ b;
int t2 = a & c;
int t3 = a | d;
int t4 = c ^ d;
int t5 = t1 & t3;
int t6 = t2 | t5;
X2 = t4 ^ t6;
int t8 = b ^ t3;
int t9 = t6 ^ t8;
int t10 = t4 & t9;
X0 = t1 ^ t10;
int t12 = X2 & X0;
X1 = t9 ^ t12;
X3 = (b | d) ^ (t4 ^ t12);
}
/**
* InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
*/
private void Ib3(int a, int b, int c, int d)
{
int t1 = a | b;
int t2 = b ^ c;
int t3 = b & t2;
int t4 = a ^ t3;
int t5 = c ^ t4;
int t6 = d | t4;
X0 = t2 ^ t6;
int t8 = t2 | t6;
int t9 = d ^ t8;
X2 = t5 ^ t9;
int t11 = t1 ^ t9;
int t12 = X0 & t11;
X3 = t4 ^ t12;
X1 = X3 ^ (X0 ^ t11);
}
/**
* S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
*/
private void Sb4(int a, int b, int c, int d)
{
int t1 = a ^ d;
int t2 = d & t1;
int t3 = c ^ t2;
int t4 = b | t3;
X3 = t1 ^ t4;
int t6 = ~b;
int t7 = t1 | t6;
X0 = t3 ^ t7;
int t9 = a & X0;
int t10 = t1 ^ t6;
int t11 = t4 & t10;
X2 = t9 ^ t11;
X1 = (a ^ t3) ^ (t10 & X2);
}
/**
* InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
*/
private void Ib4(int a, int b, int c, int d)
{
int t1 = c | d;
int t2 = a & t1;
int t3 = b ^ t2;
int t4 = a & t3;
int t5 = c ^ t4;
X1 = d ^ t5;
int t7 = ~a;
int t8 = t5 & X1;
X3 = t3 ^ t8;
int t10 = X1 | t7;
int t11 = d ^ t10;
X0 = X3 ^ t11;
X2 = (t3 & t11) ^ (X1 ^ t7);
}
/**
* S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
*/
private void Sb5(int a, int b, int c, int d)
{
int t1 = ~a;
int t2 = a ^ b;
int t3 = a ^ d;
int t4 = c ^ t1;
int t5 = t2 | t3;
X0 = t4 ^ t5;
int t7 = d & X0;
int t8 = t2 ^ X0;
X1 = t7 ^ t8;
int t10 = t1 | X0;
int t11 = t2 | t7;
int t12 = t3 ^ t10;
X2 = t11 ^ t12;
X3 = (b ^ t7) ^ (X1 & t12);
}
/**
* InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
*/
private void Ib5(int a, int b, int c, int d)
{
int t1 = ~c;
int t2 = b & t1;
int t3 = d ^ t2;
int t4 = a & t3;
int t5 = b ^ t1;
X3 = t4 ^ t5;
int t7 = b | X3;
int t8 = a & t7;
X1 = t3 ^ t8;
int t10 = a | d;
int t11 = t1 ^ t7;
X0 = t10 ^ t11;
X2 = (b & t10) ^ (t4 | (a ^ c));
}
/**
* S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
*/
private void Sb6(int a, int b, int c, int d)
{
int t1 = ~a;
int t2 = a ^ d;
int t3 = b ^ t2;
int t4 = t1 | t2;
int t5 = c ^ t4;
X1 = b ^ t5;
int t7 = t2 | X1;
int t8 = d ^ t7;
int t9 = t5 & t8;
X2 = t3 ^ t9;
int t11 = t5 ^ t8;
X0 = X2 ^ t11;
X3 = (~t5) ^ (t3 & t11);
}
/**
* InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
*/
private void Ib6(int a, int b, int c, int d)
{
int t1 = ~a;
int t2 = a ^ b;
int t3 = c ^ t2;
int t4 = c | t1;
int t5 = d ^ t4;
X1 = t3 ^ t5;
int t7 = t3 & t5;
int t8 = t2 ^ t7;
int t9 = b | t8;
X3 = t5 ^ t9;
int t11 = b | X3;
X0 = t8 ^ t11;
X2 = (d & t1) ^ (t3 ^ t11);
}
/**
* S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
*/
private void Sb7(int a, int b, int c, int d)
{
int t1 = b ^ c;
int t2 = c & t1;
int t3 = d ^ t2;
int t4 = a ^ t3;
int t5 = d | t1;
int t6 = t4 & t5;
X1 = b ^ t6;
int t8 = t3 | X1;
int t9 = a & t4;
X3 = t1 ^ t9;
int t11 = t4 ^ t8;
int t12 = X3 & t11;
X2 = t3 ^ t12;
X0 = (~t11) ^ (X3 & X2);
}
/**
* InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
*/
private void Ib7(int a, int b, int c, int d)
{
int t3 = c | (a & b);
int t4 = d & (a | b);
X3 = t3 ^ t4;
int t6 = ~d;
int t7 = b ^ t4;
int t9 = t7 | (X3 ^ t6);
X1 = a ^ t9;
X0 = (c ^ t7) ^ (d | X1);
X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
}
/**
* Apply the linear transformation to the register set.
*/
private void LT()
{
int x0 = RotateLeft(X0, 13);
int x2 = RotateLeft(X2, 3);
int x1 = X1 ^ x0 ^ x2 ;
int x3 = X3 ^ x2 ^ x0 << 3;
X1 = RotateLeft(x1, 1);
X3 = RotateLeft(x3, 7);
X0 = RotateLeft(x0 ^ X1 ^ X3, 5);
X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
}
/**
* Apply the inverse of the linear transformation to the register set.
*/
private void InverseLT()
{
int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
int x3 = RotateRight(X3, 7);
int x1 = RotateRight(X1, 1);
X3 = x3 ^ x2 ^ x0 << 3;
X1 = x1 ^ x0 ^ x2;
X2 = RotateRight(x2, 3);
X0 = RotateRight(x0, 13);
}
}
}

View File

@@ -0,0 +1,255 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* a class that provides a basic SKIPJACK engine.
*/
public class SkipjackEngine
: IBlockCipher
{
const int BLOCK_SIZE = 8;
static readonly short [] ftable =
{
0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
};
private int[] key0, key1, key2, key3;
private bool encrypting;
/**
* initialise a SKIPJACK cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + parameters.GetType().ToString());
byte[] keyBytes = ((KeyParameter)parameters).GetKey();
this.encrypting = forEncryption;
this.key0 = new int[32];
this.key1 = new int[32];
this.key2 = new int[32];
this.key3 = new int[32];
//
// expand the key to 128 bytes in 4 parts (saving us a modulo, multiply
// and an addition).
//
for (int i = 0; i < 32; i ++)
{
key0[i] = keyBytes[(i * 4) % 10] & 0xff;
key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff;
key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff;
key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff;
}
}
public string AlgorithmName
{
get { return "SKIPJACK"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (key1 == null)
throw new InvalidOperationException("SKIPJACK engine not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
}
/**
* The G permutation
*/
private int G(
int k,
int w)
{
int g1, g2, g3, g4, g5, g6;
g1 = (w >> 8) & 0xff;
g2 = w & 0xff;
g3 = ftable[g2 ^ key0[k]] ^ g1;
g4 = ftable[g3 ^ key1[k]] ^ g2;
g5 = ftable[g4 ^ key2[k]] ^ g3;
g6 = ftable[g5 ^ key3[k]] ^ g4;
return ((g5 << 8) + g6);
}
public int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
int w3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
int w4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
int k = 0;
for (int t = 0; t < 2; t++)
{
for(int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
w3 = w2;
w2 = G(k, w1);
w1 = w2 ^ tmp ^ (k + 1);
k++;
}
for(int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
w3 = w1 ^ w2 ^ (k + 1);
w2 = G(k, w1);
w1 = tmp;
k++;
}
}
outBytes[outOff + 0] = (byte)((w1 >> 8));
outBytes[outOff + 1] = (byte)(w1);
outBytes[outOff + 2] = (byte)((w2 >> 8));
outBytes[outOff + 3] = (byte)(w2);
outBytes[outOff + 4] = (byte)((w3 >> 8));
outBytes[outOff + 5] = (byte)(w3);
outBytes[outOff + 6] = (byte)((w4 >> 8));
outBytes[outOff + 7] = (byte)(w4);
return BLOCK_SIZE;
}
/**
* the inverse of the G permutation.
*/
private int H(
int k,
int w)
{
int h1, h2, h3, h4, h5, h6;
h1 = w & 0xff;
h2 = (w >> 8) & 0xff;
h3 = ftable[h2 ^ key3[k]] ^ h1;
h4 = ftable[h3 ^ key2[k]] ^ h2;
h5 = ftable[h4 ^ key1[k]] ^ h3;
h6 = ftable[h5 ^ key0[k]] ^ h4;
return ((h6 << 8) + h5);
}
public int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
int w4 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
int w3 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
int k = 31;
for (int t = 0; t < 2; t++)
{
for(int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
w3 = w2;
w2 = H(k, w1);
w1 = w2 ^ tmp ^ (k + 1);
k--;
}
for(int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
w3 = w1 ^ w2 ^ (k + 1);
w2 = H(k, w1);
w1 = tmp;
k--;
}
}
outBytes[outOff + 0] = (byte)((w2 >> 8));
outBytes[outOff + 1] = (byte)(w2);
outBytes[outOff + 2] = (byte)((w1 >> 8));
outBytes[outOff + 3] = (byte)(w1);
outBytes[outOff + 4] = (byte)((w4 >> 8));
outBytes[outOff + 5] = (byte)(w4);
outBytes[outOff + 6] = (byte)((w3 >> 8));
outBytes[outOff + 7] = (byte)(w3);
return BLOCK_SIZE;
}
}
}

View File

@@ -0,0 +1,191 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* An TEA engine.
*/
public class TeaEngine
: IBlockCipher
{
private const int
rounds = 32,
block_size = 8,
key_size = 16,
delta = unchecked((int) 0x9E3779B9),
d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt
/*
* the expanded key array of 4 subkeys
*/
private int _a, _b, _c, _d;
private bool _initialised;
private bool _forEncryption;
/**
* Create an instance of the TEA encryption algorithm
* and set some defaults
*/
public TeaEngine()
{
_initialised = false;
}
public string AlgorithmName
{
get { return "TEA"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return block_size;
}
/**
* initialise
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception ArgumentException if the params argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to TEA init - "
+ parameters.GetType().FullName);
}
_forEncryption = forEncryption;
_initialised = true;
KeyParameter p = (KeyParameter) parameters;
setKey(p.GetKey());
}
public int ProcessBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + block_size) > inBytes.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + block_size) > outBytes.Length)
throw new DataLengthException("output buffer too short");
return _forEncryption
? encryptBlock(inBytes, inOff, outBytes, outOff)
: decryptBlock(inBytes, inOff, outBytes, outOff);
}
public void Reset()
{
}
/**
* Re-key the cipher.
*
* @param key the key to be used
*/
private void setKey(
byte[] key)
{
_a = bytesToInt(key, 0);
_b = bytesToInt(key, 4);
_c = bytesToInt(key, 8);
_d = bytesToInt(key, 12);
}
private int encryptBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
// Pack bytes into integers
int v0 = bytesToInt(inBytes, inOff);
int v1 = bytesToInt(inBytes, inOff + 4);
int sum = 0;
for (int i = 0; i != rounds; i++)
{
sum += delta;
// v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b);
// v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d);
}
unpackInt(v0, outBytes, outOff);
unpackInt(v1, outBytes, outOff + 4);
return block_size;
}
private int decryptBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
// Pack bytes into integers
int v0 = bytesToInt(inBytes, inOff);
int v1 = bytesToInt(inBytes, inOff + 4);
int sum = d_sum;
for (int i = 0; i != rounds; i++)
{
// v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d);
// v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b);
sum -= delta;
}
unpackInt(v0, outBytes, outOff);
unpackInt(v1, outBytes, outOff + 4);
return block_size;
}
private int bytesToInt(
byte[] b,
int inOff)
{
return ((b[inOff++]) << 24)
| ((b[inOff++] & 255) << 16)
| ((b[inOff++] & 255) << 8)
| ((b[inOff] & 255));
}
private void unpackInt(
int v,
byte[] b,
int outOff)
{
uint uv = (uint) v;
b[outOff++] = (byte)(uv >> 24);
b[outOff++] = (byte)(uv >> 16);
b[outOff++] = (byte)(uv >> 8);
b[outOff ] = (byte)uv;
}
}
}

View File

@@ -0,0 +1,673 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* A class that provides Twofish encryption operations.
*
* This Java implementation is based on the Java reference
* implementation provided by Bruce Schneier and developed
* by Raif S. Naffah.
*/
public sealed class TwofishEngine
: IBlockCipher
{
private static readonly byte[,] P = {
{ // p0
(byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
(byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
(byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
(byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
(byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
(byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
(byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
(byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
(byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
(byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
(byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
(byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
(byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
(byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
(byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
(byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
(byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
(byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
(byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
(byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
(byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
(byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
(byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
(byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
(byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
(byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
(byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
(byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
(byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
(byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
(byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
(byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
(byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
(byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
(byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
(byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
(byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
(byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
(byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
(byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
(byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
(byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
(byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
(byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
(byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
(byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
(byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
(byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
(byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
(byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
(byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
(byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
(byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
(byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
(byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
(byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
(byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
(byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
(byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
(byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
(byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
(byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
(byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
(byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
{ // p1
(byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
(byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
(byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
(byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
(byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
(byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
(byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
(byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
(byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
(byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
(byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
(byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
(byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
(byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
(byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
(byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
(byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
(byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
(byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
(byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
(byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
(byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
(byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
(byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
(byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
(byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
(byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
(byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
(byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
(byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
(byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
(byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
(byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
(byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
(byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
(byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
(byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
(byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
(byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
(byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
(byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
(byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
(byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
(byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
(byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
(byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
(byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
(byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
(byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
(byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
(byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
(byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
(byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
(byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
(byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
(byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
(byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
(byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
(byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
(byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
(byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
(byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
(byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
(byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
};
/**
* Define the fixed p0/p1 permutations used in keyed S-box lookup.
* By changing the following constant definitions, the S-boxes will
* automatically Get changed in the Twofish engine.
*/
private const int P_00 = 1;
private const int P_01 = 0;
private const int P_02 = 0;
private const int P_03 = P_01 ^ 1;
private const int P_04 = 1;
private const int P_10 = 0;
private const int P_11 = 0;
private const int P_12 = 1;
private const int P_13 = P_11 ^ 1;
private const int P_14 = 0;
private const int P_20 = 1;
private const int P_21 = 1;
private const int P_22 = 0;
private const int P_23 = P_21 ^ 1;
private const int P_24 = 0;
private const int P_30 = 0;
private const int P_31 = 1;
private const int P_32 = 1;
private const int P_33 = P_31 ^ 1;
private const int P_34 = 1;
/* Primitive polynomial for GF(256) */
private const int GF256_FDBK = 0x169;
private const int GF256_FDBK_2 = GF256_FDBK / 2;
private const int GF256_FDBK_4 = GF256_FDBK / 4;
private const int RS_GF_FDBK = 0x14D; // field generator
//====================================
// Useful constants
//====================================
private const int ROUNDS = 16;
private const int MAX_ROUNDS = 16; // bytes = 128 bits
private const int BLOCK_SIZE = 16; // bytes = 128 bits
private const int MAX_KEY_BITS = 256;
private const int INPUT_WHITEN=0;
private const int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
private const int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
private const int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
private const int SK_STEP = 0x02020202;
private const int SK_BUMP = 0x01010101;
private const int SK_ROTL = 9;
private bool encrypting;
private int[] gMDS0 = new int[MAX_KEY_BITS];
private int[] gMDS1 = new int[MAX_KEY_BITS];
private int[] gMDS2 = new int[MAX_KEY_BITS];
private int[] gMDS3 = new int[MAX_KEY_BITS];
/**
* gSubKeys[] and gSBox[] are eventually used in the
* encryption and decryption methods.
*/
private int[] gSubKeys;
private int[] gSBox;
private int k64Cnt;
private byte[] workingKey;
public TwofishEngine()
{
// calculate the MDS matrix
int[] m1 = new int[2];
int[] mX = new int[2];
int[] mY = new int[2];
int j;
for (int i=0; i< MAX_KEY_BITS ; i++)
{
j = P[0,i] & 0xff;
m1[0] = j;
mX[0] = Mx_X(j) & 0xff;
mY[0] = Mx_Y(j) & 0xff;
j = P[1,i] & 0xff;
m1[1] = j;
mX[1] = Mx_X(j) & 0xff;
mY[1] = Mx_Y(j) & 0xff;
gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
mY[P_00] << 16 | mY[P_00] << 24;
gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
mX[P_10] << 16 | m1[P_10] << 24;
gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
m1[P_20] << 16 | mY[P_20] << 24;
gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
mY[P_30] << 16 | mX[P_30] << 24;
}
}
/**
* initialise a Twofish cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to Twofish init - " + parameters.GetType().ToString());
this.encrypting = forEncryption;
this.workingKey = ((KeyParameter)parameters).GetKey();
this.k64Cnt = (this.workingKey.Length / 8); // pre-padded ?
SetKey(this.workingKey);
}
public string AlgorithmName
{
get { return "Twofish"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int ProcessBlock(
byte[] input,
int inOff,
byte[] output,
int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("Twofish not initialised");
if ((inOff + BLOCK_SIZE) > input.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + BLOCK_SIZE) > output.Length)
throw new DataLengthException("output buffer too short");
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return BLOCK_SIZE;
}
public void Reset()
{
if (this.workingKey != null)
{
SetKey(this.workingKey);
}
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
//==================================
// Private Implementation
//==================================
private void SetKey(byte[] key)
{
int[] k32e = new int[MAX_KEY_BITS/64]; // 4
int[] k32o = new int[MAX_KEY_BITS/64]; // 4
int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
gSubKeys = new int[TOTAL_SUBKEYS];
if (k64Cnt < 1)
{
throw new ArgumentException("Key size less than 64 bits");
}
if (k64Cnt > 4)
{
throw new ArgumentException("Key size larger than 256 bits");
}
/*
* k64Cnt is the number of 8 byte blocks (64 chunks)
* that are in the input key. The input key is a
* maximum of 32 bytes ( 256 bits ), so the range
* for k64Cnt is 1..4
*/
for (int i=0,p=0; i<k64Cnt ; i++)
{
p = i* 8;
k32e[i] = BytesTo32Bits(key, p);
k32o[i] = BytesTo32Bits(key, p+4);
sBoxKeys[k64Cnt-1-i] = RS_MDS_Encode(k32e[i], k32o[i]);
}
int q,A,B;
for (int i=0; i < TOTAL_SUBKEYS / 2 ; i++)
{
q = i*SK_STEP;
A = F32(q, k32e);
B = F32(q+SK_BUMP, k32o);
B = B << 8 | (int)((uint)B >> 24);
A += B;
gSubKeys[i*2] = A;
A += B;
gSubKeys[i*2 + 1] = A << SK_ROTL | (int)((uint)A >> (32-SK_ROTL));
}
/*
* fully expand the table for speed
*/
int k0 = sBoxKeys[0];
int k1 = sBoxKeys[1];
int k2 = sBoxKeys[2];
int k3 = sBoxKeys[3];
int b0, b1, b2, b3;
gSBox = new int[4*MAX_KEY_BITS];
for (int i=0; i<MAX_KEY_BITS; i++)
{
b0 = b1 = b2 = b3 = i;
switch (k64Cnt & 3)
{
case 1:
gSBox[i*2] = gMDS0[(P[P_01,b0] & 0xff) ^ M_b0(k0)];
gSBox[i*2+1] = gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)];
gSBox[i*2+0x200] = gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)];
gSBox[i*2+0x201] = gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
break;
case 0: /* 256 bits of key */
b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
goto case 3;
case 3:
b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
goto case 2;
case 2:
gSBox[i*2] = gMDS0[( P[P_01,(P[P_02,b0] & 0xff ) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)];
gSBox[i*2+1] = gMDS1[(P[P_11,(P[P_12,b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)];
gSBox[i*2+0x200] = gMDS2[(P[P_21,(P[P_22,b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)];
gSBox[i*2+0x201] = gMDS3[(P[P_31,(P[P_32,b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)];
break;
}
}
/*
* the function exits having setup the gSBox with the
* input key material.
*/
}
/**
* Encrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*
* encryptBlock uses the pre-calculated gSBox[] and subKey[]
* arrays.
*/
private void EncryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int x0 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[INPUT_WHITEN];
int x1 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[INPUT_WHITEN + 1];
int x2 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[INPUT_WHITEN + 2];
int x3 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[INPUT_WHITEN + 3];
int k = ROUND_SUBKEYS;
int t0, t1;
for (int r = 0; r < ROUNDS; r +=2)
{
t0 = Fe32_0(x0);
t1 = Fe32_3(x1);
x2 ^= t0 + t1 + gSubKeys[k++];
x2 = (int)((uint)x2 >>1) | x2 << 31;
x3 = (x3 << 1 | (int) ((uint)x3 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
t0 = Fe32_0(x2);
t1 = Fe32_3(x3);
x0 ^= t0 + t1 + gSubKeys[k++];
x0 = (int) ((uint)x0 >>1) | x0 << 31;
x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
}
Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12);
}
/**
* Decrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
private void DecryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex)
{
int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3];
int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
int t0, t1;
for (int r = 0; r< ROUNDS ; r +=2)
{
t0 = Fe32_0(x2);
t1 = Fe32_3(x3);
x1 ^= t0 + 2*t1 + gSubKeys[k--];
x0 = (x0 << 1 | (int)((uint) x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
x1 = (int) ((uint)x1 >>1) | x1 << 31;
t0 = Fe32_0(x0);
t1 = Fe32_3(x1);
x3 ^= t0 + 2*t1 + gSubKeys[k--];
x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
x3 = (int)((uint)x3 >>1) | x3 << 31;
}
Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
}
/*
* TODO: This can be optimised and made cleaner by combining
* the functionality in this function and applying it appropriately
* to the creation of the subkeys during key setup.
*/
private int F32(int x, int[] k32)
{
int b0 = M_b0(x);
int b1 = M_b1(x);
int b2 = M_b2(x);
int b3 = M_b3(x);
int k0 = k32[0];
int k1 = k32[1];
int k2 = k32[2];
int k3 = k32[3];
int result = 0;
switch (k64Cnt & 3)
{
case 1:
result = gMDS0[(P[P_01,b0] & 0xff) ^ M_b0(k0)] ^
gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)] ^
gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)] ^
gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
break;
case 0: /* 256 bits of key */
b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
goto case 3;
case 3:
b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
goto case 2;
case 2:
result =
gMDS0[(P[P_01,(P[P_02,b0]&0xff)^M_b0(k1)]&0xff)^M_b0(k0)] ^
gMDS1[(P[P_11,(P[P_12,b1]&0xff)^M_b1(k1)]&0xff)^M_b1(k0)] ^
gMDS2[(P[P_21,(P[P_22,b2]&0xff)^M_b2(k1)]&0xff)^M_b2(k0)] ^
gMDS3[(P[P_31,(P[P_32,b3]&0xff)^M_b3(k1)]&0xff)^M_b3(k0)];
break;
}
return result;
}
/**
* Use (12, 8) Reed-Solomon code over GF(256) to produce
* a key S-box 32-bit entity from 2 key material 32-bit
* entities.
*
* @param k0 first 32-bit entity
* @param k1 second 32-bit entity
* @return Remainder polynomial Generated using RS code
*/
private int RS_MDS_Encode(int k0, int k1)
{
int r = k1;
for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
{
r = RS_rem(r);
}
r ^= k0;
for (int i=0 ; i < 4 ; i++)
{
r = RS_rem(r);
}
return r;
}
/**
* Reed-Solomon code parameters: (12,8) reversible code:
* <p>
* <pre>
* G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
* </pre>
* where a = primitive root of field generator 0x14D
* </p>
*/
private int RS_rem(int x)
{
int b = (int) (((uint)x >> 24) & 0xff);
int g2 = ((b << 1) ^
((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
int g3 = ( (int)((uint)b >> 1) ^
((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2 ;
return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
}
private int LFSR1(int x)
{
return (x >> 1) ^
(((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
}
private int LFSR2(int x)
{
return (x >> 2) ^
(((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
(((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
}
private int Mx_X(int x)
{
return x ^ LFSR2(x);
} // 5B
private int Mx_Y(int x)
{
return x ^ LFSR1(x) ^ LFSR2(x);
} // EF
private int M_b0(int x)
{
return x & 0xff;
}
private int M_b1(int x)
{
return (int)((uint)x >> 8) & 0xff;
}
private int M_b2(int x)
{
return (int)((uint)x >> 16) & 0xff;
}
private int M_b3(int x)
{
return (int)((uint)x >> 24) & 0xff;
}
private int Fe32_0(int x)
{
return gSBox[ 0x000 + 2*(x & 0xff) ] ^
gSBox[ 0x001 + 2*((int)((uint)x >> 8) & 0xff) ] ^
gSBox[ 0x200 + 2*((int)((uint)x >> 16) & 0xff) ] ^
gSBox[ 0x201 + 2*((int)((uint)x >> 24) & 0xff) ];
}
private int Fe32_3(int x)
{
return gSBox[ 0x000 + 2*((int)((uint)x >> 24) & 0xff) ] ^
gSBox[ 0x001 + 2*(x & 0xff) ] ^
gSBox[ 0x200 + 2*((int)((uint)x >> 8) & 0xff) ] ^
gSBox[ 0x201 + 2*((int)((uint)x >> 16) & 0xff) ];
}
private int BytesTo32Bits(byte[] b, int p)
{
return ((b[p] & 0xff) ) |
((b[p+1] & 0xff) << 8) |
((b[p+2] & 0xff) << 16) |
((b[p+3] & 0xff) << 24);
}
private void Bits32ToBytes(int inData, byte[] b, int offset)
{
b[offset] = (byte)inData;
b[offset + 1] = (byte)(inData >> 8);
b[offset + 2] = (byte)(inData >> 16);
b[offset + 3] = (byte)(inData >> 24);
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
public class VmpcEngine
: IStreamCipher
{
/*
* variables to hold the state of the VMPC engine during encryption and
* decryption
*/
protected byte n = 0;
protected byte[] P = null;
protected byte s = 0;
protected byte[] workingIV;
protected byte[] workingKey;
public virtual string AlgorithmName
{
get { return "VMPC"; }
}
/**
* initialise a VMPC cipher.
*
* @param forEncryption
* whether or not we are for encryption.
* @param params
* the parameters required to set up the cipher.
* @exception ArgumentException
* if the params argument is inappropriate.
*/
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is ParametersWithIV))
throw new ArgumentException("VMPC Init parameters must include an IV");
ParametersWithIV ivParams = (ParametersWithIV) parameters;
KeyParameter key = (KeyParameter) ivParams.Parameters;
if (!(ivParams.Parameters is KeyParameter))
throw new ArgumentException("VMPC Init parameters must include a key");
this.workingIV = ivParams.GetIV();
if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
this.workingKey = key.GetKey();
InitKey(this.workingKey, this.workingIV);
}
protected virtual void InitKey(
byte[] keyBytes,
byte[] ivBytes)
{
s = 0;
P = new byte[256];
for (int i = 0; i < 256; i++)
{
P[i] = (byte) i;
}
for (int m = 0; m < 768; m++)
{
s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
byte temp = P[m & 0xff];
P[m & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
}
for (int m = 0; m < 768; m++)
{
s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
byte temp = P[m & 0xff];
P[m & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
}
n = 0;
}
public virtual void ProcessBytes(
byte[] input,
int inOff,
int len,
byte[] output,
int outOff)
{
if ((inOff + len) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + len) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
for (int i = 0; i < len; i++)
{
s = P[(s + P[n & 0xff]) & 0xff];
byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
// encryption
byte temp = P[n & 0xff];
P[n & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
n = (byte) ((n + 1) & 0xff);
// xor
output[i + outOff] = (byte) (input[i + inOff] ^ z);
}
}
public virtual void Reset()
{
InitKey(this.workingKey, this.workingIV);
}
public virtual byte ReturnByte(
byte input)
{
s = P[(s + P[n & 0xff]) & 0xff];
byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
// encryption
byte temp = P[n & 0xff];
P[n & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
n = (byte) ((n + 1) & 0xff);
// xor
return (byte) (input ^ z);
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class VmpcKsa3Engine
: VmpcEngine
{
public override string AlgorithmName
{
get { return "VMPC-KSA3"; }
}
protected override void InitKey(
byte[] keyBytes,
byte[] ivBytes)
{
s = 0;
P = new byte[256];
for (int i = 0; i < 256; i++)
{
P[i] = (byte) i;
}
for (int m = 0; m < 768; m++)
{
s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
byte temp = P[m & 0xff];
P[m & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
}
for (int m = 0; m < 768; m++)
{
s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
byte temp = P[m & 0xff];
P[m & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
}
for (int m = 0; m < 768; m++)
{
s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
byte temp = P[m & 0xff];
P[m & 0xff] = P[s & 0xff];
P[s & 0xff] = temp;
}
n = 0;
}
}
}

View File

@@ -0,0 +1,185 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Engines
{
/**
* An XTEA engine.
*/
public class XteaEngine
: IBlockCipher
{
private const int
rounds = 32,
block_size = 8,
key_size = 16,
delta = unchecked((int) 0x9E3779B9),
d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt
/*
* the expanded key array of 4 subkeys
*/
private int[] _S = new int[4];
private bool _initialised;
private bool _forEncryption;
/**
* Create an instance of the TEA encryption algorithm
* and set some defaults
*/
public XteaEngine()
{
_initialised = false;
}
public string AlgorithmName
{
get { return "XTEA"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
public int GetBlockSize()
{
return block_size;
}
/**
* initialise
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception ArgumentException if the params argument is
* inappropriate.
*/
public void Init(
bool forEncryption,
ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to TEA init - "
+ parameters.GetType().FullName);
}
_forEncryption = forEncryption;
_initialised = true;
KeyParameter p = (KeyParameter) parameters;
setKey(p.GetKey());
}
public int ProcessBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if ((inOff + block_size) > inBytes.Length)
throw new DataLengthException("input buffer too short");
if ((outOff + block_size) > outBytes.Length)
throw new DataLengthException("output buffer too short");
return _forEncryption
? encryptBlock(inBytes, inOff, outBytes, outOff)
: decryptBlock(inBytes, inOff, outBytes, outOff);
}
public void Reset()
{
}
/**
* Re-key the cipher.
*
* @param key the key to be used
*/
private void setKey(
byte[] key)
{
_S[0] = bytesToInt(key, 0);
_S[1] = bytesToInt(key, 4);
_S[2] = bytesToInt(key, 8);
_S[3] = bytesToInt(key, 12);
}
private int encryptBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
// Pack bytes into integers
int v0 = bytesToInt(inBytes, inOff);
int v1 = bytesToInt(inBytes, inOff + 4);
int sum = 0;
for (int i = 0; i != rounds; i++)
{
v0 += ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]);
sum += delta;
v1 += ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]);
}
unpackInt(v0, outBytes, outOff);
unpackInt(v1, outBytes, outOff + 4);
return block_size;
}
private int decryptBlock(
byte[] inBytes,
int inOff,
byte[] outBytes,
int outOff)
{
// Pack bytes into integers
int v0 = bytesToInt(inBytes, inOff);
int v1 = bytesToInt(inBytes, inOff + 4);
int sum = d_sum;
for (int i = 0; i != rounds; i++)
{
v1 -= ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]);
sum -= delta;
v0 -= ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]);
}
unpackInt(v0, outBytes, outOff);
unpackInt(v1, outBytes, outOff + 4);
return block_size;
}
private int bytesToInt(byte[] b, int inOff)
{
return ((b[inOff++]) << 24) |
((b[inOff++] & 255) << 16) |
((b[inOff++] & 255) << 8) |
((b[inOff] & 255));
}
private void unpackInt(
int v,
byte[] b,
int outOff)
{
uint uv = (uint) v;
b[outOff++] = (byte)(uv >> 24);
b[outOff++] = (byte)(uv >> 16);
b[outOff++] = (byte)(uv >> 8);
b[outOff ] = (byte)uv;
}
}
}