diff options
author | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2002-10-04 17:31:41 +0000 |
---|---|---|
committer | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2002-10-04 17:31:41 +0000 |
commit | b21162cf8e06f40baa1f58be6a8c17435cebc34d (patch) | |
tree | 8b045309c238226c32a563b1df6b9c30a2f0e0b3 | |
download | cryptopp-b21162cf8e06f40baa1f58be6a8c17435cebc34d.tar.gz |
Initial revision
git-svn-id: svn://svn.code.sf.net/p/cryptopp/code/trunk/c5@2 57ff6487-cd31-0410-9ec3-f628ee90f5f0
-rw-r--r-- | 3desval.dat | 3 | ||||
-rw-r--r-- | 3way.cpp | 140 | ||||
-rw-r--r-- | 3way.h | 52 | ||||
-rw-r--r-- | 3wayval.dat | 5 | ||||
-rw-r--r-- | Doxyfile | 951 | ||||
-rw-r--r-- | GNUmakefile | 58 | ||||
-rw-r--r-- | License.txt | 67 | ||||
-rw-r--r-- | Readme.txt | 243 | ||||
-rw-r--r-- | adler32.cpp | 77 | ||||
-rw-r--r-- | adler32.h | 26 | ||||
-rw-r--r-- | aes.h | 24 | ||||
-rw-r--r-- | algebra.cpp | 340 | ||||
-rw-r--r-- | algebra.h | 275 | ||||
-rw-r--r-- | algparam.cpp | 16 | ||||
-rw-r--r-- | algparam.h | 323 | ||||
-rw-r--r-- | arc4.cpp | 116 | ||||
-rw-r--r-- | arc4.h | 59 | ||||
-rw-r--r-- | argnames.h | 54 | ||||
-rw-r--r-- | asn.cpp | 556 | ||||
-rw-r--r-- | asn.h | 344 | ||||
-rw-r--r-- | base64.cpp | 40 | ||||
-rw-r--r-- | base64.h | 36 | ||||
-rw-r--r-- | basecode.cpp | 214 | ||||
-rw-r--r-- | basecode.h | 82 | ||||
-rw-r--r-- | bench.cpp | 655 | ||||
-rw-r--r-- | bench.h | 8 | ||||
-rw-r--r-- | bfinit.cpp | 277 | ||||
-rw-r--r-- | blowfish.cpp | 99 | ||||
-rw-r--r-- | blowfish.h | 45 | ||||
-rw-r--r-- | blumshub.cpp | 49 | ||||
-rw-r--r-- | blumshub.h | 58 | ||||
-rw-r--r-- | cast.cpp | 296 | ||||
-rw-r--r-- | cast.h | 91 | ||||
-rw-r--r-- | cast128v.dat | 11 | ||||
-rw-r--r-- | cast256v.dat | 11 | ||||
-rw-r--r-- | casts.cpp | 545 | ||||
-rw-r--r-- | cbcmac.h | 99 | ||||
-rw-r--r-- | channels.cpp | 282 | ||||
-rw-r--r-- | channels.h | 91 | ||||
-rw-r--r-- | config.h | 246 | ||||
-rw-r--r-- | crc.cpp | 160 | ||||
-rw-r--r-- | crc.h | 40 | ||||
-rw-r--r-- | cryptest.cpp | 116 | ||||
-rw-r--r-- | cryptest.dsp | 392 | ||||
-rw-r--r-- | cryptest.dsw | 44 | ||||
-rw-r--r-- | cryptlib.cpp | 660 | ||||
-rw-r--r-- | cryptlib.dsp | 1055 | ||||
-rw-r--r-- | cryptlib.h | 1571 | ||||
-rw-r--r-- | default.cpp | 258 | ||||
-rw-r--r-- | default.h | 104 | ||||
-rw-r--r-- | des.cpp | 464 | ||||
-rw-r--r-- | des.h | 133 | ||||
-rw-r--r-- | descert.dat | 171 | ||||
-rw-r--r-- | dessp.cpp | 90 | ||||
-rw-r--r-- | dh.cpp | 14 | ||||
-rw-r--r-- | dh.h | 93 | ||||
-rw-r--r-- | dh1024.dat | 1 | ||||
-rw-r--r-- | dh2.cpp | 17 | ||||
-rw-r--r-- | dh2.h | 56 | ||||
-rw-r--r-- | dh2048.dat | 1 | ||||
-rw-r--r-- | diamond.cpp | 572 | ||||
-rw-r--r-- | diamond.dat | 14 | ||||
-rw-r--r-- | diamond.h | 109 | ||||
-rw-r--r-- | diamondt.cpp | 2270 | ||||
-rw-r--r-- | dlie1024.dat | 1 | ||||
-rw-r--r-- | dlie2048.dat | 1 | ||||
-rw-r--r-- | dmac.h | 90 | ||||
-rw-r--r-- | dsa.cpp | 114 | ||||
-rw-r--r-- | dsa.h | 35 | ||||
-rw-r--r-- | dsa1024.dat | 1 | ||||
-rw-r--r-- | dsa1024b.dat | 1 | ||||
-rw-r--r-- | dsa512.dat | 1 | ||||
-rw-r--r-- | ec2n.cpp | 287 | ||||
-rw-r--r-- | ec2n.h | 105 | ||||
-rw-r--r-- | eccrypto.cpp | 639 | ||||
-rw-r--r-- | eccrypto.h | 253 | ||||
-rw-r--r-- | ecp.cpp | 477 | ||||
-rw-r--r-- | ecp.h | 114 | ||||
-rw-r--r-- | elgamal.cpp | 17 | ||||
-rw-r--r-- | elgamal.h | 137 | ||||
-rw-r--r-- | elgc1024.dat | 1 | ||||
-rw-r--r-- | eprecomp.cpp | 107 | ||||
-rw-r--r-- | eprecomp.h | 69 | ||||
-rw-r--r-- | esig1023.dat | 1 | ||||
-rw-r--r-- | esig1536.dat | 1 | ||||
-rw-r--r-- | esig2046.dat | 1 | ||||
-rw-r--r-- | esign.cpp | 210 | ||||
-rw-r--r-- | esign.h | 127 | ||||
-rw-r--r-- | files.cpp | 188 | ||||
-rw-r--r-- | files.h | 97 | ||||
-rw-r--r-- | filters.cpp | 898 | ||||
-rw-r--r-- | filters.h | 682 | ||||
-rw-r--r-- | fips140.cpp | 65 | ||||
-rw-r--r-- | fips140.h | 44 | ||||
-rw-r--r-- | fipstest.cpp | 304 | ||||
-rw-r--r-- | fltrimpl.h | 40 | ||||
-rw-r--r-- | gf256.cpp | 34 | ||||
-rw-r--r-- | gf256.h | 66 | ||||
-rw-r--r-- | gf2_32.cpp | 99 | ||||
-rw-r--r-- | gf2_32.h | 66 | ||||
-rw-r--r-- | gf2n.cpp | 870 | ||||
-rw-r--r-- | gf2n.h | 359 | ||||
-rw-r--r-- | gfpcrypt.cpp | 249 | ||||
-rw-r--r-- | gfpcrypt.h | 492 | ||||
-rw-r--r-- | gost.cpp | 123 | ||||
-rw-r--r-- | gost.h | 57 | ||||
-rw-r--r-- | gostval.dat | 23 | ||||
-rw-r--r-- | gzip.cpp | 99 | ||||
-rw-r--r-- | gzip.h | 65 | ||||
-rw-r--r-- | haval.cpp | 275 | ||||
-rw-r--r-- | haval.h | 57 | ||||
-rw-r--r-- | havalcer.dat | 23 | ||||
-rw-r--r-- | hex.cpp | 32 | ||||
-rw-r--r-- | hex.h | 36 | ||||
-rw-r--r-- | hmac.h | 119 | ||||
-rw-r--r-- | hrtimer.cpp | 75 | ||||
-rw-r--r-- | hrtimer.h | 43 | ||||
-rw-r--r-- | ida.cpp | 425 | ||||
-rw-r--r-- | ida.h | 145 | ||||
-rw-r--r-- | idea.cpp | 190 | ||||
-rw-r--r-- | idea.h | 52 | ||||
-rw-r--r-- | ideaval.dat | 11 | ||||
-rw-r--r-- | integer.cpp | 3983 | ||||
-rw-r--r-- | integer.h | 435 | ||||
-rw-r--r-- | iterhash.cpp | 123 | ||||
-rw-r--r-- | iterhash.h | 120 | ||||
-rw-r--r-- | lubyrack.h | 138 | ||||
-rw-r--r-- | luc.cpp | 212 | ||||
-rw-r--r-- | luc.h | 234 | ||||
-rw-r--r-- | luc1024.dat | 1 | ||||
-rw-r--r-- | luc2048.dat | 1 | ||||
-rw-r--r-- | lucc1024.dat | 1 | ||||
-rw-r--r-- | lucc512.dat | 1 | ||||
-rw-r--r-- | lucd1024.dat | 4 | ||||
-rw-r--r-- | lucd512.dat | 2 | ||||
-rw-r--r-- | lucs1024.dat | 1 | ||||
-rw-r--r-- | lucs512.dat | 1 | ||||
-rw-r--r-- | mars.cpp | 210 | ||||
-rw-r--r-- | mars.h | 53 | ||||
-rw-r--r-- | marss.cpp | 139 | ||||
-rw-r--r-- | marsval.dat | 9 | ||||
-rw-r--r-- | md2.cpp | 108 | ||||
-rw-r--r-- | md2.h | 31 | ||||
-rw-r--r-- | md4.cpp | 107 | ||||
-rw-r--r-- | md4.h | 25 | ||||
-rw-r--r-- | md5.cpp | 115 | ||||
-rw-r--r-- | md5.h | 24 | ||||
-rw-r--r-- | md5mac.cpp | 166 | ||||
-rw-r--r-- | md5mac.h | 38 | ||||
-rw-r--r-- | mdc.h | 72 | ||||
-rw-r--r-- | misc.cpp | 83 | ||||
-rw-r--r-- | misc.h | 688 | ||||
-rw-r--r-- | modarith.h | 149 | ||||
-rw-r--r-- | modes.cpp | 227 | ||||
-rw-r--r-- | modes.h | 380 | ||||
-rw-r--r-- | modexppc.cpp | 80 | ||||
-rw-r--r-- | modexppc.h | 32 | ||||
-rw-r--r-- | mqueue.cpp | 182 | ||||
-rw-r--r-- | mqueue.h | 98 | ||||
-rw-r--r-- | mqv.cpp | 13 | ||||
-rw-r--r-- | mqv.h | 141 | ||||
-rw-r--r-- | mqv1024.dat | 1 | ||||
-rw-r--r-- | mqv2048.dat | 1 | ||||
-rw-r--r-- | nbtheory.cpp | 1127 | ||||
-rw-r--r-- | nbtheory.h | 143 | ||||
-rw-r--r-- | network.cpp | 211 | ||||
-rw-r--r-- | network.h | 152 | ||||
-rw-r--r-- | nr.h | 6 | ||||
-rw-r--r-- | nr1024.dat | 1 | ||||
-rw-r--r-- | nr2048.dat | 1 | ||||
-rw-r--r-- | oaep.cpp | 103 | ||||
-rw-r--r-- | oaep.h | 25 | ||||
-rw-r--r-- | oids.h | 112 | ||||
-rw-r--r-- | osrng.cpp | 170 | ||||
-rw-r--r-- | osrng.h | 157 | ||||
-rw-r--r-- | panama.cpp | 146 | ||||
-rw-r--r-- | panama.h | 105 | ||||
-rw-r--r-- | pch.cpp | 1 | ||||
-rw-r--r-- | pch.h | 13 | ||||
-rw-r--r-- | pkcspad.cpp | 151 | ||||
-rw-r--r-- | pkcspad.h | 92 | ||||
-rw-r--r-- | polynomi.cpp | 579 | ||||
-rw-r--r-- | polynomi.h | 451 | ||||
-rw-r--r-- | pssr.h | 169 | ||||
-rw-r--r-- | pubkey.cpp | 58 | ||||
-rw-r--r-- | pubkey.h | 1663 | ||||
-rw-r--r-- | pwdbased.h | 162 | ||||
-rw-r--r-- | queue.cpp | 518 | ||||
-rw-r--r-- | queue.h | 128 | ||||
-rw-r--r-- | rabi1024.dat | 1 | ||||
-rw-r--r-- | rabi2048.dat | 1 | ||||
-rw-r--r-- | rabin.cpp | 214 | ||||
-rw-r--r-- | rabin.h | 123 | ||||
-rw-r--r-- | randpool.cpp | 100 | ||||
-rw-r--r-- | randpool.h | 46 | ||||
-rw-r--r-- | rc2.cpp | 120 | ||||
-rw-r--r-- | rc2.h | 74 | ||||
-rw-r--r-- | rc2val.dat | 48 | ||||
-rw-r--r-- | rc5.cpp | 80 | ||||
-rw-r--r-- | rc5.h | 53 | ||||
-rw-r--r-- | rc5val.dat | 5 | ||||
-rw-r--r-- | rc6.cpp | 97 | ||||
-rw-r--r-- | rc6.h | 53 | ||||
-rw-r--r-- | rc6val.dat | 17 | ||||
-rw-r--r-- | rdtables.cpp | 704 | ||||
-rw-r--r-- | rijndael.cpp | 375 | ||||
-rw-r--r-- | rijndael.dat | 9 | ||||
-rw-r--r-- | rijndael.h | 66 | ||||
-rw-r--r-- | ripemd.cpp | 227 | ||||
-rw-r--r-- | ripemd.h | 24 | ||||
-rw-r--r-- | rng.cpp | 124 | ||||
-rw-r--r-- | rng.h | 77 | ||||
-rw-r--r-- | rsa.cpp | 236 | ||||
-rw-r--r-- | rsa.h | 167 | ||||
-rw-r--r-- | rsa1024.dat | 32 | ||||
-rw-r--r-- | rsa2048.dat | 61 | ||||
-rw-r--r-- | rsa400pb.dat | 10 | ||||
-rw-r--r-- | rsa400pv.dat | 41 | ||||
-rw-r--r-- | rsa512a.dat | 35 | ||||
-rw-r--r-- | rw.cpp | 243 | ||||
-rw-r--r-- | rw.h | 162 | ||||
-rw-r--r-- | rw1024.dat | 1 | ||||
-rw-r--r-- | rw2048.dat | 1 | ||||
-rw-r--r-- | safer.cpp | 148 | ||||
-rw-r--r-- | safer.h | 101 | ||||
-rw-r--r-- | saferval.dat | 16 | ||||
-rw-r--r-- | sapphire.cpp | 179 | ||||
-rw-r--r-- | sapphire.h | 115 | ||||
-rw-r--r-- | seal.cpp | 211 | ||||
-rw-r--r-- | seal.h | 47 | ||||
-rw-r--r-- | secblock.h | 376 | ||||
-rw-r--r-- | seckey.h | 237 | ||||
-rw-r--r-- | serpent.cpp | 544 | ||||
-rw-r--r-- | serpent.h | 51 | ||||
-rw-r--r-- | serpentv.dat | 9 | ||||
-rw-r--r-- | sha.cpp | 277 | ||||
-rw-r--r-- | sha.h | 72 | ||||
-rw-r--r-- | shark.cpp | 142 | ||||
-rw-r--r-- | shark.h | 68 | ||||
-rw-r--r-- | sharkbox.cpp | 4166 | ||||
-rw-r--r-- | sharkval.dat | 7 | ||||
-rw-r--r-- | simple.cpp | 23 | ||||
-rw-r--r-- | simple.h | 228 | ||||
-rw-r--r-- | skipjack.cpp | 197 | ||||
-rw-r--r-- | skipjack.dat | 1 | ||||
-rw-r--r-- | skipjack.h | 59 | ||||
-rw-r--r-- | smartptr.h | 215 | ||||
-rw-r--r-- | socketft.cpp | 475 | ||||
-rw-r--r-- | socketft.h | 218 | ||||
-rw-r--r-- | square.cpp | 174 | ||||
-rw-r--r-- | square.h | 57 | ||||
-rw-r--r-- | squaretb.cpp | 582 | ||||
-rw-r--r-- | squareva.dat | 8 | ||||
-rw-r--r-- | strciphr.cpp | 188 | ||||
-rw-r--r-- | strciphr.h | 287 | ||||
-rw-r--r-- | tea.cpp | 54 | ||||
-rw-r--r-- | tea.h | 53 | ||||
-rw-r--r-- | test.cpp | 917 | ||||
-rw-r--r-- | tftables.cpp | 317 | ||||
-rw-r--r-- | tiger.cpp | 95 | ||||
-rw-r--r-- | tiger.h | 32 | ||||
-rw-r--r-- | tigertab.cpp | 526 | ||||
-rw-r--r-- | trdlocal.cpp | 66 | ||||
-rw-r--r-- | trdlocal.h | 45 | ||||
-rw-r--r-- | trunhash.h | 46 | ||||
-rw-r--r-- | twofish.cpp | 168 | ||||
-rw-r--r-- | twofish.h | 58 | ||||
-rw-r--r-- | twofishv.dat | 9 | ||||
-rw-r--r-- | usage.dat | 66 | ||||
-rw-r--r-- | validat1.cpp | 1250 | ||||
-rw-r--r-- | validat2.cpp | 740 | ||||
-rw-r--r-- | validat3.cpp | 638 | ||||
-rw-r--r-- | validate.h | 74 | ||||
-rw-r--r-- | wait.cpp | 110 | ||||
-rw-r--r-- | wait.h | 57 | ||||
-rw-r--r-- | wake.cpp | 122 | ||||
-rw-r--r-- | wake.h | 76 | ||||
-rw-r--r-- | winpipes.cpp | 202 | ||||
-rw-r--r-- | winpipes.h | 141 | ||||
-rw-r--r-- | words.h | 103 | ||||
-rw-r--r-- | xormac.h | 170 | ||||
-rw-r--r-- | xtr.cpp | 101 | ||||
-rw-r--r-- | xtr.h | 215 | ||||
-rw-r--r-- | xtrcrypt.cpp | 108 | ||||
-rw-r--r-- | xtrcrypt.h | 54 | ||||
-rw-r--r-- | xtrdh171.dat | 3 | ||||
-rw-r--r-- | xtrdh342.dat | 5 | ||||
-rw-r--r-- | zdeflate.cpp | 736 | ||||
-rw-r--r-- | zdeflate.h | 117 | ||||
-rw-r--r-- | zinflate.cpp | 581 | ||||
-rw-r--r-- | zinflate.h | 143 | ||||
-rw-r--r-- | zlib.cpp | 90 | ||||
-rw-r--r-- | zlib.h | 58 |
293 files changed, 60886 insertions, 0 deletions
diff --git a/3desval.dat b/3desval.dat new file mode 100644 index 0000000..1d5883e --- /dev/null +++ b/3desval.dat @@ -0,0 +1,3 @@ +0123456789abcdeffedcba9876543210 0123456789abcde7 7f1d0a77826b8aff +0123456789abcdeffedcba987654321089abcdef01234567 0123456789abcde7 de0b7c06ae5e0ed5 +0123456789ABCDEF01010101010101011011121314151617 94DBE082549A14EF 9011121314151617 diff --git a/3way.cpp b/3way.cpp new file mode 100644 index 0000000..0b7d4f2 --- /dev/null +++ b/3way.cpp @@ -0,0 +1,140 @@ +// 3way.cpp - modifed by Wei Dai from Joan Daemen's 3way.c +// The original code and all modifications are in the public domain. + +#include "pch.h" +#include "3way.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void ThreeWay_TestInstantiations() +{ + ThreeWay::Encryption x1; + ThreeWay::Decryption x2; +} + +static const word32 START_E = 0x0b0b; // round constant of first encryption round +static const word32 START_D = 0xb1b1; // round constant of first decryption round +static const word32 RC_MODULUS = 0x11011; + +static inline word32 reverseBits(word32 a) +{ + a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); + a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); + return ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); +} + +#define mu(a0, a1, a2) \ +{ \ + a1 = reverseBits(a1); \ + word32 t = reverseBits(a0); \ + a0 = reverseBits(a2); \ + a2 = t; \ +} + +#define pi_gamma_pi(a0, a1, a2) \ +{ \ + word32 b0, b2; \ + b2 = rotlFixed(a2, 1U); \ + b0 = rotlFixed(a0, 22U); \ + a0 = rotlFixed(b0 ^ (a1|(~b2)), 1U); \ + a2 = rotlFixed(b2 ^ (b0|(~a1)), 22U);\ + a1 ^= (b2|(~b0)); \ +} + +// thanks to Paulo Barreto for this optimized theta() +#define theta(a0, a1, a2) \ +{ \ + word32 b0, b1, c; \ + c = a0 ^ a1 ^ a2; \ + c = rotlFixed(c, 16U) ^ rotlFixed(c, 8U); \ + b0 = (a0 << 24) ^ (a2 >> 8) ^ (a1 << 8) ^ (a0 >> 24); \ + b1 = (a1 << 24) ^ (a0 >> 8) ^ (a2 << 8) ^ (a1 >> 24); \ + a0 ^= c ^ b0; \ + a1 ^= c ^ b1; \ + a2 ^= c ^ (b0 >> 16) ^ (b1 << 16); \ +} + +#define rho(a0, a1, a2) \ +{ \ + theta(a0, a1, a2); \ + pi_gamma_pi(a0, a1, a2); \ +} + +void ThreeWay::Base::UncheckedSetKey(CipherDir dir, const byte *uk, unsigned int length, unsigned int r) +{ + AssertValidKeyLength(length); + AssertValidRounds(r); + + m_rounds = r; + + for (unsigned int i=0; i<3; i++) + m_k[i] = (word32)uk[4*i+3] | ((word32)uk[4*i+2]<<8) | ((word32)uk[4*i+1]<<16) | ((word32)uk[4*i]<<24); + + if (dir == DECRYPTION) + { + theta(m_k[0], m_k[1], m_k[2]); + mu(m_k[0], m_k[1], m_k[2]); + m_k[0] = ByteReverse(m_k[0]); + m_k[1] = ByteReverse(m_k[1]); + m_k[2] = ByteReverse(m_k[2]); + } +} + +void ThreeWay::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut<word32, BigEndian> Block; + + word32 a0, a1, a2; + Block::Get(inBlock)(a0)(a1)(a2); + + word32 rc = START_E; + + for(unsigned i=0; i<m_rounds; i++) + { + a0 ^= m_k[0] ^ (rc<<16); + a1 ^= m_k[1]; + a2 ^= m_k[2] ^ rc; + rho(a0, a1, a2); + + rc <<= 1; + if (rc&0x10000) rc ^= 0x11011; + } + a0 ^= m_k[0] ^ (rc<<16); + a1 ^= m_k[1]; + a2 ^= m_k[2] ^ rc; + theta(a0, a1, a2); + + Block::Put(xorBlock, outBlock)(a0)(a1)(a2); +} + +void ThreeWay::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut<word32, LittleEndian> Block; + + word32 a0, a1, a2; + Block::Get(inBlock)(a0)(a1)(a2); + + word32 rc = START_D; + + mu(a0, a1, a2); + for(unsigned i=0; i<m_rounds; i++) + { + a0 ^= m_k[0] ^ (rc<<16); + a1 ^= m_k[1]; + a2 ^= m_k[2] ^ rc; + rho(a0, a1, a2); + + rc <<= 1; + if (rc&0x10000) rc ^= 0x11011; + } + a0 ^= m_k[0] ^ (rc<<16); + a1 ^= m_k[1]; + a2 ^= m_k[2] ^ rc; + theta(a0, a1, a2); + mu(a0, a1, a2); + + Block::Put(xorBlock, outBlock)(a0)(a1)(a2); +} + +NAMESPACE_END @@ -0,0 +1,52 @@ +#ifndef CRYPTOPP_THREEWAY_H +#define CRYPTOPP_THREEWAY_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct ThreeWay_Info : public FixedBlockSize<12>, public FixedKeyLength<12>, public VariableRounds<11> +{ + static const char *StaticAlgorithmName() {return "3-Way";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#3-Way">3-Way</a> +class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<ThreeWay_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *key, unsigned int length, unsigned int rounds); + + protected: + unsigned int m_rounds; + FixedSizeSecBlock<word32, 3> m_k; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef ThreeWay::Encryption ThreeWayEncryption; +typedef ThreeWay::Decryption ThreeWayDecryption; + +NAMESPACE_END + +#endif diff --git a/3wayval.dat b/3wayval.dat new file mode 100644 index 0000000..51bb6c1 --- /dev/null +++ b/3wayval.dat @@ -0,0 +1,5 @@ +000000000000000000000000 000000010000000100000001 4059c76e83ae9dc4ad21ecf7 +000000060000000500000004 000000030000000200000001 d2f05b5ed6144138cab920cd +def01234456789abbcdef012 234567899abcdef001234567 0aa55dbb9cdddb6d7cdb76b2 +d2f05b5ed6144138cab920cd 4059c76e83ae9dc4ad21ecf7 478ea8716b13f17c15b155ed + diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..fbe685a --- /dev/null +++ b/Doxyfile @@ -0,0 +1,951 @@ +# Doxyfile 1.2.15-20020512 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Crypto++ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean, +# Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovene, +# Spanish, Swedish and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = No + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = Yes + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = No + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = No + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = *.h \ + *.cpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, +# or Internet explorer 4.0+). Note that for large projects the tree generation +# can take a very long time. In such cases it is better to disable this feature. +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = . + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = _WIN32 \ + _WINDOWS \ + WORD64_AVAILABLE \ + __FreeBSD__ \ + CRYPTOPP_DOXYGEN_PROCESSING + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line and do not end with a semicolon. Such function macros are typically +# used for boiler-plate code, and will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..32226e2 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,58 @@ +# can't use -fno-rtti yet because it causes problems with exception handling in GCC 2.95.2 +CXXFLAGS = -g +# uncomment the next two lines to do a release build +# CXXFLAGS = -O2 -DNDEBUG -ffunction-sections -fdata-sections +# LDFLAGS = -Wl,--gc-sections +ARFLAGS = -cr # ar needs the dash on OpenBSD +RANLIB = ranlib +UNAME = $(shell uname) + +ifeq ($(UNAME),) # for DJGPP, where uname doesn't exist +CXXFLAGS += -mbnu210 +else +CXXFLAGS += -pipe +endif + +ifeq ($(UNAME),Darwin) # -fpic conflicts with inline asm in integer.cpp on i386 +CXX = c++ +CXXFLAGS += -fno-pic +endif + +ifeq ($(UNAME),SunOS) +LDLIBS = -lnsl -lsocket +endif + +ifeq ($(CXX),gcc) # for some reason CXX is gcc on cygwin 1.1.4 +CXX = g++ +endif + +SRCS = $(wildcard *.cpp) + +ifeq ($(SRCS),) # workaround wildcard function bug in GNU Make 3.77 +SRCS = $(shell ls *.cpp) +endif + +OBJS = $(SRCS:.cpp=.o) +# test.o needs to be after bench.o for cygwin 1.1.4 (possible ld bug?) +TESTOBJS = bench.o test.o validat1.o validat2.o validat3.o +LIBOBJS = $(filter-out $(TESTOBJS),$(OBJS)) + +all: cryptest.exe + +clean: + $(RM) cryptest.exe libcryptopp.a $(LIBOBJS) $(TESTOBJS) + +libcryptopp.a: $(LIBOBJS) + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +cryptest.exe: libcryptopp.a $(TESTOBJS) + $(CXX) -o $@ $(CXXFLAGS) $(TESTOBJS) -L. -lcryptopp $(LDFLAGS) $(LDLIBS) + +nolib: $(OBJS) # makes it faster to test changes + $(CXX) -o ct $(CXXFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) + +.SUFFIXES: .cpp + +.cpp.o: + $(CXX) $(CXXFLAGS) -c $< diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..a848c33 --- /dev/null +++ b/License.txt @@ -0,0 +1,67 @@ +Compilation Copyright (c) 1995-2002 by Wei Dai. All rights reserved. +This copyright applies only to this software distribution package +as a compilation, and does not imply a copyright on any particular +file in the package. + +The following files are copyrighted by their respective original authors: + +mars.cpp - Copyright 1998 Brian Gladman. +serpent.cpp - Copyright 1998, 1999 Brian Gladman and Sam Simpson. + +All other files in this compilation are placed in the public domain by +Wei Dai and other contributors. + +I would like to thank the following authors for placing their works into +the public domain: + +Joan Daemen - 3way.cpp +Leonard Janke - cast.cpp, seal.cpp +Steve Reid - cast.cpp +Phil Karn - des.cpp +Michael Paul Johnson - diamond.cpp, sapphire.cpp +Andrew M. Kuchling - md2.cpp, md4.cpp +Colin Plumb - md5.cpp, md5mac.cpp +Seal Woods - rc6.cpp +Chris Morgan - rijndael.cpp +Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp +Richard De Moliner - safer.cpp +Matthew Skala - twofish.cpp + +Permission to use, copy, modify, and distribute this compilation for +any purpose, including commercial applications, is hereby granted +without fee, subject to the following restrictions: + +1. Any copy or modification of this compilation in any form, except +in object code form as part of an application software, must include +the above copyright notice and this license. + +2. Users of this software agree that any modification or extension +they provide to Wei Dai will be considered public domain and not +copyrighted unless it includes an explicit copyright notice. + +3. Wei Dai makes no warranty or representation that the operation of the +software in this compilation will be error-free, and Wei Dai is under no +obligation to provide any services, by way of maintenance, update, or +otherwise. THE SOFTWARE AND ANY DOCUMENTATION ARE PROVIDED "AS IS" +WITHOUT EXPRESS OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. IN NO EVENT WILL WEI DAI OR ANY OTHER CONTRIBUTOR BE LIABLE FOR +DIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +4. Users will not use Wei Dai or any other contributor's name in any +publicity or advertising, without prior written consent in each case. + +5. Export of this software from the United States may require a +specific license from the United States Government. It is the +responsibility of any person or organization contemplating export +to obtain such a license before exporting. + +6. Certain parts of this software may be protected by patents. It +is the users' responsibility to obtain the appropriate +licenses before using those parts. + +If this compilation is used in object code form in an application +software, acknowledgement of the author is not required but would be +appreciated. The contribution of any useful modifications or extensions +to Wei Dai is not required but would also be appreciated. diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..37f5327 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,243 @@ +Crypto++: a C++ Class Library of Cryptographic Primitives +Version 5.0 9/11/2002 + +This library includes: + +- a class hierarchy with an API defined by abstract base classes +- Proposed AES (Rijndael) and other AES candidates: RC6, MARS, Twofish, + Serpent, CAST-256 +- other symmetric block ciphers: IDEA, DES, Triple DES (DES-EDE2 and + DES-EDE3), DESX (DES-XEX3), RC2, RC5, Blowfish, Diamond2, TEA, SAFER, + 3-WAY, GOST, SHARK, CAST-128, Square, Skipjack +- generic block cipher modes: ECB, CBC, CBC ciphertext stealing (CTS), + CFB, OFB, counter (CTR) mode +- stream ciphers: Panama, ARC4, SEAL, WAKE, WAKE-OFB, Sapphire II, + BlumBlumShub +- public key cryptography: RSA, DSA, ElGamal, Nyberg-Rueppel (NR), Rabin, + Rabin-Williams (RW), LUC, LUCELG, DLIES (variants of DHAES), ESIGN +- padding schemes for public-key systems: PKCS#1 v2.0, OAEP, PSSR, IEEE + P1363 EMSA2 +- key agreement schemes: Diffie-Hellman (DH), Unified Diffie-Hellman + (DH2), Menezes-Qu-Vanstone (MQV), LUCDIF, XTR-DH +- elliptic curve cryptography: ECDSA, ECNR, ECIES, ECDH, ECMQV (with + optional cofactor multiplication for ECIES, ECDHC, ECMQVC) +- one-way hash functions: SHA-1, MD2, MD4, MD5, HAVAL, RIPEMD-160, Tiger, + SHA-2 (SHA-256, SHA-384, and SHA-512), Panama +- public and private key validation for asymmetric algorithms +- message authentication codes: MD5-MAC, HMAC, XOR-MAC, CBC-MAC, DMAC +- cipher constructions based on hash functions: Luby-Rackoff, MDC +- pseudo random number generators (PRNG): ANSI X9.17 appendix C, PGP's + RandPool +- Shamir's secret sharing scheme and Rabin's information dispersal + algorithm (IDA) +- DEFLATE (RFC 1951) compression/decompression with gzip (RFC 1952) and + zlib (RFC 1950) format support +- fast multi-precision integer (bignum) and polynomial operations +- finite field arithmetics, including GF(p) and GF(2^n) +- prime number generation and verification +- various miscellaneous modules such as base 64 coding and 32-bit CRC +- class wrappers for these operating system features (optional): + - high resolution timers on Windows, Unix, and MacOS + - Berkeley and Windows style sockets + - Windows named pipes + - /dev/random and /dev/urandom on Linux and FreeBSD + - Microsoft's CryptGenRandom on Windows +- A high level interface for most of the above, using a filter/pipeline + metaphor +- benchmarks and validation testing + +You are welcome to use it for any purpose without paying me, but see +license.txt for the fine print. + +This version of Crypto++ has been compiled successfully with MSVC 6.0 +and 7.0 on Windows XP, GCC 2.95.4 on FreeBSD 4.6, GCC 2.95.3 on +Linux 2.4 and SunOS 5.8, GCC 3.2 on Cygwin 1.3.12, and Metrowerks +CodeWarrior 8.2. + +To compile Crypto++ with MSVC, open the "cryptest.dsw" workspace file +and build the "cryptest" project. This will compile Crypto++ as a static +library and also build the test driver. Run the test driver and make sure +the validation suite passes. Then to use the library simply insert the +"cryptlib.dsp" project file into your own application workspace as a +dependent project. You may need to check the compiler options to make sure +that the library and your application are using the same C++ run-time +libraries. + +A makefile is included for you to compile Crypto++ with GCC. Make sure +you are using GNU Make and GNU ld. The make process will produce two files, +libcryptopp.a and cryptest.exe. Run "cryptest.exe v" for the validation +suite. + +Crypto++ is documented mostly through comments in header files. If you are +not familiar with cryptography, I suggest that you read an introductory +text (such as Bruce Schneier's _Applied Cryptography_) before attempting +to use this library. Then, you should start by looking at +cryptlib.h, which contains the main abstract base classes and their +descriptions, and test.cpp, which contains sample/test code. There +should also be a link on http://www.cryptopp.com to an HTML reference +manual generated from the inline documentation. + +If you run into any problems, please try the Crypto++ mailing list. +The subscription information and the list archive are available on +http://www.cryptopp.com. You can also email me directly at +weidai@eskimo.com, but you will probably get a faster response through +the mailing list. + +Finally, a couple of usage notes to keep in mind: + +1. If a constructor for A takes a pointer to an object B (except primitive +types such as int and char), then A owns B and will delete B at A's +destruction. If a constructor for A takes a reference to an object B, +then the caller retains ownership of B and should not destroy it until +A no longer needs it. + +2. Crypto++ is thread safe at the class level. This means you can use +Crypto++ safely in a multithreaded application, but you must provide +synchronization when multiple threads access a common Crypto++ object. + +Wei Dai + +History + +1.0 - First public release. Withdrawn at the request of RSA DSI. + - included Blowfish, BBS, DES, DH, Diamond, DSA, ElGamal, IDEA, + MD5, RC4, RC5, RSA, SHA, WAKE, secret sharing, DEFLATE compression + - had a serious bug in the RSA key generation code. + +1.1 - Removed RSA, RC4, RC5 + - Disabled calls to RSAREF's non-public functions + - Minor bugs fixed + +2.0 - a completely new, faster multiprecision integer class + - added MD5-MAC, HAVAL, 3-WAY, TEA, SAFER, LUC, Rabin, BlumGoldwasser, + elliptic curve algorithms + - added the Lucas strong probable primality test + - ElGamal encryption and signature schemes modified to avoid weaknesses + - Diamond changed to Diamond2 because of key schedule weakness + - fixed bug in WAKE key setup + - SHS class renamed to SHA + - lots of miscellaneous optimizations + +2.1 - added Tiger, HMAC, GOST, RIPE-MD160, LUCELG, LUCDIF, XOR-MAC, + OAEP, PSSR, SHARK + - added precomputation to DH, ElGamal, DSA, and elliptic curve algorithms + - added back RC5 and a new RSA + - optimizations in elliptic curves over GF(p) + - changed Rabin to use OAEP and PSSR + - changed many classes to allow copy constructors to work correctly + - improved exception generation and handling + +2.2 - added SEAL, CAST-128, Square + - fixed bug in HAVAL (padding problem) + - fixed bug in triple-DES (decryption order was reversed) + - fixed bug in RC5 (couldn't handle key length not a multiple of 4) + - changed HMAC to conform to RFC-2104 (which is not compatible + with the original HMAC) + - changed secret sharing and information dispersal to use GF(2^32) + instead of GF(65521) + - removed zero knowledge prover/verifier for graph isomorphism + - removed several utility classes in favor of the C++ standard library + +2.3 - ported to EGCS + - fixed incomplete workaround of min/max conflict in MSVC + +3.0 - placed all names into the "CryptoPP" namespace + - added MD2, RC2, RC6, MARS, RW, DH2, MQV, ECDHC, CBC-CTS + - added abstract base classes PK_SimpleKeyAgreementDomain and + PK_AuthenticatedKeyAgreementDomain + - changed DH and LUCDIF to implement the PK_SimpleKeyAgreementDomain + interface and to perform domain parameter and key validation + - changed interfaces of PK_Signer and PK_Verifier to sign and verify + messages instead of message digests + - changed OAEP to conform to PKCS#1 v2.0 + - changed benchmark code to produce HTML tables as output + - changed PSSR to track IEEE P1363a + - renamed ElGamalSignature to NR and changed it to track IEEE P1363 + - renamed ECKEP to ECMQVC and changed it to track IEEE P1363 + - renamed several other classes for clarity + - removed support for calling RSAREF + - removed option to compile old SHA (SHA-0) + - removed option not to throw exceptions + +3.1 - added ARC4, Rijndael, Twofish, Serpent, CBC-MAC, DMAC + - added interface for querying supported key lengths of symmetric ciphers + and MACs + - added sample code for RSA signature and verification + - changed CBC-CTS to be compatible with RFC 2040 + - updated SEAL to version 3.0 of the cipher specification + - optimized multiprecision squaring and elliptic curves over GF(p) + - fixed bug in MARS key setup + - fixed bug with attaching objects to Deflator + +3.2 - added DES-XEX3, ECDSA, DefaultEncryptorWithMAC + - renamed DES-EDE to DES-EDE2 and TripleDES to DES-EDE3 + - optimized ARC4 + - generalized DSA to allow keys longer than 1024 bits + - fixed bugs in GF2N and ModularArithmetic that can cause calculation errors + - fixed crashing bug in Inflator when given invalid inputs + - fixed endian bug in Serpent + - fixed padding bug in Tiger + +4.0 - added Skipjack, CAST-256, Panama, SHA-2 (SHA-256, SHA-384, and SHA-512), + and XTR-DH + - added a faster variant of Rabin's Information Dispersal Algorithm (IDA) + - added class wrappers for these operating system features: + - high resolution timers on Windows, Unix, and MacOS + - Berkeley and Windows style sockets + - Windows named pipes + - /dev/random and /dev/urandom on Linux and FreeBSD + - Microsoft's CryptGenRandom on Windows + - added support for SEC 1 elliptic curve key format and compressed points + - added support for X.509 public key format (subjectPublicKeyInfo) for + RSA, DSA, and elliptic curve schemes + - added support for DER and OpenPGP signature format for DSA + - added support for ZLIB compressed data format (RFC 1950) + - changed elliptic curve encryption to use ECIES (as defined in SEC 1) + - changed MARS key schedule to reflect the latest specification + - changed BufferedTransformation interface to support multiple channels + and messages + - changed CAST and SHA-1 implementations to use public domain source code + - fixed bug in StringSource + - optmized multi-precision integer code for better performance + +4.1 - added more support for the recommended elliptic curve parameters in SEC 2 + - added Panama MAC, MARC4 + - added IV stealing feature to CTS mode + - added support for PKCS #8 private key format for RSA, DSA, and elliptic + curve schemes + - changed Deflate, MD5, Rijndael, and Twofish to use public domain code + - fixed a bug with flushing compressed streams + - fixed a bug with decompressing stored blocks + - fixed a bug with EC point decompression using non-trinomial basis + - fixed a bug in NetworkSource::GeneralPump() + - fixed a performance issue with EC over GF(p) decryption + - fixed syntax to allow GCC to compile without -fpermissive + - relaxed some restrictions in the license + +4.2 - added support for longer HMAC keys + - added MD4 (which is not secure so use for compatibility purposes only) + - added compatibility fixes/workarounds for STLport 4.5, GCC 3.0.2, + and MSVC 7.0 + - changed MD2 to use public domain code + - fixed a bug with decompressing multiple messages with the same object + - fixed a bug in CBC-MAC with MACing multiple messages with the same object + - fixed a bug in RC5 and RC6 with zero-length keys + - fixed a bug in Adler32 where incorrect checksum may be generated + +5.0 - added ESIGN, DLIES, WAKE-OFB, PBKDF1 and PBKDF2 from PKCS #5 + - added key validation for encryption and signature public/private keys + - renamed StreamCipher interface to SymmetricCipher, which is now implemented + by both stream ciphers and block cipher modes including ECB and CBC + - added keying interfaces to support resetting of keys and IVs without + having to destroy and recreate objects + - changed filter interface to support non-blocking input/output + - changed SocketSource and SocketSink to use overlapped I/O on Microsoft Windows + - grouped related classes inside structs to help templates, for example + AESEncryption and AESDecryption are now AES::Encryption and AES::Decryption + - where possible, typedefs have been added to improve backwards + compatibility when the CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY macro is defined + - changed HAVAL and IDEA to use public domain code + - implemented SSE2 optimizations for Integer operations + - is being evaluated for FIPS 140-2 compliance + - fixed a bug in HMAC::TruncatedFinal() + - fixed SKIPJACK byte ordering following NIST clarification dated 5/9/02 diff --git a/adler32.cpp b/adler32.cpp new file mode 100644 index 0000000..5811d5c --- /dev/null +++ b/adler32.cpp @@ -0,0 +1,77 @@ +// adler32.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "adler32.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Adler32::Update(const byte *input, unsigned int length) +{ + const unsigned long BASE = 65521; + + unsigned long s1 = m_s1; + unsigned long s2 = m_s2; + + if (length % 8 != 0) + { + do + { + s1 += *input++; + s2 += s1; + length--; + } while (length % 8 != 0); + + if (s1 >= BASE) + s1 -= BASE; + s2 %= BASE; + } + + while (length > 0) + { + s1 += input[0]; s2 += s1; + s1 += input[1]; s2 += s1; + s1 += input[2]; s2 += s1; + s1 += input[3]; s2 += s1; + s1 += input[4]; s2 += s1; + s1 += input[5]; s2 += s1; + s1 += input[6]; s2 += s1; + s1 += input[7]; s2 += s1; + + length -= 8; + input += 8; + + if (s1 >= BASE) + s1 -= BASE; + if (length % 0x8000 == 0) + s2 %= BASE; + } + + assert(s1 < BASE); + assert(s2 < BASE); + + m_s1 = (word16)s1; + m_s2 = (word16)s2; +} + +void Adler32::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + switch (size) + { + default: + hash[3] = byte(m_s1); + case 3: + hash[2] = byte(m_s1 >> 8); + case 2: + hash[1] = byte(m_s2); + case 1: + hash[0] = byte(m_s2 >> 8); + case 0: + ; + } + + Reset(); +} + +NAMESPACE_END diff --git a/adler32.h b/adler32.h new file mode 100644 index 0000000..5c9d8cf --- /dev/null +++ b/adler32.h @@ -0,0 +1,26 @@ +#ifndef CRYPTOPP_ADLER32_H +#define CRYPTOPP_ADLER32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! ADLER-32 checksum calculations +class Adler32 : public HashTransformation +{ +public: + enum {DIGESTSIZE = 4}; + Adler32() {Reset();} + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *hash, unsigned int size); + unsigned int DigestSize() const {return DIGESTSIZE;} + +private: + void Reset() {m_s1 = 1; m_s2 = 0;} + + word16 m_s1, m_s2; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,24 @@ +#ifndef CRYPTOPP_AES_H +#define CRYPTOPP_AES_H + +/** \file + AES winner announced on 10/2/2000 +*/ + +#include "rijndael.h" + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING // Use inheritance instead of typedef to get a seperate API reference page for AES +//! AES +class AES : public Rijndael, public BlockCipherDocumentation {}; +#else +typedef Rijndael AES; +#endif + +typedef RijndaelEncryption AESEncryption; +typedef RijndaelDecryption AESDecryption; + +NAMESPACE_END + +#endif diff --git a/algebra.cpp b/algebra.cpp new file mode 100644 index 0000000..222109a --- /dev/null +++ b/algebra.cpp @@ -0,0 +1,340 @@ +// algebra.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "algebra.h" +#include "integer.h" + +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> const T& AbstractGroup<T>::Double(const Element &a) const +{ + return Add(a, a); +} + +template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, const Element &b) const +{ + // make copy of a in case Inverse() overwrites it + Element a1(a); + return Add(a1, Inverse(b)); +} + +template <class T> T& AbstractGroup<T>::Accumulate(Element &a, const Element &b) const +{ + return a = Add(a, b); +} + +template <class T> T& AbstractGroup<T>::Reduce(Element &a, const Element &b) const +{ + return a = Subtract(a, b); +} + +template <class T> const T& AbstractRing<T>::Square(const Element &a) const +{ + return Multiply(a, a); +} + +template <class T> const T& AbstractRing<T>::Divide(const Element &a, const Element &b) const +{ + // make copy of a in case MultiplicativeInverse() overwrites it + Element a1(a); + return Multiply(a1, MultiplicativeInverse(b)); +} + +template <class T> const T& AbstractEuclideanDomain<T>::Mod(const Element &a, const Element &b) const +{ + Element q; + DivisionAlgorithm(result, q, a, b); + return result; +} + +template <class T> const T& AbstractEuclideanDomain<T>::Gcd(const Element &a, const Element &b) const +{ + Element g[3]={b, a}; + unsigned int i0=0, i1=1, i2=2; + + while (!Equal(g[i1], Identity())) + { + g[i2] = Mod(g[i0], g[i1]); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return result = g[i0]; +} + +template <class T> const typename QuotientRing<T>::Element& QuotientRing<T>::MultiplicativeInverse(const Element &a) const +{ + Element g[3]={m_modulus, a}; +#ifdef __BCPLUSPLUS__ + // BC++50 workaround + Element v[3]; + v[0]=m_domain.Identity(); + v[1]=m_domain.MultiplicativeIdentity(); +#else + Element v[3]={m_domain.Identity(), m_domain.MultiplicativeIdentity()}; +#endif + Element y; + unsigned int i0=0, i1=1, i2=2; + + while (!Equal(g[i1], Identity())) + { + // y = g[i0] / g[i1]; + // g[i2] = g[i0] % g[i1]; + m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]); + // v[i2] = v[i0] - (v[i1] * y); + v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y)); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]) : m_domain.Identity(); +} + +template <class T> T AbstractGroup<T>::ScalarMultiply(const Element &base, const Integer &exponent) const +{ + Element result; + SimultaneousMultiply(&result, base, &exponent, 1); + return result; +} + +template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const +{ + const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount()); + if (expLen==0) + return Identity(); + + const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3)); + const unsigned tableSize = 1<<w; + std::vector<Element> powerTable(tableSize << w); + + powerTable[1] = x; + powerTable[tableSize] = y; + if (w==1) + powerTable[3] = Add(x,y); + else + { + powerTable[2] = Double(x); + powerTable[2*tableSize] = Double(y); + + unsigned i, j; + + for (i=3; i<tableSize; i+=2) + powerTable[i] = Add(powerTable[i-2], powerTable[2]); + for (i=1; i<tableSize; i+=2) + for (j=i+tableSize; j<(tableSize<<w); j+=tableSize) + powerTable[j] = Add(powerTable[j-tableSize], y); + + for (i=3*tableSize; i<(tableSize<<w); i+=2*tableSize) + powerTable[i] = Add(powerTable[i-2*tableSize], powerTable[2*tableSize]); + for (i=tableSize; i<(tableSize<<w); i+=2*tableSize) + for (j=i+2; j<i+tableSize; j+=2) + powerTable[j] = Add(powerTable[j-1], x); + } + + Element result; + unsigned power1 = 0, power2 = 0, prevPosition = expLen-1; + bool firstTime = true; + + for (int i = expLen-1; i>=0; i--) + { + power1 = 2*power1 + e1.GetBit(i); + power2 = 2*power2 + e2.GetBit(i); + + if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize) + { + unsigned squaresBefore = prevPosition-i; + unsigned squaresAfter = 0; + prevPosition = i; + while ((power1 || power2) && power1%2 == 0 && power2%2==0) + { + power1 /= 2; + power2 /= 2; + squaresBefore--; + squaresAfter++; + } + if (firstTime) + { + result = powerTable[(power2<<w) + power1]; + firstTime = false; + } + else + { + while (squaresBefore--) + result = Double(result); + if (power1 || power2) + Accumulate(result, powerTable[(power2<<w) + power1]); + } + while (squaresAfter--) + result = Double(result); + power1 = power2 = 0; + } + } + return result; +} + +template <class Element, class Iterator> Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end) +{ + if (end-begin == 1) + return group.ScalarMultiply(begin->base, begin->exponent); + else if (end-begin == 2) + return group.CascadeScalarMultiply(begin->base, begin->exponent, (begin+1)->base, (begin+1)->exponent); + else + { + Integer q, t; + Iterator last = end; + --last; + + std::make_heap(begin, end); + std::pop_heap(begin, end); + + while (!!begin->exponent) + { + // last->exponent is largest exponent, begin->exponent is next largest + t = last->exponent; + Integer::Divide(last->exponent, q, t, begin->exponent); + + if (q == Integer::One()) + group.Accumulate(begin->base, last->base); // avoid overhead of ScalarMultiply() + else + group.Accumulate(begin->base, group.ScalarMultiply(last->base, q)); + + std::push_heap(begin, end); + std::pop_heap(begin, end); + } + + return group.ScalarMultiply(last->base, last->exponent); + } +} + +struct WindowSlider +{ + WindowSlider(const Integer &exp, bool fastNegate, unsigned int windowSizeIn=0) + : exp(exp), windowModulus(Integer::One()), windowSize(windowSizeIn), windowBegin(0), fastNegate(fastNegate), firstTime(true), finished(false) + { + if (windowSize == 0) + { + unsigned int expLen = exp.BitCount(); + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7))))); + } + windowModulus <<= windowSize; + } + + void FindNextWindow() + { + unsigned int expLen = exp.WordCount() * WORD_BITS; + unsigned int skipCount = firstTime ? 0 : windowSize; + firstTime = false; + while (!exp.GetBit(skipCount)) + { + if (skipCount >= expLen) + { + finished = true; + return; + } + skipCount++; + } + + exp >>= skipCount; + windowBegin += skipCount; + expWindow = exp % (1 << windowSize); + + if (fastNegate && exp.GetBit(windowSize)) + { + negateNext = true; + expWindow = (1 << windowSize) - expWindow; + exp += windowModulus; + } + else + negateNext = false; + } + + Integer exp, windowModulus; + unsigned int windowSize, windowBegin, expWindow; + bool fastNegate, negateNext, firstTime, finished; +}; + +template <class T> +void AbstractGroup<T>::SimultaneousMultiply(T *results, const T &base, const Integer *expBegin, unsigned int expCount) const +{ + std::vector<std::vector<Element> > buckets(expCount); + std::vector<WindowSlider> exponents; + exponents.reserve(expCount); + unsigned int i; + + for (i=0; i<expCount; i++) + { + assert(expBegin->NotNegative()); + exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0)); + exponents[i].FindNextWindow(); + buckets[i].resize(1<<(exponents[i].windowSize-1), Identity()); + } + + unsigned int expBitPosition = 0; + Element g = base; + bool notDone = true; + + while (notDone) + { + notDone = false; + for (i=0; i<expCount; i++) + { + if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin) + { + Element &bucket = buckets[i][exponents[i].expWindow/2]; + if (exponents[i].negateNext) + Accumulate(bucket, Inverse(g)); + else + Accumulate(bucket, g); + exponents[i].FindNextWindow(); + } + notDone = notDone || !exponents[i].finished; + } + + if (notDone) + { + g = Double(g); + expBitPosition++; + } + } + + for (i=0; i<expCount; i++) + { + Element &r = *results++; + r = buckets[i][buckets[i].size()-1]; + if (buckets[i].size() > 1) + { + for (int j = buckets[i].size()-2; j >= 1; j--) + { + Accumulate(buckets[i][j], buckets[i][j+1]); + Accumulate(r, buckets[i][j]); + } + Accumulate(buckets[i][0], buckets[i][1]); + r = Add(Double(r), buckets[i][0]); + } + } +} + +template <class T> T AbstractRing<T>::Exponentiate(const Element &base, const Integer &exponent) const +{ + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; +} + +template <class T> T AbstractRing<T>::CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const +{ + return MultiplicativeGroup().AbstractGroup<T>::CascadeScalarMultiply(x, e1, y, e2); +} + +template <class Element, class Iterator> Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end) +{ + return GeneralCascadeMultiplication<Element>(ring.MultiplicativeGroup(), begin, end); +} + +template <class T> +void AbstractRing<T>::SimultaneousExponentiate(T *results, const T &base, const Integer *exponents, unsigned int expCount) const +{ + MultiplicativeGroup().AbstractGroup<T>::SimultaneousMultiply(results, base, exponents, expCount); +} + +NAMESPACE_END diff --git a/algebra.h b/algebra.h new file mode 100644 index 0000000..bb36e59 --- /dev/null +++ b/algebra.h @@ -0,0 +1,275 @@ +#ifndef CRYPTOPP_ALGEBRA_H +#define CRYPTOPP_ALGEBRA_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; + +// "const Element&" returned by member functions are references +// to internal data members. Since each object may have only +// one such data member for holding results, the following code +// will produce incorrect results: +// abcd = group.Add(group.Add(a,b), group.Add(c,d)); +// But this should be fine: +// abcd = group.Add(a, group.Add(b, group.Add(c,d)); + +//! Abstract Group +template <class T> class AbstractGroup +{ +public: + typedef T Element; + + virtual ~AbstractGroup() {} + + virtual bool Equal(const Element &a, const Element &b) const =0; + virtual const Element& Identity() const =0; + virtual const Element& Add(const Element &a, const Element &b) const =0; + virtual const Element& Inverse(const Element &a) const =0; + virtual bool InversionIsFast() const {return false;} + + virtual const Element& Double(const Element &a) const; + virtual const Element& Subtract(const Element &a, const Element &b) const; + virtual Element& Accumulate(Element &a, const Element &b) const; + virtual Element& Reduce(Element &a, const Element &b) const; + + virtual Element ScalarMultiply(const Element &a, const Integer &e) const; + virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; +}; + +//! Abstract Ring +template <class T> class AbstractRing : public AbstractGroup<T> +{ +public: + typedef T Element; + + AbstractRing() {m_mg.m_pRing = this;} + AbstractRing(const AbstractRing &source) {m_mg.m_pRing = this;} + AbstractRing& operator=(const AbstractRing &source) {return *this;} + + virtual bool IsUnit(const Element &a) const =0; + virtual const Element& MultiplicativeIdentity() const =0; + virtual const Element& Multiply(const Element &a, const Element &b) const =0; + virtual const Element& MultiplicativeInverse(const Element &a) const =0; + + virtual const Element& Square(const Element &a) const; + virtual const Element& Divide(const Element &a, const Element &b) const; + + virtual Element Exponentiate(const Element &a, const Integer &e) const; + virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + virtual const AbstractGroup<T>& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup<T> + { + public: + const AbstractRing<T>& GetRing() const + {return *m_pRing;} + + bool Equal(const Element &a, const Element &b) const + {return GetRing().Equal(a, b);} + + const Element& Identity() const + {return GetRing().MultiplicativeIdentity();} + + const Element& Add(const Element &a, const Element &b) const + {return GetRing().Multiply(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return a = GetRing().Multiply(a, b);} + + const Element& Inverse(const Element &a) const + {return GetRing().MultiplicativeInverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return GetRing().Divide(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return a = GetRing().Divide(a, b);} + + const Element& Double(const Element &a) const + {return GetRing().Square(a);} + + Element ScalarMultiply(const Element &a, const Integer &e) const + {return GetRing().Exponentiate(a, e);} + + Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const + {return GetRing().CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);} + + const AbstractRing<T> *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +//! Base and Exponent +template <class T, class E = Integer> +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {} + bool operator<(const BaseAndExponent<T, E> &rhs) const {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template <class Element, class Iterator> + Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end); +template <class Element, class Iterator> + Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end); + +// ******************************************************** + +//! Abstract Euclidean Domain +template <class T> class AbstractEuclideanDomain : public AbstractRing<T> +{ +public: + typedef T Element; + + virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0; + + virtual const Element& Mod(const Element &a, const Element &b) const =0; + virtual const Element& Gcd(const Element &a, const Element &b) const; + +protected: + mutable Element result; +}; + +// ******************************************************** + +//! EuclideanDomainOf +template <class T> class EuclideanDomainOf : public AbstractEuclideanDomain<T> +{ +public: + typedef T Element; + + EuclideanDomainOf() {} + + bool Equal(const Element &a, const Element &b) const + {return a==b;} + + const Element& Identity() const + {return Element::Zero();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a+b;} + + Element& Accumulate(Element &a, const Element &b) const + {return a+=b;} + + const Element& Inverse(const Element &a) const + {return result = -a;} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a-b;} + + Element& Reduce(Element &a, const Element &b) const + {return a-=b;} + + const Element& Double(const Element &a) const + {return result = a.Doubled();} + + const Element& MultiplicativeIdentity() const + {return Element::One();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a*b;} + + const Element& Square(const Element &a) const + {return result = a.Squared();} + + bool IsUnit(const Element &a) const + {return a.IsUnit();} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse();} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a/b;} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a%b;} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d);} + +private: + mutable Element result; +}; + +//! Quotient Ring +template <class T> class QuotientRing : public AbstractRing<typename T::Element> +{ +public: + typedef T EuclideanDomain; + typedef typename T::Element Element; + + QuotientRing(const EuclideanDomain &domain, const Element &modulus) + : m_domain(domain), m_modulus(modulus) {} + + const EuclideanDomain & GetDomain() const + {return m_domain;} + + const Element& GetModulus() const + {return m_modulus;} + + bool Equal(const Element &a, const Element &b) const + {return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());} + + const Element& Identity() const + {return m_domain.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return m_domain.Add(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return m_domain.Accumulate(a, b);} + + const Element& Inverse(const Element &a) const + {return m_domain.Inverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return m_domain.Subtract(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return m_domain.Reduce(a, b);} + + const Element& Double(const Element &a) const + {return m_domain.Double(a);} + + bool IsUnit(const Element &a) const + {return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));} + + const Element& MultiplicativeIdentity() const + {return m_domain.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);} + + const Element& Square(const Element &a) const + {return m_domain.Mod(m_domain.Square(a), m_modulus);} + + const Element& MultiplicativeInverse(const Element &a) const; + +protected: + EuclideanDomain m_domain; + Element m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/algparam.cpp b/algparam.cpp new file mode 100644 index 0000000..1ef7de4 --- /dev/null +++ b/algparam.cpp @@ -0,0 +1,16 @@ +// algparam.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "algparam.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +const std::type_info &g_typeidInteger = typeid(Integer); + +void AssignIntToInteger(void *pInteger, const void *pInt) +{ + *reinterpret_cast<Integer *>(pInteger) = *reinterpret_cast<const int *>(pInt); +} + +NAMESPACE_END diff --git a/algparam.h b/algparam.h new file mode 100644 index 0000000..3e09d1f --- /dev/null +++ b/algparam.h @@ -0,0 +1,323 @@ +#ifndef CRYPTOPP_ALGPARAM_H +#define CRYPTOPP_ALGPARAM_H + +#include "cryptlib.h" +#include "smartptr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! used to pass byte array input as part of a NameValuePairs object +/*! the deepCopy option is used when the NameValuePairs object can't + keep a copy of the data available */ +class ConstByteArrayParameter +{ +public: + ConstByteArrayParameter(const char *data = NULL, bool deepCopy = false) + { + Assign((const byte *)data, data ? strlen(data) : 0, deepCopy); + } + ConstByteArrayParameter(const byte *data, unsigned int size, bool deepCopy = false) + { + Assign(data, size, deepCopy); + } + template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(string[0])==1); + Assign((const byte *)string.data(), string.size(), deepCopy); + } + + void Assign(const byte *data, unsigned int size, bool deepCopy) + { + if (deepCopy) + m_block.Assign(data, size); + else + { + m_data = data; + m_size = size; + } + m_deepCopy = deepCopy; + } + + const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;} + const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;} + unsigned int size() const {return m_deepCopy ? m_block.size() : m_size;} + +private: + bool m_deepCopy; + const byte *m_data; + unsigned int m_size; + SecByteBlock m_block; +}; + +class ByteArrayParameter +{ +public: + ByteArrayParameter(byte *data = NULL, unsigned int size = 0) + : m_data(data), m_size(size) {} + ByteArrayParameter(SecByteBlock &block) + : m_data(block.begin()), m_size(block.size()) {} + + byte *begin() const {return m_data;} + byte *end() const {return m_data + m_size;} + unsigned int size() const {return m_size;} + +private: + byte *m_data; + unsigned int m_size; +}; + +class CombinedNameValuePairs : public NameValuePairs +{ +public: + CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2) + : m_pairs1(pairs1), m_pairs2(pairs2) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + if (strcmp(name, "ValueNames") == 0) + return m_pairs1.GetVoidValue(name, valueType, pValue) && m_pairs2.GetVoidValue(name, valueType, pValue); + else + return m_pairs1.GetVoidValue(name, valueType, pValue) || m_pairs2.GetVoidValue(name, valueType, pValue); + } + + const NameValuePairs &m_pairs1, &m_pairs2; +}; + +template <class T, class BASE> +class GetValueHelperClass +{ +public: + GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue) + : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) + { + if (strcmp(name, "ValueNames") == 0) + m_found = m_getValueNames = true; + + std::string thisPointerName = std::string("ThisPointer:") + typeid(T).name(); + + if (m_getValueNames) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(std::string), *m_valueType); + if (typeid(T) != typeid(BASE)) + pObject->BASE::GetVoidValue(name, valueType, pValue); + (*reinterpret_cast<std::string *>(m_pValue) += thisPointerName) += ";"; + } + else if (name == thisPointerName) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(T *), *m_valueType); + *reinterpret_cast<const T **>(pValue) = pObject; + m_found = true; + } + else if (typeid(T) != typeid(BASE)) + m_found = pObject->BASE::GetVoidValue(name, valueType, pValue); + } + + operator bool() const {return m_found;} + + template <class R> + GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const) + { + if (m_getValueNames) + (*reinterpret_cast<std::string *>(m_pValue) += name) += ";"; + else if (!m_found && strcmp(name, m_name) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType); + *reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)(); + m_found = true; + } + return *this; + } + + GetValueHelperClass<T,BASE> &Assignable() + { + std::string thisObjectName = std::string("ThisObject:") + typeid(T).name(); + if (m_getValueNames) + (*reinterpret_cast<std::string *>(m_pValue) += thisObjectName) += ";"; + else if (!m_found && m_name == thisObjectName) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); + *reinterpret_cast<T *>(m_pValue) = *m_pObject; + m_found = true; + } + return *this; + } + +private: + const T *m_pObject; + const char *m_name; + const std::type_info *m_valueType; + void *m_pValue; + bool m_found, m_getValueNames; +}; + +template <class BASE, class T> +GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, BASE *dummy=NULL) +{ + return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue); +} + +template <class T> +GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue) +{ + return GetValueHelperClass<T, T>(pObject, name, valueType, pValue); +} + +// ******************************************************** + +template <class R> +R Hack_DefaultValueFromConstReferenceType(const R &) +{ + return R(); +} + +template <class R> +bool Hack_GetValueIntoConstReference(const NameValuePairs &source, const char *name, const R &value) +{ + return source.GetValue(name, const_cast<R &>(value)); +} + +template <class T, class BASE> +class AssignFromHelperClass +{ +public: + AssignFromHelperClass(T *pObject, const NameValuePairs &source) + : m_pObject(pObject), m_source(source), m_done(false) + { + if (source.GetThisObject(*pObject)) + m_done = true; + else if (typeid(BASE) != typeid(T)) + pObject->BASE::AssignFrom(source); + } + + template <class R> + AssignFromHelperClass & operator()(const char *name, void (T::*pm)(R)) // VC60 workaround: "const R &" here causes compiler error + { + if (!m_done) + { + R value = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL)); + if (!Hack_GetValueIntoConstReference(m_source, name, value)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'"); + (m_pObject->*pm)(value); + } + return *this; + } + + template <class R, class S> + AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(R, S)) // VC60 workaround: "const R &" here causes compiler error + { + if (!m_done) + { + R value1 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL)); + if (!Hack_GetValueIntoConstReference(m_source, name1, value1)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'"); + S value2 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<S>(*(int *)NULL)); + if (!Hack_GetValueIntoConstReference(m_source, name2, value2)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'"); + (m_pObject->*pm)(value1, value2); + } + return *this; + } + +private: + T *m_pObject; + const NameValuePairs &m_source; + bool m_done; +}; + +template <class BASE, class T> +AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source, BASE *dummy=NULL) +{ + return AssignFromHelperClass<T, BASE>(pObject, source); +} + +template <class T> +AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass<T, T>(pObject, source); +} + +// ******************************************************** + +void AssignIntToInteger(void *pInteger, const void *pInt); + +extern const std::type_info &g_typeidInteger; + +template <class BASE, class T> +class AlgorithmParameters : public NameValuePairs +{ +public: + AlgorithmParameters(const BASE &base, const char *name, const T &value) + : m_base(base), m_name(name), m_value(value) +#ifndef NDEBUG + , m_used(false) +#endif + {} + +#ifndef NDEBUG + AlgorithmParameters(const AlgorithmParameters ©) + : m_base(copy.m_base), m_name(copy.m_name), m_value(copy.m_value), m_used(false) + { + copy.m_used = true; + } + + // TODO: revisit after implementing some tracing mechanism, this won't work because of exceptions +// ~AlgorithmParameters() {assert(m_used);} // use assert here because we don't want to throw out of a destructor +#endif + + template <class R> + AlgorithmParameters<AlgorithmParameters<BASE,T>, R> operator()(const char *name, const R &value) const + { + return AlgorithmParameters<AlgorithmParameters<BASE,T>, R>(*this, name, value); + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + if (strcmp(name, "ValueNames") == 0) + { + ThrowIfTypeMismatch(name, typeid(std::string), valueType); + m_base.GetVoidValue(name, valueType, pValue); + (*reinterpret_cast<std::string *>(pValue) += m_name) += ";"; + return true; + } + else if (strcmp(name, m_name) == 0) + { + // special case for retrieving an Integer parameter when an int was passed in + if (valueType == g_typeidInteger && typeid(T) == typeid(int)) + AssignIntToInteger(pValue, &m_value); + else + { + ThrowIfTypeMismatch(name, typeid(T), valueType); + *reinterpret_cast<T *>(pValue) = m_value; + } +#ifndef NDEBUG + m_used = true; +#endif + return true; + } + else + return m_base.GetVoidValue(name, valueType, pValue); + } + +private: + BASE m_base; + const char *m_name; + T m_value; +#ifndef NDEBUG + mutable bool m_used; +#endif +}; + +template <class T> +AlgorithmParameters<NullNameValuePairs,T> MakeParameters(const char *name, const T &value) +{ + return AlgorithmParameters<NullNameValuePairs,T>(g_nullNameValuePairs, name, value); +} + +#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2) + +NAMESPACE_END + +#endif diff --git a/arc4.cpp b/arc4.cpp new file mode 100644 index 0000000..7d8d05a --- /dev/null +++ b/arc4.cpp @@ -0,0 +1,116 @@ +// arc4.cpp - written and placed in the public domain by Wei Dai + +// The ARC4 algorithm was first revealed in an anonymous email to the +// cypherpunks mailing list. This file originally contained some +// code copied from this email. The code has since been rewritten in order +// to clarify the copyright status of this file. It should now be +// completely in the public domain. + +#include "pch.h" +#include "arc4.h" + +NAMESPACE_BEGIN(CryptoPP) + +void ARC4_TestInstantiations() +{ + ARC4 x; +} + +ARC4_Base::~ARC4_Base() +{ + m_x = m_y = 0; +} + +void ARC4_Base::UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int keyLen) +{ + AssertValidKeyLength(keyLen); + + m_x = 1; + m_y = 0; + + unsigned int i; + for (i=0; i<256; i++) + m_state[i] = i; + + unsigned int keyIndex = 0, stateIndex = 0; + for (i=0; i<256; i++) + { + unsigned int a = m_state[i]; + stateIndex += key[keyIndex] + a; + stateIndex &= 0xff; + m_state[i] = m_state[stateIndex]; + m_state[stateIndex] = a; + if (++keyIndex >= keyLen) + keyIndex = 0; + } + + int discardBytes = params.GetIntValueWithDefault("DiscardBytes", GetDefaultDiscardBytes()); + DiscardBytes(discardBytes); +} + +template <class T> +static inline unsigned int MakeByte(T &x, T &y, byte *s) +{ + unsigned int a = s[x]; + y = (y+a) & 0xff; + unsigned int b = s[y]; + s[x] = b; + s[y] = a; + x = (x+1) & 0xff; + return s[(a+b) & 0xff]; +} + +byte ARC4_Base::GenerateByte() +{ + return MakeByte(m_x, m_y, m_state); +} + +void ARC4_Base::ProcessData(byte *outString, const byte *inString, unsigned int length) +{ + if (length == 0) + return; + + byte *const s = m_state; + unsigned int x = m_x; + unsigned int y = m_y; + + if (inString == outString) + { + do + { + *outString++ ^= MakeByte(x, y, s); + } while (--length); + } + else + { + do + { + *outString++ = *inString++ ^ MakeByte(x, y, s); + } + while(--length); + } + + m_x = x; + m_y = y; +} + +void ARC4_Base::DiscardBytes(unsigned int length) +{ + if (length == 0) + return; + + byte *const s = m_state; + unsigned int x = m_x; + unsigned int y = m_y; + + do + { + MakeByte(x, y, s); + } + while(--length); + + m_x = x; + m_y = y; +} + +NAMESPACE_END @@ -0,0 +1,59 @@ +#ifndef CRYPTOPP_ARC4_H +#define CRYPTOPP_ARC4_H + +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#RC4">Alleged RC4</a> +/*! You can #ARC4 typedef rather than this class directly. */ +class ARC4_Base : public VariableKeyLength<16, 1, 256>, public RandomNumberGenerator, public SymmetricCipher +{ +public: + ~ARC4_Base(); + + static const char *StaticAlgorithmName() {return "ARC4";} + + byte GenerateByte(); + void DiscardBytes(unsigned int n); + + void ProcessData(byte *outString, const byte *inString, unsigned int length); + + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + + typedef SymmetricCipherFinalTemplate<ARC4_Base> Encryption; + typedef SymmetricCipherFinalTemplate<ARC4_Base> Decryption; + +protected: + void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + virtual unsigned int GetDefaultDiscardBytes() const {return 0;} + + FixedSizeSecBlock<byte, 256> m_state; + byte m_x, m_y; +}; + +//! . +typedef SymmetricCipherFinalTemplate<ARC4_Base> ARC4; + +//! Modified ARC4: it discards the first 256 bytes of keystream which may be weaker than the rest +/*! You can #MARC4 typedef rather than this class directly. */ +class MARC4_Base : public ARC4_Base +{ +public: + static const char *StaticAlgorithmName() {return "MARC4";} + + typedef SymmetricCipherFinalTemplate<MARC4_Base> Encryption; + typedef SymmetricCipherFinalTemplate<MARC4_Base> Decryption; + +protected: + unsigned int GetDefaultDiscardBytes() const {return 256;} +}; + +//! . +typedef SymmetricCipherFinalTemplate<MARC4_Base> MARC4; + +NAMESPACE_END + +#endif diff --git a/argnames.h b/argnames.h new file mode 100644 index 0000000..ed227ee --- /dev/null +++ b/argnames.h @@ -0,0 +1,54 @@ +#ifndef CRYPTOPP_ARGNAMES_H +#define CRYPTOPP_ARGNAMES_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +DOCUMENTED_NAMESPACE_BEGIN(Name) + +#define CRYPTOPP_DEFINE_NAME_STRING(name) inline const char *name() {return #name;} + +CRYPTOPP_DEFINE_NAME_STRING(ValueNames) //!< string, a list of value names with a semicolon (';') after each name +CRYPTOPP_DEFINE_NAME_STRING(Version) //!< int +CRYPTOPP_DEFINE_NAME_STRING(Seed) //!< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Key) //!< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(IV) //!< const byte * +CRYPTOPP_DEFINE_NAME_STRING(StolenIV) //!< byte * +CRYPTOPP_DEFINE_NAME_STRING(Rounds) //!< int +CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize) //!< int +CRYPTOPP_DEFINE_NAME_STRING(WordSize) //!< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(BlockSize) //!< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength) //!< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(KeySize) //!< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(ModulusSize) //!< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize) //!< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)//!< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(Modulus) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicExponent) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicElement) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(Cofactor) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator) //!< Integer, ECP::Point, or EC2N::Point +CRYPTOPP_DEFINE_NAME_STRING(Curve) //!< ECP or EC2N +CRYPTOPP_DEFINE_NAME_STRING(GroupOID) //!< OID +CRYPTOPP_DEFINE_NAME_STRING(Prime1) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(Prime2) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2) //!< Integer +CRYPTOPP_DEFINE_NAME_STRING(PutMessage) //!< bool +CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags) //!< word32 +CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags) //!< word32 +CRYPTOPP_DEFINE_NAME_STRING(InputBuffer) //!< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer) //!< ByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(XMACC_Counter) //!< word32 + +DOCUMENTED_NAMESPACE_END + +NAMESPACE_END + +#endif @@ -0,0 +1,556 @@ +// asn.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "asn.h" + +#include <iomanip> +#include <time.h> + +NAMESPACE_BEGIN(CryptoPP) +USING_NAMESPACE(std) + +/// DER Length +unsigned int DERLengthEncode(BufferedTransformation &bt, unsigned int length) +{ + unsigned int i=0; + if (length <= 0x7f) + { + bt.Put(byte(length)); + i++; + } + else + { + bt.Put(byte(BytePrecision(length) | 0x80)); + i++; + for (int j=BytePrecision(length); j; --j) + { + bt.Put(byte(length >> (j-1)*8)); + i++; + } + } + return i; +} + +bool BERLengthDecode(BufferedTransformation &bt, unsigned int &length, bool &definiteLength) +{ + byte b; + + if (!bt.Get(b)) + return false; + + if (!(b & 0x80)) + { + definiteLength = true; + length = b; + } + else + { + unsigned int lengthBytes = b & 0x7f; + + if (lengthBytes == 0) + { + definiteLength = false; + return true; + } + + definiteLength = true; + length = 0; + while (lengthBytes--) + { + if (length >> (8*(sizeof(length)-1))) + BERDecodeError(); // length about to overflow + + if (!bt.Get(b)) + return false; + + length = (length << 8) | b; + } + } + return true; +} + +bool BERLengthDecode(BufferedTransformation &bt, unsigned int &length) +{ + bool definiteLength; + if (!BERLengthDecode(bt, length, definiteLength)) + BERDecodeError(); + return definiteLength; +} + +void DEREncodeNull(BufferedTransformation &out) +{ + out.Put(TAG_NULL); + out.Put(0); +} + +void BERDecodeNull(BufferedTransformation &in) +{ + byte b; + if (!in.Get(b) || b != TAG_NULL) + BERDecodeError(); + unsigned int length; + if (!BERLengthDecode(in, length) || length != 0) + BERDecodeError(); +} + +/// ASN Strings +unsigned int DEREncodeOctetString(BufferedTransformation &bt, const byte *str, unsigned int strLen) +{ + bt.Put(OCTET_STRING); + unsigned int lengthBytes = DERLengthEncode(bt, strLen); + bt.Put(str, strLen); + return 1+lengthBytes+strLen; +} + +unsigned int DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str) +{ + return DEREncodeOctetString(bt, str.begin(), str.size()); +} + +unsigned int BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str) +{ + byte b; + if (!bt.Get(b) || b != OCTET_STRING) + BERDecodeError(); + + unsigned int bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + + str.resize(bc); + if (bc != bt.Get(str, bc)) + BERDecodeError(); + return bc; +} + +unsigned int BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str) +{ + byte b; + if (!bt.Get(b) || b != OCTET_STRING) + BERDecodeError(); + + unsigned int bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + + bt.TransferTo(str, bc); + return bc; +} + +unsigned int DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag) +{ + bt.Put(asnTag); + unsigned int lengthBytes = DERLengthEncode(bt, str.size()); + bt.Put((const byte *)str.data(), str.size()); + return 1+lengthBytes+str.size(); +} + +unsigned int BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag) +{ + byte b; + if (!bt.Get(b) || b != asnTag) + BERDecodeError(); + + unsigned int bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + + SecByteBlock temp(bc); + if (bc != bt.Get(temp, bc)) + BERDecodeError(); + str.assign((char *)temp.begin(), bc); + return bc; +} + +/// ASN BitString +unsigned int DEREncodeBitString(BufferedTransformation &bt, const byte *str, unsigned int strLen, unsigned int unusedBits) +{ + bt.Put(BIT_STRING); + unsigned int lengthBytes = DERLengthEncode(bt, strLen+1); + bt.Put((byte)unusedBits); + bt.Put(str, strLen); + return 2+lengthBytes+strLen; +} + +unsigned int BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits) +{ + byte b; + if (!bt.Get(b) || b != BIT_STRING) + BERDecodeError(); + + unsigned int bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + + byte unused; + if (!bt.Get(unused)) + BERDecodeError(); + unusedBits = unused; + str.resize(bc-1); + if ((bc-1) != bt.Get(str, bc-1)) + BERDecodeError(); + return bc-1; +} + +void OID::EncodeValue(BufferedTransformation &bt, unsigned long v) +{ + for (unsigned int i=RoundUpToMultipleOf(STDMAX(7U,BitPrecision(v)), 7U)-7; i != 0; i-=7) + bt.Put((byte)(0x80 | ((v >> i) & 0x7f))); + bt.Put((byte)(v & 0x7f)); +} + +unsigned int OID::DecodeValue(BufferedTransformation &bt, unsigned long &v) +{ + byte b; + unsigned int i=0; + v = 0; + while (true) + { + if (!bt.Get(b)) + BERDecodeError(); + i++; + v <<= 7; + v += b & 0x7f; + if (!(b & 0x80)) + return i; + } +} + +void OID::DEREncode(BufferedTransformation &bt) const +{ + assert(m_values.size() >= 2); + ByteQueue temp; + temp.Put(byte(m_values[0] * 40 + m_values[1])); + for (unsigned int i=2; i<m_values.size(); i++) + EncodeValue(temp, m_values[i]); + bt.Put(OBJECT_IDENTIFIER); + DERLengthEncode(bt, temp.CurrentSize()); + temp.TransferTo(bt); +} + +void OID::BERDecode(BufferedTransformation &bt) +{ + byte b; + if (!bt.Get(b) || b != OBJECT_IDENTIFIER) + BERDecodeError(); + + unsigned int length; + if (!BERLengthDecode(bt, length) || length < 1) + BERDecodeError(); + + if (!bt.Get(b)) + BERDecodeError(); + + length--; + m_values.resize(2); + m_values[0] = b / 40; + m_values[1] = b % 40; + + while (length > 0) + { + unsigned long v; + unsigned int valueLen = DecodeValue(bt, v); + if (valueLen > length) + BERDecodeError(); + m_values.push_back(v); + length -= valueLen; + } +} + +void OID::BERDecodeAndCheck(BufferedTransformation &bt) const +{ + OID oid(bt); + if (*this != oid) + BERDecodeError(); +} + +inline BufferedTransformation & EncodedObjectFilter::CurrentTarget() +{ + if (m_flags & PUT_OBJECTS) + return *AttachedTransformation(); + else + return TheBitBucket(); +} + +void EncodedObjectFilter::Put(const byte *inString, unsigned int length) +{ + if (m_nCurrentObject == m_nObjects) + { + AttachedTransformation()->Put(inString, length); + return; + } + + LazyPutter lazyPutter(m_queue, inString, length); + + while (m_queue.AnyRetrievable()) + { + switch (m_state) + { + case IDENTIFIER: + if (!m_queue.Get(m_id)) + return; + m_queue.TransferTo(CurrentTarget(), 1); + m_state = LENGTH; // fall through + case LENGTH: + { + byte b; + if (m_level > 0 && m_id == 0 && m_queue.Peek(b) && b == 0) + { + m_queue.TransferTo(CurrentTarget(), 1); + m_level--; + m_state = IDENTIFIER; + break; + } + ByteQueue::Walker walker(m_queue); + bool definiteLength; + if (!BERLengthDecode(walker, m_lengthRemaining, definiteLength)) + return; + m_queue.TransferTo(CurrentTarget(), walker.GetCurrentPosition()); + if (!((m_id & CONSTRUCTED) || definiteLength)) + BERDecodeError(); + if (!definiteLength) + { + if (!(m_id & CONSTRUCTED)) + BERDecodeError(); + m_level++; + m_state = IDENTIFIER; + break; + } + m_state = BODY; // fall through + } + case BODY: + m_lengthRemaining -= m_queue.TransferTo(CurrentTarget(), m_lengthRemaining); + + if (m_lengthRemaining == 0) + m_state = IDENTIFIER; + } + + if (m_state == IDENTIFIER && m_level == 0) + { + // just finished processing a level 0 object + ++m_nCurrentObject; + + if (m_flags & PUT_MESSANGE_END_AFTER_EACH_OBJECT) + AttachedTransformation()->MessageEnd(); + + if (m_nCurrentObject == m_nObjects) + { + if (m_flags & PUT_MESSANGE_END_AFTER_ALL_OBJECTS) + AttachedTransformation()->MessageEnd(); + + if (m_flags & PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS) + AttachedTransformation()->MessageSeriesEnd(); + + m_queue.TransferAllTo(*AttachedTransformation()); + return; + } + } + } +} + +BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag) + : m_inQueue(inQueue), m_finished(false) +{ + byte b; + if (!m_inQueue.Get(b) || b != asnTag) + BERDecodeError(); + + m_definiteLength = BERLengthDecode(m_inQueue, m_length); +} + +BERGeneralDecoder::BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag) + : m_inQueue(inQueue), m_finished(false) +{ + byte b; + if (!m_inQueue.Get(b) || b != asnTag) + BERDecodeError(); + + m_definiteLength = BERLengthDecode(m_inQueue, m_length); + if (!m_definiteLength && !(asnTag & CONSTRUCTED)) + BERDecodeError(); // cannot be primitive have indefinite length +} + +BERGeneralDecoder::~BERGeneralDecoder() +{ + try // avoid throwing in constructor + { + if (!m_finished) + MessageEnd(); + } + catch (...) + { + } +} + +bool BERGeneralDecoder::EndReached() const +{ + if (m_definiteLength) + return m_length == 0; + else + { // check end-of-content octets + word16 i; + return (m_inQueue.PeekWord16(i)==2 && i==0); + } +} + +byte BERGeneralDecoder::PeekByte() const +{ + byte b; + if (!Peek(b)) + BERDecodeError(); + return b; +} + +void BERGeneralDecoder::CheckByte(byte check) +{ + byte b; + if (!Get(b) || b != check) + BERDecodeError(); +} + +void BERGeneralDecoder::MessageEnd() +{ + m_finished = true; + if (m_definiteLength) + { + if (m_length != 0) + BERDecodeError(); + } + else + { // remove end-of-content octets + word16 i; + if (m_inQueue.GetWord16(i) != 2 || i != 0) + BERDecodeError(); + } +} + +unsigned int BERGeneralDecoder::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + if (m_definiteLength && transferBytes > m_length) + transferBytes = m_length; + unsigned int blockedBytes = m_inQueue.TransferTo2(target, transferBytes, channel, blocking); + ReduceLength(transferBytes); + return blockedBytes; +} + +unsigned int BERGeneralDecoder::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + if (m_definiteLength) + end = STDMIN((unsigned long)m_length, end); + return m_inQueue.CopyRangeTo2(target, begin, end, channel, blocking); +} + +unsigned int BERGeneralDecoder::ReduceLength(unsigned int delta) +{ + if (m_definiteLength) + { + if (m_length < delta) + BERDecodeError(); + m_length -= delta; + } + return delta; +} + +DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag) + : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag) +{ +} + +DERGeneralEncoder::DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag) + : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag) +{ +} + +DERGeneralEncoder::~DERGeneralEncoder() +{ + try // avoid throwing in constructor + { + if (!m_finished) + MessageEnd(); + } + catch (...) + { + } +} + +void DERGeneralEncoder::MessageEnd() +{ + m_finished = true; + unsigned int length = (unsigned int)CurrentSize(); + m_outQueue.Put(m_asnTag); + DERLengthEncode(m_outQueue, length); + TransferTo(m_outQueue); +} + +// ************************************************************* + +void X509PublicKey::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder subjectPublicKeyInfo(bt); + BERSequenceDecoder algorithm(subjectPublicKeyInfo); + GetAlgorithmID().BERDecodeAndCheck(algorithm); + bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); + subjectPublicKey.CheckByte(0); // unused bits + BERDecodeKey2(subjectPublicKey, parametersPresent, subjectPublicKey.RemainingLength()); + subjectPublicKey.MessageEnd(); + subjectPublicKeyInfo.MessageEnd(); +} + +void X509PublicKey::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder subjectPublicKeyInfo(bt); + + DERSequenceEncoder algorithm(subjectPublicKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + DEREncodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); + subjectPublicKey.Put(0); // unused bits + DEREncodeKey(subjectPublicKey); + subjectPublicKey.MessageEnd(); + + subjectPublicKeyInfo.MessageEnd(); +} + +void PKCS8PrivateKey::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKeyInfo(bt); + word32 version; + BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0); // check version + + BERSequenceDecoder algorithm(privateKeyInfo); + GetAlgorithmID().BERDecodeAndCheck(algorithm); + bool parametersPresent = BERDecodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING); + BERDecodeKey2(octetString, parametersPresent, privateKeyInfo.RemainingLength()); + octetString.MessageEnd(); + + BERDecodeOptionalAttributes(privateKeyInfo); + privateKeyInfo.MessageEnd(); +} + +void PKCS8PrivateKey::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKeyInfo(bt); + DEREncodeUnsigned<word32>(privateKeyInfo, 0); // version + + DERSequenceEncoder algorithm(privateKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + DEREncodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING); + DEREncodeKey(octetString); + octetString.MessageEnd(); + + DEREncodeOptionalAttributes(privateKeyInfo); + privateKeyInfo.MessageEnd(); +} + +NAMESPACE_END @@ -0,0 +1,344 @@ +#ifndef CRYPTOPP_ASN_H +#define CRYPTOPP_ASN_H + +#include "filters.h" +#include "queue.h" +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +// these tags and flags are not complete +enum ASNTag +{ + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + TAG_NULL = 0x05, + OBJECT_IDENTIFIER = 0x06, + OBJECT_DESCRIPTOR = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0a, + UTF8_STRING = 0x0c, + SEQUENCE = 0x10, + SET = 0x11, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + VIDEOTEXT_STRING = 0x15, + IA5_STRING = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + GRAPHIC_STRING = 0x19, + VISIBLE_STRING = 0x1a, + GENERAL_STRING = 0x1b +}; + +enum ASNIdFlag +{ + UNIVERSAL = 0x00, +// DATA = 0x01, +// HEADER = 0x02, + CONSTRUCTED = 0x20, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xc0 +}; + +inline void BERDecodeError() {throw BERDecodeErr();} + +class UnknownOID : public BERDecodeErr +{ +public: + UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {} + UnknownOID(const char *err) : BERDecodeErr(err) {} +}; + +// unsigned int DERLengthEncode(unsigned int length, byte *output=0); +unsigned int DERLengthEncode(BufferedTransformation &out, unsigned int length); +// returns false if indefinite length +bool BERLengthDecode(BufferedTransformation &in, unsigned int &length); + +void DEREncodeNull(BufferedTransformation &out); +void BERDecodeNull(BufferedTransformation &in); + +unsigned int DEREncodeOctetString(BufferedTransformation &out, const byte *str, unsigned int strLen); +unsigned int DEREncodeOctetString(BufferedTransformation &out, const SecByteBlock &str); +unsigned int BERDecodeOctetString(BufferedTransformation &in, SecByteBlock &str); +unsigned int BERDecodeOctetString(BufferedTransformation &in, BufferedTransformation &str); + +// for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +unsigned int DEREncodeTextString(BufferedTransformation &out, const std::string &str, byte asnTag); +unsigned int BERDecodeTextString(BufferedTransformation &in, std::string &str, byte asnTag); + +unsigned int DEREncodeBitString(BufferedTransformation &out, const byte *str, unsigned int strLen, unsigned int unusedBits=0); +unsigned int BERDecodeBitString(BufferedTransformation &in, SecByteBlock &str, unsigned int &unusedBits); + +//! Object Identifier +class OID +{ +public: + OID() {} + OID(unsigned long v) : m_values(1, v) {} + OID(BufferedTransformation &bt) {BERDecode(bt);} + + inline OID & operator+=(unsigned long rhs) {m_values.push_back(rhs); return *this;} + + void DEREncode(BufferedTransformation &bt) const; + void BERDecode(BufferedTransformation &bt); + + // throw BERDecodeErr() if decoded value doesn't equal this OID + void BERDecodeAndCheck(BufferedTransformation &bt) const; + + std::vector<unsigned long> m_values; + +private: + static void EncodeValue(BufferedTransformation &bt, unsigned long v); + static unsigned int DecodeValue(BufferedTransformation &bt, unsigned long &v); +}; + +class EncodedObjectFilter : public Filter +{ +public: + enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8}; + EncodedObjectFilter(BufferedTransformation *attachment = NULL, unsigned int nObjects = 1, word32 flags = 0); + + void Put(const byte *inString, unsigned int length); + + unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;} + unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];} + +private: + BufferedTransformation & CurrentTarget(); + + word32 m_flags; + unsigned int m_nObjects, m_nCurrentObject, m_level; + std::vector<unsigned int> m_positions; + ByteQueue m_queue; + enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state; + byte m_id; + unsigned int m_lengthRemaining; +}; + +//! BER General Decoder +class BERGeneralDecoder : public Store +{ +public: + explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag); + explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag); + ~BERGeneralDecoder(); + + bool IsDefiniteLength() const {return m_definiteLength;} + unsigned int RemainingLength() const {assert(m_definiteLength); return m_length;} + bool EndReached() const; + byte PeekByte() const; + void CheckByte(byte b); + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + + // call this to denote end of sequence + void MessageEnd(); + +protected: + BufferedTransformation &m_inQueue; + bool m_finished, m_definiteLength; + unsigned int m_length; + +private: + void StoreInitialize(const NameValuePairs ¶meters) {assert(false);} + unsigned int ReduceLength(unsigned int delta); +}; + +//! DER General Encoder +class DERGeneralEncoder : public ByteQueue +{ +public: + explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED); + explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED); + ~DERGeneralEncoder(); + + // call this to denote end of sequence + void MessageEnd(); + +private: + BufferedTransformation &m_outQueue; + bool m_finished; + + byte m_asnTag; +}; + +//! BER Sequence Decoder +class BERSequenceDecoder : public BERGeneralDecoder +{ +public: + explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +//! DER Sequence Encoder +class DERSequenceEncoder : public DERGeneralEncoder +{ +public: + explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +//! BER Set Decoder +class BERSetDecoder : public BERGeneralDecoder +{ +public: + explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag = SET | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} + explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag = SET | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +//! DER Set Encoder +class DERSetEncoder : public DERGeneralEncoder +{ +public: + explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag = SET | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} + explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag = SET | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +template <class T> +class ASNOptional : public member_ptr<T> +{ +public: + void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED) + { + byte b; + if (seqDecoder.Peek(b) && (b & mask) == tag) + reset(new T(seqDecoder)); + } + void DEREncode(BufferedTransformation &out) + { + if (get() != NULL) + get()->DEREncode(out); + } +}; + +//! . +class ASN1Key : public ASN1CryptoMaterial +{ +public: + virtual OID GetAlgorithmID() const =0; + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} // see RFC 2459, section 7.3.1 + // one of the following two should be overriden + virtual void BERDecodeKey(BufferedTransformation &bt) {assert(false);} + virtual void BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size) + {BERDecodeKey(bt);} + virtual void DEREncodeKey(BufferedTransformation &bt) const =0; +}; + +//! . +class X509PublicKey : virtual public ASN1Key, public PublicKey +{ +public: + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; +}; + +//! . +class PKCS8PrivateKey : virtual public ASN1Key, public PrivateKey +{ +public: + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt) + {} // TODO: skip optional attributes if present + virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const + {} +}; + +// ******************************************************** + +//! DER Encode Unsigned +/*! for INTEGER, BOOLEAN, and ENUM */ +template <class T> +unsigned int DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER) +{ + byte buf[sizeof(w)+1]; + unsigned int bc; + if (asnTag == BOOLEAN) + { + buf[sizeof(w)] = w ? 0xff : 0; + bc = 1; + } + else + { + buf[0] = 0; + for (unsigned int i=0; i<sizeof(w); i++) + buf[i+1] = byte(w >> (sizeof(w)-1-i)*8); + bc = sizeof(w); + while (bc > 1 && buf[sizeof(w)+1-bc] == 0) + --bc; + if (buf[sizeof(w)+1-bc] & 0x80) + ++bc; + } + out.Put(asnTag); + unsigned int lengthBytes = DERLengthEncode(out, bc); + out.Put(buf+sizeof(w)+1-bc, bc); + return 1+lengthBytes+bc; +} + +//! BER Decode Unsigned +// VC60 workaround: std::numeric_limits<T>::max conflicts with MFC max macro +// CW41 workaround: std::numeric_limits<T>::max causes a template error +template <class T> +void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER, + T minValue = 0, T maxValue = 0xffffffff) +{ + byte b; + if (!in.Get(b) || b != asnTag) + BERDecodeError(); + + unsigned int bc; + BERLengthDecode(in, bc); + + SecByteBlock buf(bc); + + if (bc != in.Get(buf, bc)) + BERDecodeError(); + + const byte *ptr = buf; + while (bc > sizeof(w) && *ptr == 0) + { + bc--; + ptr++; + } + if (bc > sizeof(w)) + BERDecodeError(); + + w = 0; + for (unsigned int i=0; i<bc; i++) + w = (w << 8) | ptr[i]; + + if (w < minValue || w > maxValue) + BERDecodeError(); +} + +inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values == rhs.m_values;} +inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values != rhs.m_values;} +inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());} +inline ::CryptoPP::OID operator+(const ::CryptoPP::OID &lhs, unsigned long rhs) + {return ::CryptoPP::OID(lhs)+=rhs;} + +NAMESPACE_END + +#endif diff --git a/base64.cpp b/base64.cpp new file mode 100644 index 0000000..0cc48b9 --- /dev/null +++ b/base64.cpp @@ -0,0 +1,40 @@ +// base64.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "base64.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const byte s_vec[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const byte s_padding = '='; + +void Base64Encoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool insertLineBreaks = parameters.GetValueWithDefault("InsertLineBreaks", true); + int maxLineLength = parameters.GetIntValueWithDefault("MaxLineLength", 72); + + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters("EncodingLookupArray", (const byte *)s_vec) + ("PaddingByte", s_padding) + ("Log2Base", 6) + ("GroupSize", insertLineBreaks ? maxLineLength : 0) + ("Seperator", ConstByteArrayParameter("\n")) + ("Terminator", ConstByteArrayParameter("\n")))); +} + +const int *Base64Decoder::GetDecodingLookupArray() +{ + static bool s_initialized = false; + static int s_array[256]; + + if (!s_initialized) + { + InitializeDecodingLookupArray(s_array, s_vec, 64, false); + s_initialized = true; + } + return s_array; +} + +NAMESPACE_END diff --git a/base64.h b/base64.h new file mode 100644 index 0000000..33072a0 --- /dev/null +++ b/base64.h @@ -0,0 +1,36 @@ +#ifndef CRYPTOPP_BASE64_H +#define CRYPTOPP_BASE64_H + +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Base64 Encoder Class +class Base64Encoder : public SimpleProxyFilter +{ +public: + Base64Encoder(BufferedTransformation *attachment = NULL, bool insertLineBreaks = true, int maxLineLength = 72) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters("InsertLineBreaks", insertLineBreaks)("MaxLineLength", maxLineLength)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +//! Base64 Decoder Class +class Base64Decoder : public BaseN_Decoder +{ +public: + Base64Decoder(BufferedTransformation *attachment = NULL) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) {} + +private: + static const int *GetDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/basecode.cpp b/basecode.cpp new file mode 100644 index 0000000..51347b6 --- /dev/null +++ b/basecode.cpp @@ -0,0 +1,214 @@ +// basecode.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "basecode.h" +#include "fltrimpl.h" +#include <ctype.h> + +NAMESPACE_BEGIN(CryptoPP) + +void BaseN_Encoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("BaseN_Encoder", "EncodingLookupArray", m_alphabet); + + parameters.GetRequiredIntParameter("BaseN_Encoder", "Log2Base", m_bitsPerChar); + if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8) + throw InvalidArgument("BaseN_Encoder: Log2Base must be between 1 and 7 inclusive"); + + byte padding; + bool pad; + if (parameters.GetValue("PaddingByte", padding)) + pad = parameters.GetValueWithDefault("Pad", true); + else + pad = false; + m_padding = pad ? padding : -1; + + m_bytePos = m_bitPos = 0; + + int i = 8; + while (i%m_bitsPerChar != 0) + i += 8; + m_outputBlockSize = i/m_bitsPerChar; + + m_outBuf.New(m_outputBlockSize); +} + +unsigned int BaseN_Encoder::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + while (m_inputPosition < length) + { + if (m_bytePos == 0) + memset(m_outBuf, 0, m_outputBlockSize); + + m_outBuf[m_bytePos] |= begin[m_inputPosition] >> (8-m_bitsPerChar+m_bitPos); + m_outBuf[m_bytePos+1] |= ((begin[m_inputPosition] << (m_bitsPerChar-m_bitPos)) & 0xff) >> (8-m_bitsPerChar); + ++m_inputPosition; + + m_bitPos += 8; + while (m_bitPos >= m_bitsPerChar) + { + m_bitPos -= m_bitsPerChar; + ++m_bytePos; + } + + if (m_bytePos == m_outputBlockSize) + { + int i; + for (i=0; i<m_bytePos; i++) + { + assert(m_outBuf[i] < (1 << m_bitsPerChar)); + m_outBuf[i] = m_alphabet[m_outBuf[i]]; + } + FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0); + + m_bytePos = m_bitPos = 0; + } + } + if (messageEnd) + { + if (m_bitPos > 0) + ++m_bytePos; + + int i; + for (i=0; i<m_bytePos; i++) + m_outBuf[i] = m_alphabet[m_outBuf[i]]; + + if (m_padding != -1 && m_bytePos > 0) + { + memset(m_outBuf+m_bytePos, m_padding, m_outputBlockSize-m_bytePos); + m_bytePos = m_outputBlockSize; + } + FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd); + m_bytePos = m_bitPos = 0; + } + FILTER_END; +} + +void BaseN_Decoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("BaseN_Decoder", "DecodingLookupArray", m_lookup); + + parameters.GetRequiredIntParameter("BaseN_Decoder", "Log2Base", m_bitsPerChar); + if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8) + throw InvalidArgument("BaseN_Decoder: Log2Base must be between 1 and 7 inclusive"); + + m_bytePos = m_bitPos = 0; + + int i = m_bitsPerChar; + while (i%8 != 0) + i += m_bitsPerChar; + m_outputBlockSize = i/8; + + m_outBuf.New(m_outputBlockSize); +} + +unsigned int BaseN_Decoder::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + while (m_inputPosition < length) + { + unsigned int value; + value = m_lookup[begin[m_inputPosition++]]; + if (value >= 256) + continue; + + if (m_bytePos == 0 && m_bitPos == 0) + memset(m_outBuf, 0, m_outputBlockSize); + + { + int newBitPos = m_bitPos + m_bitsPerChar; + if (newBitPos <= 8) + m_outBuf[m_bytePos] |= value << (8-newBitPos); + else + { + m_outBuf[m_bytePos] |= value >> (newBitPos-8); + m_outBuf[m_bytePos+1] |= value << (16-newBitPos); + } + + m_bitPos = newBitPos; + while (m_bitPos >= 8) + { + m_bitPos -= 8; + ++m_bytePos; + } + } + + if (m_bytePos == m_outputBlockSize) + { + FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0); + m_bytePos = m_bitPos = 0; + } + } + if (messageEnd) + { + FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd); + m_bytePos = m_bitPos = 0; + } + FILTER_END_NO_MESSAGE_END; +} + +void BaseN_Decoder::InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive) +{ + std::fill(lookup, lookup+256, -1); + + for (unsigned int i=0; i<base; i++) + { + if (caseInsensitive && isalpha(alphabet[i])) + { + assert(lookup[toupper(alphabet[i])] == -1); + lookup[toupper(alphabet[i])] = i; + assert(lookup[tolower(alphabet[i])] == -1); + lookup[tolower(alphabet[i])] = i; + } + else + { + assert(lookup[alphabet[i]] == -1); + lookup[alphabet[i]] = i; + } + } +} + +void Grouper::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_groupSize = parameters.GetIntValueWithDefault("GroupSize", 0); + ConstByteArrayParameter seperator, terminator; + if (m_groupSize) + parameters.GetRequiredParameter("Grouper", "Seperator", seperator); + else + parameters.GetValue("Seperator", seperator); + parameters.GetValue("Terminator", terminator); + + m_seperator.Assign(seperator.begin(), seperator.size()); + m_terminator.Assign(terminator.begin(), terminator.size()); + m_counter = 0; +} + +unsigned int Grouper::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (m_groupSize) + { + FILTER_BEGIN; + while (m_inputPosition < length) + { + if (m_counter == m_groupSize) + { + FILTER_OUTPUT(1, m_seperator, m_seperator.size(), 0); + m_counter = 0; + } + + unsigned int len; + FILTER_OUTPUT2(2, len = STDMIN(length-m_inputPosition, m_groupSize-m_counter), + begin+m_inputPosition, len, 0); + m_inputPosition += len; + m_counter += len; + } + if (messageEnd) + FILTER_OUTPUT(3, m_terminator, m_terminator.size(), messageEnd); + FILTER_END_NO_MESSAGE_END + } + else + return Output(0, begin, length, messageEnd, blocking); +} + +NAMESPACE_END diff --git a/basecode.h b/basecode.h new file mode 100644 index 0000000..dcb49b0 --- /dev/null +++ b/basecode.h @@ -0,0 +1,82 @@ +#ifndef CRYPTOPP_BASECODE_H +#define CRYPTOPP_BASECODE_H + +#include "filters.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +class BaseN_Encoder : public Unflushable<Filter> +{ +public: + BaseN_Encoder(BufferedTransformation *attachment=NULL) + : Unflushable<Filter>(attachment) {} + + BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULL, int padding=-1) + : Unflushable<Filter>(attachment) + { + IsolatedInitialize(MakeParameters("EncodingLookupArray", alphabet) + ("Log2Base", log2base) + ("Pad", padding != -1) + ("PaddingByte", byte(padding))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + +private: + const byte *m_alphabet; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +class BaseN_Decoder : public Unflushable<Filter> +{ +public: + BaseN_Decoder(BufferedTransformation *attachment=NULL) + : Unflushable<Filter>(attachment) {} + + BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULL) + : Unflushable<Filter>(attachment) + { + IsolatedInitialize(MakeParameters("DecodingLookupArray", lookup)("Log2Base", log2base)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + + static void InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int log2base, bool caseInsensitive); + +private: + const int *m_lookup; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +class Grouper : public Bufferless<Filter> +{ +public: + Grouper(BufferedTransformation *attachment=NULL) + : Bufferless<Filter>(attachment) {} + + Grouper(int groupSize, const std::string &seperator, const std::string &terminator, BufferedTransformation *attachment=NULL) + : Bufferless<Filter>(attachment) + { + IsolatedInitialize(MakeParameters("GroupSize", groupSize) + ("Seperator", ConstByteArrayParameter(seperator)) + ("Terminator", ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + +private: + SecByteBlock m_seperator, m_terminator; + unsigned int m_groupSize, m_counter; +}; + +NAMESPACE_END + +#endif diff --git a/bench.cpp b/bench.cpp new file mode 100644 index 0000000..9a38a03 --- /dev/null +++ b/bench.cpp @@ -0,0 +1,655 @@ +// bench.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "crc.h" +#include "adler32.h" +#include "md2.h" +#include "md5.h" +#include "md5mac.h" +#include "sha.h" +#include "haval.h" +#include "tiger.h" +#include "ripemd.h" +#include "panama.h" +#include "idea.h" +#include "des.h" +#include "rc2.h" +#include "arc4.h" +#include "rc5.h" +#include "blowfish.h" +#include "diamond.h" +#include "wake.h" +#include "3way.h" +#include "safer.h" +#include "gost.h" +#include "shark.h" +#include "cast.h" +#include "square.h" +#include "skipjack.h" +#include "seal.h" +#include "rc6.h" +#include "mars.h" +#include "rijndael.h" +#include "twofish.h" +#include "serpent.h" +#include "hmac.h" +#include "xormac.h" +#include "cbcmac.h" +#include "dmac.h" +#include "blumshub.h" +#include "rsa.h" +#include "nr.h" +#include "dsa.h" +#include "luc.h" +#include "rabin.h" +#include "rw.h" +#include "eccrypto.h" +#include "ecp.h" +#include "ec2n.h" +#include "asn.h" +#include "rng.h" +#include "files.h" +#include "hex.h" +#include "modes.h" +#include "mdc.h" +#include "lubyrack.h" +#include "sapphire.h" +#include "tea.h" +#include "dh.h" +#include "mqv.h" +#include "xtrcrypt.h" +#include "esign.h" + +#include "bench.h" + +#include <time.h> +#include <math.h> +#include <iostream> +#include <iomanip> + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +#ifdef CLOCKS_PER_SEC +static const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC; +#elif defined(CLK_TCK) +static const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK; +#else +static const double CLOCK_TICKS_PER_SECOND = 1000000.0; +#endif + +static const byte *const key=(byte *)"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + +static double logtotal = 0; +static unsigned int logcount = 0; + +void OutputResultBytes(const char *name, unsigned long length, double timeTaken) +{ + double mbs = length / timeTaken / (1024*1024); + cout << "<TR><TH>" << name; + cout << "<TD>" << length; + cout << setiosflags(ios::fixed); + cout << "<TD>" << setprecision(3) << timeTaken; + cout << "<TD>" << setprecision(3) << mbs << endl; + cout << resetiosflags(ios::fixed); + logtotal += log(mbs); + logcount++; +} + +void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken) +{ + cout << "<TR><TH>" << name << " " << operation << (pc ? " with precomputation" : ""); + cout << "<TD>" << iterations; + cout << setiosflags(ios::fixed); + cout << "<TD>" << setprecision(3) << timeTaken; + cout << "<TD>" << setprecision(2) << (1000*timeTaken/iterations) << endl; + cout << resetiosflags(ios::fixed); + + logtotal += log(iterations/timeTaken); + logcount++; +} + +void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal) +{ + const int BUF_SIZE = RoundDownToMultipleOf(1024U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize()); + SecByteBlock buf(BUF_SIZE); + const int nBlocks = BUF_SIZE / cipher.BlockSize(); + clock_t start = clock(); + + unsigned long i=0, length=BUF_SIZE; + double timeTaken; + do + { + length *= 2; + for (; i<length; i+=BUF_SIZE) + cipher.ProcessAndXorMultipleBlocks(buf, NULL, buf, nBlocks); + timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND; + } + while (timeTaken < 2.0/3*timeTotal); + + OutputResultBytes(name, length, timeTaken); +} + +void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal) +{ + const int BUF_SIZE=1024; + SecByteBlock buf(BUF_SIZE); + clock_t start = clock(); + + unsigned long i=0, length=BUF_SIZE; + double timeTaken; + do + { + length *= 2; + for (; i<length; i+=BUF_SIZE) + cipher.ProcessString(buf, BUF_SIZE); + timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND; + } + while (timeTaken < 2.0/3*timeTotal); + + OutputResultBytes(name, length, timeTaken); +} + +void BenchMark(const char *name, HashTransformation &hash, double timeTotal) +{ + const int BUF_SIZE=1024; + SecByteBlock buf(BUF_SIZE); + LC_RNG rng(time(NULL)); + rng.GenerateBlock(buf, BUF_SIZE); + clock_t start = clock(); + + unsigned long i=0, length=BUF_SIZE; + double timeTaken; + do + { + length *= 2; + for (; i<length; i+=BUF_SIZE) + hash.Update(buf, BUF_SIZE); + timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND; + } + while (timeTaken < 2.0/3*timeTotal); + + OutputResultBytes(name, length, timeTaken); +} + +void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal) +{ + const int BUF_SIZE=1024; + SecByteBlock buf(BUF_SIZE); + LC_RNG rng(time(NULL)); + rng.GenerateBlock(buf, BUF_SIZE); + clock_t start = clock(); + + unsigned long i=0, length=BUF_SIZE; + double timeTaken; + do + { + length *= 2; + for (; i<length; i+=BUF_SIZE) + bt.Put(buf, BUF_SIZE); + timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND; + } + while (timeTaken < 2.0/3*timeTotal); + + OutputResultBytes(name, length, timeTaken); +} + +void BenchMarkEncryption(const char *name, PK_Encryptor &key, double timeTotal, bool pc=false) +{ + unsigned int len = 16; + LC_RNG rng(time(NULL)); + SecByteBlock plaintext(len), ciphertext(key.CiphertextLength(len)); + rng.GenerateBlock(plaintext, len); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + key.Encrypt(rng, plaintext, len, ciphertext); + + OutputResultOperations(name, "Encryption", pc, i, timeTaken); + + if (!pc && key.GetMaterial().SupportsPrecomputation()) + { + key.AccessMaterial().Precompute(16); + BenchMarkEncryption(name, key, timeTotal, true); + } +} + +void BenchMarkDecryption(const char *name, PK_Decryptor &priv, PK_Encryptor &pub, double timeTotal) +{ + unsigned int len = 16; + LC_RNG rng(time(NULL)); + SecByteBlock ciphertext(pub.CiphertextLength(len)); + SecByteBlock plaintext(pub.MaxPlaintextLength(ciphertext.size())); + rng.GenerateBlock(plaintext, len); + pub.Encrypt(rng, plaintext, len, ciphertext); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + priv.Decrypt(ciphertext, ciphertext.size(), plaintext); + + OutputResultOperations(name, "Decryption", false, i, timeTaken); +} + +void BenchMarkSigning(const char *name, PK_Signer &key, double timeTotal, bool pc=false) +{ + unsigned int len = 16; + LC_RNG rng(time(NULL)); + SecByteBlock message(len), signature(key.SignatureLength()); + rng.GenerateBlock(message, len); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + key.SignMessage(rng, message, len, signature); + + OutputResultOperations(name, "Signature", pc, i, timeTaken); + + if (!pc && key.GetMaterial().SupportsPrecomputation()) + { + key.AccessMaterial().Precompute(16); + BenchMarkSigning(name, key, timeTotal, true); + } +} + +void BenchMarkVerification(const char *name, const PK_Signer &priv, PK_Verifier &pub, double timeTotal, bool pc=false) +{ + unsigned int len = 16; + LC_RNG rng(time(NULL)); + SecByteBlock message(len), signature(pub.SignatureLength()); + rng.GenerateBlock(message, len); + priv.SignMessage(rng, message, len, signature); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + pub.VerifyMessage(message, len, signature); + + OutputResultOperations(name, "Verification", pc, i, timeTaken); + + if (!pc && pub.GetMaterial().SupportsPrecomputation()) + { + pub.AccessMaterial().Precompute(16); + BenchMarkVerification(name, priv, pub, timeTotal, true); + } +} + +void BenchMarkKeyGen(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + LC_RNG rng(time(NULL)); + SecByteBlock priv(d.PrivateKeyLength()), pub(d.PublicKeyLength()); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + d.GenerateKeyPair(rng, priv, pub); + + OutputResultOperations(name, "Key-Pair Generation", pc, i, timeTaken); + + if (!pc && d.GetMaterial().SupportsPrecomputation()) + { + d.AccessMaterial().Precompute(16); + BenchMarkKeyGen(name, d, timeTotal, true); + } +} + +void BenchMarkKeyGen(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + LC_RNG rng(time(NULL)); + SecByteBlock priv(d.EphemeralPrivateKeyLength()), pub(d.EphemeralPublicKeyLength()); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++) + d.GenerateEphemeralKeyPair(rng, priv, pub); + + OutputResultOperations(name, "Key-Pair Generation", pc, i, timeTaken); + + if (!pc && d.GetMaterial().SupportsPrecomputation()) + { + d.AccessMaterial().Precompute(16); + BenchMarkKeyGen(name, d, timeTotal, true); + } +} + +void BenchMarkAgreement(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + LC_RNG rng(time(NULL)); + SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength()); + SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength()); + d.GenerateKeyPair(rng, priv1, pub1); + d.GenerateKeyPair(rng, priv2, pub2); + SecByteBlock val(d.AgreedValueLength()); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2) + { + d.Agree(val, priv1, pub2); + d.Agree(val, priv2, pub1); + } + + OutputResultOperations(name, "Key Agreement", pc, i, timeTaken); +} + +void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + LC_RNG rng(time(NULL)); + SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength()); + SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength()); + SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength()); + SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength()); + d.GenerateStaticKeyPair(rng, spriv1, spub1); + d.GenerateStaticKeyPair(rng, spriv2, spub2); + d.GenerateEphemeralKeyPair(rng, epriv1, epub1); + d.GenerateEphemeralKeyPair(rng, epriv2, epub2); + SecByteBlock val(d.AgreedValueLength()); + + clock_t start = clock(); + unsigned int i; + double timeTaken; + for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2) + { + d.Agree(val, spriv1, epriv1, spub2, epub2); + d.Agree(val, spriv2, epriv2, spub1, epub1); + } + + OutputResultOperations(name, "Key Agreement", pc, i, timeTaken); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class T> +void BenchMarkKeyed(const char *name, double timeTotal, T *x=NULL) +{ + T c; + c.SetKeyWithIV(key, c.DefaultKeyLength(), key); + BenchMark(name, c, timeTotal); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class T> +void BenchMarkKeyedVariable(const char *name, double timeTotal, unsigned int keyLength, T *x=NULL) +{ + T c; + c.SetKeyWithIV(key, keyLength, key); + BenchMark(name, c, timeTotal); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class T> +void BenchMarkKeyless(const char *name, double timeTotal, T *x=NULL) +{ + T c; + BenchMark(name, c, timeTotal); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class SCHEME> +void BenchMarkCrypto(const char *filename, const char *name, double timeTotal, SCHEME *x=NULL) +{ + FileSource f(filename, true, new HexDecoder()); + typename SCHEME::Decryptor priv(f); + typename SCHEME::Encryptor pub(priv); + BenchMarkEncryption(name, pub, timeTotal); + BenchMarkDecryption(name, priv, pub, timeTotal); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class SCHEME> +void BenchMarkSignature(const char *filename, const char *name, double timeTotal, SCHEME *x=NULL) +{ + FileSource f(filename, true, new HexDecoder()); + typename SCHEME::Signer priv(f); + typename SCHEME::Verifier pub(priv); + BenchMarkSigning(name, priv, timeTotal); + BenchMarkVerification(name, priv, pub, timeTotal); +} + +//VC60 workaround: compiler bug triggered without the extra dummy parameters +template <class D> +void BenchMarkKeyAgreement(const char *filename, const char *name, double timeTotal, D *x=NULL) +{ + FileSource f(filename, true, new HexDecoder()); + D d(f); + BenchMarkKeyGen(name, d, timeTotal); + BenchMarkAgreement(name, d, timeTotal); +} + +void BenchMarkAll(double t) +{ +#if 1 + logtotal = 0; + logcount = 0; + + cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right>" << endl; + cout << "<THEAD><TR><TH>Algorithm<TH>Bytes Processed<TH>Time Taken<TH>Megabytes(2^20 bytes)/Second\n<TBODY>" << endl; + + BenchMarkKeyless<CRC32>("CRC-32", t); + BenchMarkKeyless<Adler32>("Adler-32", t); + BenchMarkKeyless<MD2>("MD2", t); + BenchMarkKeyless<MD5>("MD5", t); + BenchMarkKeyless<SHA>("SHA-1", t); + BenchMarkKeyless<SHA256>("SHA-256", t); + BenchMarkKeyless<SHA512>("SHA-512", t); + BenchMarkKeyless<HAVAL3>("HAVAL (pass=3)", t); + BenchMarkKeyless<HAVAL4>("HAVAL (pass=4)", t); + BenchMarkKeyless<HAVAL5>("HAVAL (pass=5)", t); +#ifdef WORD64_AVAILABLE + BenchMarkKeyless<Tiger>("Tiger", t); +#endif + BenchMarkKeyless<RIPEMD160>("RIPE-MD160", t); + BenchMarkKeyless<PanamaHash<LittleEndian> >("Panama Hash (little endian)", t); + BenchMarkKeyless<PanamaHash<BigEndian> >("Panama Hash (big endian)", t); + BenchMarkKeyed<MDC<MD5>::Encryption>("MDC/MD5", t); + BenchMarkKeyed<LR<MD5>::Encryption>("Luby-Rackoff/MD5", t); + BenchMarkKeyed<DES::Encryption>("DES", t); + BenchMarkKeyed<DES_XEX3::Encryption>("DES-XEX3", t); + BenchMarkKeyed<DES_EDE3::Encryption>("DES-EDE3", t); + BenchMarkKeyed<IDEA::Encryption>("IDEA", t); + BenchMarkKeyed<RC2::Encryption>("RC2", t); + BenchMarkKeyed<RC5::Encryption>("RC5 (r=16)", t); + BenchMarkKeyed<Blowfish::Encryption>("Blowfish", t); + BenchMarkKeyed<Diamond2::Encryption>("Diamond2", t); + BenchMarkKeyed<Diamond2Lite::Encryption>("Diamond2 Lite", t); + BenchMarkKeyed<ThreeWayDecryption>("3-WAY", t); + BenchMarkKeyed<TEA::Encryption>("TEA", t); + BenchMarkKeyedVariable<SAFER_SK::Encryption>("SAFER (r=8)", t, 8); + BenchMarkKeyed<GOST::Encryption>("GOST", t); +#ifdef WORD64_AVAILABLE + BenchMarkKeyed<SHARK::Encryption>("SHARK (r=6)", t); +#endif + BenchMarkKeyed<CAST128::Encryption>("CAST-128", t); + BenchMarkKeyed<CAST256::Encryption>("CAST-256", t); + BenchMarkKeyed<Square::Encryption>("Square", t); + BenchMarkKeyed<SKIPJACK::Encryption>("SKIPJACK", t); + BenchMarkKeyed<RC6::Encryption>("RC6", t); + BenchMarkKeyed<MARS::Encryption>("MARS", t); + BenchMarkKeyedVariable<Rijndael::Encryption>("Rijndael (128-bit key)", t, 16); + BenchMarkKeyedVariable<Rijndael::Encryption>("Rijndael (192-bit key)", t, 24); + BenchMarkKeyedVariable<Rijndael::Encryption>("Rijndael (256-bit key)", t, 32); + BenchMarkKeyedVariable<CTR_Mode<Rijndael>::Encryption>("Rijndael (128) CTR", t, 16); + BenchMarkKeyedVariable<OFB_Mode<Rijndael>::Encryption>("Rijndael (128) OFB", t, 16); + BenchMarkKeyedVariable<CFB_Mode<Rijndael>::Encryption>("Rijndael (128) CFB", t, 16); + BenchMarkKeyedVariable<CBC_Mode<Rijndael>::Encryption>("Rijndael (128) CBC", t, 16); + BenchMarkKeyed<Twofish::Encryption>("Twofish", t); + BenchMarkKeyed<Serpent::Encryption>("Serpent", t); + BenchMarkKeyed<ARC4>("ARC4", t); + BenchMarkKeyed<SEAL<BigEndian>::Encryption>("SEAL-3.0-BE", t); + BenchMarkKeyed<SEAL<LittleEndian>::Encryption>("SEAL-3.0-LE", t); + BenchMarkKeyed<WAKE_CFB<BigEndian>::Encryption>("WAKE-CFB-BE", t); + BenchMarkKeyed<WAKE_CFB<LittleEndian>::Encryption>("WAKE-CFB-LE", t); + BenchMarkKeyed<WAKE_OFB<BigEndian>::Encryption>("WAKE-OFB-BE", t); + BenchMarkKeyed<WAKE_OFB<LittleEndian>::Encryption>("WAKE-OFB-LE", t); + BenchMarkKeyed<PanamaCipher<LittleEndian>::Encryption>("Panama Cipher (little endian)", t); + BenchMarkKeyed<PanamaCipher<BigEndian>::Encryption>("Panama Cipher (big endian)", t); + BenchMarkKeyed<MD5MAC>("MD5-MAC", t); + BenchMarkKeyed<XMACC<MD5> >("XMACC/MD5", t); + BenchMarkKeyed<HMAC<MD5> >("HMAC/MD5", t); + BenchMarkKeyed<CBC_MAC<Rijndael> >("CBC-MAC/Rijndael", t); + BenchMarkKeyed<DMAC<Rijndael> >("DMAC/Rijndael", t); + + { + Integer p("CB6C,B8CE,6351,164F,5D0C,0C9E,9E31,E231,CF4E,D551,CBD0,E671,5D6A,7B06,D8DF,C4A7h"); + Integer q("FD2A,8594,A132,20CC,4E6D,DE77,3AAA,CF15,CD9E,E447,8592,FF46,CC77,87BE,9876,A2AFh"); + Integer s("63239752671357255800299643604761065219897634268887145610573595874544114193025997412441121667211431"); + BlumBlumShub c(p, q, s); + BenchMark("BlumBlumShub 512", c, t); + } + { + Integer p("FD2A,8594,A132,20CC,4E6D,DE77,3AAA,CF15,CD9E,E447,8592,FF46,CC77,87BE,9876,9E2C," + "8572,64C3,4CF4,188A,44D4,2130,1135,7982,6FF6,EDD3,26F0,5FAA,BAF4,A81E,7ADC,B80Bh"); + Integer q("C8B9,5797,B349,6BA3,FD72,F2C0,A796,8A65,EE0F,B4BA,272F,4FEE,4DB1,06D5,ECEB,7142," + "E8A8,E5A8,6BF9,A32F,BA37,BACC,8A75,8A6B,2DCE,D6EC,B515,980A,4BB1,08FB,6F2C,2383h"); + Integer s("3578,8F00,2965,71A4,4382,699F,45FD,3922,8238,241B,CEBA,0543,3443,E8D9,12FB,AC46," + "7EC4,8505,EC9E,7EE8,5A23,9B2A,B615,D0C4,9448,F23A,ADEE,E850,1A7A,CA30,0B5B,A408," + "D936,21BA,844E,BDD6,7848,3D1E,9137,CC87,DAA5,773B,D45A,C8BB,5392,1393,108B,6992," + "74E3,C5E2,C235,A321,0111,3BA4,BAB4,1A2F,17EE,C371,DE67,01C9,0F3D,907A,B252,9BDDh"); + BlumBlumShub c(p, q, s); + BenchMark("BlumBlumShub 1024", c, t); + } + { + Integer p("EB56,978A,7BA7,B5D9,1383,4611,94F5,4766,FCEF,CF41,958A,FC41,43D0,839F,C56B,B568," + "4ED3,9E5A,BABB,5ACE,8B11,CEBC,88A2,7C12,FFEE,E6E8,CF0A,E231,5BC2,DEDE,80B7,32F6," + "340E,D8A6,B7DE,C779,7EE5,0E16,9C88,FC9F,2A0E,EE6C,7D47,C5F2,6B06,EB8C,F1C8,2E67," + "5B82,8C28,4FB8,542F,2874,C355,CEEE,7A54,1B06,A8AB,8B66,6A5C,9DB2,72B8,74F3,7BC7h"); + Integer q("EB6B,3645,4591,8343,7331,7CAC,B02E,4BB9,DEF5,8EDC,1772,DB9B,9571,5FAB,1CDD,4FB1," + "7B9A,07CD,E715,D448,F552,CBBD,D387,C037,DE70,6661,F360,D0E8,D42E,292A,9321,DDCB," + "0BF9,C514,BFAC,3F2C,C06E,DF64,A9B8,50D6,AC4F,B9E4,014B,5624,2B40,A0D4,5D0B,6DD4," + "0989,D00E,0268,99AB,21DB,0BB4,DB38,84DA,594F,575F,95AC,1B70,45E4,96C8,C6AD,CE67h"); + Integer s("C75A,8A0D,E231,295F,C08A,1716,8611,D5EC,E9EF,B565,90EC,58C0,57D0,DA7D,C6E6,DB00," + "2282,1CA7,EA31,D64E,768C,0B19,8563,36DF,2226,F4EC,74A4,2844,2E8D,37E8,53DC,0172," + "5F56,8CF9,B444,CA02,78B3,17AF,7C78,D320,16AE,AC3D,B97F,7259,1B8F,9C84,6A16,B878," + "0595,70BB,9C52,18B5,9100,9C1F,E85A,4035,06F3,5F38,7462,F01D,0462,BFBC,A4CD,4A45," + "3A77,E7F8,DED1,D6EF,CEF7,0937,CD3F,3AF1,4F88,932D,6D4B,002C,3735,304C,C5D3,B88A," + "B57B,24B6,5346,9B46,5153,B7ED,B216,C181,B1C6,C52E,CD2B,E0AA,B1BB,0A93,C92E,4F79," + "4931,E303,7C8F,A408,8ACF,56CD,6EC0,76A2,5015,6BA4,4C50,C44D,53B9,E168,5F84,B381," + "2514,10B2,00E5,B4D1,4156,A2FE,0BF6,6F33,0A1B,91C6,31B8,1C90,02F1,FB1F,C494,8B65h"); + BlumBlumShub c(p, q, s); + BenchMark("BlumBlumShub 2048", c, t); + } + cout << "</TABLE>" << endl; + + cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right>" << endl; + cout << "<THEAD><TR><TH>Operation<TH>Iterations<TH>Total Time<TH>Milliseconds/Operation" << endl; + + cout << "<TBODY style=\"background: yellow\">" << endl; + BenchMarkCrypto<RSAES<OAEP<SHA> > >("rsa1024.dat", "RSA 1024", t); + BenchMarkCrypto<RabinES<OAEP<SHA> > >("rabi1024.dat", "Rabin 1024", t); + BenchMarkCrypto<LUCES<OAEP<SHA> > >("luc1024.dat", "LUC 1024", t); + BenchMarkCrypto<DLIES<> >("dlie1024.dat", "DLIES 1024", t); + BenchMarkCrypto<LUC_IES<> >("lucc512.dat", "LUCELG 512", t); + + cout << "<TBODY style=\"background: white\">" << endl; + BenchMarkCrypto<RSAES<OAEP<SHA> > >("rsa2048.dat", "RSA 2048", t); + BenchMarkCrypto<RabinES<OAEP<SHA> > >("rabi2048.dat", "Rabin 2048", t); + BenchMarkCrypto<LUCES<OAEP<SHA> > >("luc2048.dat", "LUC 2048", t); + BenchMarkCrypto<DLIES<> >("dlie2048.dat", "DLIES 2048", t); + BenchMarkCrypto<LUC_IES<> >("lucc1024.dat", "LUCELG 1024", t); + + cout << "<TBODY style=\"background: yellow\">" << endl; + BenchMarkSignature<RSASSA<PKCS1v15, SHA> >("rsa1024.dat", "RSA 1024", t); + BenchMarkSignature<RabinPSSR<SHA> >("rabi1024.dat", "Rabin 1024", t); + BenchMarkSignature<RWSSA<SHA> >("rw1024.dat", "RW 1024", t); + BenchMarkSignature<LUCSSA<SHA> >("luc1024.dat", "LUC 1024", t); + BenchMarkSignature<NR<SHA> >("nr1024.dat", "NR 1024", t); + BenchMarkSignature<DSA>("dsa1024.dat", "DSA 1024", t); + BenchMarkSignature<LUC_HMP<SHA> >("lucs512.dat", "LUC-HMP 512", t); + BenchMarkSignature<ESIGN<SHA> >("esig1023.dat", "ESIGN 1023", t); + BenchMarkSignature<ESIGN<SHA> >("esig1536.dat", "ESIGN 1536", t); + + cout << "<TBODY style=\"background: white\">" << endl; + BenchMarkSignature<RSASSA<PKCS1v15, SHA> >("rsa2048.dat", "RSA 2048", t); + BenchMarkSignature<RabinPSSR<SHA> >("rabi2048.dat", "Rabin 2048", t); + BenchMarkSignature<RWSSA<SHA> >("rw2048.dat", "RW 2048", t); + BenchMarkSignature<LUCSSA<SHA> >("luc2048.dat", "LUC 2048", t); + BenchMarkSignature<NR<SHA> >("nr2048.dat", "NR 2048", t); + BenchMarkSignature<LUC_HMP<SHA> >("lucs1024.dat", "LUC-HMP 1024", t); + BenchMarkSignature<ESIGN<SHA> >("esig2046.dat", "ESIGN 2046", t); + + cout << "<TBODY style=\"background: yellow\">" << endl; + BenchMarkKeyAgreement<XTR_DH>("xtrdh171.dat", "XTR-DH 171", t); + BenchMarkKeyAgreement<XTR_DH>("xtrdh342.dat", "XTR-DH 342", t); + BenchMarkKeyAgreement<DH>("dh1024.dat", "DH 1024", t); + BenchMarkKeyAgreement<DH>("dh2048.dat", "DH 2048", t); + BenchMarkKeyAgreement<LUC_DH>("lucd512.dat", "LUCDIF 512", t); + BenchMarkKeyAgreement<LUC_DH>("lucd1024.dat", "LUCDIF 1024", t); + BenchMarkKeyAgreement<MQV>("mqv1024.dat", "MQV 1024", t); + BenchMarkKeyAgreement<MQV>("mqv2048.dat", "MQV 2048", t); + + cout << "<TBODY style=\"background: white\">" << endl; + { + Integer modulus("199999999999999999999999980586675243082581144187569"); + Integer a("659942,b7261b,249174,c86bd5,e2a65b,45fe07,37d110h"); + Integer b("3ece7d,09473d,666000,5baef5,d4e00e,30159d,2df49ah"); + Integer x("25dd61,4c0667,81abc0,fe6c84,fefaa3,858ca6,96d0e8h"); + Integer y("4e2477,05aab0,b3497f,d62b5e,78a531,446729,6c3fach"); + Integer r("100000000000000000000000000000000000000000000000151"); + Integer k(2); + Integer d("76572944925670636209790912427415155085360939712345"); + + ECP ec(modulus, a, b); + ECP::Point P(x, y); + P = ec.Multiply(k, P); + ECP::Point Q(ec.Multiply(d, P)); + ECIES<ECP>::Decryptor cpriv(ec, P, r, d); + ECIES<ECP>::Encryptor cpub(cpriv); + ECDSA<ECP, SHA>::Signer spriv(cpriv); + ECDSA<ECP, SHA>::Verifier spub(spriv); + ECDH<ECP>::Domain ecdhc(ec, P, r, k); + ECMQV<ECP>::Domain ecmqvc(ec, P, r, k); + + BenchMarkEncryption("ECIES over GF(p) 168", cpub, t); + BenchMarkDecryption("ECIES over GF(p) 168", cpriv, cpub, t); + BenchMarkSigning("ECNR over GF(p) 168", spriv, t); + BenchMarkVerification("ECNR over GF(p) 168", spriv, spub, t); + BenchMarkKeyGen("ECDHC over GF(p) 168", ecdhc, t); + BenchMarkAgreement("ECDHC over GF(p) 168", ecdhc, t); + BenchMarkKeyGen("ECMQVC over GF(p) 168", ecmqvc, t); + BenchMarkAgreement("ECMQVC over GF(p) 168", ecmqvc, t); + } + + cout << "<TBODY style=\"background: yellow\">" << endl; + { + Integer r("3805993847215893016155463826195386266397436443"); + Integer k(12); + Integer d("2065729449256706362097909124274151550853609397"); + + GF2NT gf2n(155, 62, 0); + byte b[]={0x7, 0x33, 0x8f}; + EC2N ec(gf2n, PolynomialMod2::Zero(), PolynomialMod2(b,3)); + EC2N::Point P(0x7B, 0x1C8); + P = ec.Multiply(k, P); + EC2N::Point Q(ec.Multiply(d, P)); + ECIES<EC2N>::Decryptor cpriv(ec, P, r, d); + ECIES<EC2N>::Encryptor cpub(cpriv); + ECDSA<EC2N, SHA>::Signer spriv(cpriv); + ECDSA<EC2N, SHA>::Verifier spub(spriv); + ECDH<EC2N>::Domain ecdhc(ec, P, r, k); + ECMQV<EC2N>::Domain ecmqvc(ec, P, r, k); + + BenchMarkEncryption("ECIES over GF(2^n) 155", cpub, t); + BenchMarkDecryption("ECIES over GF(2^n) 155", cpriv, cpub, t); + BenchMarkSigning("ECNR over GF(2^n) 155", spriv, t); + BenchMarkVerification("ECNR over GF(2^n) 155", spriv, spub, t); + BenchMarkKeyGen("ECDHC over GF(2^n) 155", ecdhc, t); + BenchMarkAgreement("ECDHC over GF(2^n) 155", ecdhc, t); + BenchMarkKeyGen("ECMQVC over GF(2^n) 155", ecmqvc, t); + BenchMarkAgreement("ECMQVC over GF(2^n) 155", ecmqvc, t); + } + cout << "</TABLE>" << endl; + + cout << "Throughput Geometric Average: " << setiosflags(ios::fixed) << exp(logtotal/logcount) << endl; + + time_t endTime = time(NULL); + cout << "\nTest ended at " << asctime(localtime(&endTime)); +#endif +} @@ -0,0 +1,8 @@ +#ifndef CRYPTOPP_BENCH_H +#define CRYPTOPP_BENCH_H + +#include "cryptlib.h" + +void BenchMarkAll(double t=1.0); + +#endif diff --git a/bfinit.cpp b/bfinit.cpp new file mode 100644 index 0000000..714570a --- /dev/null +++ b/bfinit.cpp @@ -0,0 +1,277 @@ +#include "pch.h" +#include "blowfish.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 Blowfish::Base::p_init[Blowfish::ROUNDS+2] = +{ + 608135816U, 2242054355U, 320440878U, 57701188U, + 2752067618U, 698298832U, 137296536U, 3964562569U, + 1160258022U, 953160567U, 3193202383U, 887688300U, + 3232508343U, 3380367581U, 1065670069U, 3041331479U, + 2450970073U, 2306472731U +} ; + +const word32 Blowfish::Base::s_init[4*256] = { + 3509652390U, 2564797868U, 805139163U, 3491422135U, + 3101798381U, 1780907670U, 3128725573U, 4046225305U, + 614570311U, 3012652279U, 134345442U, 2240740374U, + 1667834072U, 1901547113U, 2757295779U, 4103290238U, + 227898511U, 1921955416U, 1904987480U, 2182433518U, + 2069144605U, 3260701109U, 2620446009U, 720527379U, + 3318853667U, 677414384U, 3393288472U, 3101374703U, + 2390351024U, 1614419982U, 1822297739U, 2954791486U, + 3608508353U, 3174124327U, 2024746970U, 1432378464U, + 3864339955U, 2857741204U, 1464375394U, 1676153920U, + 1439316330U, 715854006U, 3033291828U, 289532110U, + 2706671279U, 2087905683U, 3018724369U, 1668267050U, + 732546397U, 1947742710U, 3462151702U, 2609353502U, + 2950085171U, 1814351708U, 2050118529U, 680887927U, + 999245976U, 1800124847U, 3300911131U, 1713906067U, + 1641548236U, 4213287313U, 1216130144U, 1575780402U, + 4018429277U, 3917837745U, 3693486850U, 3949271944U, + 596196993U, 3549867205U, 258830323U, 2213823033U, + 772490370U, 2760122372U, 1774776394U, 2652871518U, + 566650946U, 4142492826U, 1728879713U, 2882767088U, + 1783734482U, 3629395816U, 2517608232U, 2874225571U, + 1861159788U, 326777828U, 3124490320U, 2130389656U, + 2716951837U, 967770486U, 1724537150U, 2185432712U, + 2364442137U, 1164943284U, 2105845187U, 998989502U, + 3765401048U, 2244026483U, 1075463327U, 1455516326U, + 1322494562U, 910128902U, 469688178U, 1117454909U, + 936433444U, 3490320968U, 3675253459U, 1240580251U, + 122909385U, 2157517691U, 634681816U, 4142456567U, + 3825094682U, 3061402683U, 2540495037U, 79693498U, + 3249098678U, 1084186820U, 1583128258U, 426386531U, + 1761308591U, 1047286709U, 322548459U, 995290223U, + 1845252383U, 2603652396U, 3431023940U, 2942221577U, + 3202600964U, 3727903485U, 1712269319U, 422464435U, + 3234572375U, 1170764815U, 3523960633U, 3117677531U, + 1434042557U, 442511882U, 3600875718U, 1076654713U, + 1738483198U, 4213154764U, 2393238008U, 3677496056U, + 1014306527U, 4251020053U, 793779912U, 2902807211U, + 842905082U, 4246964064U, 1395751752U, 1040244610U, + 2656851899U, 3396308128U, 445077038U, 3742853595U, + 3577915638U, 679411651U, 2892444358U, 2354009459U, + 1767581616U, 3150600392U, 3791627101U, 3102740896U, + 284835224U, 4246832056U, 1258075500U, 768725851U, + 2589189241U, 3069724005U, 3532540348U, 1274779536U, + 3789419226U, 2764799539U, 1660621633U, 3471099624U, + 4011903706U, 913787905U, 3497959166U, 737222580U, + 2514213453U, 2928710040U, 3937242737U, 1804850592U, + 3499020752U, 2949064160U, 2386320175U, 2390070455U, + 2415321851U, 4061277028U, 2290661394U, 2416832540U, + 1336762016U, 1754252060U, 3520065937U, 3014181293U, + 791618072U, 3188594551U, 3933548030U, 2332172193U, + 3852520463U, 3043980520U, 413987798U, 3465142937U, + 3030929376U, 4245938359U, 2093235073U, 3534596313U, + 375366246U, 2157278981U, 2479649556U, 555357303U, + 3870105701U, 2008414854U, 3344188149U, 4221384143U, + 3956125452U, 2067696032U, 3594591187U, 2921233993U, + 2428461U, 544322398U, 577241275U, 1471733935U, + 610547355U, 4027169054U, 1432588573U, 1507829418U, + 2025931657U, 3646575487U, 545086370U, 48609733U, + 2200306550U, 1653985193U, 298326376U, 1316178497U, + 3007786442U, 2064951626U, 458293330U, 2589141269U, + 3591329599U, 3164325604U, 727753846U, 2179363840U, + 146436021U, 1461446943U, 4069977195U, 705550613U, + 3059967265U, 3887724982U, 4281599278U, 3313849956U, + 1404054877U, 2845806497U, 146425753U, 1854211946U, + + 1266315497U, 3048417604U, 3681880366U, 3289982499U, + 2909710000U, 1235738493U, 2632868024U, 2414719590U, + 3970600049U, 1771706367U, 1449415276U, 3266420449U, + 422970021U, 1963543593U, 2690192192U, 3826793022U, + 1062508698U, 1531092325U, 1804592342U, 2583117782U, + 2714934279U, 4024971509U, 1294809318U, 4028980673U, + 1289560198U, 2221992742U, 1669523910U, 35572830U, + 157838143U, 1052438473U, 1016535060U, 1802137761U, + 1753167236U, 1386275462U, 3080475397U, 2857371447U, + 1040679964U, 2145300060U, 2390574316U, 1461121720U, + 2956646967U, 4031777805U, 4028374788U, 33600511U, + 2920084762U, 1018524850U, 629373528U, 3691585981U, + 3515945977U, 2091462646U, 2486323059U, 586499841U, + 988145025U, 935516892U, 3367335476U, 2599673255U, + 2839830854U, 265290510U, 3972581182U, 2759138881U, + 3795373465U, 1005194799U, 847297441U, 406762289U, + 1314163512U, 1332590856U, 1866599683U, 4127851711U, + 750260880U, 613907577U, 1450815602U, 3165620655U, + 3734664991U, 3650291728U, 3012275730U, 3704569646U, + 1427272223U, 778793252U, 1343938022U, 2676280711U, + 2052605720U, 1946737175U, 3164576444U, 3914038668U, + 3967478842U, 3682934266U, 1661551462U, 3294938066U, + 4011595847U, 840292616U, 3712170807U, 616741398U, + 312560963U, 711312465U, 1351876610U, 322626781U, + 1910503582U, 271666773U, 2175563734U, 1594956187U, + 70604529U, 3617834859U, 1007753275U, 1495573769U, + 4069517037U, 2549218298U, 2663038764U, 504708206U, + 2263041392U, 3941167025U, 2249088522U, 1514023603U, + 1998579484U, 1312622330U, 694541497U, 2582060303U, + 2151582166U, 1382467621U, 776784248U, 2618340202U, + 3323268794U, 2497899128U, 2784771155U, 503983604U, + 4076293799U, 907881277U, 423175695U, 432175456U, + 1378068232U, 4145222326U, 3954048622U, 3938656102U, + 3820766613U, 2793130115U, 2977904593U, 26017576U, + 3274890735U, 3194772133U, 1700274565U, 1756076034U, + 4006520079U, 3677328699U, 720338349U, 1533947780U, + 354530856U, 688349552U, 3973924725U, 1637815568U, + 332179504U, 3949051286U, 53804574U, 2852348879U, + 3044236432U, 1282449977U, 3583942155U, 3416972820U, + 4006381244U, 1617046695U, 2628476075U, 3002303598U, + 1686838959U, 431878346U, 2686675385U, 1700445008U, + 1080580658U, 1009431731U, 832498133U, 3223435511U, + 2605976345U, 2271191193U, 2516031870U, 1648197032U, + 4164389018U, 2548247927U, 300782431U, 375919233U, + 238389289U, 3353747414U, 2531188641U, 2019080857U, + 1475708069U, 455242339U, 2609103871U, 448939670U, + 3451063019U, 1395535956U, 2413381860U, 1841049896U, + 1491858159U, 885456874U, 4264095073U, 4001119347U, + 1565136089U, 3898914787U, 1108368660U, 540939232U, + 1173283510U, 2745871338U, 3681308437U, 4207628240U, + 3343053890U, 4016749493U, 1699691293U, 1103962373U, + 3625875870U, 2256883143U, 3830138730U, 1031889488U, + 3479347698U, 1535977030U, 4236805024U, 3251091107U, + 2132092099U, 1774941330U, 1199868427U, 1452454533U, + 157007616U, 2904115357U, 342012276U, 595725824U, + 1480756522U, 206960106U, 497939518U, 591360097U, + 863170706U, 2375253569U, 3596610801U, 1814182875U, + 2094937945U, 3421402208U, 1082520231U, 3463918190U, + 2785509508U, 435703966U, 3908032597U, 1641649973U, + 2842273706U, 3305899714U, 1510255612U, 2148256476U, + 2655287854U, 3276092548U, 4258621189U, 236887753U, + 3681803219U, 274041037U, 1734335097U, 3815195456U, + 3317970021U, 1899903192U, 1026095262U, 4050517792U, + 356393447U, 2410691914U, 3873677099U, 3682840055U, + + 3913112168U, 2491498743U, 4132185628U, 2489919796U, + 1091903735U, 1979897079U, 3170134830U, 3567386728U, + 3557303409U, 857797738U, 1136121015U, 1342202287U, + 507115054U, 2535736646U, 337727348U, 3213592640U, + 1301675037U, 2528481711U, 1895095763U, 1721773893U, + 3216771564U, 62756741U, 2142006736U, 835421444U, + 2531993523U, 1442658625U, 3659876326U, 2882144922U, + 676362277U, 1392781812U, 170690266U, 3921047035U, + 1759253602U, 3611846912U, 1745797284U, 664899054U, + 1329594018U, 3901205900U, 3045908486U, 2062866102U, + 2865634940U, 3543621612U, 3464012697U, 1080764994U, + 553557557U, 3656615353U, 3996768171U, 991055499U, + 499776247U, 1265440854U, 648242737U, 3940784050U, + 980351604U, 3713745714U, 1749149687U, 3396870395U, + 4211799374U, 3640570775U, 1161844396U, 3125318951U, + 1431517754U, 545492359U, 4268468663U, 3499529547U, + 1437099964U, 2702547544U, 3433638243U, 2581715763U, + 2787789398U, 1060185593U, 1593081372U, 2418618748U, + 4260947970U, 69676912U, 2159744348U, 86519011U, + 2512459080U, 3838209314U, 1220612927U, 3339683548U, + 133810670U, 1090789135U, 1078426020U, 1569222167U, + 845107691U, 3583754449U, 4072456591U, 1091646820U, + 628848692U, 1613405280U, 3757631651U, 526609435U, + 236106946U, 48312990U, 2942717905U, 3402727701U, + 1797494240U, 859738849U, 992217954U, 4005476642U, + 2243076622U, 3870952857U, 3732016268U, 765654824U, + 3490871365U, 2511836413U, 1685915746U, 3888969200U, + 1414112111U, 2273134842U, 3281911079U, 4080962846U, + 172450625U, 2569994100U, 980381355U, 4109958455U, + 2819808352U, 2716589560U, 2568741196U, 3681446669U, + 3329971472U, 1835478071U, 660984891U, 3704678404U, + 4045999559U, 3422617507U, 3040415634U, 1762651403U, + 1719377915U, 3470491036U, 2693910283U, 3642056355U, + 3138596744U, 1364962596U, 2073328063U, 1983633131U, + 926494387U, 3423689081U, 2150032023U, 4096667949U, + 1749200295U, 3328846651U, 309677260U, 2016342300U, + 1779581495U, 3079819751U, 111262694U, 1274766160U, + 443224088U, 298511866U, 1025883608U, 3806446537U, + 1145181785U, 168956806U, 3641502830U, 3584813610U, + 1689216846U, 3666258015U, 3200248200U, 1692713982U, + 2646376535U, 4042768518U, 1618508792U, 1610833997U, + 3523052358U, 4130873264U, 2001055236U, 3610705100U, + 2202168115U, 4028541809U, 2961195399U, 1006657119U, + 2006996926U, 3186142756U, 1430667929U, 3210227297U, + 1314452623U, 4074634658U, 4101304120U, 2273951170U, + 1399257539U, 3367210612U, 3027628629U, 1190975929U, + 2062231137U, 2333990788U, 2221543033U, 2438960610U, + 1181637006U, 548689776U, 2362791313U, 3372408396U, + 3104550113U, 3145860560U, 296247880U, 1970579870U, + 3078560182U, 3769228297U, 1714227617U, 3291629107U, + 3898220290U, 166772364U, 1251581989U, 493813264U, + 448347421U, 195405023U, 2709975567U, 677966185U, + 3703036547U, 1463355134U, 2715995803U, 1338867538U, + 1343315457U, 2802222074U, 2684532164U, 233230375U, + 2599980071U, 2000651841U, 3277868038U, 1638401717U, + 4028070440U, 3237316320U, 6314154U, 819756386U, + 300326615U, 590932579U, 1405279636U, 3267499572U, + 3150704214U, 2428286686U, 3959192993U, 3461946742U, + 1862657033U, 1266418056U, 963775037U, 2089974820U, + 2263052895U, 1917689273U, 448879540U, 3550394620U, + 3981727096U, 150775221U, 3627908307U, 1303187396U, + 508620638U, 2975983352U, 2726630617U, 1817252668U, + 1876281319U, 1457606340U, 908771278U, 3720792119U, + 3617206836U, 2455994898U, 1729034894U, 1080033504U, + + 976866871U, 3556439503U, 2881648439U, 1522871579U, + 1555064734U, 1336096578U, 3548522304U, 2579274686U, + 3574697629U, 3205460757U, 3593280638U, 3338716283U, + 3079412587U, 564236357U, 2993598910U, 1781952180U, + 1464380207U, 3163844217U, 3332601554U, 1699332808U, + 1393555694U, 1183702653U, 3581086237U, 1288719814U, + 691649499U, 2847557200U, 2895455976U, 3193889540U, + 2717570544U, 1781354906U, 1676643554U, 2592534050U, + 3230253752U, 1126444790U, 2770207658U, 2633158820U, + 2210423226U, 2615765581U, 2414155088U, 3127139286U, + 673620729U, 2805611233U, 1269405062U, 4015350505U, + 3341807571U, 4149409754U, 1057255273U, 2012875353U, + 2162469141U, 2276492801U, 2601117357U, 993977747U, + 3918593370U, 2654263191U, 753973209U, 36408145U, + 2530585658U, 25011837U, 3520020182U, 2088578344U, + 530523599U, 2918365339U, 1524020338U, 1518925132U, + 3760827505U, 3759777254U, 1202760957U, 3985898139U, + 3906192525U, 674977740U, 4174734889U, 2031300136U, + 2019492241U, 3983892565U, 4153806404U, 3822280332U, + 352677332U, 2297720250U, 60907813U, 90501309U, + 3286998549U, 1016092578U, 2535922412U, 2839152426U, + 457141659U, 509813237U, 4120667899U, 652014361U, + 1966332200U, 2975202805U, 55981186U, 2327461051U, + 676427537U, 3255491064U, 2882294119U, 3433927263U, + 1307055953U, 942726286U, 933058658U, 2468411793U, + 3933900994U, 4215176142U, 1361170020U, 2001714738U, + 2830558078U, 3274259782U, 1222529897U, 1679025792U, + 2729314320U, 3714953764U, 1770335741U, 151462246U, + 3013232138U, 1682292957U, 1483529935U, 471910574U, + 1539241949U, 458788160U, 3436315007U, 1807016891U, + 3718408830U, 978976581U, 1043663428U, 3165965781U, + 1927990952U, 4200891579U, 2372276910U, 3208408903U, + 3533431907U, 1412390302U, 2931980059U, 4132332400U, + 1947078029U, 3881505623U, 4168226417U, 2941484381U, + 1077988104U, 1320477388U, 886195818U, 18198404U, + 3786409000U, 2509781533U, 112762804U, 3463356488U, + 1866414978U, 891333506U, 18488651U, 661792760U, + 1628790961U, 3885187036U, 3141171499U, 876946877U, + 2693282273U, 1372485963U, 791857591U, 2686433993U, + 3759982718U, 3167212022U, 3472953795U, 2716379847U, + 445679433U, 3561995674U, 3504004811U, 3574258232U, + 54117162U, 3331405415U, 2381918588U, 3769707343U, + 4154350007U, 1140177722U, 4074052095U, 668550556U, + 3214352940U, 367459370U, 261225585U, 2610173221U, + 4209349473U, 3468074219U, 3265815641U, 314222801U, + 3066103646U, 3808782860U, 282218597U, 3406013506U, + 3773591054U, 379116347U, 1285071038U, 846784868U, + 2669647154U, 3771962079U, 3550491691U, 2305946142U, + 453669953U, 1268987020U, 3317592352U, 3279303384U, + 3744833421U, 2610507566U, 3859509063U, 266596637U, + 3847019092U, 517658769U, 3462560207U, 3443424879U, + 370717030U, 4247526661U, 2224018117U, 4143653529U, + 4112773975U, 2788324899U, 2477274417U, 1456262402U, + 2901442914U, 1517677493U, 1846949527U, 2295493580U, + 3734397586U, 2176403920U, 1280348187U, 1908823572U, + 3871786941U, 846861322U, 1172426758U, 3287448474U, + 3383383037U, 1655181056U, 3139813346U, 901632758U, + 1897031941U, 2986607138U, 3066810236U, 3447102507U, + 1393639104U, 373351379U, 950779232U, 625454576U, + 3124240540U, 4148612726U, 2007998917U, 544563296U, + 2244738638U, 2330496472U, 2058025392U, 1291430526U, + 424198748U, 50039436U, 29584100U, 3605783033U, + 2429876329U, 2791104160U, 1057563949U, 3255363231U, + 3075367218U, 3463963227U, 1469046755U, 985887462U +}; + +NAMESPACE_END diff --git a/blowfish.cpp b/blowfish.cpp new file mode 100644 index 0000000..fa6c723 --- /dev/null +++ b/blowfish.cpp @@ -0,0 +1,99 @@ +// blowfish.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "blowfish.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Blowfish::Base::UncheckedSetKey(CipherDir dir, const byte *key_string, unsigned int keylength) +{ + AssertValidKeyLength(keylength); + + unsigned i, j=0, k; + word32 data, dspace[2] = {0, 0}; + + memcpy(pbox, p_init, sizeof(p_init)); + memcpy(sbox, s_init, sizeof(s_init)); + + // Xor key string into encryption key vector + for (i=0 ; i<ROUNDS+2 ; ++i) + { + data = 0 ; + for (k=0 ; k<4 ; ++k ) + data = (data << 8) | key_string[j++ % keylength]; + pbox[i] ^= data; + } + + crypt_block(dspace, pbox); + + for (i=0; i<ROUNDS; i+=2) + crypt_block(pbox+i, pbox+i+2); + + crypt_block(pbox+ROUNDS, sbox); + + for (i=0; i<4*256-2; i+=2) + crypt_block(sbox+i, sbox+i+2); + + if (dir==DECRYPTION) + for (i=0; i<(ROUNDS+2)/2; i++) + std::swap(pbox[i], pbox[ROUNDS+1-i]); +} + +// this version is only used to make pbox and sbox +void Blowfish::Base::crypt_block(const word32 in[2], word32 out[2]) const +{ + word32 left = in[0]; + word32 right = in[1]; + + const word32 *const s=sbox; + const word32 *p=pbox; + + left ^= p[0]; + + for (unsigned i=0; i<ROUNDS/2; i++) + { + right ^= (((s[GETBYTE(left,3)] + s[256+GETBYTE(left,2)]) + ^ s[2*256+GETBYTE(left,1)]) + s[3*256+GETBYTE(left,0)]) + ^ p[2*i+1]; + + left ^= (((s[GETBYTE(right,3)] + s[256+GETBYTE(right,2)]) + ^ s[2*256+GETBYTE(right,1)]) + s[3*256+GETBYTE(right,0)]) + ^ p[2*i+2]; + } + + right ^= p[ROUNDS+1]; + + out[0] = right; + out[1] = left; +} + +void Blowfish::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut<word32, BigEndian> Block; + + word32 left, right; + Block::Get(inBlock)(left)(right); + + const word32 *const s=sbox; + const word32 *p=pbox; + + left ^= p[0]; + + for (unsigned i=0; i<ROUNDS/2; i++) + { + right ^= (((s[GETBYTE(left,3)] + s[256+GETBYTE(left,2)]) + ^ s[2*256+GETBYTE(left,1)]) + s[3*256+GETBYTE(left,0)]) + ^ p[2*i+1]; + + left ^= (((s[GETBYTE(right,3)] + s[256+GETBYTE(right,2)]) + ^ s[2*256+GETBYTE(right,1)]) + s[3*256+GETBYTE(right,0)]) + ^ p[2*i+2]; + } + + right ^= p[ROUNDS+1]; + + Block::Put(xorBlock, outBlock)(right)(left); +} + +NAMESPACE_END diff --git a/blowfish.h b/blowfish.h new file mode 100644 index 0000000..1ca2c20 --- /dev/null +++ b/blowfish.h @@ -0,0 +1,45 @@ +#ifndef CRYPTOPP_BLOWFISH_H +#define CRYPTOPP_BLOWFISH_H + +/** \file */ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Blowfish_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 56>, public FixedRounds<16> +{ + static const char *StaticAlgorithmName() {return "Blowfish";} +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#Blowfish">Blowfish</a> +class Blowfish : public Blowfish_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Blowfish_Info> + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void UncheckedSetKey(CipherDir direction, const byte *key_string, unsigned int keylength); + + private: + void crypt_block(const word32 in[2], word32 out[2]) const; + + static const word32 p_init[ROUNDS+2]; + static const word32 s_init[4*256]; + + FixedSizeSecBlock<word32, ROUNDS+2> pbox; + FixedSizeSecBlock<word32, 4*256> sbox; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +typedef Blowfish::Encryption BlowfishEncryption; +typedef Blowfish::Decryption BlowfishDecryption; + +NAMESPACE_END + +#endif diff --git a/blumshub.cpp b/blumshub.cpp new file mode 100644 index 0000000..f715c84 --- /dev/null +++ b/blumshub.cpp @@ -0,0 +1,49 @@ +// blumshub.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "blumshub.h" + +NAMESPACE_BEGIN(CryptoPP) + +PublicBlumBlumShub::PublicBlumBlumShub(const Integer &n, const Integer &seed) + : modn(n), + maxBits(BitPrecision(n.BitCount())-1) +{ + current = modn.Square(modn.Square(seed)); + bitsLeft = maxBits; +} + +unsigned int PublicBlumBlumShub::GenerateBit() +{ + if (bitsLeft==0) + { + current = modn.Square(current); + bitsLeft = maxBits; + } + + return current.GetBit(--bitsLeft); +} + +byte PublicBlumBlumShub::GenerateByte() +{ + byte b=0; + for (int i=0; i<8; i++) + b = (b << 1) | PublicBlumBlumShub::GenerateBit(); + return b; +} + +BlumBlumShub::BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed) + : PublicBlumBlumShub(p*q, seed), + p(p), q(q), + x0(modn.Square(seed)) +{ +} + +void BlumBlumShub::Seek(dword index) +{ + Integer e = a_exp_b_mod_c (2, ((index*8) / maxBits + 1), (p-1)*(q-1)); + current = modn.Exponentiate(x0, e); + bitsLeft = maxBits - int((index*8) % maxBits); +} + +NAMESPACE_END diff --git a/blumshub.h b/blumshub.h new file mode 100644 index 0000000..10b3cac --- /dev/null +++ b/blumshub.h @@ -0,0 +1,58 @@ +#ifndef CRYPTOPP_BLUMSHUB_H +#define CRYPTOPP_BLUMSHUB_H + +#include "modarith.h" + +NAMESPACE_BEGIN(CryptoPP) + +class BlumGoldwasserPublicKey; +class BlumGoldwasserPrivateKey; + +//! BlumBlumShub without factorization of the modulus +class PublicBlumBlumShub : public RandomNumberGenerator, + public StreamTransformation +{ +public: + PublicBlumBlumShub(const Integer &n, const Integer &seed); + + unsigned int GenerateBit(); + byte GenerateByte(); + + void ProcessData(byte *outString, const byte *inString, unsigned int length) + { + while (length--) + *outString++ = *inString ^ GenerateByte(); + } + + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + +protected: + const ModularArithmetic modn; + const int maxBits; + Integer current; + int bitsLeft; + + friend class BlumGoldwasserPublicKey; + friend class BlumGoldwasserPrivateKey; +}; + +//! BlumBlumShub with factorization of the modulus +class BlumBlumShub : public PublicBlumBlumShub +{ +public: + // Make sure p and q are both primes congruent to 3 mod 4 and at least 512 bits long, + // seed is the secret key and should be about as big as p*q + BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed); + + bool IsRandomAccess() const {return true;} + void Seek(dword index); + +protected: + const Integer p, q; + const Integer x0; +}; + +NAMESPACE_END + +#endif diff --git a/cast.cpp b/cast.cpp new file mode 100644 index 0000000..5eec498 --- /dev/null +++ b/cast.cpp @@ -0,0 +1,296 @@ +// cast.cpp - written and placed in the public domain by Wei Dai and Leonard Janke +// based on Steve Reid's public domain cast.c + +#include "pch.h" +#include "cast.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/* Macros to access 8-bit bytes out of a 32-bit word */ +#define U8a(x) GETBYTE(x,3) +#define U8b(x) GETBYTE(x,2) +#define U8c(x) GETBYTE(x,1) +#define U8d(x) GETBYTE(x,0) + +/* CAST uses three different round functions */ +#define f1(l, r, km, kr) \ + t = rotlVariable(km + r, kr); \ + l ^= ((S[0][U8a(t)] ^ S[1][U8b(t)]) - \ + S[2][U8c(t)]) + S[3][U8d(t)]; +#define f2(l, r, km, kr) \ + t = rotlVariable(km ^ r, kr); \ + l ^= ((S[0][U8a(t)] - S[1][U8b(t)]) + \ + S[2][U8c(t)]) ^ S[3][U8d(t)]; +#define f3(l, r, km, kr) \ + t = rotlVariable(km - r, kr); \ + l ^= ((S[0][U8a(t)] + S[1][U8b(t)]) ^ \ + S[2][U8c(t)]) - S[3][U8d(t)]; + +#define F1(l, r, i, j) f1(l, r, K[i], K[i+j]) +#define F2(l, r, i, j) f2(l, r, K[i], K[i+j]) +#define F3(l, r, i, j) f3(l, r, K[i], K[i+j]) + +typedef BlockGetAndPut<word32, BigEndian> Block; + +void CAST128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 t, l, r; + + /* Get inblock into l,r */ + Block::Get(inBlock)(l)(r); + /* Do the work */ + F1(l, r, 0, 16); + F2(r, l, 1, 16); + F3(l, r, 2, 16); + F1(r, l, 3, 16); + F2(l, r, 4, 16); + F3(r, l, 5, 16); + F1(l, r, 6, 16); + F2(r, l, 7, 16); + F3(l, r, 8, 16); + F1(r, l, 9, 16); + F2(l, r, 10, 16); + F3(r, l, 11, 16); + /* Only do full 16 rounds if key length > 80 bits */ + if (!reduced) { + F1(l, r, 12, 16); + F2(r, l, 13, 16); + F3(l, r, 14, 16); + F1(r, l, 15, 16); + } + /* Put l,r into outblock */ + Block::Put(xorBlock, outBlock)(r)(l); +} + +void CAST128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 t, l, r; + + /* Get inblock into l,r */ + Block::Get(inBlock)(r)(l); + /* Only do full 16 rounds if key length > 80 bits */ + if (!reduced) { + F1(r, l, 15, 16); + F3(l, r, 14, 16); + F2(r, l, 13, 16); + F1(l, r, 12, 16); + } + F3(r, l, 11, 16); + F2(l, r, 10, 16); + F1(r, l, 9, 16); + F3(l, r, 8, 16); + F2(r, l, 7, 16); + F1(l, r, 6, 16); + F3(r, l, 5, 16); + F2(l, r, 4, 16); + F1(r, l, 3, 16); + F3(l, r, 2, 16); + F2(r, l, 1, 16); + F1(l, r, 0, 16); + /* Put l,r into outblock */ + Block::Put(xorBlock, outBlock)(l)(r); + /* Wipe clean */ + t = l = r = 0; +} + +void CAST128::Base::UncheckedSetKey(CipherDir dir, const byte *userKey, unsigned int keylength) +{ + AssertValidKeyLength(keylength); + + reduced = (keylength <= 10); + + word32 X[4], Z[4]; + GetUserKey(BIG_ENDIAN_ORDER, X, 4, userKey, keylength); + +#define x(i) GETBYTE(X[i/4], 3-i%4) +#define z(i) GETBYTE(Z[i/4], 3-i%4) + + unsigned int i; + for (i=0; i<=16; i+=16) + { + // this part is copied directly from RFC 2144 (with some search and replace) by Wei Dai + Z[0] = X[0] ^ S[4][x(0xD)] ^ S[5][x(0xF)] ^ S[6][x(0xC)] ^ S[7][x(0xE)] ^ S[6][x(0x8)]; + Z[1] = X[2] ^ S[4][z(0x0)] ^ S[5][z(0x2)] ^ S[6][z(0x1)] ^ S[7][z(0x3)] ^ S[7][x(0xA)]; + Z[2] = X[3] ^ S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[4][x(0x9)]; + Z[3] = X[1] ^ S[4][z(0xA)] ^ S[5][z(0x9)] ^ S[6][z(0xB)] ^ S[7][z(0x8)] ^ S[5][x(0xB)]; + K[i+0] = S[4][z(0x8)] ^ S[5][z(0x9)] ^ S[6][z(0x7)] ^ S[7][z(0x6)] ^ S[4][z(0x2)]; + K[i+1] = S[4][z(0xA)] ^ S[5][z(0xB)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[5][z(0x6)]; + K[i+2] = S[4][z(0xC)] ^ S[5][z(0xD)] ^ S[6][z(0x3)] ^ S[7][z(0x2)] ^ S[6][z(0x9)]; + K[i+3] = S[4][z(0xE)] ^ S[5][z(0xF)] ^ S[6][z(0x1)] ^ S[7][z(0x0)] ^ S[7][z(0xC)]; + X[0] = Z[2] ^ S[4][z(0x5)] ^ S[5][z(0x7)] ^ S[6][z(0x4)] ^ S[7][z(0x6)] ^ S[6][z(0x0)]; + X[1] = Z[0] ^ S[4][x(0x0)] ^ S[5][x(0x2)] ^ S[6][x(0x1)] ^ S[7][x(0x3)] ^ S[7][z(0x2)]; + X[2] = Z[1] ^ S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[4][z(0x1)]; + X[3] = Z[3] ^ S[4][x(0xA)] ^ S[5][x(0x9)] ^ S[6][x(0xB)] ^ S[7][x(0x8)] ^ S[5][z(0x3)]; + K[i+4] = S[4][x(0x3)] ^ S[5][x(0x2)] ^ S[6][x(0xC)] ^ S[7][x(0xD)] ^ S[4][x(0x8)]; + K[i+5] = S[4][x(0x1)] ^ S[5][x(0x0)] ^ S[6][x(0xE)] ^ S[7][x(0xF)] ^ S[5][x(0xD)]; + K[i+6] = S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x8)] ^ S[7][x(0x9)] ^ S[6][x(0x3)]; + K[i+7] = S[4][x(0x5)] ^ S[5][x(0x4)] ^ S[6][x(0xA)] ^ S[7][x(0xB)] ^ S[7][x(0x7)]; + Z[0] = X[0] ^ S[4][x(0xD)] ^ S[5][x(0xF)] ^ S[6][x(0xC)] ^ S[7][x(0xE)] ^ S[6][x(0x8)]; + Z[1] = X[2] ^ S[4][z(0x0)] ^ S[5][z(0x2)] ^ S[6][z(0x1)] ^ S[7][z(0x3)] ^ S[7][x(0xA)]; + Z[2] = X[3] ^ S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[4][x(0x9)]; + Z[3] = X[1] ^ S[4][z(0xA)] ^ S[5][z(0x9)] ^ S[6][z(0xB)] ^ S[7][z(0x8)] ^ S[5][x(0xB)]; + K[i+8] = S[4][z(0x3)] ^ S[5][z(0x2)] ^ S[6][z(0xC)] ^ S[7][z(0xD)] ^ S[4][z(0x9)]; + K[i+9] = S[4][z(0x1)] ^ S[5][z(0x0)] ^ S[6][z(0xE)] ^ S[7][z(0xF)] ^ S[5][z(0xC)]; + K[i+10] = S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x8)] ^ S[7][z(0x9)] ^ S[6][z(0x2)]; + K[i+11] = S[4][z(0x5)] ^ S[5][z(0x4)] ^ S[6][z(0xA)] ^ S[7][z(0xB)] ^ S[7][z(0x6)]; + X[0] = Z[2] ^ S[4][z(0x5)] ^ S[5][z(0x7)] ^ S[6][z(0x4)] ^ S[7][z(0x6)] ^ S[6][z(0x0)]; + X[1] = Z[0] ^ S[4][x(0x0)] ^ S[5][x(0x2)] ^ S[6][x(0x1)] ^ S[7][x(0x3)] ^ S[7][z(0x2)]; + X[2] = Z[1] ^ S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[4][z(0x1)]; + X[3] = Z[3] ^ S[4][x(0xA)] ^ S[5][x(0x9)] ^ S[6][x(0xB)] ^ S[7][x(0x8)] ^ S[5][z(0x3)]; + K[i+12] = S[4][x(0x8)] ^ S[5][x(0x9)] ^ S[6][x(0x7)] ^ S[7][x(0x6)] ^ S[4][x(0x3)]; + K[i+13] = S[4][x(0xA)] ^ S[5][x(0xB)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[5][x(0x7)]; + K[i+14] = S[4][x(0xC)] ^ S[5][x(0xD)] ^ S[6][x(0x3)] ^ S[7][x(0x2)] ^ S[6][x(0x8)]; + K[i+15] = S[4][x(0xE)] ^ S[5][x(0xF)] ^ S[6][x(0x1)] ^ S[7][x(0x0)] ^ S[7][x(0xD)]; + } + + for (i=16; i<32; i++) + K[i] &= 0x1f; +} + +// The following CAST-256 implementation was contributed by Leonard Janke + +const word32 CAST256::Base::t_m[8][24]={ + 0x5a827999, 0xd151d6a1, 0x482133a9, 0xbef090b1, 0x35bfedb9, 0xac8f4ac1, + 0x235ea7c9, 0x9a2e04d1, 0x10fd61d9, 0x87ccbee1, 0xfe9c1be9, 0x756b78f1, + 0xec3ad5f9, 0x630a3301, 0xd9d99009, 0x50a8ed11, 0xc7784a19, 0x3e47a721, + 0xb5170429, 0x2be66131, 0xa2b5be39, 0x19851b41, 0x90547849, 0x0723d551, + 0xc95c653a, 0x402bc242, 0xb6fb1f4a, 0x2dca7c52, 0xa499d95a, 0x1b693662, + 0x9238936a, 0x0907f072, 0x7fd74d7a, 0xf6a6aa82, 0x6d76078a, 0xe4456492, + 0x5b14c19a, 0xd1e41ea2, 0x48b37baa, 0xbf82d8b2, 0x365235ba, 0xad2192c2, + 0x23f0efca, 0x9ac04cd2, 0x118fa9da, 0x885f06e2, 0xff2e63ea, 0x75fdc0f2, + 0x383650db, 0xaf05ade3, 0x25d50aeb, 0x9ca467f3, 0x1373c4fb, 0x8a432203, + 0x01127f0b, 0x77e1dc13, 0xeeb1391b, 0x65809623, 0xdc4ff32b, 0x531f5033, + 0xc9eead3b, 0x40be0a43, 0xb78d674b, 0x2e5cc453, 0xa52c215b, 0x1bfb7e63, + 0x92cadb6b, 0x099a3873, 0x8069957b, 0xf738f283, 0x6e084f8b, 0xe4d7ac93, + 0xa7103c7c, 0x1ddf9984, 0x94aef68c, 0x0b7e5394, 0x824db09c, 0xf91d0da4, + 0x6fec6aac, 0xe6bbc7b4, 0x5d8b24bc, 0xd45a81c4, 0x4b29decc, 0xc1f93bd4, + 0x38c898dc, 0xaf97f5e4, 0x266752ec, 0x9d36aff4, 0x14060cfc, 0x8ad56a04, + 0x01a4c70c, 0x78742414, 0xef43811c, 0x6612de24, 0xdce23b2c, 0x53b19834, + 0x15ea281d, 0x8cb98525, 0x0388e22d, 0x7a583f35, 0xf1279c3d, 0x67f6f945, + 0xdec6564d, 0x5595b355, 0xcc65105d, 0x43346d65, 0xba03ca6d, 0x30d32775, + 0xa7a2847d, 0x1e71e185, 0x95413e8d, 0x0c109b95, 0x82dff89d, 0xf9af55a5, + 0x707eb2ad, 0xe74e0fb5, 0x5e1d6cbd, 0xd4ecc9c5, 0x4bbc26cd, 0xc28b83d5, + 0x84c413be, 0xfb9370c6, 0x7262cdce, 0xe9322ad6, 0x600187de, 0xd6d0e4e6, + 0x4da041ee, 0xc46f9ef6, 0x3b3efbfe, 0xb20e5906, 0x28ddb60e, 0x9fad1316, + 0x167c701e, 0x8d4bcd26, 0x041b2a2e, 0x7aea8736, 0xf1b9e43e, 0x68894146, + 0xdf589e4e, 0x5627fb56, 0xccf7585e, 0x43c6b566, 0xba96126e, 0x31656f76, + 0xf39dff5f, 0x6a6d5c67, 0xe13cb96f, 0x580c1677, 0xcedb737f, 0x45aad087, + 0xbc7a2d8f, 0x33498a97, 0xaa18e79f, 0x20e844a7, 0x97b7a1af, 0x0e86feb7, + 0x85565bbf, 0xfc25b8c7, 0x72f515cf, 0xe9c472d7, 0x6093cfdf, 0xd7632ce7, + 0x4e3289ef, 0xc501e6f7, 0x3bd143ff, 0xb2a0a107, 0x296ffe0f, 0xa03f5b17, + 0x6277eb00, 0xd9474808, 0x5016a510, 0xc6e60218, 0x3db55f20, 0xb484bc28, + 0x2b541930, 0xa2237638, 0x18f2d340, 0x8fc23048, 0x06918d50, 0x7d60ea58, + 0xf4304760, 0x6affa468, 0xe1cf0170, 0x589e5e78, 0xcf6dbb80, 0x463d1888, + 0xbd0c7590, 0x33dbd298, 0xaaab2fa0, 0x217a8ca8, 0x9849e9b0, 0x0f1946b8 +}; + +const unsigned int CAST256::Base::t_r[8][24]={ + 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, + 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, + 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, + 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, + 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, + 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, + 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, + 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2 +}; + +#define Q(i) \ + F1(block[2],block[3],8*i+4,-4); \ + F2(block[1],block[2],8*i+5,-4); \ + F3(block[0],block[1],8*i+6,-4); \ + F1(block[3],block[0],8*i+7,-4); + +#define QBar(i) \ + F1(block[3],block[0],8*i+7,-4); \ + F3(block[0],block[1],8*i+6,-4); \ + F2(block[1],block[2],8*i+5,-4); \ + F1(block[2],block[3],8*i+4,-4); + +/* CAST256's encrypt/decrypt functions are identical except for the order that +the keys are used */ + +void CAST256::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 t, block[4]; + Block::Get(inBlock)(block[0])(block[1])(block[2])(block[3]); + + // Perform 6 forward quad rounds + Q(0); + Q(1); + Q(2); + Q(3); + Q(4); + Q(5); + + // Perform 6 reverse quad rounds + QBar(6); + QBar(7); + QBar(8); + QBar(9); + QBar(10); + QBar(11); + + Block::Put(xorBlock, outBlock)(block[0])(block[1])(block[2])(block[3]); +} + +/* Set up a CAST-256 key */ + +void CAST256::Base::Omega(int i, word32 kappa[8]) +{ + word32 t; + + f1(kappa[6],kappa[7],t_m[0][i],t_r[0][i]); + f2(kappa[5],kappa[6],t_m[1][i],t_r[1][i]); + f3(kappa[4],kappa[5],t_m[2][i],t_r[2][i]); + f1(kappa[3],kappa[4],t_m[3][i],t_r[3][i]); + f2(kappa[2],kappa[3],t_m[4][i],t_r[4][i]); + f3(kappa[1],kappa[2],t_m[5][i],t_r[5][i]); + f1(kappa[0],kappa[1],t_m[6][i],t_r[6][i]); + f2(kappa[7],kappa[0],t_m[7][i],t_r[7][i]); +} + +void CAST256::Base::UncheckedSetKey(CipherDir dir, const byte *userKey, unsigned int keylength) +{ + AssertValidKeyLength(keylength); + + word32 kappa[8]; + GetUserKey(BIG_ENDIAN_ORDER, kappa, 8, userKey, keylength); + + for(int i=0; i<12; ++i) + { + Omega(2*i,kappa); + Omega(2*i+1,kappa); + + K[8*i]=kappa[0] & 31; + K[8*i+1]=kappa[2] & 31; + K[8*i+2]=kappa[4] & 31; + K[8*i+3]=kappa[6] & 31; + K[8*i+4]=kappa[7]; + K[8*i+5]=kappa[5]; + K[8*i+6]=kappa[3]; + K[8*i+7]=kappa[1]; + } + + if (dir == DECRYPTION) + { + for(int j=0; j<6; ++j) + { + for(int i=0; i<4; ++i) + { + int i1=8*j+i; + int i2=8*(11-j)+i; + + assert(i1<i2); + + std::swap(K[i1],K[i2]); + std::swap(K[i1+4],K[i2+4]); + } + } + } + + memset(kappa, 0, sizeof(kappa)); +} + +NAMESPACE_END @@ -0,0 +1,91 @@ +#ifndef CRYPTOPP_CAST_H +#define CRYPTOPP_CAST_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +class CAST +{ +protected: + static const word32 S[8][256]; +}; + +//! . +struct CAST128_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 5, 16> +{ + static const char *StaticAlgorithmName() {return "CAST-128";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#CAST-128">CAST-128</a> +class CAST128 : public CAST128_Info, public BlockCipherDocumentation +{ + class Base : public CAST, public BlockCipherBaseTemplate<CAST128_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + bool reduced; + FixedSizeSecBlock<word32, 32> K; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +//! . +struct CAST256_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32> +{ + static const char *StaticAlgorithmName() {return "CAST-256";} +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#CAST-256">CAST-256</a> +class CAST256 : public CAST256_Info, public BlockCipherDocumentation +{ + class Base : public CAST, public BlockCipherBaseTemplate<CAST256_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length = 8); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + static const word32 t_m[8][24]; + static const unsigned int t_r[8][24]; + + static void Omega(int i, word32 kappa[8]); + + FixedSizeSecBlock<word32, 8*12> K; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +typedef CAST128::Encryption CAST128Encryption; +typedef CAST128::Decryption CAST128Decryption; + +typedef CAST256::Encryption CAST256Encryption; +typedef CAST256::Decryption CAST256Decryption; + +NAMESPACE_END + +#endif diff --git a/cast128v.dat b/cast128v.dat new file mode 100644 index 0000000..4445305 --- /dev/null +++ b/cast128v.dat @@ -0,0 +1,11 @@ +01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A +01 23 45 67 89 AB CD EF +23 8B 4F E5 84 7E 44 B2 + +01 23 45 67 12 34 56 78 23 45 +01 23 45 67 89 AB CD EF +EB 6A 71 1A 2C 02 27 1B + +01 23 45 67 12 +01 23 45 67 89 AB CD EF +7A C8 16 D1 6E 9B 30 2E diff --git a/cast256v.dat b/cast256v.dat new file mode 100644 index 0000000..65a15dc --- /dev/null +++ b/cast256v.dat @@ -0,0 +1,11 @@ +2342bb9efa38542c0af75647f29f615d +00000000000000000000000000000000 +c842a08972b43d20836c91d1b7530f6b + +2342bb9efa38542cbed0ac83940ac298bac77a7717942863 +00000000000000000000000000000000 +1b386c0210dcadcbdd0e41aa08a7a7e8 + +2342bb9efa38542cbed0ac83940ac2988d7c47ce264908461cc1b5137ae6b604 +00000000000000000000000000000000 +4f6a2038286897b9c9870136553317fa diff --git a/casts.cpp b/casts.cpp new file mode 100644 index 0000000..16fa2b1 --- /dev/null +++ b/casts.cpp @@ -0,0 +1,545 @@ +#include "pch.h" +#include "cast.h" + +NAMESPACE_BEGIN(CryptoPP) + +// CAST S-boxes + +const word32 CAST::S[8][256] = { +{ + 0x30FB40D4UL, 0x9FA0FF0BUL, 0x6BECCD2FUL, 0x3F258C7AUL, + 0x1E213F2FUL, 0x9C004DD3UL, 0x6003E540UL, 0xCF9FC949UL, + 0xBFD4AF27UL, 0x88BBBDB5UL, 0xE2034090UL, 0x98D09675UL, + 0x6E63A0E0UL, 0x15C361D2UL, 0xC2E7661DUL, 0x22D4FF8EUL, + 0x28683B6FUL, 0xC07FD059UL, 0xFF2379C8UL, 0x775F50E2UL, + 0x43C340D3UL, 0xDF2F8656UL, 0x887CA41AUL, 0xA2D2BD2DUL, + 0xA1C9E0D6UL, 0x346C4819UL, 0x61B76D87UL, 0x22540F2FUL, + 0x2ABE32E1UL, 0xAA54166BUL, 0x22568E3AUL, 0xA2D341D0UL, + 0x66DB40C8UL, 0xA784392FUL, 0x004DFF2FUL, 0x2DB9D2DEUL, + 0x97943FACUL, 0x4A97C1D8UL, 0x527644B7UL, 0xB5F437A7UL, + 0xB82CBAEFUL, 0xD751D159UL, 0x6FF7F0EDUL, 0x5A097A1FUL, + 0x827B68D0UL, 0x90ECF52EUL, 0x22B0C054UL, 0xBC8E5935UL, + 0x4B6D2F7FUL, 0x50BB64A2UL, 0xD2664910UL, 0xBEE5812DUL, + 0xB7332290UL, 0xE93B159FUL, 0xB48EE411UL, 0x4BFF345DUL, + 0xFD45C240UL, 0xAD31973FUL, 0xC4F6D02EUL, 0x55FC8165UL, + 0xD5B1CAADUL, 0xA1AC2DAEUL, 0xA2D4B76DUL, 0xC19B0C50UL, + 0x882240F2UL, 0x0C6E4F38UL, 0xA4E4BFD7UL, 0x4F5BA272UL, + 0x564C1D2FUL, 0xC59C5319UL, 0xB949E354UL, 0xB04669FEUL, + 0xB1B6AB8AUL, 0xC71358DDUL, 0x6385C545UL, 0x110F935DUL, + 0x57538AD5UL, 0x6A390493UL, 0xE63D37E0UL, 0x2A54F6B3UL, + 0x3A787D5FUL, 0x6276A0B5UL, 0x19A6FCDFUL, 0x7A42206AUL, + 0x29F9D4D5UL, 0xF61B1891UL, 0xBB72275EUL, 0xAA508167UL, + 0x38901091UL, 0xC6B505EBUL, 0x84C7CB8CUL, 0x2AD75A0FUL, + 0x874A1427UL, 0xA2D1936BUL, 0x2AD286AFUL, 0xAA56D291UL, + 0xD7894360UL, 0x425C750DUL, 0x93B39E26UL, 0x187184C9UL, + 0x6C00B32DUL, 0x73E2BB14UL, 0xA0BEBC3CUL, 0x54623779UL, + 0x64459EABUL, 0x3F328B82UL, 0x7718CF82UL, 0x59A2CEA6UL, + 0x04EE002EUL, 0x89FE78E6UL, 0x3FAB0950UL, 0x325FF6C2UL, + 0x81383F05UL, 0x6963C5C8UL, 0x76CB5AD6UL, 0xD49974C9UL, + 0xCA180DCFUL, 0x380782D5UL, 0xC7FA5CF6UL, 0x8AC31511UL, + 0x35E79E13UL, 0x47DA91D0UL, 0xF40F9086UL, 0xA7E2419EUL, + 0x31366241UL, 0x051EF495UL, 0xAA573B04UL, 0x4A805D8DUL, + 0x548300D0UL, 0x00322A3CUL, 0xBF64CDDFUL, 0xBA57A68EUL, + 0x75C6372BUL, 0x50AFD341UL, 0xA7C13275UL, 0x915A0BF5UL, + 0x6B54BFABUL, 0x2B0B1426UL, 0xAB4CC9D7UL, 0x449CCD82UL, + 0xF7FBF265UL, 0xAB85C5F3UL, 0x1B55DB94UL, 0xAAD4E324UL, + 0xCFA4BD3FUL, 0x2DEAA3E2UL, 0x9E204D02UL, 0xC8BD25ACUL, + 0xEADF55B3UL, 0xD5BD9E98UL, 0xE31231B2UL, 0x2AD5AD6CUL, + 0x954329DEUL, 0xADBE4528UL, 0xD8710F69UL, 0xAA51C90FUL, + 0xAA786BF6UL, 0x22513F1EUL, 0xAA51A79BUL, 0x2AD344CCUL, + 0x7B5A41F0UL, 0xD37CFBADUL, 0x1B069505UL, 0x41ECE491UL, + 0xB4C332E6UL, 0x032268D4UL, 0xC9600ACCUL, 0xCE387E6DUL, + 0xBF6BB16CUL, 0x6A70FB78UL, 0x0D03D9C9UL, 0xD4DF39DEUL, + 0xE01063DAUL, 0x4736F464UL, 0x5AD328D8UL, 0xB347CC96UL, + 0x75BB0FC3UL, 0x98511BFBUL, 0x4FFBCC35UL, 0xB58BCF6AUL, + 0xE11F0ABCUL, 0xBFC5FE4AUL, 0xA70AEC10UL, 0xAC39570AUL, + 0x3F04442FUL, 0x6188B153UL, 0xE0397A2EUL, 0x5727CB79UL, + 0x9CEB418FUL, 0x1CACD68DUL, 0x2AD37C96UL, 0x0175CB9DUL, + 0xC69DFF09UL, 0xC75B65F0UL, 0xD9DB40D8UL, 0xEC0E7779UL, + 0x4744EAD4UL, 0xB11C3274UL, 0xDD24CB9EUL, 0x7E1C54BDUL, + 0xF01144F9UL, 0xD2240EB1UL, 0x9675B3FDUL, 0xA3AC3755UL, + 0xD47C27AFUL, 0x51C85F4DUL, 0x56907596UL, 0xA5BB15E6UL, + 0x580304F0UL, 0xCA042CF1UL, 0x011A37EAUL, 0x8DBFAADBUL, + 0x35BA3E4AUL, 0x3526FFA0UL, 0xC37B4D09UL, 0xBC306ED9UL, + 0x98A52666UL, 0x5648F725UL, 0xFF5E569DUL, 0x0CED63D0UL, + 0x7C63B2CFUL, 0x700B45E1UL, 0xD5EA50F1UL, 0x85A92872UL, + 0xAF1FBDA7UL, 0xD4234870UL, 0xA7870BF3UL, 0x2D3B4D79UL, + 0x42E04198UL, 0x0CD0EDE7UL, 0x26470DB8UL, 0xF881814CUL, + 0x474D6AD7UL, 0x7C0C5E5CUL, 0xD1231959UL, 0x381B7298UL, + 0xF5D2F4DBUL, 0xAB838653UL, 0x6E2F1E23UL, 0x83719C9EUL, + 0xBD91E046UL, 0x9A56456EUL, 0xDC39200CUL, 0x20C8C571UL, + 0x962BDA1CUL, 0xE1E696FFUL, 0xB141AB08UL, 0x7CCA89B9UL, + 0x1A69E783UL, 0x02CC4843UL, 0xA2F7C579UL, 0x429EF47DUL, + 0x427B169CUL, 0x5AC9F049UL, 0xDD8F0F00UL, 0x5C8165BFUL +}, + +{ + 0x1F201094UL, 0xEF0BA75BUL, 0x69E3CF7EUL, 0x393F4380UL, + 0xFE61CF7AUL, 0xEEC5207AUL, 0x55889C94UL, 0x72FC0651UL, + 0xADA7EF79UL, 0x4E1D7235UL, 0xD55A63CEUL, 0xDE0436BAUL, + 0x99C430EFUL, 0x5F0C0794UL, 0x18DCDB7DUL, 0xA1D6EFF3UL, + 0xA0B52F7BUL, 0x59E83605UL, 0xEE15B094UL, 0xE9FFD909UL, + 0xDC440086UL, 0xEF944459UL, 0xBA83CCB3UL, 0xE0C3CDFBUL, + 0xD1DA4181UL, 0x3B092AB1UL, 0xF997F1C1UL, 0xA5E6CF7BUL, + 0x01420DDBUL, 0xE4E7EF5BUL, 0x25A1FF41UL, 0xE180F806UL, + 0x1FC41080UL, 0x179BEE7AUL, 0xD37AC6A9UL, 0xFE5830A4UL, + 0x98DE8B7FUL, 0x77E83F4EUL, 0x79929269UL, 0x24FA9F7BUL, + 0xE113C85BUL, 0xACC40083UL, 0xD7503525UL, 0xF7EA615FUL, + 0x62143154UL, 0x0D554B63UL, 0x5D681121UL, 0xC866C359UL, + 0x3D63CF73UL, 0xCEE234C0UL, 0xD4D87E87UL, 0x5C672B21UL, + 0x071F6181UL, 0x39F7627FUL, 0x361E3084UL, 0xE4EB573BUL, + 0x602F64A4UL, 0xD63ACD9CUL, 0x1BBC4635UL, 0x9E81032DUL, + 0x2701F50CUL, 0x99847AB4UL, 0xA0E3DF79UL, 0xBA6CF38CUL, + 0x10843094UL, 0x2537A95EUL, 0xF46F6FFEUL, 0xA1FF3B1FUL, + 0x208CFB6AUL, 0x8F458C74UL, 0xD9E0A227UL, 0x4EC73A34UL, + 0xFC884F69UL, 0x3E4DE8DFUL, 0xEF0E0088UL, 0x3559648DUL, + 0x8A45388CUL, 0x1D804366UL, 0x721D9BFDUL, 0xA58684BBUL, + 0xE8256333UL, 0x844E8212UL, 0x128D8098UL, 0xFED33FB4UL, + 0xCE280AE1UL, 0x27E19BA5UL, 0xD5A6C252UL, 0xE49754BDUL, + 0xC5D655DDUL, 0xEB667064UL, 0x77840B4DUL, 0xA1B6A801UL, + 0x84DB26A9UL, 0xE0B56714UL, 0x21F043B7UL, 0xE5D05860UL, + 0x54F03084UL, 0x066FF472UL, 0xA31AA153UL, 0xDADC4755UL, + 0xB5625DBFUL, 0x68561BE6UL, 0x83CA6B94UL, 0x2D6ED23BUL, + 0xECCF01DBUL, 0xA6D3D0BAUL, 0xB6803D5CUL, 0xAF77A709UL, + 0x33B4A34CUL, 0x397BC8D6UL, 0x5EE22B95UL, 0x5F0E5304UL, + 0x81ED6F61UL, 0x20E74364UL, 0xB45E1378UL, 0xDE18639BUL, + 0x881CA122UL, 0xB96726D1UL, 0x8049A7E8UL, 0x22B7DA7BUL, + 0x5E552D25UL, 0x5272D237UL, 0x79D2951CUL, 0xC60D894CUL, + 0x488CB402UL, 0x1BA4FE5BUL, 0xA4B09F6BUL, 0x1CA815CFUL, + 0xA20C3005UL, 0x8871DF63UL, 0xB9DE2FCBUL, 0x0CC6C9E9UL, + 0x0BEEFF53UL, 0xE3214517UL, 0xB4542835UL, 0x9F63293CUL, + 0xEE41E729UL, 0x6E1D2D7CUL, 0x50045286UL, 0x1E6685F3UL, + 0xF33401C6UL, 0x30A22C95UL, 0x31A70850UL, 0x60930F13UL, + 0x73F98417UL, 0xA1269859UL, 0xEC645C44UL, 0x52C877A9UL, + 0xCDFF33A6UL, 0xA02B1741UL, 0x7CBAD9A2UL, 0x2180036FUL, + 0x50D99C08UL, 0xCB3F4861UL, 0xC26BD765UL, 0x64A3F6ABUL, + 0x80342676UL, 0x25A75E7BUL, 0xE4E6D1FCUL, 0x20C710E6UL, + 0xCDF0B680UL, 0x17844D3BUL, 0x31EEF84DUL, 0x7E0824E4UL, + 0x2CCB49EBUL, 0x846A3BAEUL, 0x8FF77888UL, 0xEE5D60F6UL, + 0x7AF75673UL, 0x2FDD5CDBUL, 0xA11631C1UL, 0x30F66F43UL, + 0xB3FAEC54UL, 0x157FD7FAUL, 0xEF8579CCUL, 0xD152DE58UL, + 0xDB2FFD5EUL, 0x8F32CE19UL, 0x306AF97AUL, 0x02F03EF8UL, + 0x99319AD5UL, 0xC242FA0FUL, 0xA7E3EBB0UL, 0xC68E4906UL, + 0xB8DA230CUL, 0x80823028UL, 0xDCDEF3C8UL, 0xD35FB171UL, + 0x088A1BC8UL, 0xBEC0C560UL, 0x61A3C9E8UL, 0xBCA8F54DUL, + 0xC72FEFFAUL, 0x22822E99UL, 0x82C570B4UL, 0xD8D94E89UL, + 0x8B1C34BCUL, 0x301E16E6UL, 0x273BE979UL, 0xB0FFEAA6UL, + 0x61D9B8C6UL, 0x00B24869UL, 0xB7FFCE3FUL, 0x08DC283BUL, + 0x43DAF65AUL, 0xF7E19798UL, 0x7619B72FUL, 0x8F1C9BA4UL, + 0xDC8637A0UL, 0x16A7D3B1UL, 0x9FC393B7UL, 0xA7136EEBUL, + 0xC6BCC63EUL, 0x1A513742UL, 0xEF6828BCUL, 0x520365D6UL, + 0x2D6A77ABUL, 0x3527ED4BUL, 0x821FD216UL, 0x095C6E2EUL, + 0xDB92F2FBUL, 0x5EEA29CBUL, 0x145892F5UL, 0x91584F7FUL, + 0x5483697BUL, 0x2667A8CCUL, 0x85196048UL, 0x8C4BACEAUL, + 0x833860D4UL, 0x0D23E0F9UL, 0x6C387E8AUL, 0x0AE6D249UL, + 0xB284600CUL, 0xD835731DUL, 0xDCB1C647UL, 0xAC4C56EAUL, + 0x3EBD81B3UL, 0x230EABB0UL, 0x6438BC87UL, 0xF0B5B1FAUL, + 0x8F5EA2B3UL, 0xFC184642UL, 0x0A036B7AUL, 0x4FB089BDUL, + 0x649DA589UL, 0xA345415EUL, 0x5C038323UL, 0x3E5D3BB9UL, + 0x43D79572UL, 0x7E6DD07CUL, 0x06DFDF1EUL, 0x6C6CC4EFUL, + 0x7160A539UL, 0x73BFBE70UL, 0x83877605UL, 0x4523ECF1UL +}, + +{ + 0x8DEFC240UL, 0x25FA5D9FUL, 0xEB903DBFUL, 0xE810C907UL, + 0x47607FFFUL, 0x369FE44BUL, 0x8C1FC644UL, 0xAECECA90UL, + 0xBEB1F9BFUL, 0xEEFBCAEAUL, 0xE8CF1950UL, 0x51DF07AEUL, + 0x920E8806UL, 0xF0AD0548UL, 0xE13C8D83UL, 0x927010D5UL, + 0x11107D9FUL, 0x07647DB9UL, 0xB2E3E4D4UL, 0x3D4F285EUL, + 0xB9AFA820UL, 0xFADE82E0UL, 0xA067268BUL, 0x8272792EUL, + 0x553FB2C0UL, 0x489AE22BUL, 0xD4EF9794UL, 0x125E3FBCUL, + 0x21FFFCEEUL, 0x825B1BFDUL, 0x9255C5EDUL, 0x1257A240UL, + 0x4E1A8302UL, 0xBAE07FFFUL, 0x528246E7UL, 0x8E57140EUL, + 0x3373F7BFUL, 0x8C9F8188UL, 0xA6FC4EE8UL, 0xC982B5A5UL, + 0xA8C01DB7UL, 0x579FC264UL, 0x67094F31UL, 0xF2BD3F5FUL, + 0x40FFF7C1UL, 0x1FB78DFCUL, 0x8E6BD2C1UL, 0x437BE59BUL, + 0x99B03DBFUL, 0xB5DBC64BUL, 0x638DC0E6UL, 0x55819D99UL, + 0xA197C81CUL, 0x4A012D6EUL, 0xC5884A28UL, 0xCCC36F71UL, + 0xB843C213UL, 0x6C0743F1UL, 0x8309893CUL, 0x0FEDDD5FUL, + 0x2F7FE850UL, 0xD7C07F7EUL, 0x02507FBFUL, 0x5AFB9A04UL, + 0xA747D2D0UL, 0x1651192EUL, 0xAF70BF3EUL, 0x58C31380UL, + 0x5F98302EUL, 0x727CC3C4UL, 0x0A0FB402UL, 0x0F7FEF82UL, + 0x8C96FDADUL, 0x5D2C2AAEUL, 0x8EE99A49UL, 0x50DA88B8UL, + 0x8427F4A0UL, 0x1EAC5790UL, 0x796FB449UL, 0x8252DC15UL, + 0xEFBD7D9BUL, 0xA672597DUL, 0xADA840D8UL, 0x45F54504UL, + 0xFA5D7403UL, 0xE83EC305UL, 0x4F91751AUL, 0x925669C2UL, + 0x23EFE941UL, 0xA903F12EUL, 0x60270DF2UL, 0x0276E4B6UL, + 0x94FD6574UL, 0x927985B2UL, 0x8276DBCBUL, 0x02778176UL, + 0xF8AF918DUL, 0x4E48F79EUL, 0x8F616DDFUL, 0xE29D840EUL, + 0x842F7D83UL, 0x340CE5C8UL, 0x96BBB682UL, 0x93B4B148UL, + 0xEF303CABUL, 0x984FAF28UL, 0x779FAF9BUL, 0x92DC560DUL, + 0x224D1E20UL, 0x8437AA88UL, 0x7D29DC96UL, 0x2756D3DCUL, + 0x8B907CEEUL, 0xB51FD240UL, 0xE7C07CE3UL, 0xE566B4A1UL, + 0xC3E9615EUL, 0x3CF8209DUL, 0x6094D1E3UL, 0xCD9CA341UL, + 0x5C76460EUL, 0x00EA983BUL, 0xD4D67881UL, 0xFD47572CUL, + 0xF76CEDD9UL, 0xBDA8229CUL, 0x127DADAAUL, 0x438A074EUL, + 0x1F97C090UL, 0x081BDB8AUL, 0x93A07EBEUL, 0xB938CA15UL, + 0x97B03CFFUL, 0x3DC2C0F8UL, 0x8D1AB2ECUL, 0x64380E51UL, + 0x68CC7BFBUL, 0xD90F2788UL, 0x12490181UL, 0x5DE5FFD4UL, + 0xDD7EF86AUL, 0x76A2E214UL, 0xB9A40368UL, 0x925D958FUL, + 0x4B39FFFAUL, 0xBA39AEE9UL, 0xA4FFD30BUL, 0xFAF7933BUL, + 0x6D498623UL, 0x193CBCFAUL, 0x27627545UL, 0x825CF47AUL, + 0x61BD8BA0UL, 0xD11E42D1UL, 0xCEAD04F4UL, 0x127EA392UL, + 0x10428DB7UL, 0x8272A972UL, 0x9270C4A8UL, 0x127DE50BUL, + 0x285BA1C8UL, 0x3C62F44FUL, 0x35C0EAA5UL, 0xE805D231UL, + 0x428929FBUL, 0xB4FCDF82UL, 0x4FB66A53UL, 0x0E7DC15BUL, + 0x1F081FABUL, 0x108618AEUL, 0xFCFD086DUL, 0xF9FF2889UL, + 0x694BCC11UL, 0x236A5CAEUL, 0x12DECA4DUL, 0x2C3F8CC5UL, + 0xD2D02DFEUL, 0xF8EF5896UL, 0xE4CF52DAUL, 0x95155B67UL, + 0x494A488CUL, 0xB9B6A80CUL, 0x5C8F82BCUL, 0x89D36B45UL, + 0x3A609437UL, 0xEC00C9A9UL, 0x44715253UL, 0x0A874B49UL, + 0xD773BC40UL, 0x7C34671CUL, 0x02717EF6UL, 0x4FEB5536UL, + 0xA2D02FFFUL, 0xD2BF60C4UL, 0xD43F03C0UL, 0x50B4EF6DUL, + 0x07478CD1UL, 0x006E1888UL, 0xA2E53F55UL, 0xB9E6D4BCUL, + 0xA2048016UL, 0x97573833UL, 0xD7207D67UL, 0xDE0F8F3DUL, + 0x72F87B33UL, 0xABCC4F33UL, 0x7688C55DUL, 0x7B00A6B0UL, + 0x947B0001UL, 0x570075D2UL, 0xF9BB88F8UL, 0x8942019EUL, + 0x4264A5FFUL, 0x856302E0UL, 0x72DBD92BUL, 0xEE971B69UL, + 0x6EA22FDEUL, 0x5F08AE2BUL, 0xAF7A616DUL, 0xE5C98767UL, + 0xCF1FEBD2UL, 0x61EFC8C2UL, 0xF1AC2571UL, 0xCC8239C2UL, + 0x67214CB8UL, 0xB1E583D1UL, 0xB7DC3E62UL, 0x7F10BDCEUL, + 0xF90A5C38UL, 0x0FF0443DUL, 0x606E6DC6UL, 0x60543A49UL, + 0x5727C148UL, 0x2BE98A1DUL, 0x8AB41738UL, 0x20E1BE24UL, + 0xAF96DA0FUL, 0x68458425UL, 0x99833BE5UL, 0x600D457DUL, + 0x282F9350UL, 0x8334B362UL, 0xD91D1120UL, 0x2B6D8DA0UL, + 0x642B1E31UL, 0x9C305A00UL, 0x52BCE688UL, 0x1B03588AUL, + 0xF7BAEFD5UL, 0x4142ED9CUL, 0xA4315C11UL, 0x83323EC5UL, + 0xDFEF4636UL, 0xA133C501UL, 0xE9D3531CUL, 0xEE353783UL +}, + +{ + 0x9DB30420UL, 0x1FB6E9DEUL, 0xA7BE7BEFUL, 0xD273A298UL, + 0x4A4F7BDBUL, 0x64AD8C57UL, 0x85510443UL, 0xFA020ED1UL, + 0x7E287AFFUL, 0xE60FB663UL, 0x095F35A1UL, 0x79EBF120UL, + 0xFD059D43UL, 0x6497B7B1UL, 0xF3641F63UL, 0x241E4ADFUL, + 0x28147F5FUL, 0x4FA2B8CDUL, 0xC9430040UL, 0x0CC32220UL, + 0xFDD30B30UL, 0xC0A5374FUL, 0x1D2D00D9UL, 0x24147B15UL, + 0xEE4D111AUL, 0x0FCA5167UL, 0x71FF904CUL, 0x2D195FFEUL, + 0x1A05645FUL, 0x0C13FEFEUL, 0x081B08CAUL, 0x05170121UL, + 0x80530100UL, 0xE83E5EFEUL, 0xAC9AF4F8UL, 0x7FE72701UL, + 0xD2B8EE5FUL, 0x06DF4261UL, 0xBB9E9B8AUL, 0x7293EA25UL, + 0xCE84FFDFUL, 0xF5718801UL, 0x3DD64B04UL, 0xA26F263BUL, + 0x7ED48400UL, 0x547EEBE6UL, 0x446D4CA0UL, 0x6CF3D6F5UL, + 0x2649ABDFUL, 0xAEA0C7F5UL, 0x36338CC1UL, 0x503F7E93UL, + 0xD3772061UL, 0x11B638E1UL, 0x72500E03UL, 0xF80EB2BBUL, + 0xABE0502EUL, 0xEC8D77DEUL, 0x57971E81UL, 0xE14F6746UL, + 0xC9335400UL, 0x6920318FUL, 0x081DBB99UL, 0xFFC304A5UL, + 0x4D351805UL, 0x7F3D5CE3UL, 0xA6C866C6UL, 0x5D5BCCA9UL, + 0xDAEC6FEAUL, 0x9F926F91UL, 0x9F46222FUL, 0x3991467DUL, + 0xA5BF6D8EUL, 0x1143C44FUL, 0x43958302UL, 0xD0214EEBUL, + 0x022083B8UL, 0x3FB6180CUL, 0x18F8931EUL, 0x281658E6UL, + 0x26486E3EUL, 0x8BD78A70UL, 0x7477E4C1UL, 0xB506E07CUL, + 0xF32D0A25UL, 0x79098B02UL, 0xE4EABB81UL, 0x28123B23UL, + 0x69DEAD38UL, 0x1574CA16UL, 0xDF871B62UL, 0x211C40B7UL, + 0xA51A9EF9UL, 0x0014377BUL, 0x041E8AC8UL, 0x09114003UL, + 0xBD59E4D2UL, 0xE3D156D5UL, 0x4FE876D5UL, 0x2F91A340UL, + 0x557BE8DEUL, 0x00EAE4A7UL, 0x0CE5C2ECUL, 0x4DB4BBA6UL, + 0xE756BDFFUL, 0xDD3369ACUL, 0xEC17B035UL, 0x06572327UL, + 0x99AFC8B0UL, 0x56C8C391UL, 0x6B65811CUL, 0x5E146119UL, + 0x6E85CB75UL, 0xBE07C002UL, 0xC2325577UL, 0x893FF4ECUL, + 0x5BBFC92DUL, 0xD0EC3B25UL, 0xB7801AB7UL, 0x8D6D3B24UL, + 0x20C763EFUL, 0xC366A5FCUL, 0x9C382880UL, 0x0ACE3205UL, + 0xAAC9548AUL, 0xECA1D7C7UL, 0x041AFA32UL, 0x1D16625AUL, + 0x6701902CUL, 0x9B757A54UL, 0x31D477F7UL, 0x9126B031UL, + 0x36CC6FDBUL, 0xC70B8B46UL, 0xD9E66A48UL, 0x56E55A79UL, + 0x026A4CEBUL, 0x52437EFFUL, 0x2F8F76B4UL, 0x0DF980A5UL, + 0x8674CDE3UL, 0xEDDA04EBUL, 0x17A9BE04UL, 0x2C18F4DFUL, + 0xB7747F9DUL, 0xAB2AF7B4UL, 0xEFC34D20UL, 0x2E096B7CUL, + 0x1741A254UL, 0xE5B6A035UL, 0x213D42F6UL, 0x2C1C7C26UL, + 0x61C2F50FUL, 0x6552DAF9UL, 0xD2C231F8UL, 0x25130F69UL, + 0xD8167FA2UL, 0x0418F2C8UL, 0x001A96A6UL, 0x0D1526ABUL, + 0x63315C21UL, 0x5E0A72ECUL, 0x49BAFEFDUL, 0x187908D9UL, + 0x8D0DBD86UL, 0x311170A7UL, 0x3E9B640CUL, 0xCC3E10D7UL, + 0xD5CAD3B6UL, 0x0CAEC388UL, 0xF73001E1UL, 0x6C728AFFUL, + 0x71EAE2A1UL, 0x1F9AF36EUL, 0xCFCBD12FUL, 0xC1DE8417UL, + 0xAC07BE6BUL, 0xCB44A1D8UL, 0x8B9B0F56UL, 0x013988C3UL, + 0xB1C52FCAUL, 0xB4BE31CDUL, 0xD8782806UL, 0x12A3A4E2UL, + 0x6F7DE532UL, 0x58FD7EB6UL, 0xD01EE900UL, 0x24ADFFC2UL, + 0xF4990FC5UL, 0x9711AAC5UL, 0x001D7B95UL, 0x82E5E7D2UL, + 0x109873F6UL, 0x00613096UL, 0xC32D9521UL, 0xADA121FFUL, + 0x29908415UL, 0x7FBB977FUL, 0xAF9EB3DBUL, 0x29C9ED2AUL, + 0x5CE2A465UL, 0xA730F32CUL, 0xD0AA3FE8UL, 0x8A5CC091UL, + 0xD49E2CE7UL, 0x0CE454A9UL, 0xD60ACD86UL, 0x015F1919UL, + 0x77079103UL, 0xDEA03AF6UL, 0x78A8565EUL, 0xDEE356DFUL, + 0x21F05CBEUL, 0x8B75E387UL, 0xB3C50651UL, 0xB8A5C3EFUL, + 0xD8EEB6D2UL, 0xE523BE77UL, 0xC2154529UL, 0x2F69EFDFUL, + 0xAFE67AFBUL, 0xF470C4B2UL, 0xF3E0EB5BUL, 0xD6CC9876UL, + 0x39E4460CUL, 0x1FDA8538UL, 0x1987832FUL, 0xCA007367UL, + 0xA99144F8UL, 0x296B299EUL, 0x492FC295UL, 0x9266BEABUL, + 0xB5676E69UL, 0x9BD3DDDAUL, 0xDF7E052FUL, 0xDB25701CUL, + 0x1B5E51EEUL, 0xF65324E6UL, 0x6AFCE36CUL, 0x0316CC04UL, + 0x8644213EUL, 0xB7DC59D0UL, 0x7965291FUL, 0xCCD6FD43UL, + 0x41823979UL, 0x932BCDF6UL, 0xB657C34DUL, 0x4EDFD282UL, + 0x7AE5290CUL, 0x3CB9536BUL, 0x851E20FEUL, 0x9833557EUL, + 0x13ECF0B0UL, 0xD3FFB372UL, 0x3F85C5C1UL, 0x0AEF7ED2UL +}, + +{ + 0x7EC90C04UL, 0x2C6E74B9UL, 0x9B0E66DFUL, 0xA6337911UL, + 0xB86A7FFFUL, 0x1DD358F5UL, 0x44DD9D44UL, 0x1731167FUL, + 0x08FBF1FAUL, 0xE7F511CCUL, 0xD2051B00UL, 0x735ABA00UL, + 0x2AB722D8UL, 0x386381CBUL, 0xACF6243AUL, 0x69BEFD7AUL, + 0xE6A2E77FUL, 0xF0C720CDUL, 0xC4494816UL, 0xCCF5C180UL, + 0x38851640UL, 0x15B0A848UL, 0xE68B18CBUL, 0x4CAADEFFUL, + 0x5F480A01UL, 0x0412B2AAUL, 0x259814FCUL, 0x41D0EFE2UL, + 0x4E40B48DUL, 0x248EB6FBUL, 0x8DBA1CFEUL, 0x41A99B02UL, + 0x1A550A04UL, 0xBA8F65CBUL, 0x7251F4E7UL, 0x95A51725UL, + 0xC106ECD7UL, 0x97A5980AUL, 0xC539B9AAUL, 0x4D79FE6AUL, + 0xF2F3F763UL, 0x68AF8040UL, 0xED0C9E56UL, 0x11B4958BUL, + 0xE1EB5A88UL, 0x8709E6B0UL, 0xD7E07156UL, 0x4E29FEA7UL, + 0x6366E52DUL, 0x02D1C000UL, 0xC4AC8E05UL, 0x9377F571UL, + 0x0C05372AUL, 0x578535F2UL, 0x2261BE02UL, 0xD642A0C9UL, + 0xDF13A280UL, 0x74B55BD2UL, 0x682199C0UL, 0xD421E5ECUL, + 0x53FB3CE8UL, 0xC8ADEDB3UL, 0x28A87FC9UL, 0x3D959981UL, + 0x5C1FF900UL, 0xFE38D399UL, 0x0C4EFF0BUL, 0x062407EAUL, + 0xAA2F4FB1UL, 0x4FB96976UL, 0x90C79505UL, 0xB0A8A774UL, + 0xEF55A1FFUL, 0xE59CA2C2UL, 0xA6B62D27UL, 0xE66A4263UL, + 0xDF65001FUL, 0x0EC50966UL, 0xDFDD55BCUL, 0x29DE0655UL, + 0x911E739AUL, 0x17AF8975UL, 0x32C7911CUL, 0x89F89468UL, + 0x0D01E980UL, 0x524755F4UL, 0x03B63CC9UL, 0x0CC844B2UL, + 0xBCF3F0AAUL, 0x87AC36E9UL, 0xE53A7426UL, 0x01B3D82BUL, + 0x1A9E7449UL, 0x64EE2D7EUL, 0xCDDBB1DAUL, 0x01C94910UL, + 0xB868BF80UL, 0x0D26F3FDUL, 0x9342EDE7UL, 0x04A5C284UL, + 0x636737B6UL, 0x50F5B616UL, 0xF24766E3UL, 0x8ECA36C1UL, + 0x136E05DBUL, 0xFEF18391UL, 0xFB887A37UL, 0xD6E7F7D4UL, + 0xC7FB7DC9UL, 0x3063FCDFUL, 0xB6F589DEUL, 0xEC2941DAUL, + 0x26E46695UL, 0xB7566419UL, 0xF654EFC5UL, 0xD08D58B7UL, + 0x48925401UL, 0xC1BACB7FUL, 0xE5FF550FUL, 0xB6083049UL, + 0x5BB5D0E8UL, 0x87D72E5AUL, 0xAB6A6EE1UL, 0x223A66CEUL, + 0xC62BF3CDUL, 0x9E0885F9UL, 0x68CB3E47UL, 0x086C010FUL, + 0xA21DE820UL, 0xD18B69DEUL, 0xF3F65777UL, 0xFA02C3F6UL, + 0x407EDAC3UL, 0xCBB3D550UL, 0x1793084DUL, 0xB0D70EBAUL, + 0x0AB378D5UL, 0xD951FB0CUL, 0xDED7DA56UL, 0x4124BBE4UL, + 0x94CA0B56UL, 0x0F5755D1UL, 0xE0E1E56EUL, 0x6184B5BEUL, + 0x580A249FUL, 0x94F74BC0UL, 0xE327888EUL, 0x9F7B5561UL, + 0xC3DC0280UL, 0x05687715UL, 0x646C6BD7UL, 0x44904DB3UL, + 0x66B4F0A3UL, 0xC0F1648AUL, 0x697ED5AFUL, 0x49E92FF6UL, + 0x309E374FUL, 0x2CB6356AUL, 0x85808573UL, 0x4991F840UL, + 0x76F0AE02UL, 0x083BE84DUL, 0x28421C9AUL, 0x44489406UL, + 0x736E4CB8UL, 0xC1092910UL, 0x8BC95FC6UL, 0x7D869CF4UL, + 0x134F616FUL, 0x2E77118DUL, 0xB31B2BE1UL, 0xAA90B472UL, + 0x3CA5D717UL, 0x7D161BBAUL, 0x9CAD9010UL, 0xAF462BA2UL, + 0x9FE459D2UL, 0x45D34559UL, 0xD9F2DA13UL, 0xDBC65487UL, + 0xF3E4F94EUL, 0x176D486FUL, 0x097C13EAUL, 0x631DA5C7UL, + 0x445F7382UL, 0x175683F4UL, 0xCDC66A97UL, 0x70BE0288UL, + 0xB3CDCF72UL, 0x6E5DD2F3UL, 0x20936079UL, 0x459B80A5UL, + 0xBE60E2DBUL, 0xA9C23101UL, 0xEBA5315CUL, 0x224E42F2UL, + 0x1C5C1572UL, 0xF6721B2CUL, 0x1AD2FFF3UL, 0x8C25404EUL, + 0x324ED72FUL, 0x4067B7FDUL, 0x0523138EUL, 0x5CA3BC78UL, + 0xDC0FD66EUL, 0x75922283UL, 0x784D6B17UL, 0x58EBB16EUL, + 0x44094F85UL, 0x3F481D87UL, 0xFCFEAE7BUL, 0x77B5FF76UL, + 0x8C2302BFUL, 0xAAF47556UL, 0x5F46B02AUL, 0x2B092801UL, + 0x3D38F5F7UL, 0x0CA81F36UL, 0x52AF4A8AUL, 0x66D5E7C0UL, + 0xDF3B0874UL, 0x95055110UL, 0x1B5AD7A8UL, 0xF61ED5ADUL, + 0x6CF6E479UL, 0x20758184UL, 0xD0CEFA65UL, 0x88F7BE58UL, + 0x4A046826UL, 0x0FF6F8F3UL, 0xA09C7F70UL, 0x5346ABA0UL, + 0x5CE96C28UL, 0xE176EDA3UL, 0x6BAC307FUL, 0x376829D2UL, + 0x85360FA9UL, 0x17E3FE2AUL, 0x24B79767UL, 0xF5A96B20UL, + 0xD6CD2595UL, 0x68FF1EBFUL, 0x7555442CUL, 0xF19F06BEUL, + 0xF9E0659AUL, 0xEEB9491DUL, 0x34010718UL, 0xBB30CAB8UL, + 0xE822FE15UL, 0x88570983UL, 0x750E6249UL, 0xDA627E55UL, + 0x5E76FFA8UL, 0xB1534546UL, 0x6D47DE08UL, 0xEFE9E7D4UL +}, + +{ + 0xF6FA8F9DUL, 0x2CAC6CE1UL, 0x4CA34867UL, 0xE2337F7CUL, + 0x95DB08E7UL, 0x016843B4UL, 0xECED5CBCUL, 0x325553ACUL, + 0xBF9F0960UL, 0xDFA1E2EDUL, 0x83F0579DUL, 0x63ED86B9UL, + 0x1AB6A6B8UL, 0xDE5EBE39UL, 0xF38FF732UL, 0x8989B138UL, + 0x33F14961UL, 0xC01937BDUL, 0xF506C6DAUL, 0xE4625E7EUL, + 0xA308EA99UL, 0x4E23E33CUL, 0x79CBD7CCUL, 0x48A14367UL, + 0xA3149619UL, 0xFEC94BD5UL, 0xA114174AUL, 0xEAA01866UL, + 0xA084DB2DUL, 0x09A8486FUL, 0xA888614AUL, 0x2900AF98UL, + 0x01665991UL, 0xE1992863UL, 0xC8F30C60UL, 0x2E78EF3CUL, + 0xD0D51932UL, 0xCF0FEC14UL, 0xF7CA07D2UL, 0xD0A82072UL, + 0xFD41197EUL, 0x9305A6B0UL, 0xE86BE3DAUL, 0x74BED3CDUL, + 0x372DA53CUL, 0x4C7F4448UL, 0xDAB5D440UL, 0x6DBA0EC3UL, + 0x083919A7UL, 0x9FBAEED9UL, 0x49DBCFB0UL, 0x4E670C53UL, + 0x5C3D9C01UL, 0x64BDB941UL, 0x2C0E636AUL, 0xBA7DD9CDUL, + 0xEA6F7388UL, 0xE70BC762UL, 0x35F29ADBUL, 0x5C4CDD8DUL, + 0xF0D48D8CUL, 0xB88153E2UL, 0x08A19866UL, 0x1AE2EAC8UL, + 0x284CAF89UL, 0xAA928223UL, 0x9334BE53UL, 0x3B3A21BFUL, + 0x16434BE3UL, 0x9AEA3906UL, 0xEFE8C36EUL, 0xF890CDD9UL, + 0x80226DAEUL, 0xC340A4A3UL, 0xDF7E9C09UL, 0xA694A807UL, + 0x5B7C5ECCUL, 0x221DB3A6UL, 0x9A69A02FUL, 0x68818A54UL, + 0xCEB2296FUL, 0x53C0843AUL, 0xFE893655UL, 0x25BFE68AUL, + 0xB4628ABCUL, 0xCF222EBFUL, 0x25AC6F48UL, 0xA9A99387UL, + 0x53BDDB65UL, 0xE76FFBE7UL, 0xE967FD78UL, 0x0BA93563UL, + 0x8E342BC1UL, 0xE8A11BE9UL, 0x4980740DUL, 0xC8087DFCUL, + 0x8DE4BF99UL, 0xA11101A0UL, 0x7FD37975UL, 0xDA5A26C0UL, + 0xE81F994FUL, 0x9528CD89UL, 0xFD339FEDUL, 0xB87834BFUL, + 0x5F04456DUL, 0x22258698UL, 0xC9C4C83BUL, 0x2DC156BEUL, + 0x4F628DAAUL, 0x57F55EC5UL, 0xE2220ABEUL, 0xD2916EBFUL, + 0x4EC75B95UL, 0x24F2C3C0UL, 0x42D15D99UL, 0xCD0D7FA0UL, + 0x7B6E27FFUL, 0xA8DC8AF0UL, 0x7345C106UL, 0xF41E232FUL, + 0x35162386UL, 0xE6EA8926UL, 0x3333B094UL, 0x157EC6F2UL, + 0x372B74AFUL, 0x692573E4UL, 0xE9A9D848UL, 0xF3160289UL, + 0x3A62EF1DUL, 0xA787E238UL, 0xF3A5F676UL, 0x74364853UL, + 0x20951063UL, 0x4576698DUL, 0xB6FAD407UL, 0x592AF950UL, + 0x36F73523UL, 0x4CFB6E87UL, 0x7DA4CEC0UL, 0x6C152DAAUL, + 0xCB0396A8UL, 0xC50DFE5DUL, 0xFCD707ABUL, 0x0921C42FUL, + 0x89DFF0BBUL, 0x5FE2BE78UL, 0x448F4F33UL, 0x754613C9UL, + 0x2B05D08DUL, 0x48B9D585UL, 0xDC049441UL, 0xC8098F9BUL, + 0x7DEDE786UL, 0xC39A3373UL, 0x42410005UL, 0x6A091751UL, + 0x0EF3C8A6UL, 0x890072D6UL, 0x28207682UL, 0xA9A9F7BEUL, + 0xBF32679DUL, 0xD45B5B75UL, 0xB353FD00UL, 0xCBB0E358UL, + 0x830F220AUL, 0x1F8FB214UL, 0xD372CF08UL, 0xCC3C4A13UL, + 0x8CF63166UL, 0x061C87BEUL, 0x88C98F88UL, 0x6062E397UL, + 0x47CF8E7AUL, 0xB6C85283UL, 0x3CC2ACFBUL, 0x3FC06976UL, + 0x4E8F0252UL, 0x64D8314DUL, 0xDA3870E3UL, 0x1E665459UL, + 0xC10908F0UL, 0x513021A5UL, 0x6C5B68B7UL, 0x822F8AA0UL, + 0x3007CD3EUL, 0x74719EEFUL, 0xDC872681UL, 0x073340D4UL, + 0x7E432FD9UL, 0x0C5EC241UL, 0x8809286CUL, 0xF592D891UL, + 0x08A930F6UL, 0x957EF305UL, 0xB7FBFFBDUL, 0xC266E96FUL, + 0x6FE4AC98UL, 0xB173ECC0UL, 0xBC60B42AUL, 0x953498DAUL, + 0xFBA1AE12UL, 0x2D4BD736UL, 0x0F25FAABUL, 0xA4F3FCEBUL, + 0xE2969123UL, 0x257F0C3DUL, 0x9348AF49UL, 0x361400BCUL, + 0xE8816F4AUL, 0x3814F200UL, 0xA3F94043UL, 0x9C7A54C2UL, + 0xBC704F57UL, 0xDA41E7F9UL, 0xC25AD33AUL, 0x54F4A084UL, + 0xB17F5505UL, 0x59357CBEUL, 0xEDBD15C8UL, 0x7F97C5ABUL, + 0xBA5AC7B5UL, 0xB6F6DEAFUL, 0x3A479C3AUL, 0x5302DA25UL, + 0x653D7E6AUL, 0x54268D49UL, 0x51A477EAUL, 0x5017D55BUL, + 0xD7D25D88UL, 0x44136C76UL, 0x0404A8C8UL, 0xB8E5A121UL, + 0xB81A928AUL, 0x60ED5869UL, 0x97C55B96UL, 0xEAEC991BUL, + 0x29935913UL, 0x01FDB7F1UL, 0x088E8DFAUL, 0x9AB6F6F5UL, + 0x3B4CBF9FUL, 0x4A5DE3ABUL, 0xE6051D35UL, 0xA0E1D855UL, + 0xD36B4CF1UL, 0xF544EDEBUL, 0xB0E93524UL, 0xBEBB8FBDUL, + 0xA2D762CFUL, 0x49C92F54UL, 0x38B5F331UL, 0x7128A454UL, + 0x48392905UL, 0xA65B1DB8UL, 0x851C97BDUL, 0xD675CF2FUL +}, + +{ + 0x85E04019UL, 0x332BF567UL, 0x662DBFFFUL, 0xCFC65693UL, + 0x2A8D7F6FUL, 0xAB9BC912UL, 0xDE6008A1UL, 0x2028DA1FUL, + 0x0227BCE7UL, 0x4D642916UL, 0x18FAC300UL, 0x50F18B82UL, + 0x2CB2CB11UL, 0xB232E75CUL, 0x4B3695F2UL, 0xB28707DEUL, + 0xA05FBCF6UL, 0xCD4181E9UL, 0xE150210CUL, 0xE24EF1BDUL, + 0xB168C381UL, 0xFDE4E789UL, 0x5C79B0D8UL, 0x1E8BFD43UL, + 0x4D495001UL, 0x38BE4341UL, 0x913CEE1DUL, 0x92A79C3FUL, + 0x089766BEUL, 0xBAEEADF4UL, 0x1286BECFUL, 0xB6EACB19UL, + 0x2660C200UL, 0x7565BDE4UL, 0x64241F7AUL, 0x8248DCA9UL, + 0xC3B3AD66UL, 0x28136086UL, 0x0BD8DFA8UL, 0x356D1CF2UL, + 0x107789BEUL, 0xB3B2E9CEUL, 0x0502AA8FUL, 0x0BC0351EUL, + 0x166BF52AUL, 0xEB12FF82UL, 0xE3486911UL, 0xD34D7516UL, + 0x4E7B3AFFUL, 0x5F43671BUL, 0x9CF6E037UL, 0x4981AC83UL, + 0x334266CEUL, 0x8C9341B7UL, 0xD0D854C0UL, 0xCB3A6C88UL, + 0x47BC2829UL, 0x4725BA37UL, 0xA66AD22BUL, 0x7AD61F1EUL, + 0x0C5CBAFAUL, 0x4437F107UL, 0xB6E79962UL, 0x42D2D816UL, + 0x0A961288UL, 0xE1A5C06EUL, 0x13749E67UL, 0x72FC081AUL, + 0xB1D139F7UL, 0xF9583745UL, 0xCF19DF58UL, 0xBEC3F756UL, + 0xC06EBA30UL, 0x07211B24UL, 0x45C28829UL, 0xC95E317FUL, + 0xBC8EC511UL, 0x38BC46E9UL, 0xC6E6FA14UL, 0xBAE8584AUL, + 0xAD4EBC46UL, 0x468F508BUL, 0x7829435FUL, 0xF124183BUL, + 0x821DBA9FUL, 0xAFF60FF4UL, 0xEA2C4E6DUL, 0x16E39264UL, + 0x92544A8BUL, 0x009B4FC3UL, 0xABA68CEDUL, 0x9AC96F78UL, + 0x06A5B79AUL, 0xB2856E6EUL, 0x1AEC3CA9UL, 0xBE838688UL, + 0x0E0804E9UL, 0x55F1BE56UL, 0xE7E5363BUL, 0xB3A1F25DUL, + 0xF7DEBB85UL, 0x61FE033CUL, 0x16746233UL, 0x3C034C28UL, + 0xDA6D0C74UL, 0x79AAC56CUL, 0x3CE4E1ADUL, 0x51F0C802UL, + 0x98F8F35AUL, 0x1626A49FUL, 0xEED82B29UL, 0x1D382FE3UL, + 0x0C4FB99AUL, 0xBB325778UL, 0x3EC6D97BUL, 0x6E77A6A9UL, + 0xCB658B5CUL, 0xD45230C7UL, 0x2BD1408BUL, 0x60C03EB7UL, + 0xB9068D78UL, 0xA33754F4UL, 0xF430C87DUL, 0xC8A71302UL, + 0xB96D8C32UL, 0xEBD4E7BEUL, 0xBE8B9D2DUL, 0x7979FB06UL, + 0xE7225308UL, 0x8B75CF77UL, 0x11EF8DA4UL, 0xE083C858UL, + 0x8D6B786FUL, 0x5A6317A6UL, 0xFA5CF7A0UL, 0x5DDA0033UL, + 0xF28EBFB0UL, 0xF5B9C310UL, 0xA0EAC280UL, 0x08B9767AUL, + 0xA3D9D2B0UL, 0x79D34217UL, 0x021A718DUL, 0x9AC6336AUL, + 0x2711FD60UL, 0x438050E3UL, 0x069908A8UL, 0x3D7FEDC4UL, + 0x826D2BEFUL, 0x4EEB8476UL, 0x488DCF25UL, 0x36C9D566UL, + 0x28E74E41UL, 0xC2610ACAUL, 0x3D49A9CFUL, 0xBAE3B9DFUL, + 0xB65F8DE6UL, 0x92AEAF64UL, 0x3AC7D5E6UL, 0x9EA80509UL, + 0xF22B017DUL, 0xA4173F70UL, 0xDD1E16C3UL, 0x15E0D7F9UL, + 0x50B1B887UL, 0x2B9F4FD5UL, 0x625ABA82UL, 0x6A017962UL, + 0x2EC01B9CUL, 0x15488AA9UL, 0xD716E740UL, 0x40055A2CUL, + 0x93D29A22UL, 0xE32DBF9AUL, 0x058745B9UL, 0x3453DC1EUL, + 0xD699296EUL, 0x496CFF6FUL, 0x1C9F4986UL, 0xDFE2ED07UL, + 0xB87242D1UL, 0x19DE7EAEUL, 0x053E561AUL, 0x15AD6F8CUL, + 0x66626C1CUL, 0x7154C24CUL, 0xEA082B2AUL, 0x93EB2939UL, + 0x17DCB0F0UL, 0x58D4F2AEUL, 0x9EA294FBUL, 0x52CF564CUL, + 0x9883FE66UL, 0x2EC40581UL, 0x763953C3UL, 0x01D6692EUL, + 0xD3A0C108UL, 0xA1E7160EUL, 0xE4F2DFA6UL, 0x693ED285UL, + 0x74904698UL, 0x4C2B0EDDUL, 0x4F757656UL, 0x5D393378UL, + 0xA132234FUL, 0x3D321C5DUL, 0xC3F5E194UL, 0x4B269301UL, + 0xC79F022FUL, 0x3C997E7EUL, 0x5E4F9504UL, 0x3FFAFBBDUL, + 0x76F7AD0EUL, 0x296693F4UL, 0x3D1FCE6FUL, 0xC61E45BEUL, + 0xD3B5AB34UL, 0xF72BF9B7UL, 0x1B0434C0UL, 0x4E72B567UL, + 0x5592A33DUL, 0xB5229301UL, 0xCFD2A87FUL, 0x60AEB767UL, + 0x1814386BUL, 0x30BCC33DUL, 0x38A0C07DUL, 0xFD1606F2UL, + 0xC363519BUL, 0x589DD390UL, 0x5479F8E6UL, 0x1CB8D647UL, + 0x97FD61A9UL, 0xEA7759F4UL, 0x2D57539DUL, 0x569A58CFUL, + 0xE84E63ADUL, 0x462E1B78UL, 0x6580F87EUL, 0xF3817914UL, + 0x91DA55F4UL, 0x40A230F3UL, 0xD1988F35UL, 0xB6E318D2UL, + 0x3FFA50BCUL, 0x3D40F021UL, 0xC3C0BDAEUL, 0x4958C24CUL, + 0x518F36B2UL, 0x84B1D370UL, 0x0FEDCE83UL, 0x878DDADAUL, + 0xF2A279C7UL, 0x94E01BE8UL, 0x90716F4BUL, 0x954B8AA3UL +}, + +{ + 0xE216300DUL, 0xBBDDFFFCUL, 0xA7EBDABDUL, 0x35648095UL, + 0x7789F8B7UL, 0xE6C1121BUL, 0x0E241600UL, 0x052CE8B5UL, + 0x11A9CFB0UL, 0xE5952F11UL, 0xECE7990AUL, 0x9386D174UL, + 0x2A42931CUL, 0x76E38111UL, 0xB12DEF3AUL, 0x37DDDDFCUL, + 0xDE9ADEB1UL, 0x0A0CC32CUL, 0xBE197029UL, 0x84A00940UL, + 0xBB243A0FUL, 0xB4D137CFUL, 0xB44E79F0UL, 0x049EEDFDUL, + 0x0B15A15DUL, 0x480D3168UL, 0x8BBBDE5AUL, 0x669DED42UL, + 0xC7ECE831UL, 0x3F8F95E7UL, 0x72DF191BUL, 0x7580330DUL, + 0x94074251UL, 0x5C7DCDFAUL, 0xABBE6D63UL, 0xAA402164UL, + 0xB301D40AUL, 0x02E7D1CAUL, 0x53571DAEUL, 0x7A3182A2UL, + 0x12A8DDECUL, 0xFDAA335DUL, 0x176F43E8UL, 0x71FB46D4UL, + 0x38129022UL, 0xCE949AD4UL, 0xB84769ADUL, 0x965BD862UL, + 0x82F3D055UL, 0x66FB9767UL, 0x15B80B4EUL, 0x1D5B47A0UL, + 0x4CFDE06FUL, 0xC28EC4B8UL, 0x57E8726EUL, 0x647A78FCUL, + 0x99865D44UL, 0x608BD593UL, 0x6C200E03UL, 0x39DC5FF6UL, + 0x5D0B00A3UL, 0xAE63AFF2UL, 0x7E8BD632UL, 0x70108C0CUL, + 0xBBD35049UL, 0x2998DF04UL, 0x980CF42AUL, 0x9B6DF491UL, + 0x9E7EDD53UL, 0x06918548UL, 0x58CB7E07UL, 0x3B74EF2EUL, + 0x522FFFB1UL, 0xD24708CCUL, 0x1C7E27CDUL, 0xA4EB215BUL, + 0x3CF1D2E2UL, 0x19B47A38UL, 0x424F7618UL, 0x35856039UL, + 0x9D17DEE7UL, 0x27EB35E6UL, 0xC9AFF67BUL, 0x36BAF5B8UL, + 0x09C467CDUL, 0xC18910B1UL, 0xE11DBF7BUL, 0x06CD1AF8UL, + 0x7170C608UL, 0x2D5E3354UL, 0xD4DE495AUL, 0x64C6D006UL, + 0xBCC0C62CUL, 0x3DD00DB3UL, 0x708F8F34UL, 0x77D51B42UL, + 0x264F620FUL, 0x24B8D2BFUL, 0x15C1B79EUL, 0x46A52564UL, + 0xF8D7E54EUL, 0x3E378160UL, 0x7895CDA5UL, 0x859C15A5UL, + 0xE6459788UL, 0xC37BC75FUL, 0xDB07BA0CUL, 0x0676A3ABUL, + 0x7F229B1EUL, 0x31842E7BUL, 0x24259FD7UL, 0xF8BEF472UL, + 0x835FFCB8UL, 0x6DF4C1F2UL, 0x96F5B195UL, 0xFD0AF0FCUL, + 0xB0FE134CUL, 0xE2506D3DUL, 0x4F9B12EAUL, 0xF215F225UL, + 0xA223736FUL, 0x9FB4C428UL, 0x25D04979UL, 0x34C713F8UL, + 0xC4618187UL, 0xEA7A6E98UL, 0x7CD16EFCUL, 0x1436876CUL, + 0xF1544107UL, 0xBEDEEE14UL, 0x56E9AF27UL, 0xA04AA441UL, + 0x3CF7C899UL, 0x92ECBAE6UL, 0xDD67016DUL, 0x151682EBUL, + 0xA842EEDFUL, 0xFDBA60B4UL, 0xF1907B75UL, 0x20E3030FUL, + 0x24D8C29EUL, 0xE139673BUL, 0xEFA63FB8UL, 0x71873054UL, + 0xB6F2CF3BUL, 0x9F326442UL, 0xCB15A4CCUL, 0xB01A4504UL, + 0xF1E47D8DUL, 0x844A1BE5UL, 0xBAE7DFDCUL, 0x42CBDA70UL, + 0xCD7DAE0AUL, 0x57E85B7AUL, 0xD53F5AF6UL, 0x20CF4D8CUL, + 0xCEA4D428UL, 0x79D130A4UL, 0x3486EBFBUL, 0x33D3CDDCUL, + 0x77853B53UL, 0x37EFFCB5UL, 0xC5068778UL, 0xE580B3E6UL, + 0x4E68B8F4UL, 0xC5C8B37EUL, 0x0D809EA2UL, 0x398FEB7CUL, + 0x132A4F94UL, 0x43B7950EUL, 0x2FEE7D1CUL, 0x223613BDUL, + 0xDD06CAA2UL, 0x37DF932BUL, 0xC4248289UL, 0xACF3EBC3UL, + 0x5715F6B7UL, 0xEF3478DDUL, 0xF267616FUL, 0xC148CBE4UL, + 0x9052815EUL, 0x5E410FABUL, 0xB48A2465UL, 0x2EDA7FA4UL, + 0xE87B40E4UL, 0xE98EA084UL, 0x5889E9E1UL, 0xEFD390FCUL, + 0xDD07D35BUL, 0xDB485694UL, 0x38D7E5B2UL, 0x57720101UL, + 0x730EDEBCUL, 0x5B643113UL, 0x94917E4FUL, 0x503C2FBAUL, + 0x646F1282UL, 0x7523D24AUL, 0xE0779695UL, 0xF9C17A8FUL, + 0x7A5B2121UL, 0xD187B896UL, 0x29263A4DUL, 0xBA510CDFUL, + 0x81F47C9FUL, 0xAD1163EDUL, 0xEA7B5965UL, 0x1A00726EUL, + 0x11403092UL, 0x00DA6D77UL, 0x4A0CDD61UL, 0xAD1F4603UL, + 0x605BDFB0UL, 0x9EEDC364UL, 0x22EBE6A8UL, 0xCEE7D28AUL, + 0xA0E736A0UL, 0x5564A6B9UL, 0x10853209UL, 0xC7EB8F37UL, + 0x2DE705CAUL, 0x8951570FUL, 0xDF09822BUL, 0xBD691A6CUL, + 0xAA12E4F2UL, 0x87451C0FUL, 0xE0F6A27AUL, 0x3ADA4819UL, + 0x4CF1764FUL, 0x0D771C2BUL, 0x67CDB156UL, 0x350D8384UL, + 0x5938FA0FUL, 0x42399EF3UL, 0x36997B07UL, 0x0E84093DUL, + 0x4AA93E61UL, 0x8360D87BUL, 0x1FA98B0CUL, 0x1149382CUL, + 0xE97625A5UL, 0x0614D1B7UL, 0x0E25244BUL, 0x0C768347UL, + 0x589E8D82UL, 0x0D2059D1UL, 0xA466BB1EUL, 0xF8DA0A82UL, + 0x04F19130UL, 0xBA6E4EC0UL, 0x99265164UL, 0x1EE7230DUL, + 0x50B2AD80UL, 0xEAEE6801UL, 0x8DB2A283UL, 0xEA8BF59EUL +}}; + +NAMESPACE_END diff --git a/cbcmac.h b/cbcmac.h new file mode 100644 index 0000000..0297f9d --- /dev/null +++ b/cbcmac.h @@ -0,0 +1,99 @@ +#ifndef CRYPTOPP_CBCMAC_H +#define CRYPTOPP_CBCMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +class CBC_MAC_Base : public SameKeyLengthAs<T>, public MessageAuthenticationCode +{ +public: + static std::string StaticAlgorithmName() {return std::string("CBC-MAC(") + T::StaticAlgorithmName() + ")";} + + CBC_MAC_Base() {} + + void CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *mac, unsigned int size); + unsigned int DigestSize() const {return m_cipher.BlockSize();} + +private: + void ProcessBuf(); + typename T::Encryption m_cipher; + SecByteBlock m_reg; + unsigned int m_counter; +}; + +//! <a href="http://www.weidai.com/scan-mirror/mac.html#CBC-MAC">CBC-MAC</a> +/*! Compatible with FIPS 113. T should be an encryption class. + Secure only for fixed length messages. For variable length + messages use DMAC. +*/ +template <class T> +class CBC_MAC : public MessageAuthenticationCodeTemplate<CBC_MAC_Base<T> > +{ +public: + CBC_MAC() {} + CBC_MAC(const byte *key, unsigned int length=CBC_MAC_Base<T>::DEFAULT_KEYLENGTH) + {SetKey(key, length);} +}; + +template <class T> +void CBC_MAC_Base<T>::CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_cipher.SetKey(key, length, params); + m_reg.CleanNew(m_cipher.BlockSize()); + m_counter = 0; +} + +template <class T> +void CBC_MAC_Base<T>::Update(const byte *input, unsigned int length) +{ + while (m_counter && length) + { + m_reg[m_counter++] ^= *input++; + if (m_counter == T::BLOCKSIZE) + ProcessBuf(); + length--; + } + + while (length >= T::BLOCKSIZE) + { + xorbuf(m_reg, input, T::BLOCKSIZE); + ProcessBuf(); + input += T::BLOCKSIZE; + length -= T::BLOCKSIZE; + } + + while (length--) + { + m_reg[m_counter++] ^= *input++; + if (m_counter == T::BLOCKSIZE) + ProcessBuf(); + } +} + +template <class T> +void CBC_MAC_Base<T>::TruncatedFinal(byte *mac, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + if (m_counter) + ProcessBuf(); + + memcpy(mac, m_reg, size); + memset(m_reg, 0, T::BLOCKSIZE); +} + +template <class T> +void CBC_MAC_Base<T>::ProcessBuf() +{ + m_cipher.ProcessBlock(m_reg); + m_counter = 0; +} + +NAMESPACE_END + +#endif diff --git a/channels.cpp b/channels.cpp new file mode 100644 index 0000000..d13bcf4 --- /dev/null +++ b/channels.cpp @@ -0,0 +1,282 @@ +// channels.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "channels.h" + +NAMESPACE_BEGIN(CryptoPP) +USING_NAMESPACE(std) + +#if 0 +void MessageSwitch::AddDefaultRoute(BufferedTransformation &destination, const std::string &channel) +{ + m_defaultRoutes.push_back(Route(&destination, channel)); +} + +void MessageSwitch::AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel) +{ + RangeRoute route(begin, end, Route(&destination, channel)); + RouteList::iterator it = upper_bound(m_routes.begin(), m_routes.end(), route); + m_routes.insert(it, route); +} + +/* +class MessageRouteIterator +{ +public: + typedef MessageSwitch::RouteList::const_iterator RouteIterator; + typedef MessageSwitch::DefaultRouteList::const_iterator DefaultIterator; + + bool m_useDefault; + RouteIterator m_itRouteCurrent, m_itRouteEnd; + DefaultIterator m_itDefaultCurrent, m_itDefaultEnd; + + MessageRouteIterator(MessageSwitch &ms, const std::string &channel) + : m_channel(channel) + { + pair<MapIterator, MapIterator> range = cs.m_routeMap.equal_range(channel); + if (range.first == range.second) + { + m_useDefault = true; + m_itListCurrent = cs.m_defaultRoutes.begin(); + m_itListEnd = cs.m_defaultRoutes.end(); + } + else + { + m_useDefault = false; + m_itMapCurrent = range.first; + m_itMapEnd = range.second; + } + } + + bool End() const + { + return m_useDefault ? m_itListCurrent == m_itListEnd : m_itMapCurrent == m_itMapEnd; + } + + void Next() + { + if (m_useDefault) + ++m_itListCurrent; + else + ++m_itMapCurrent; + } + + BufferedTransformation & Destination() + { + return m_useDefault ? *m_itListCurrent->first : *m_itMapCurrent->second.first; + } + + const std::string & Message() + { + if (m_useDefault) + return m_itListCurrent->second.get() ? *m_itListCurrent->second.get() : m_channel; + else + return m_itMapCurrent->second.second; + } +}; + +void MessageSwitch::Put(byte inByte); +void MessageSwitch::Put(const byte *inString, unsigned int length); + +void MessageSwitch::Flush(bool completeFlush, int propagation=-1); +void MessageSwitch::MessageEnd(int propagation=-1); +void MessageSwitch::PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); +void MessageSwitch::MessageSeriesEnd(int propagation=-1); +*/ +#endif + +class ChannelRouteIterator +{ +public: + typedef ChannelSwitch::RouteMap::const_iterator MapIterator; + typedef ChannelSwitch::DefaultRouteList::const_iterator ListIterator; + + const std::string m_channel; + bool m_useDefault; + MapIterator m_itMapCurrent, m_itMapEnd; + ListIterator m_itListCurrent, m_itListEnd; + + ChannelRouteIterator(ChannelSwitch &cs, const std::string &channel) + : m_channel(channel) + { + pair<MapIterator, MapIterator> range = cs.m_routeMap.equal_range(channel); + if (range.first == range.second) + { + m_useDefault = true; + m_itListCurrent = cs.m_defaultRoutes.begin(); + m_itListEnd = cs.m_defaultRoutes.end(); + } + else + { + m_useDefault = false; + m_itMapCurrent = range.first; + m_itMapEnd = range.second; + } + } + + bool End() const + { + return m_useDefault ? m_itListCurrent == m_itListEnd : m_itMapCurrent == m_itMapEnd; + } + + void Next() + { + if (m_useDefault) + ++m_itListCurrent; + else + ++m_itMapCurrent; + } + + BufferedTransformation & Destination() + { + return m_useDefault ? *m_itListCurrent->first : *m_itMapCurrent->second.first; + } + + const std::string & Channel() + { + if (m_useDefault) + return m_itListCurrent->second.get() ? *m_itListCurrent->second.get() : m_channel; + else + return m_itMapCurrent->second.second; + } +}; + +unsigned int ChannelSwitch::ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("ChannelSwitch"); + + ChannelRouteIterator it(*this, channel); + while (!it.End()) + { + it.Destination().ChannelPut2(it.Channel(), begin, length, messageEnd, blocking); + it.Next(); + } + return 0; +} + +void ChannelSwitch::ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters/* =g_nullNameValuePairs */, int propagation/* =-1 */) +{ + if (channel.empty()) + { + m_routeMap.clear(); + m_defaultRoutes.clear(); + } + + ChannelRouteIterator it(*this, channel); + while (!it.End()) + { + it.Destination().ChannelInitialize(it.Channel(), parameters, propagation); + it.Next(); + } +} + +bool ChannelSwitch::ChannelFlush(const std::string &channel, bool completeFlush, int propagation, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("ChannelSwitch"); + + ChannelRouteIterator it(*this, channel); + while (!it.End()) + { + it.Destination().ChannelFlush(it.Channel(), completeFlush, propagation, blocking); + it.Next(); + } + return false; +} + +bool ChannelSwitch::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("ChannelSwitch"); + + ChannelRouteIterator it(*this, channel); + while (!it.End()) + { + it.Destination().ChannelMessageSeriesEnd(it.Channel(), propagation); + it.Next(); + } + return false; +} + +byte * ChannelSwitch::ChannelCreatePutSpace(const std::string &channel, unsigned int &size) +{ + ChannelRouteIterator it(*this, channel); + if (!it.End()) + { + BufferedTransformation &target = it.Destination(); + it.Next(); + if (it.End()) // there is only one target channel + return target.ChannelCreatePutSpace(it.Channel(), size); + } + size = 0; + return NULL; +} + +unsigned int ChannelSwitch::ChannelPutModifiable2(const std::string &channel, byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("ChannelSwitch"); + + ChannelRouteIterator it(*this, channel); + if (!it.End()) + { + BufferedTransformation &target = it.Destination(); + const std::string &targetChannel = it.Channel(); + it.Next(); + if (it.End()) // there is only one target channel + return target.ChannelPutModifiable2(targetChannel, inString, length, messageEnd, blocking); + } + ChannelPut2(channel, inString, length, messageEnd, blocking); + return false; +} + +void ChannelSwitch::AddDefaultRoute(BufferedTransformation &destination) +{ + m_defaultRoutes.push_back(DefaultRoute(&destination, value_ptr<std::string>(NULL))); +} + +void ChannelSwitch::RemoveDefaultRoute(BufferedTransformation &destination) +{ + for (DefaultRouteList::iterator it = m_defaultRoutes.begin(); it != m_defaultRoutes.end(); ++it) + if (it->first == &destination && !it->second.get()) + { + m_defaultRoutes.erase(it); + break; + } +} + +void ChannelSwitch::AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel) +{ + m_defaultRoutes.push_back(DefaultRoute(&destination, outChannel)); +} + +void ChannelSwitch::RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel) +{ + for (DefaultRouteList::iterator it = m_defaultRoutes.begin(); it != m_defaultRoutes.end(); ++it) + if (it->first == &destination && (it->second.get() && *it->second == outChannel)) + { + m_defaultRoutes.erase(it); + break; + } +} + +void ChannelSwitch::AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel) +{ + m_routeMap.insert(RouteMap::value_type(inChannel, Route(&destination, outChannel))); +} + +void ChannelSwitch::RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel) +{ + typedef ChannelSwitch::RouteMap::iterator MapIterator; + pair<MapIterator, MapIterator> range = m_routeMap.equal_range(inChannel); + + for (MapIterator it = range.first; it != range.second; ++it) + if (it->second.first == &destination && it->second.second == outChannel) + { + m_routeMap.erase(it); + break; + } +} + +NAMESPACE_END diff --git a/channels.h b/channels.h new file mode 100644 index 0000000..4b12ce6 --- /dev/null +++ b/channels.h @@ -0,0 +1,91 @@ +#ifndef CRYPTOPP_CHANNELS_H +#define CRYPTOPP_CHANNELS_H + +#include "simple.h" +#include "smartptr.h" +#include <map> +#include <list> + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +//! Route input on default channel to different and/or multiple channels based on message sequence number +class MessageSwitch : public Sink +{ +public: + void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel); + void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel); + + void Put(byte inByte); + void Put(const byte *inString, unsigned int length); + + void Flush(bool completeFlush, int propagation=-1); + void MessageEnd(int propagation=-1); + void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); + void MessageSeriesEnd(int propagation=-1); + +private: + typedef std::pair<BufferedTransformation *, std::string> Route; + struct RangeRoute + { + RangeRoute(unsigned int begin, unsigned int end, const Route &route) + : begin(begin), end(end), route(route) {} + bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;} + unsigned int begin, end; + Route route; + }; + + typedef std::list<RangeRoute> RouteList; + typedef std::list<Route> DefaultRouteList; + + RouteList m_routes; + DefaultRouteList m_defaultRoutes; + unsigned int m_nCurrentMessage; +}; +#endif + +//! Route input to different and/or multiple channels based on channel ID +class ChannelSwitch : public Multichannel<Sink> +{ +public: + ChannelSwitch() {} + ChannelSwitch(BufferedTransformation &destination) + { + AddDefaultRoute(destination); + } + ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) + { + AddDefaultRoute(destination, outChannel); + } + + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking); + unsigned int ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking); + + void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + byte * ChannelCreatePutSpace(const std::string &channel, unsigned int &size); + + void AddDefaultRoute(BufferedTransformation &destination); + void RemoveDefaultRoute(BufferedTransformation &destination); + void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + +private: + typedef std::pair<BufferedTransformation *, std::string> Route; + typedef std::multimap<std::string, Route> RouteMap; + RouteMap m_routeMap; + + typedef std::pair<BufferedTransformation *, value_ptr<std::string> > DefaultRoute; + typedef std::list<DefaultRoute> DefaultRouteList; + DefaultRouteList m_defaultRoutes; + + friend class ChannelRouteIterator; +}; + +NAMESPACE_END + +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..cd4156b --- /dev/null +++ b/config.h @@ -0,0 +1,246 @@ +#ifndef CRYPTOPP_CONFIG_H +#define CRYPTOPP_CONFIG_H + +// ***************** Important Settings ******************** + +// define this if running on a big-endian CPU +#if !defined(IS_LITTLE_ENDIAN) && (defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__PPC__) || defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__))) +# define IS_BIG_ENDIAN +#endif + +// define this if running on a little-endian CPU +// big endian will be assumed if IS_LITTLE_ENDIAN is not defined +#ifndef IS_BIG_ENDIAN +# define IS_LITTLE_ENDIAN +#endif + +// define this if you want to disable all OS-dependent features, +// such as sockets and OS-provided random number generators +// #define NO_OS_DEPENDENCE + +// Define this to use features provided by Microsoft's CryptoAPI. +// Currently the only feature used is random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +#define USE_MS_CRYPTOAPI + +// Define this to 1 to enforce the requirement in FIPS 186-2 Change Notice 1 that only 1024 bit moduli be used +#ifndef DSA_1024_BIT_MODULUS_ONLY +# define DSA_1024_BIT_MODULUS_ONLY 1 +#endif + +// ***************** Less Important Settings *************** + +// define this to retain (as much as possible) old deprecated function and class names +// #define CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + +#define GZIP_OS_CODE 0 + +// Try this if your CPU has 256K internal cache or a slow multiply instruction +// and you want a (possibly) faster IDEA implementation using log tables +// #define IDEA_LARGECACHE + +// Try this if you have a large cache or your CPU is slow manipulating +// individual bytes. +// #define DIAMOND_USE_PERMTABLE + +// Define this if, for the linear congruential RNG, you want to use +// the original constants as specified in S.K. Park and K.W. Miller's +// CACM paper. +// #define LCRNG_ORIGINAL_NUMBERS + +// choose which style of sockets to wrap (mostly useful for cygwin which has both) +#define PREFER_BERKELEY_STYLE_SOCKETS +// #define PREFER_WINDOWS_STYLE_SOCKETS + +// ***************** Important Settings Again ******************** +// But the defaults should be ok. + +// namespace support is now required +#ifdef NO_NAMESPACE +# error namespace support is now required +#endif + +// Define this to workaround a Microsoft CryptoAPI bug where +// each call to CryptAcquireContext causes a 100 KB memory leak. +// Defining this will cause Crypto++ to make only one call to CryptAcquireContext. +#define WORKAROUND_MS_BUG_Q258000 + +// Avoid putting "CryptoPP::" in front of everything in Doxygen output +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +# define CryptoPP +# define NAMESPACE_BEGIN(x) +# define NAMESPACE_END +#else +# define NAMESPACE_BEGIN(x) namespace x { +# define NAMESPACE_END } +#endif +#define ANONYMOUS_NAMESPACE_BEGIN namespace { +#define USING_NAMESPACE(x) using namespace x; +#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x { +#define DOCUMENTED_NAMESPACE_END } + +// What is the type of the third parameter to bind? +// For Unix, the new standard is ::socklen_t (typically unsigned int), and the old standard is int. +// Unfortunately there is no way to tell whether or not socklen_t is defined. +// To work around this, TYPE_OF_SOCKLEN_T is a macro so that you can change it from the makefile. +#ifndef TYPE_OF_SOCKLEN_T +# if defined(_WIN32) || defined(__CYGWIN__) +# define TYPE_OF_SOCKLEN_T int +# else +# define TYPE_OF_SOCKLEN_T ::socklen_t +# endif +#endif + +#if defined(__CYGWIN__) && defined(PREFER_WINDOWS_STYLE_SOCKETS) +# define __USE_W32_SOCKETS +#endif + +typedef unsigned char byte; // moved outside namespace for Borland C++Builder 5 + +NAMESPACE_BEGIN(CryptoPP) + +typedef unsigned short word16; +#if defined(__alpha) && !defined(_MSC_VER) + typedef unsigned int word32; +#else + typedef unsigned long word32; +#endif + +#if defined(__GNUC__) || defined(__MWERKS__) +# define WORD64_AVAILABLE + typedef unsigned long long word64; +# define W64LIT(x) x##LL +#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__) +# define WORD64_AVAILABLE + typedef unsigned __int64 word64; +# define W64LIT(x) x##ui64 +#endif + +// defined this if your CPU is not 64-bit +#if defined(WORD64_AVAILABLE) && !defined(__alpha) +# define SLOW_WORD64 +#endif + +// word should have the same size as your CPU registers +// dword should be twice as big as word + +#if (defined(__GNUC__) && !defined(__alpha)) || defined(__MWERKS__) + typedef unsigned long word; + typedef unsigned long long dword; +#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__) + typedef unsigned __int32 word; + typedef unsigned __int64 dword; +#else + typedef unsigned int word; + typedef unsigned long dword; +#endif + +const unsigned int WORD_SIZE = sizeof(word); +const unsigned int WORD_BITS = WORD_SIZE * 8; + +#define LOW_WORD(x) (word)(x) + +union dword_union +{ + dword_union (const dword &dw) : dw(dw) {} + dword dw; + word w[2]; +}; + +#ifdef IS_LITTLE_ENDIAN +# define HIGH_WORD(x) (dword_union(x).w[1]) +#else +# define HIGH_WORD(x) (dword_union(x).w[0]) +#endif + +// if the above HIGH_WORD macro doesn't work (if you are not sure, compile it +// and run the validation tests), try this: +// #define HIGH_WORD(x) (word)((x)>>WORD_BITS) + +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) +# define INTEL_INTRINSICS +# define FAST_ROTATE +#elif defined(__MWERKS__) && TARGET_CPU_PPC +# define PPC_INTRINSICS +# define FAST_ROTATE +#elif defined(__GNUC__) && defined(__i386__) + // GCC does peephole optimizations which should result in using rotate instructions +# define FAST_ROTATE +#endif + +NAMESPACE_END + +// VC60 workaround: it doesn't allow typename in some places +#ifdef _MSC_VER +#define CPP_TYPENAME +#else +#define CPP_TYPENAME typename +#endif + +#ifdef _MSC_VER + // 4250: dominance + // 4660: explicitly instantiating a class that's already implicitly instantiated + // 4661: no suitable definition provided for explicit template instantiation request + // 4786: identifer was truncated in debug information + // 4355: 'this' : used in base member initializer list +# pragma warning(disable: 4250 4660 4661 4786 4355) +#endif + +// ***************** determine availability of OS features ******************** + +#ifndef NO_OS_DEPENDENCE + +#if defined(_WIN32) || defined(__CYGWIN__) +#define CRYPTOPP_WIN32_AVAILABLE +#endif + +#if !defined(NO_OS_DEPENDENCE) && defined(WORD64_AVAILABLE) && (defined(_WIN32) || defined(__unix__) || defined(macintosh)) +# define HIGHRES_TIMER_AVAILABLE +#endif + +#if defined(__unix__) +# define HAS_BERKELEY_STYLE_SOCKETS +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# define HAS_WINDOWS_STYLE_SOCKETS +#endif + +#if defined(HIGHRES_TIMER_AVAILABLE) && (defined(HAS_BERKELEY_STYLE_SOCKETS) || defined(HAS_WINDOWS_STYLE_SOCKETS)) +# define SOCKETS_AVAILABLE +#endif + +#if defined(HAS_WINDOWS_STYLE_SOCKETS) && (!defined(HAS_BERKELEY_STYLE_SOCKETS) || defined(PREFER_WINDOWS_STYLE_SOCKETS)) +# define USE_WINDOWS_STYLE_SOCKETS +#else +# define USE_BERKELEY_STYLE_SOCKETS +#endif + +#if defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(USE_BERKELEY_STYLE_SOCKETS) +# define WINDOWS_PIPES_AVAILABLE +#endif + +#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(USE_MS_CRYPTOAPI) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +#endif + +#if (defined(__FreeBSD__) || defined(__linux__) || defined(__MACH__)) +# define NONBLOCKING_RNG_AVAILABLE +# define BLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +#endif + +#ifdef __unix__ +# define HAS_PTHREADS +# define THREADS_AVAILABLE +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# define HAS_WINTHREADS +# define THREADS_AVAILABLE +#endif + +#endif // NO_OS_DEPENDENCE + +#endif @@ -0,0 +1,160 @@ +// crc.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "crc.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/* Table of CRC-32's of all single byte values (made by makecrc.c) */ +const word32 CRC32::m_tab[] = { +#ifdef IS_LITTLE_ENDIAN + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +#else + 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L, + 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L, + 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L, + 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L, + 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L, + 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L, + 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L, + 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L, + 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L, + 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L, + 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL, + 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L, + 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L, + 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L, + 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L, + 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L, + 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL, + 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L, + 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL, + 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L, + 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L, + 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L, + 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL, + 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL, + 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L, + 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL, + 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L, + 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL, + 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L, + 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L, + 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L, + 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L, + 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L, + 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL, + 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L, + 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L, + 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L, + 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L, + 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L, + 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L, + 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L, + 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L, + 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL, + 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L, + 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L, + 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L, + 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L, + 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L, + 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL, + 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L, + 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL, + 0x8def022dL +#endif +}; + +CRC32::CRC32() +{ + Reset(); +} + +void CRC32::Update(const byte *s, unsigned int n) +{ + word32 crc = m_crc; + + for(; !IsAligned<word32>(s) && n > 0; n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + while (n >= 4) + { + crc ^= *(const word32 *)s; + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + n -= 4; + s += 4; + } + + while (n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + m_crc = crc; +} + +void CRC32::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + m_crc ^= CRC32_NEGL; + for (unsigned int i=0; i<size; i++) + hash[i] = GetCrcByte(i); + + Reset(); +} + +NAMESPACE_END @@ -0,0 +1,40 @@ +#ifndef CRYPTOPP_CRC32_H +#define CRYPTOPP_CRC32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 CRC32_NEGL = 0xffffffffL; + +#ifdef IS_LITTLE_ENDIAN +#define CRC32_INDEX(c) (c & 0xff) +#define CRC32_SHIFTED(c) (c >> 8) +#else +#define CRC32_INDEX(c) (c >> 24) +#define CRC32_SHIFTED(c) (c << 8) +#endif + +//! CRC Checksum Calculation +class CRC32 : public HashTransformation +{ +public: + enum {DIGESTSIZE = 4}; + CRC32(); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *hash, unsigned int size); + unsigned int DigestSize() const {return DIGESTSIZE;} + + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + byte GetCrcByte(unsigned int i) const {return ((byte *)&(m_crc))[i];} + +private: + void Reset() {m_crc = CRC32_NEGL;} + + static const word32 m_tab[256]; + word32 m_crc; +}; + +NAMESPACE_END + +#endif diff --git a/cryptest.cpp b/cryptest.cpp new file mode 100644 index 0000000..5302331 --- /dev/null +++ b/cryptest.cpp @@ -0,0 +1,116 @@ +#include "pch.h" + +#ifdef __BCPLUSPLUS__ +#include <condefs.h> + + +//--------------------------------------------------------------------------- +USEUNIT("3way.cpp"); +USEUNIT("algebra.cpp"); +USEUNIT("asn.cpp"); +USEUNIT("base64.cpp"); +USEUNIT("bench.cpp"); +USEUNIT("bfinit.cpp"); +USEUNIT("blowfish.cpp"); +USEUNIT("blumgold.cpp"); +USEUNIT("blumshub.cpp"); +USEUNIT("cast.cpp"); +USEUNIT("cast128s.cpp"); +USEUNIT("crc.cpp"); +USEUNIT("cryptlib.cpp"); +USEUNIT("default.cpp"); +USEUNIT("des.cpp"); +USEUNIT("dessp.cpp"); +USEUNIT("dh.cpp"); +USEUNIT("diamond.cpp"); +USEUNIT("diamondt.cpp"); +USEUNIT("dsa.cpp"); +USEUNIT("ec2n.cpp"); +USEUNIT("eccrypto.cpp"); +USEUNIT("ecp.cpp"); +USEUNIT("elgamal.cpp"); +USEUNIT("eprecomp.cpp"); +USEUNIT("files.cpp"); +USEUNIT("filters.cpp"); +USEUNIT("forkjoin.cpp"); +USEUNIT("gf2_32.cpp"); +USEUNIT("gf256.cpp"); +USEUNIT("gf2n.cpp"); +USEUNIT("gost.cpp"); +USEUNIT("gzip.cpp"); +USEUNIT("haval.cpp"); +USEUNIT("hex.cpp"); +USEUNIT("idea.cpp"); +USEUNIT("integer.cpp"); +USEUNIT("iterhash.cpp"); +USEUNIT("luc.cpp"); +USEUNIT("md5.cpp"); +USEUNIT("md5mac.cpp"); +USEUNIT("misc.cpp"); +USEUNIT("modes.cpp"); +USEUNIT("nbtheory.cpp"); +USEUNIT("oaep.cpp"); +USEUNIT("pch.cpp"); +USEUNIT("pkcspad.cpp"); +USEUNIT("polynomi.cpp"); +USEUNIT("pubkey.cpp"); +USEUNIT("queue.cpp"); +USEUNIT("rabin.cpp"); +USEUNIT("randpool.cpp"); +USEUNIT("rc5.cpp"); +USEUNIT("ripemd.cpp"); +USEUNIT("rng.cpp"); +USEUNIT("rsa.cpp"); +USEUNIT("safer.cpp"); +USEUNIT("sapphire.cpp"); +USEUNIT("seal.cpp"); +USEUNIT("secshare.cpp"); +USEUNIT("secsplit.cpp"); +USEUNIT("sha.cpp"); +USEUNIT("shark.cpp"); +USEUNIT("sharkbox.cpp"); +USEUNIT("square.cpp"); +USEUNIT("squaretb.cpp"); +USEUNIT("tea.cpp"); +USEUNIT("test.cpp"); +USEUNIT("tiger.cpp"); +USEUNIT("tigertab.cpp"); +USEUNIT("validat1.cpp"); +USEUNIT("validat2.cpp"); +USEUNIT("validat3.cpp"); +USEUNIT("wake.cpp"); +USEUNIT("zbits.cpp"); +USEUNIT("zdeflate.cpp"); +USEUNIT("zinflate.cpp"); +USEUNIT("ztrees.cpp"); +USEUNIT("cbc.cpp"); +USEUNIT("arc4.cpp"); +USEUNIT("modexppc.cpp"); +USEUNIT("md2.cpp"); +USEUNIT("rc2.cpp"); +USEUNIT("rc6.cpp"); +USEUNIT("mars.cpp"); +USEUNIT("rw.cpp"); +USEUNIT("marss.cpp"); +USEUNIT("nr.cpp"); +USEUNIT("mqv.cpp"); +USEUNIT("rijndael.cpp"); +USEUNIT("twofish.cpp"); +USEUNIT("serpent.cpp"); +USEUNIT("rdtables.cpp"); +USEUNIT("tftables.cpp"); +USEUNIT("xtr.cpp"); +USEUNIT("skipjack.cpp"); +USEUNIT("mqueue.cpp"); +USEUNIT("xtrcrypt.cpp"); +USEUNIT("network.cpp"); +USEUNIT("osrng.cpp"); +USEUNIT("socketft.cpp"); +//--------------------------------------------------------------------------- +int cmain(int argc, char **argv); + +int main(int argc, char **argv) +{ + return cmain(argc, argv); +} +#endif diff --git a/cryptest.dsp b/cryptest.dsp new file mode 100644 index 0000000..dc4ba3f --- /dev/null +++ b/cryptest.dsp @@ -0,0 +1,392 @@ +# Microsoft Developer Studio Project File - Name="cryptest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cryptest - Win32 FIPS 140 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cryptest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cryptest.mak" CFG="cryptest - Win32 FIPS 140 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cryptest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cryptest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "cryptest - Win32 FIPS 140 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cryptest - Win32 FIPS 140 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/cryptlib", BAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cryptest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "cryptes0" +# PROP BASE Intermediate_Dir "cryptes0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "CTRelease" +# PROP Intermediate_Dir "CTRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /GB /Gd /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /OPT:NOWIN98 + +!ELSEIF "$(CFG)" == "cryptest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "cryptes1" +# PROP BASE Intermediate_Dir "cryptes1" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "CTDebug" +# PROP Intermediate_Dir "CTDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /OPT:NOWIN98 + +!ELSEIF "$(CFG)" == "cryptest - Win32 FIPS 140 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "cryptest___Win32_FIPS_140_Release" +# PROP BASE Intermediate_Dir "cryptest___Win32_FIPS_140_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "CT_FIPS_140_Release" +# PROP Intermediate_Dir "CT_FIPS_140_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /Gz /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /Zm200 /c +# ADD CPP /nologo /G5 /Gz /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /OPT:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /OPT:NOWIN98 + +!ELSEIF "$(CFG)" == "cryptest - Win32 FIPS 140 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "cryptest___Win32_FIPS_140_Debug" +# PROP BASE Intermediate_Dir "cryptest___Win32_FIPS_140_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "CT_FIPS_140_Debug" +# PROP Intermediate_Dir "CT_FIPS_140_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /Zm200 /c +# ADD CPP /nologo /G5 /Gz /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /OPT:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /OPT:NOWIN98 + +!ENDIF + +# Begin Target + +# Name "cryptest - Win32 Release" +# Name "cryptest - Win32 Debug" +# Name "cryptest - Win32 FIPS 140 Release" +# Name "cryptest - Win32 FIPS 140 Debug" +# Begin Group "Test Data" + +# PROP Default_Filter ".dat" +# Begin Source File + +SOURCE=.\3desval.dat +# End Source File +# Begin Source File + +SOURCE=.\3wayval.dat +# End Source File +# Begin Source File + +SOURCE=.\cast128v.dat +# End Source File +# Begin Source File + +SOURCE=.\cast256v.dat +# End Source File +# Begin Source File + +SOURCE=.\descert.dat +# End Source File +# Begin Source File + +SOURCE=.\dh1024.dat +# End Source File +# Begin Source File + +SOURCE=.\dh2048.dat +# End Source File +# Begin Source File + +SOURCE=.\diamond.dat +# End Source File +# Begin Source File + +SOURCE=.\digest.dat +# End Source File +# Begin Source File + +SOURCE=.\dsa1024.dat +# End Source File +# Begin Source File + +SOURCE=.\dsa1024b.dat +# End Source File +# Begin Source File + +SOURCE=.\dsa512.dat +# End Source File +# Begin Source File + +SOURCE=.\elgc1024.dat +# End Source File +# Begin Source File + +SOURCE=.\esig1023.dat +# End Source File +# Begin Source File + +SOURCE=.\esig1536.dat +# End Source File +# Begin Source File + +SOURCE=.\esig2046.dat +# End Source File +# Begin Source File + +SOURCE=.\gostval.dat +# End Source File +# Begin Source File + +SOURCE=.\havalcer.dat +# End Source File +# Begin Source File + +SOURCE=.\ideaval.dat +# End Source File +# Begin Source File + +SOURCE=.\luc1024.dat +# End Source File +# Begin Source File + +SOURCE=.\luc2048.dat +# End Source File +# Begin Source File + +SOURCE=.\lucc1024.dat +# End Source File +# Begin Source File + +SOURCE=.\lucc512.dat +# End Source File +# Begin Source File + +SOURCE=.\lucd1024.dat +# End Source File +# Begin Source File + +SOURCE=.\lucd512.dat +# End Source File +# Begin Source File + +SOURCE=.\lucs1024.dat +# End Source File +# Begin Source File + +SOURCE=.\lucs512.dat +# End Source File +# Begin Source File + +SOURCE=.\marsval.dat +# End Source File +# Begin Source File + +SOURCE=.\mqv1024.dat +# End Source File +# Begin Source File + +SOURCE=.\mqv2048.dat +# End Source File +# Begin Source File + +SOURCE=.\nr1024.dat +# End Source File +# Begin Source File + +SOURCE=.\nr2048.dat +# End Source File +# Begin Source File + +SOURCE=.\rabi1024.dat +# End Source File +# Begin Source File + +SOURCE=.\rabi2048.dat +# End Source File +# Begin Source File + +SOURCE=.\rc2val.dat +# End Source File +# Begin Source File + +SOURCE=.\rc5val.dat +# End Source File +# Begin Source File + +SOURCE=.\rc6val.dat +# End Source File +# Begin Source File + +SOURCE=.\rijndael.dat +# End Source File +# Begin Source File + +SOURCE=.\rsa1024.dat +# End Source File +# Begin Source File + +SOURCE=.\rsa2048.dat +# End Source File +# Begin Source File + +SOURCE=.\rsa400pb.dat +# End Source File +# Begin Source File + +SOURCE=.\rsa400pv.dat +# End Source File +# Begin Source File + +SOURCE=.\rsa512a.dat +# End Source File +# Begin Source File + +SOURCE=.\rw1024.dat +# End Source File +# Begin Source File + +SOURCE=.\rw2048.dat +# End Source File +# Begin Source File + +SOURCE=.\saferval.dat +# End Source File +# Begin Source File + +SOURCE=.\serpentv.dat +# End Source File +# Begin Source File + +SOURCE=.\sharkval.dat +# End Source File +# Begin Source File + +SOURCE=.\skipjack.dat +# End Source File +# Begin Source File + +SOURCE=.\squareva.dat +# End Source File +# Begin Source File + +SOURCE=.\twofishv.dat +# End Source File +# Begin Source File + +SOURCE=.\usage.dat +# End Source File +# Begin Source File + +SOURCE=.\xtrdh171.dat +# End Source File +# Begin Source File + +SOURCE=.\xtrdh342.dat +# End Source File +# End Group +# Begin Group "Source Code" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\bench.cpp +# End Source File +# Begin Source File + +SOURCE=.\bench.h +# End Source File +# Begin Source File + +SOURCE=.\test.cpp +# End Source File +# Begin Source File + +SOURCE=.\validat1.cpp +# End Source File +# Begin Source File + +SOURCE=.\validat2.cpp +# End Source File +# Begin Source File + +SOURCE=.\validat3.cpp +# End Source File +# Begin Source File + +SOURCE=.\validate.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cryptest.dsw b/cryptest.dsw new file mode 100644 index 0000000..bce8473 --- /dev/null +++ b/cryptest.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cryptest"=.\cryptest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cryptlib + End Project Dependency +}}} + +############################################################################### + +Project: "cryptlib"=.\cryptlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/cryptlib.cpp b/cryptlib.cpp new file mode 100644 index 0000000..9e0d59f --- /dev/null +++ b/cryptlib.cpp @@ -0,0 +1,660 @@ +// cryptlib.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "cryptlib.h" +#include "misc.h" +#include "filters.h" +#include "algparam.h" +#include "fips140.h" +#include "argnames.h" + +#include <memory> + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_COMPILE_ASSERT(sizeof(byte) == 1); +CRYPTOPP_COMPILE_ASSERT(sizeof(word16) == 2); +CRYPTOPP_COMPILE_ASSERT(sizeof(word32) == 4); +#ifdef WORD64_AVAILABLE +CRYPTOPP_COMPILE_ASSERT(sizeof(word64) == 8); +#endif +CRYPTOPP_COMPILE_ASSERT(sizeof(dword) == 2*sizeof(word)); + +const std::string BufferedTransformation::NULL_CHANNEL; +const NullNameValuePairs g_nullNameValuePairs; + +BufferedTransformation & TheBitBucket() +{ + static BitBucket bitBucket; + return bitBucket; +} + +Algorithm::Algorithm(bool checkSelfTestStatus) +{ + if (checkSelfTestStatus && FIPS_140_2_ComplianceEnabled()) + { + if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_NOT_DONE && !PowerUpSelfTestInProgressOnThisThread()) + throw SelfTestFailure("Cryptographic algorithms are disabled before the power-up self tests are performed."); + + if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_FAILED) + throw SelfTestFailure("Cryptographic algorithms are disabled after power-up a self test failed."); + } +} + +void SimpleKeyingInterface::SetKeyWithRounds(const byte *key, unsigned int length, int rounds) +{ + SetKey(key, length, MakeParameters(Name::Rounds(), rounds)); +} + +void SimpleKeyingInterface::SetKeyWithIV(const byte *key, unsigned int length, const byte *iv) +{ + SetKey(key, length, MakeParameters(Name::IV(), iv)); +} + +void SimpleKeyingInterface::ThrowIfInvalidKeyLength(const Algorithm &algorithm, unsigned int length) +{ + if (!IsValidKeyLength(length)) + throw InvalidKeyLength(algorithm.AlgorithmName(), length); +} + +void BlockTransformation::ProcessAndXorMultipleBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, unsigned int numberOfBlocks) const +{ + unsigned int blockSize = BlockSize(); + while (numberOfBlocks--) + { + ProcessAndXorBlock(inBlocks, xorBlocks, outBlocks); + inBlocks += blockSize; + outBlocks += blockSize; + if (xorBlocks) + xorBlocks += blockSize; + } +} + +void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inString, unsigned int length) +{ + assert(MinLastBlockSize() == 0); // this function should be overriden otherwise + + if (length == MandatoryBlockSize()) + ProcessData(outString, inString, length); + else if (length != 0) + throw NotImplemented("StreamTransformation: this object does't support a special last block"); +} + +unsigned int RandomNumberGenerator::GenerateBit() +{ + return Parity(GenerateByte()); +} + +void RandomNumberGenerator::GenerateBlock(byte *output, unsigned int size) +{ + while (size--) + *output++ = GenerateByte(); +} + +word32 RandomNumberGenerator::GenerateWord32(word32 min, word32 max) +{ + word32 range = max-min; + const int maxBytes = BytePrecision(range); + const int maxBits = BitPrecision(range); + + word32 value; + + do + { + value = 0; + for (int i=0; i<maxBytes; i++) + value = (value << 8) | GenerateByte(); + + value = Crop(value, maxBits); + } while (value > range); + + return value+min; +} + +void RandomNumberGenerator::DiscardBytes(unsigned int n) +{ + while (n--) + GenerateByte(); +} + +RandomNumberGenerator & NullRNG() +{ + class NullRNG : public RandomNumberGenerator + { + public: + std::string AlgorithmName() const {return "NullRNG";} + byte GenerateByte() {throw NotImplemented("NullRNG: NullRNG should only be passed to functions that don't need to generate random bytes");} + }; + + static NullRNG s_nullRNG; + return s_nullRNG; +} + +bool HashTransformation::TruncatedVerify(const byte *digestIn, unsigned int digestLength) +{ + ThrowIfInvalidTruncatedSize(digestLength); + SecByteBlock digest(digestLength); + TruncatedFinal(digest, digestLength); + return memcmp(digest, digestIn, digestLength) == 0; +} + +void HashTransformation::ThrowIfInvalidTruncatedSize(unsigned int size) const +{ + if (size > DigestSize()) + throw InvalidArgument("HashTransformation: can't truncate a " + IntToString(DigestSize()) + " byte digest to " + IntToString(size) + " bytes"); +} + +unsigned int BufferedTransformation::GetMaxWaitObjectCount() const +{ + const BufferedTransformation *t = AttachedTransformation(); + return t ? t->GetMaxWaitObjectCount() : 0; +} + +void BufferedTransformation::GetWaitObjects(WaitObjectContainer &container) +{ + BufferedTransformation *t = AttachedTransformation(); + if (t) + t->GetWaitObjects(container); +} + +void BufferedTransformation::Initialize(const NameValuePairs ¶meters, int propagation) +{ + assert(!AttachedTransformation()); + IsolatedInitialize(parameters); +} + +bool BufferedTransformation::Flush(bool hardFlush, int propagation, bool blocking) +{ + assert(!AttachedTransformation()); + return IsolatedFlush(hardFlush, blocking); +} + +bool BufferedTransformation::MessageSeriesEnd(int propagation, bool blocking) +{ + assert(!AttachedTransformation()); + return IsolatedMessageSeriesEnd(blocking); +} + +byte * BufferedTransformation::ChannelCreatePutSpace(const std::string &channel, unsigned int &size) +{ + if (channel.empty()) + return CreatePutSpace(size); + else + throw NoChannelSupport(); +} + +unsigned int BufferedTransformation::ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (channel.empty()) + return Put2(begin, length, messageEnd, blocking); + else + throw NoChannelSupport(); +} + +unsigned int BufferedTransformation::ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (channel.empty()) + return PutModifiable2(begin, length, messageEnd, blocking); + else + return ChannelPut2(channel, begin, length, messageEnd, blocking); +} + +void BufferedTransformation::ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters, int propagation) +{ + if (channel.empty()) + Initialize(parameters, propagation); + else + throw NoChannelSupport(); +} + +bool BufferedTransformation::ChannelFlush(const std::string &channel, bool completeFlush, int propagation, bool blocking) +{ + if (channel.empty()) + return Flush(completeFlush, propagation, blocking); + else + throw NoChannelSupport(); +} + +bool BufferedTransformation::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + if (channel.empty()) + return MessageSeriesEnd(propagation, blocking); + else + throw NoChannelSupport(); +} + +unsigned long BufferedTransformation::MaxRetrievable() const +{ + if (AttachedTransformation()) + return AttachedTransformation()->MaxRetrievable(); + else + return CopyTo(TheBitBucket()); +} + +bool BufferedTransformation::AnyRetrievable() const +{ + if (AttachedTransformation()) + return AttachedTransformation()->AnyRetrievable(); + else + { + byte b; + return Peek(b) != 0; + } +} + +unsigned int BufferedTransformation::Get(byte &outByte) +{ + if (AttachedTransformation()) + return AttachedTransformation()->Get(outByte); + else + return Get(&outByte, 1); +} + +unsigned int BufferedTransformation::Get(byte *outString, unsigned int getMax) +{ + if (AttachedTransformation()) + return AttachedTransformation()->Get(outString, getMax); + else + { + ArraySink arraySink(outString, getMax); + return TransferTo(arraySink, getMax); + } +} + +unsigned int BufferedTransformation::Peek(byte &outByte) const +{ + if (AttachedTransformation()) + return AttachedTransformation()->Peek(outByte); + else + return Peek(&outByte, 1); +} + +unsigned int BufferedTransformation::Peek(byte *outString, unsigned int peekMax) const +{ + if (AttachedTransformation()) + return AttachedTransformation()->Peek(outString, peekMax); + else + { + ArraySink arraySink(outString, peekMax); + return CopyTo(arraySink, peekMax); + } +} + +unsigned long BufferedTransformation::Skip(unsigned long skipMax) +{ + if (AttachedTransformation()) + return AttachedTransformation()->Skip(skipMax); + else + return TransferTo(TheBitBucket(), skipMax); +} + +unsigned long BufferedTransformation::TotalBytesRetrievable() const +{ + if (AttachedTransformation()) + return AttachedTransformation()->TotalBytesRetrievable(); + else + return MaxRetrievable(); +} + +unsigned int BufferedTransformation::NumberOfMessages() const +{ + if (AttachedTransformation()) + return AttachedTransformation()->NumberOfMessages(); + else + return CopyMessagesTo(TheBitBucket()); +} + +bool BufferedTransformation::AnyMessages() const +{ + if (AttachedTransformation()) + return AttachedTransformation()->AnyMessages(); + else + return NumberOfMessages() != 0; +} + +bool BufferedTransformation::GetNextMessage() +{ + if (AttachedTransformation()) + return AttachedTransformation()->GetNextMessage(); + else + { + assert(!AnyMessages()); + return false; + } +} + +unsigned int BufferedTransformation::SkipMessages(unsigned int count) +{ + if (AttachedTransformation()) + return AttachedTransformation()->SkipMessages(count); + else + return TransferMessagesTo(TheBitBucket(), count); +} + +unsigned int BufferedTransformation::TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel, bool blocking) +{ + if (AttachedTransformation()) + return AttachedTransformation()->TransferMessagesTo2(target, messageCount, channel, blocking); + else + { + unsigned int maxMessages = messageCount; + for (messageCount=0; messageCount < maxMessages && AnyMessages(); messageCount++) + { + unsigned int blockedBytes; + unsigned long transferedBytes; + + while (AnyRetrievable()) + { + transferedBytes = ULONG_MAX; + blockedBytes = TransferTo2(target, transferedBytes, channel, blocking); + if (blockedBytes > 0) + return blockedBytes; + } + + if (target.ChannelMessageEnd(channel, GetAutoSignalPropagation(), blocking)) + return 1; + + bool result = GetNextMessage(); + assert(result); + } + return 0; + } +} + +unsigned int BufferedTransformation::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + if (AttachedTransformation()) + return AttachedTransformation()->CopyMessagesTo(target, count, channel); + else + return 0; +} + +void BufferedTransformation::SkipAll() +{ + if (AttachedTransformation()) + AttachedTransformation()->SkipAll(); + else + { + while (SkipMessages()) {} + while (Skip()) {} + } +} + +unsigned int BufferedTransformation::TransferAllTo2(BufferedTransformation &target, const std::string &channel, bool blocking) +{ + if (AttachedTransformation()) + return AttachedTransformation()->TransferAllTo2(target, channel, blocking); + else + { + assert(!NumberOfMessageSeries()); + + unsigned int messageCount; + do + { + messageCount = UINT_MAX; + unsigned int blockedBytes = TransferMessagesTo2(target, messageCount, channel, blocking); + if (blockedBytes) + return blockedBytes; + } + while (messageCount != 0); + + unsigned long byteCount; + do + { + byteCount = ULONG_MAX; + unsigned int blockedBytes = TransferTo2(target, byteCount, channel, blocking); + if (blockedBytes) + return blockedBytes; + } + while (byteCount != 0); + + return 0; + } +} + +void BufferedTransformation::CopyAllTo(BufferedTransformation &target, const std::string &channel) const +{ + if (AttachedTransformation()) + AttachedTransformation()->CopyAllTo(target, channel); + else + { + assert(!NumberOfMessageSeries()); + while (CopyMessagesTo(target, UINT_MAX, channel)) {} + } +} + +void BufferedTransformation::SetRetrievalChannel(const std::string &channel) +{ + if (AttachedTransformation()) + AttachedTransformation()->SetRetrievalChannel(channel); +} + +unsigned int BufferedTransformation::ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order, bool blocking) +{ + FixedSizeSecBlock<byte, 2> buf; + PutWord(false, order, buf, value); + return ChannelPut(channel, buf, 2, blocking); +} + +unsigned int BufferedTransformation::ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order, bool blocking) +{ + FixedSizeSecBlock<byte, 4> buf; + PutWord(false, order, buf, value); + return ChannelPut(channel, buf, 4, blocking); +} + +unsigned int BufferedTransformation::PutWord16(word16 value, ByteOrder order, bool blocking) +{ + return ChannelPutWord16(NULL_CHANNEL, value, order, blocking); +} + +unsigned int BufferedTransformation::PutWord32(word32 value, ByteOrder order, bool blocking) +{ + return ChannelPutWord32(NULL_CHANNEL, value, order, blocking); +} + +unsigned int BufferedTransformation::PeekWord16(word16 &value, ByteOrder order) +{ + byte buf[2] = {0, 0}; + unsigned int len = Peek(buf, 2); + + if (order) + value = (buf[0] << 8) | buf[1]; + else + value = (buf[1] << 8) | buf[0]; + + return len; +} + +unsigned int BufferedTransformation::PeekWord32(word32 &value, ByteOrder order) +{ + byte buf[4] = {0, 0, 0, 0}; + unsigned int len = Peek(buf, 4); + + if (order) + value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf [3]; + else + value = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf [0]; + + return len; +} + +unsigned int BufferedTransformation::GetWord16(word16 &value, ByteOrder order) +{ + return Skip(PeekWord16(value, order)); +} + +unsigned int BufferedTransformation::GetWord32(word32 &value, ByteOrder order) +{ + return Skip(PeekWord32(value, order)); +} + +void BufferedTransformation::Attach(BufferedTransformation *newOut) +{ + if (AttachedTransformation() && AttachedTransformation()->Attachable()) + AttachedTransformation()->Attach(newOut); + else + Detach(newOut); +} + +void GeneratableCryptoMaterial::GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize) +{ + GenerateRandom(rng, MakeParameters("KeySize", (int)keySize)); +} + +BufferedTransformation * PK_Encryptor::CreateEncryptionFilter(RandomNumberGenerator &rng, BufferedTransformation *attachment) const +{ + struct EncryptionFilter : public Unflushable<FilterWithInputQueue> + { + // VC60 complains if this function is missing + EncryptionFilter(const EncryptionFilter &x) : Unflushable<FilterWithInputQueue>(NULL), m_rng(x.m_rng), m_encryptor(x.m_encryptor) {} + + EncryptionFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment) + : Unflushable<FilterWithInputQueue>(attachment), m_rng(rng), m_encryptor(encryptor) + { + } + + bool IsolatedMessageEnd(bool blocking) + { + switch (m_continueAt) + { + case 0: + { + unsigned int plaintextLength = m_inQueue.CurrentSize(); + m_ciphertextLength = m_encryptor.CiphertextLength(plaintextLength); + + SecByteBlock plaintext(plaintextLength); + m_inQueue.Get(plaintext, plaintextLength); + m_ciphertext.resize(m_ciphertextLength); + m_encryptor.Encrypt(m_rng, plaintext, plaintextLength, m_ciphertext); + } + + case 1: + if (!Output(1, m_ciphertext, m_ciphertextLength, 0, blocking)) + return false; + }; + return true; + } + + RandomNumberGenerator &m_rng; + const PK_Encryptor &m_encryptor; + unsigned int m_ciphertextLength; + SecByteBlock m_ciphertext; + }; + + return new EncryptionFilter(rng, *this, attachment); +} + +BufferedTransformation * PK_Decryptor::CreateDecryptionFilter(BufferedTransformation *attachment) const +{ + struct DecryptionFilter : public Unflushable<FilterWithInputQueue> + { + // VC60 complains if this function is missing + DecryptionFilter(const DecryptionFilter &x) : Unflushable<FilterWithInputQueue>(NULL), m_decryptor(x.m_decryptor) {} + + DecryptionFilter(const PK_Decryptor &decryptor, BufferedTransformation *attachment) + : Unflushable<FilterWithInputQueue>(attachment), m_decryptor(decryptor) + { + } + + bool IsolatedMessageEnd(bool blocking) + { + switch (m_continueAt) + { + case 0: + { + unsigned int ciphertextLength = m_inQueue.CurrentSize(); + unsigned int maxPlaintextLength = m_decryptor.MaxPlaintextLength(ciphertextLength); + + SecByteBlock ciphertext(ciphertextLength); + m_inQueue.Get(ciphertext, ciphertextLength); + m_plaintext.resize(maxPlaintextLength); + m_result = m_decryptor.Decrypt(ciphertext, ciphertextLength, m_plaintext); + if (!m_result.isValidCoding) + throw InvalidCiphertext(m_decryptor.AlgorithmName() + ": invalid ciphertext"); + } + + case 1: + if (!Output(1, m_plaintext, m_result.messageLength, 0, blocking)) + return false; + } + return true; + } + + const PK_Decryptor &m_decryptor; + SecByteBlock m_plaintext; + DecodingResult m_result; + }; + + return new DecryptionFilter(*this, attachment); +} + +unsigned int PK_FixedLengthCryptoSystem::MaxPlaintextLength(unsigned int cipherTextLength) const +{ + if (cipherTextLength == FixedCiphertextLength()) + return FixedMaxPlaintextLength(); + else + return 0; +} + +unsigned int PK_FixedLengthCryptoSystem::CiphertextLength(unsigned int plainTextLength) const +{ + if (plainTextLength <= FixedMaxPlaintextLength()) + return FixedCiphertextLength(); + else + return 0; +} + +DecodingResult PK_FixedLengthDecryptor::Decrypt(const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const +{ + if (cipherTextLength != FixedCiphertextLength()) + return DecodingResult(); + + return FixedLengthDecrypt(cipherText, plainText); +} + +void PK_Signer::Sign(RandomNumberGenerator &rng, HashTransformation *messageAccumulator, byte *signature) const +{ + std::auto_ptr<HashTransformation> m(messageAccumulator); + SignAndRestart(rng, *m, signature); +} + +void PK_Signer::SignMessage(RandomNumberGenerator &rng, const byte *message, unsigned int messageLen, byte *signature) const +{ + std::auto_ptr<HashTransformation> accumulator(NewSignatureAccumulator()); + accumulator->Update(message, messageLen); + SignAndRestart(rng, *accumulator, signature); +} + +bool PK_Verifier::Verify(HashTransformation *messageAccumulator, const byte *signature) const +{ + std::auto_ptr<HashTransformation> m(messageAccumulator); + return VerifyAndRestart(*m, signature); +} + +bool PK_Verifier::VerifyMessage(const byte *message, unsigned int messageLen, const byte *sig) const +{ + std::auto_ptr<HashTransformation> accumulator(NewVerificationAccumulator()); + accumulator->Update(message, messageLen); + return VerifyAndRestart(*accumulator, sig); +} + +void SimpleKeyAgreementDomain::GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GeneratePrivateKey(rng, privateKey); + GeneratePublicKey(rng, privateKey, publicKey); +} + +void AuthenticatedKeyAgreementDomain::GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GenerateStaticPrivateKey(rng, privateKey); + GenerateStaticPublicKey(rng, privateKey, publicKey); +} + +void AuthenticatedKeyAgreementDomain::GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GenerateEphemeralPrivateKey(rng, privateKey); + GenerateEphemeralPublicKey(rng, privateKey, publicKey); +} + +NAMESPACE_END diff --git a/cryptlib.dsp b/cryptlib.dsp new file mode 100644 index 0000000..c3eb412 --- /dev/null +++ b/cryptlib.dsp @@ -0,0 +1,1055 @@ +# Microsoft Developer Studio Project File - Name="cryptlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=cryptlib - Win32 FIPS 140 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cryptlib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cryptlib.mak" CFG="cryptlib - Win32 FIPS 140 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cryptlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "cryptlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "cryptlib - Win32 FIPS 140 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "cryptlib - Win32 FIPS 140 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/cryptlib", BAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cryptlib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "cryptlib" +# PROP BASE Intermediate_Dir "cryptlib" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release" +# PROP Intermediate_Dir "release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /GB /Gd /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /Yu"pch.h" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "cryptlib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "cryptli0" +# PROP BASE Intermediate_Dir "cryptli0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug" +# PROP Intermediate_Dir "debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /Yu"pch.h" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "cryptlib - Win32 FIPS 140 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "cryptlib___Win32_FIPS_140_Release" +# PROP BASE Intermediate_Dir "cryptlib___Win32_FIPS_140_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "FIPS_140_Release" +# PROP Intermediate_Dir "FIPS_140_Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /Gz /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /Yu"pch.h" /FD /c +# ADD CPP /nologo /G5 /Gz /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /D "WIN32" /D CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2=1 /Yu"pch.h" /Fd"FIPS_140_Release/cryptopp" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"FIPS_140_Release\cryptopp.lib" + +!ELSEIF "$(CFG)" == "cryptlib - Win32 FIPS 140 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "cryptlib___Win32_FIPS_140_Debug" +# PROP BASE Intermediate_Dir "cryptlib___Win32_FIPS_140_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "FIPS_140_Debug" +# PROP Intermediate_Dir "FIPS_140_Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /Yu"pch.h" /FD /c +# ADD CPP /nologo /G5 /Gz /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /D "WIN32" /D CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2=1 /Yu"pch.h" /Fd"FIPS_140_Debug/cryptopp" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"FIPS_140_Debug\cryptopp.lib" + +!ENDIF + +# Begin Target + +# Name "cryptlib - Win32 Release" +# Name "cryptlib - Win32 Debug" +# Name "cryptlib - Win32 FIPS 140 Release" +# Name "cryptlib - Win32 FIPS 140 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter ".cpp" +# Begin Source File + +SOURCE=.\3way.cpp +# End Source File +# Begin Source File + +SOURCE=.\adler32.cpp +# End Source File +# Begin Source File + +SOURCE=.\algebra.cpp +# End Source File +# Begin Source File + +SOURCE=.\algparam.cpp +# End Source File +# Begin Source File + +SOURCE=.\arc4.cpp +# End Source File +# Begin Source File + +SOURCE=.\asn.cpp +# End Source File +# Begin Source File + +SOURCE=.\base64.cpp +# End Source File +# Begin Source File + +SOURCE=.\basecode.cpp +# End Source File +# Begin Source File + +SOURCE=.\bfinit.cpp +# End Source File +# Begin Source File + +SOURCE=.\blowfish.cpp +# End Source File +# Begin Source File + +SOURCE=.\blumshub.cpp +# End Source File +# Begin Source File + +SOURCE=.\cast.cpp +# End Source File +# Begin Source File + +SOURCE=.\casts.cpp +# End Source File +# Begin Source File + +SOURCE=.\channels.cpp +# End Source File +# Begin Source File + +SOURCE=.\crc.cpp +# End Source File +# Begin Source File + +SOURCE=.\cryptlib.cpp +# End Source File +# Begin Source File + +SOURCE=.\default.cpp +# End Source File +# Begin Source File + +SOURCE=.\des.cpp +# End Source File +# Begin Source File + +SOURCE=.\dessp.cpp +# End Source File +# Begin Source File + +SOURCE=.\dh.cpp +# End Source File +# Begin Source File + +SOURCE=.\dh2.cpp +# End Source File +# Begin Source File + +SOURCE=.\diamond.cpp +# End Source File +# Begin Source File + +SOURCE=.\diamondt.cpp +# End Source File +# Begin Source File + +SOURCE=.\dsa.cpp +# End Source File +# Begin Source File + +SOURCE=.\ec2n.cpp +# End Source File +# Begin Source File + +SOURCE=.\eccrypto.cpp +# End Source File +# Begin Source File + +SOURCE=.\ecp.cpp +# End Source File +# Begin Source File + +SOURCE=.\elgamal.cpp +# End Source File +# Begin Source File + +SOURCE=.\eprecomp.cpp +# End Source File +# Begin Source File + +SOURCE=.\esign.cpp +# End Source File +# Begin Source File + +SOURCE=.\files.cpp +# End Source File +# Begin Source File + +SOURCE=.\filters.cpp +# End Source File +# Begin Source File + +SOURCE=.\fips140.cpp +# End Source File +# Begin Source File + +SOURCE=.\fipstest.cpp +# End Source File +# Begin Source File + +SOURCE=.\gf256.cpp +# End Source File +# Begin Source File + +SOURCE=.\gf2_32.cpp +# End Source File +# Begin Source File + +SOURCE=.\gf2n.cpp +# End Source File +# Begin Source File + +SOURCE=.\gfpcrypt.cpp +# End Source File +# Begin Source File + +SOURCE=.\gost.cpp +# End Source File +# Begin Source File + +SOURCE=.\gzip.cpp +# End Source File +# Begin Source File + +SOURCE=.\haval.cpp +# End Source File +# Begin Source File + +SOURCE=.\hex.cpp +# End Source File +# Begin Source File + +SOURCE=.\hrtimer.cpp +# End Source File +# Begin Source File + +SOURCE=.\ida.cpp +# End Source File +# Begin Source File + +SOURCE=.\idea.cpp +# End Source File +# Begin Source File + +SOURCE=.\integer.cpp +# End Source File +# Begin Source File + +SOURCE=.\iterhash.cpp +# End Source File +# Begin Source File + +SOURCE=.\luc.cpp +# End Source File +# Begin Source File + +SOURCE=.\mars.cpp +# End Source File +# Begin Source File + +SOURCE=.\marss.cpp +# End Source File +# Begin Source File + +SOURCE=.\md2.cpp +# End Source File +# Begin Source File + +SOURCE=.\md4.cpp +# End Source File +# Begin Source File + +SOURCE=.\md5.cpp +# End Source File +# Begin Source File + +SOURCE=.\md5mac.cpp +# End Source File +# Begin Source File + +SOURCE=.\misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\modes.cpp +# End Source File +# Begin Source File + +SOURCE=.\modexppc.cpp +# End Source File +# Begin Source File + +SOURCE=.\mqueue.cpp +# End Source File +# Begin Source File + +SOURCE=.\mqv.cpp +# End Source File +# Begin Source File + +SOURCE=.\nbtheory.cpp +# End Source File +# Begin Source File + +SOURCE=.\network.cpp +# End Source File +# Begin Source File + +SOURCE=.\oaep.cpp +# End Source File +# Begin Source File + +SOURCE=.\osrng.cpp +# End Source File +# Begin Source File + +SOURCE=.\panama.cpp +# End Source File +# Begin Source File + +SOURCE=.\pch.cpp +# ADD CPP /Yc"pch.h" +# End Source File +# Begin Source File + +SOURCE=.\pkcspad.cpp +# End Source File +# Begin Source File + +SOURCE=.\polynomi.cpp +# End Source File +# Begin Source File + +SOURCE=.\pubkey.cpp +# End Source File +# Begin Source File + +SOURCE=.\queue.cpp +# End Source File +# Begin Source File + +SOURCE=.\rabin.cpp +# End Source File +# Begin Source File + +SOURCE=.\randpool.cpp +# End Source File +# Begin Source File + +SOURCE=.\rc2.cpp +# End Source File +# Begin Source File + +SOURCE=.\rc5.cpp +# End Source File +# Begin Source File + +SOURCE=.\rc6.cpp +# End Source File +# Begin Source File + +SOURCE=.\rdtables.cpp +# End Source File +# Begin Source File + +SOURCE=.\rijndael.cpp +# End Source File +# Begin Source File + +SOURCE=.\ripemd.cpp +# End Source File +# Begin Source File + +SOURCE=.\rng.cpp +# End Source File +# Begin Source File + +SOURCE=.\rsa.cpp +# End Source File +# Begin Source File + +SOURCE=.\rw.cpp +# End Source File +# Begin Source File + +SOURCE=.\safer.cpp +# End Source File +# Begin Source File + +SOURCE=.\sapphire.cpp +# End Source File +# Begin Source File + +SOURCE=.\seal.cpp +# End Source File +# Begin Source File + +SOURCE=.\serpent.cpp +# End Source File +# Begin Source File + +SOURCE=.\sha.cpp +# End Source File +# Begin Source File + +SOURCE=.\shark.cpp +# End Source File +# Begin Source File + +SOURCE=.\sharkbox.cpp +# End Source File +# Begin Source File + +SOURCE=.\simple.cpp +# End Source File +# Begin Source File + +SOURCE=.\skipjack.cpp +# End Source File +# Begin Source File + +SOURCE=.\socketft.cpp +# End Source File +# Begin Source File + +SOURCE=.\square.cpp +# End Source File +# Begin Source File + +SOURCE=.\squaretb.cpp +# End Source File +# Begin Source File + +SOURCE=.\strciphr.cpp +# End Source File +# Begin Source File + +SOURCE=.\tea.cpp +# End Source File +# Begin Source File + +SOURCE=.\tftables.cpp +# End Source File +# Begin Source File + +SOURCE=.\tiger.cpp +# End Source File +# Begin Source File + +SOURCE=.\tigertab.cpp +# End Source File +# Begin Source File + +SOURCE=.\trdlocal.cpp +# End Source File +# Begin Source File + +SOURCE=.\twofish.cpp +# End Source File +# Begin Source File + +SOURCE=.\wait.cpp +# End Source File +# Begin Source File + +SOURCE=.\wake.cpp +# End Source File +# Begin Source File + +SOURCE=.\winpipes.cpp +# End Source File +# Begin Source File + +SOURCE=.\xtr.cpp +# End Source File +# Begin Source File + +SOURCE=.\xtrcrypt.cpp +# End Source File +# Begin Source File + +SOURCE=.\zdeflate.cpp +# End Source File +# Begin Source File + +SOURCE=.\zinflate.cpp +# End Source File +# Begin Source File + +SOURCE=.\zlib.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".;.h" +# Begin Source File + +SOURCE=.\3way.h +# End Source File +# Begin Source File + +SOURCE=.\adler32.h +# End Source File +# Begin Source File + +SOURCE=.\aes.h +# End Source File +# Begin Source File + +SOURCE=.\algebra.h +# End Source File +# Begin Source File + +SOURCE=.\algparam.h +# End Source File +# Begin Source File + +SOURCE=.\arc4.h +# End Source File +# Begin Source File + +SOURCE=.\argnames.h +# End Source File +# Begin Source File + +SOURCE=.\asn.h +# End Source File +# Begin Source File + +SOURCE=.\base64.h +# End Source File +# Begin Source File + +SOURCE=.\basecode.h +# End Source File +# Begin Source File + +SOURCE=.\blowfish.h +# End Source File +# Begin Source File + +SOURCE=.\blumshub.h +# End Source File +# Begin Source File + +SOURCE=.\cast.h +# End Source File +# Begin Source File + +SOURCE=.\cbcmac.h +# End Source File +# Begin Source File + +SOURCE=.\channels.h +# End Source File +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=.\crc.h +# End Source File +# Begin Source File + +SOURCE=.\cryptlib.h +# End Source File +# Begin Source File + +SOURCE=.\default.h +# End Source File +# Begin Source File + +SOURCE=.\des.h +# End Source File +# Begin Source File + +SOURCE=.\dh.h +# End Source File +# Begin Source File + +SOURCE=.\dh2.h +# End Source File +# Begin Source File + +SOURCE=.\diamond.h +# End Source File +# Begin Source File + +SOURCE=.\dmac.h +# End Source File +# Begin Source File + +SOURCE=.\dsa.h +# End Source File +# Begin Source File + +SOURCE=.\ec2n.h +# End Source File +# Begin Source File + +SOURCE=.\eccrypto.h +# End Source File +# Begin Source File + +SOURCE=.\ecp.h +# End Source File +# Begin Source File + +SOURCE=.\elgamal.h +# End Source File +# Begin Source File + +SOURCE=.\eprecomp.h +# End Source File +# Begin Source File + +SOURCE=.\esign.h +# End Source File +# Begin Source File + +SOURCE=.\files.h +# End Source File +# Begin Source File + +SOURCE=.\filters.h +# End Source File +# Begin Source File + +SOURCE=.\fips140.h +# End Source File +# Begin Source File + +SOURCE=.\fltrimpl.h +# End Source File +# Begin Source File + +SOURCE=.\gf256.h +# End Source File +# Begin Source File + +SOURCE=.\gf2_32.h +# End Source File +# Begin Source File + +SOURCE=.\gf2n.h +# End Source File +# Begin Source File + +SOURCE=.\gfpcrypt.h +# End Source File +# Begin Source File + +SOURCE=.\gost.h +# End Source File +# Begin Source File + +SOURCE=.\gzip.h +# End Source File +# Begin Source File + +SOURCE=.\haval.h +# End Source File +# Begin Source File + +SOURCE=.\hex.h +# End Source File +# Begin Source File + +SOURCE=.\hmac.h +# End Source File +# Begin Source File + +SOURCE=.\hrtimer.h +# End Source File +# Begin Source File + +SOURCE=.\ida.h +# End Source File +# Begin Source File + +SOURCE=.\idea.h +# End Source File +# Begin Source File + +SOURCE=.\integer.h +# End Source File +# Begin Source File + +SOURCE=.\iterhash.h +# End Source File +# Begin Source File + +SOURCE=.\lubyrack.h +# End Source File +# Begin Source File + +SOURCE=.\luc.h +# End Source File +# Begin Source File + +SOURCE=.\mars.h +# End Source File +# Begin Source File + +SOURCE=.\md2.h +# End Source File +# Begin Source File + +SOURCE=.\md4.h +# End Source File +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# Begin Source File + +SOURCE=.\md5mac.h +# End Source File +# Begin Source File + +SOURCE=.\mdc.h +# End Source File +# Begin Source File + +SOURCE=.\misc.h +# End Source File +# Begin Source File + +SOURCE=.\modarith.h +# End Source File +# Begin Source File + +SOURCE=.\modes.h +# End Source File +# Begin Source File + +SOURCE=.\modexppc.h +# End Source File +# Begin Source File + +SOURCE=.\mqueue.h +# End Source File +# Begin Source File + +SOURCE=.\mqv.h +# End Source File +# Begin Source File + +SOURCE=.\nbtheory.h +# End Source File +# Begin Source File + +SOURCE=.\network.h +# End Source File +# Begin Source File + +SOURCE=.\nr.h +# End Source File +# Begin Source File + +SOURCE=.\oaep.h +# End Source File +# Begin Source File + +SOURCE=.\oids.h +# End Source File +# Begin Source File + +SOURCE=.\osrng.h +# End Source File +# Begin Source File + +SOURCE=.\panama.h +# End Source File +# Begin Source File + +SOURCE=.\pch.h +# End Source File +# Begin Source File + +SOURCE=.\pkcspad.h +# End Source File +# Begin Source File + +SOURCE=.\polynomi.h +# End Source File +# Begin Source File + +SOURCE=.\pssr.h +# End Source File +# Begin Source File + +SOURCE=.\pubkey.h +# End Source File +# Begin Source File + +SOURCE=.\pwdbased.h +# End Source File +# Begin Source File + +SOURCE=.\queue.h +# End Source File +# Begin Source File + +SOURCE=.\rabin.h +# End Source File +# Begin Source File + +SOURCE=.\randpool.h +# End Source File +# Begin Source File + +SOURCE=.\rc2.h +# End Source File +# Begin Source File + +SOURCE=.\rc5.h +# End Source File +# Begin Source File + +SOURCE=.\rc6.h +# End Source File +# Begin Source File + +SOURCE=.\rijndael.h +# End Source File +# Begin Source File + +SOURCE=.\ripemd.h +# End Source File +# Begin Source File + +SOURCE=.\rng.h +# End Source File +# Begin Source File + +SOURCE=.\rsa.h +# End Source File +# Begin Source File + +SOURCE=.\rw.h +# End Source File +# Begin Source File + +SOURCE=.\safer.h +# End Source File +# Begin Source File + +SOURCE=.\sapphire.h +# End Source File +# Begin Source File + +SOURCE=.\seal.h +# End Source File +# Begin Source File + +SOURCE=.\secblock.h +# End Source File +# Begin Source File + +SOURCE=.\seckey.h +# End Source File +# Begin Source File + +SOURCE=.\serpent.h +# End Source File +# Begin Source File + +SOURCE=.\sha.h +# End Source File +# Begin Source File + +SOURCE=.\shark.h +# End Source File +# Begin Source File + +SOURCE=.\simple.h +# End Source File +# Begin Source File + +SOURCE=.\skipjack.h +# End Source File +# Begin Source File + +SOURCE=.\smartptr.h +# End Source File +# Begin Source File + +SOURCE=.\socketft.h +# End Source File +# Begin Source File + +SOURCE=.\square.h +# End Source File +# Begin Source File + +SOURCE=.\strciphr.h +# End Source File +# Begin Source File + +SOURCE=.\tea.h +# End Source File +# Begin Source File + +SOURCE=.\tiger.h +# End Source File +# Begin Source File + +SOURCE=.\trdlocal.h +# End Source File +# Begin Source File + +SOURCE=.\trunhash.h +# End Source File +# Begin Source File + +SOURCE=.\twofish.h +# End Source File +# Begin Source File + +SOURCE=.\wait.h +# End Source File +# Begin Source File + +SOURCE=.\wake.h +# End Source File +# Begin Source File + +SOURCE=.\winpipes.h +# End Source File +# Begin Source File + +SOURCE=.\words.h +# End Source File +# Begin Source File + +SOURCE=.\xormac.h +# End Source File +# Begin Source File + +SOURCE=.\xtr.h +# End Source File +# Begin Source File + +SOURCE=.\xtrcrypt.h +# End Source File +# Begin Source File + +SOURCE=.\zdeflate.h +# End Source File +# Begin Source File + +SOURCE=.\zinflate.h +# End Source File +# Begin Source File + +SOURCE=.\zlib.h +# End Source File +# End Group +# Begin Group "Miscellaneous" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Doxyfile +# End Source File +# Begin Source File + +SOURCE=.\GNUmakefile +# End Source File +# Begin Source File + +SOURCE=.\license.txt +# End Source File +# Begin Source File + +SOURCE=.\readme.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/cryptlib.h b/cryptlib.h new file mode 100644 index 0000000..9be8849 --- /dev/null +++ b/cryptlib.h @@ -0,0 +1,1571 @@ +// cryptlib.h - written and placed in the public domain by Wei Dai +/*! \file + This file contains the declarations for the abstract base + classes that provide a uniform interface to this library. +*/ + +/*! \mainpage <a href="http://www.cryptopp.com">Crypto++</a><sup><small>TM</small></sup> Library 5.0 Reference Manual +<dl> +<dt>Abstract Base Classes<dd> + cryptlib.h +<dt>Symmetric Ciphers<dd> + SymmetricCipherDocumentation +<dt>Hash Functions<dd> + HAVAL, MD2, MD4, MD5, PanamaHash, RIPEMD160, SHA, SHA256, SHA384, SHA512, Tiger +<dt>Non-Cryptographic Checksums<dd> + CRC32, Adler32 +<dt>Message Authentication Codes<dd> + #MD5MAC, XMACC, HMAC, CBC_MAC, DMAC, PanamaMAC +<dt>Random Number Generators<dd> + NullRNG(), LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG +<dt>Public Key Cryptosystems<dd> + DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES +<dt>Public Key Signature Schemes<dd> + DSA, GDSA, ECDSA, NR, ECNR, LUCSSA, RSASSA, RabinSSR, RWSSA, ESIGN +<dt>Key Agreement<dd> + #DH, DH2, #MQV, ECDH, ECMQV, XTR_DH +<dt>Algebraic Structures<dd> + Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, + ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, + GF2NP, GF256, GF2_32, EC2N, ECP +<dt>Secret Sharing and Information Dispersal<dd> + SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery +<dt>Compression<dd> + Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor +<dt>Input Source Classes<dd> + StringSource, FileSource, SocketSource, WindowsPipeSource, RandomNumberSource +<dt>Output Sink Classes<dd> + StringSinkTemplate, ArraySink, FileSink, SocketSink, WindowsPipeSink +<dt>Filter Wrappers<dd> + StreamTransformationFilter, HashFilter, HashVerificationFilter, SignerFilter, SignatureVerificationFilter +<dt>Binary to Text Encoders and Decoders<dd> + HexEncoder, HexDecoder, Base64Encoder, Base64Decoder +<dt>Wrappers for OS features<dd> + Timer, Socket, WindowsHandle, ThreadLocalStorage +<dt>FIPS 140 related<dd> + fips140.h +</dl> + +<p>This reference manual is a work in progress. Some classes are still lacking detailed descriptions. +<p>Click <a href="CryptoPPRef.zip">here</a> to download a zip archive containing this manual. +<p>Thanks to Ryan Phillips for providing the Doxygen configuration file +and getting me started with this manual. +*/ + +#ifndef CRYPTOPP_CRYPTLIB_H +#define CRYPTOPP_CRYPTLIB_H + +#include "config.h" +#include <limits.h> +#include <exception> +#include <string> +#include <typeinfo> +#include <assert.h> + +NAMESPACE_BEGIN(CryptoPP) + +// forward declarations +class Integer; + +//! used to specify a direction for a cipher to operate in (encrypt or decrypt) +enum CipherDir {ENCRYPTION, DECRYPTION}; + +//! used to represent infinite time +const unsigned long INFINITE_TIME = ULONG_MAX; + +// VC60 workaround: using enums as template parameters causes problems +template <typename ENUM_TYPE, int VALUE> +struct EnumToType +{ + static ENUM_TYPE ToEnum() {return (ENUM_TYPE)VALUE;} +}; + +enum ByteOrder {LITTLE_ENDIAN_ORDER = 0, BIG_ENDIAN_ORDER = 1}; +typedef EnumToType<ByteOrder, LITTLE_ENDIAN_ORDER> LittleEndian; +typedef EnumToType<ByteOrder, BIG_ENDIAN_ORDER> BigEndian; + +//! base class for all exceptions thrown by Crypto++ +class Exception : public std::exception +{ +public: + //! error types + enum ErrorType { + //! a method is not implemented + NOT_IMPLEMENTED, + //! invalid function argument + INVALID_ARGUMENT, + //! BufferedTransformation received a Flush(true) signal but can't flush buffers + CANNOT_FLUSH, + //! data integerity check (such as CRC or MAC) failed + DATA_INTEGRITY_CHECK_FAILED, + //! received input data that doesn't conform to expected format + INVALID_DATA_FORMAT, + //! error reading from input device or writing to output device + IO_ERROR, + //! some error not belong to any of the above categories + OTHER_ERROR + }; + + explicit Exception(ErrorType errorType, const std::string &s) : m_what(s) {} + virtual ~Exception() throw() {} + const char *what() const throw() {return (m_what.c_str());} + const std::string &GetWhat() const {return m_what;} + void SetWhat(const std::string &s) {m_what = s;} + ErrorType GetErrorType() const {return m_errorType;} + void SetErrorType(ErrorType errorType) {m_errorType = errorType;} + +private: + ErrorType m_errorType; + std::string m_what; +}; + +//! exception thrown when an invalid argument is detected +class InvalidArgument : public Exception +{ +public: + explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} +}; + +//! exception thrown by decryption filters when trying to decrypt an invalid ciphertext +class InvalidDataFormat : public Exception +{ +public: + explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {} +}; + +//! exception thrown by decryption filters when trying to decrypt an invalid ciphertext +class InvalidCiphertext : public InvalidDataFormat +{ +public: + explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {} +}; + +//! exception thrown by a class if a non-implemented method is called +class NotImplemented : public Exception +{ +public: + explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {} +}; + +//! exception thrown by a class when Flush(true) is called but it can't completely flush its buffers +class CannotFlush : public Exception +{ +public: + explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {} +}; + +//! error reported by the operating system +class OS_Error : public Exception +{ +public: + OS_Error(ErrorType errorType, const std::string s, const std::string& operation, int errorCode) + : Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {} + ~OS_Error() throw() {} + + // the operating system API that reported the error + const std::string & GetOperation() const {return m_operation;} + // the error code return by the operating system + int GetErrorCode() const {return m_errorCode;} + +protected: + std::string m_operation; + int m_errorCode; +}; + +//! used to return decoding results +struct DecodingResult +{ + explicit DecodingResult() : isValidCoding(false), messageLength(0) {} + explicit DecodingResult(unsigned int len) : isValidCoding(true), messageLength(len) {} + + bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;} + bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);} + + bool isValidCoding; + unsigned int messageLength; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + operator unsigned int() const {return isValidCoding ? messageLength : 0;} +#endif +}; + +//! interface for retrieving values given their names +/*! This class is used to safely pass a variable number of arbitrarily typed arguments to functions + and to read values from keys and crypto parameters. + To get a value, you need to know the name and the type of the value. + Call GetValueNames() on a NameValuePairs object to obtain a list of value names that it supports. + Then look at the Name namespace documentation to see what the type of each value is, or + alternatively, call GetIntValue() with the value name, and if the type is not int, a + ValueTypeMismatch exception will be thrown and you can get the actual type from the exception object. +*/ +class NameValuePairs +{ +public: + virtual ~NameValuePairs() {} + + //! exception thrown when trying to retrieve a value using a different type than expected + class ValueTypeMismatch : public InvalidArgument + { + public: + ValueTypeMismatch(std::string name, const std::type_info &stored, const std::type_info &retrieving) + : InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'") + , m_stored(stored), m_retrieving(retrieving) {} + + const std::type_info & GetStoredTypeInfo() const {return m_stored;} + const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;} + + private: + const std::type_info &m_stored; + const std::type_info &m_retrieving; + }; + + //! get a copy of this object or a subobject of it + template <class T> + bool GetThisObject(T &object) const + { + return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object); + } + + //! get a pointer to this object, as a pointer to T + template <class T> + bool GetThisPointer(T *&p) const + { + return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), p); + } + + //! get a named value, returns true if the name exists + template <class T> + bool GetValue(const char *name, T &value) const + { + return GetVoidValue(name, typeid(T), &value); + } + + //! get a named value, returns the default if the name doesn't exist + template <class T> + T GetValueWithDefault(const char *name, T defaultValue) const + { + GetValue(name, defaultValue); + return defaultValue; + } + + //! get a list of value names that can be retrieved + std::string GetValueNames() const + {std::string result; GetValue("ValueNames", result); return result;} + + //! get a named value with type int + /*! used to ensure we don't accidentally try to get an unsigned int + or some other type when we mean int (which is the most common case) */ + bool GetIntValue(const char *name, int &value) const + {return GetValue(name, value);} + + //! get a named value with type int, with default + int GetIntValueWithDefault(const char *name, int defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + //! used by derived classes to check for type mismatch + static void ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving) + {if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);} + + template <class T> + void GetRequiredParameter(const char *className, const char *name, T &value) const + { + if (!GetValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + void GetRequiredIntParameter(const char *className, const char *name, int &value) const + { + if (!GetIntValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + //! to be implemented by derived classes, users should use one of the above functions instead + virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0; +}; + +//! namespace containing value name definitions +/*! value names, types and semantics: + + ThisObject:ClassName (ClassName, copy of this object or a subobject) + ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject) +*/ +DOCUMENTED_NAMESPACE_BEGIN(Name) +// more names defined in argnames.h +DOCUMENTED_NAMESPACE_END + +//! . +class NullNameValuePairs : public NameValuePairs +{ +public: + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const {return false;} +}; + +//! . +extern const NullNameValuePairs g_nullNameValuePairs; + +// ******************************************************** + +//! interface for cloning objects, this is not implemented by most classes yet +class Clonable +{ +public: + virtual ~Clonable() {} + //! this is not implemented by most classes yet + virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");} // TODO: make this =0 +}; + +//! interface for all crypto algorithms + +class Algorithm : public Clonable +{ +public: + /*! When FIPS-140-2 compliance is enabled and checkSelfTestStatus == true, + this constructor throws SelfTestFailure if the self test hasn't been run or fails. */ + Algorithm(bool checkSelfTestStatus = true); + //! returns name of this algorithm, not universally implemented yet + virtual std::string AlgorithmName() const {return "unknown";} +}; + +//! keying interface for crypto algorithms that take byte strings as keys + +class SimpleKeyingInterface +{ +public: + //! returns smallest valid key length in bytes */ + virtual unsigned int MinKeyLength() const =0; + //! returns largest valid key length in bytes */ + virtual unsigned int MaxKeyLength() const =0; + //! returns default (recommended) key length in bytes */ + virtual unsigned int DefaultKeyLength() const =0; + + //! returns the smallest valid key length in bytes that is >= min(n, GetMaxKeyLength()) + virtual unsigned int GetValidKeyLength(unsigned int n) const =0; + + //! returns whether n is a valid key length + virtual bool IsValidKeyLength(unsigned int n) const + {return n == GetValidKeyLength(n);} + + //! set or reset the key of this object + /*! \param params is used to specify Rounds, BlockSize, etc */ + virtual void SetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms = g_nullNameValuePairs) =0; + + //! calls SetKey() with an NameValuePairs object that just specifies "Rounds" + void SetKeyWithRounds(const byte *key, unsigned int length, int rounds); + + //! calls SetKey() with an NameValuePairs object that just specifies "IV" + void SetKeyWithIV(const byte *key, unsigned int length, const byte *iv); + + enum IV_Requirement {STRUCTURED_IV = 0, RANDOM_IV, UNPREDICTABLE_RANDOM_IV, INTERNALLY_GENERATED_IV, NOT_RESYNCHRONIZABLE}; + //! returns the minimal requirement for secure IVs + virtual IV_Requirement IVRequirement() const =0; + + //! returns whether this object can be resynchronized (i.e. supports initialization vectors) + /*! If this function returns true, and no IV is passed to SetKey() and CanUseStructuredIVs()==true, an IV of all 0's will be assumed. */ + bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;} + //! returns whether this object can use random IVs (in addition to ones returned by GetNextIV) + bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;} + //! returns whether this object can use random but possibly predictable IVs (in addition to ones returned by GetNextIV) + bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;} + //! returns whether this object can use structured IVs, for example a counter (in addition to ones returned by GetNextIV) + bool CanUseStructuredIVs() const {return IVRequirement() <= STRUCTURED_IV;} + + //! returns size of IVs used by this object + virtual unsigned int IVSize() const {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + //! resynchronize with an IV + virtual void Resynchronize(const byte *IV) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + //! get a secure IV for the next message + /*! This method should be called after you finish encrypting one message and are ready to start the next one. + After calling it, you must call SetKey() or Resynchronize() before using this object again. + This method is not implemented on decryption objects. */ + virtual void GetNextIV(byte *IV) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support GetNextIV()");} + +protected: + void ThrowIfInvalidKeyLength(const Algorithm &algorithm, unsigned int length); + + inline void AssertValidKeyLength(unsigned int length) const + { + assert(IsValidKeyLength(length)); + } +}; + +//! interface for the data processing part of block ciphers + +/*! Classes derived from BlockTransformation are block ciphers + in ECB mode (for example the DES::Encryption class), which are stateless, + and they can make assumptions about the memory alignment of their inputs and outputs. + These classes should not be used directly, but only in combination with + a mode class (see CipherModeDocumentation in modes.h). +*/ +class BlockTransformation : public Algorithm +{ +public: + //! encrypt or decrypt inBlock, xor with xorBlock, and write to outBlock + virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0; + + //! encrypt or decrypt one block + /*! \pre size of inBlock and outBlock == BlockSize() */ + void ProcessBlock(const byte *inBlock, byte *outBlock) const + {ProcessAndXorBlock(inBlock, NULL, outBlock);} + + //! encrypt or decrypt one block in place + void ProcessBlock(byte *inoutBlock) const + {ProcessAndXorBlock(inoutBlock, NULL, inoutBlock);} + + //! block size of the cipher in bytes + virtual unsigned int BlockSize() const =0; + + //! block pointers must be divisible by this + virtual unsigned int BlockAlignment() const {return 4;} + + //! returns true if this is a permutation (i.e. there is an inverse transformation) + virtual bool IsPermutation() const {return true;} + + //! returns true if this is an encryption object + virtual bool IsForwardTransformation() const =0; + + //! return number of blocks that can be processed in parallel, for bit-slicing implementations + virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;} + + //! encrypt or decrypt multiple blocks, for bit-slicing implementations + virtual void ProcessAndXorMultipleBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, unsigned int numberOfBlocks) const; +}; + +//! interface for the data processing part of stream ciphers + +class StreamTransformation : public Algorithm +{ +public: + //! return a reference to this object, + /*! This function is useful for passing a temporary StreamTransformation object to a + function that takes a non-const reference. */ + StreamTransformation& Ref() {return *this;} + + //! returns block size, if input must be processed in blocks, otherwise 1 + virtual unsigned int MandatoryBlockSize() const {return 1;} + + //! returns the input block size that is most efficient for this cipher + /*! \note optimal input length is n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n > 0 */ + virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();} + //! returns how much of the current block is used up + virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;} + + //! returns how input should be aligned for optimal performance + virtual unsigned int OptimalDataAlignment() const {return 1;} + + //! encrypt or decrypt an array of bytes of specified length + /*! \note either inString == outString, or they don't overlap */ + virtual void ProcessData(byte *outString, const byte *inString, unsigned int length) =0; + + //! for ciphers where the last block of data is special, encrypt or decrypt the last block of data + /*! For now the only use of this function is for CBC-CTS mode. */ + virtual void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length); + //! returns the minimum size of the last block, 0 indicating the last block is not special + virtual unsigned int MinLastBlockSize() const {return 0;} + + //! same as ProcessData(inoutString, inoutString, length) + inline void ProcessString(byte *inoutString, unsigned int length) + {ProcessData(inoutString, inoutString, length);} + //! same as ProcessData(outString, inString, length) + inline void ProcessString(byte *outString, const byte *inString, unsigned int length) + {ProcessData(outString, inString, length);} + //! implemented as {ProcessData(&input, &input, 1); return input;} + inline byte ProcessByte(byte input) + {ProcessData(&input, &input, 1); return input;} + + //! returns whether this cipher supports random access + virtual bool IsRandomAccess() const =0; + //! for random access ciphers, seek to an absolute position + virtual void Seek(dword n) + { + assert(!IsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access"); + } + + //! returns whether this transformation is self-inverting (e.g. xor with a keystream) + virtual bool IsSelfInverting() const =0; + //! returns whether this is an encryption object + virtual bool IsForwardTransformation() const =0; +}; + +//! interface for hash functions and data processing part of MACs + +/*! HashTransformation objects are stateful. They are created in an initial state, + change state as Update() is called, and return to the initial + state when Final() is called. This interface allows a large message to + be hashed in pieces by calling Update() on each piece followed by + calling Final(). +*/ +class HashTransformation : public Algorithm +{ +public: + //! process more input + virtual void Update(const byte *input, unsigned int length) =0; + + //! request space to write input into + virtual byte * CreateUpdateSpace(unsigned int &size) {size=0; return NULL;} + + //! compute hash for current message, then restart for a new message + /*! \pre size of digest == DigestSize(). */ + virtual void Final(byte *digest) + {TruncatedFinal(digest, DigestSize());} + + //! discard the current state, and restart with a new message + virtual void Restart() + {TruncatedFinal(NULL, 0);} + + //! size of the hash returned by Final() + virtual unsigned int DigestSize() const =0; + + //! input to Update() should have length a multiple of this for optimal speed + virtual unsigned int OptimalBlockSize() const {return 1;} + + //! use this if your input is in one piece and you don't want to call Update() and Final() separately + virtual void CalculateDigest(byte *digest, const byte *input, unsigned int length) + {Update(input, length); Final(digest);} + + //! verify that digest is a valid digest for the current message, then reinitialize the object + /*! Default implementation is to call Final() and do a bitwise comparison + between its output and digest. */ + virtual bool Verify(const byte *digest) + {return TruncatedVerify(digest, DigestSize());} + + //! use this if your input is in one piece and you don't want to call Update() and Verify() separately + virtual bool VerifyDigest(const byte *digest, const byte *input, unsigned int length) + {Update(input, length); return Verify(digest);} + + //! truncated version of Final() + virtual void TruncatedFinal(byte *digest, unsigned int digestSize) =0; + + //! truncated version of CalculateDigest() + virtual void CalculateTruncatedDigest(byte *digest, unsigned int digestSize, const byte *input, unsigned int length) + {Update(input, length); TruncatedFinal(digest, digestSize);} + + //! truncated version of Verify() + virtual bool TruncatedVerify(const byte *digest, unsigned int digestLength); + + //! truncated version of VerifyDigest() + virtual bool VerifyTruncatedDigest(const byte *digest, unsigned int digestLength, const byte *input, unsigned int length) + {Update(input, length); return TruncatedVerify(digest, digestLength);} + +protected: + void ThrowIfInvalidTruncatedSize(unsigned int size) const; +}; + +//! . +template <class T> +class SimpleKeyedTransformation : public T, public SimpleKeyingInterface +{ +public: + void ThrowIfInvalidKeyLength(unsigned int length) + {SimpleKeyingInterface::ThrowIfInvalidKeyLength(*this, length);} +}; + +//! . +typedef HashTransformation HashFunction; +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +//! These objects usually should not be used directly. See BlockTransformation for more details. +class BlockCipher : public BlockTransformation, public SimpleKeyingInterface {}; +//! interface for stream ciphers +class SymmetricCipher : public StreamTransformation, public SimpleKeyingInterface {}; +//! interface for message authentication codes +class MessageAuthenticationCode : public HashTransformation, public SimpleKeyingInterface {}; +#else +typedef SimpleKeyedTransformation<BlockTransformation> BlockCipher; +typedef SimpleKeyedTransformation<StreamTransformation> SymmetricCipher; +typedef SimpleKeyedTransformation<HashTransformation> MessageAuthenticationCode; +#endif + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY +typedef SymmetricCipher StreamCipher; +#endif + +//! interface for random number generators +/*! All return values are uniformly distributed over the range specified. +*/ +class RandomNumberGenerator : public Algorithm +{ +public: + //! generate new random byte and return it + virtual byte GenerateByte() =0; + + //! generate new random bit and return it + /*! Default implementation is to call GenerateByte() and return its parity. */ + virtual unsigned int GenerateBit(); + + //! generate a random 32 bit word in the range min to max, inclusive + virtual word32 GenerateWord32(word32 a=0, word32 b=0xffffffffL); + + //! generate random array of bytes + /*! Default implementation is to call GenerateByte() size times. */ + virtual void GenerateBlock(byte *output, unsigned int size); + + //! generate and discard n bytes + /*! Default implementation is to call GenerateByte() n times. */ + virtual void DiscardBytes(unsigned int n); + + //! randomly shuffle the specified array, resulting permutation is uniformly distributed + template <class IT> void Shuffle(IT begin, IT end) + { + for (; begin != end; ++begin) + std::iter_swap(begin, begin + GenerateWord32(0, end-begin-1)); + } + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + byte GetByte() {return GenerateByte();} + unsigned int GetBit() {return GenerateBit();} + word32 GetLong(word32 a=0, word32 b=0xffffffffL) {return GenerateWord32(a, b);} + word16 GetShort(word16 a=0, word16 b=0xffff) {return (word16)GenerateWord32(a, b);} + void GetBlock(byte *output, unsigned int size) {GenerateBlock(output, size);} +#endif +}; + +//! returns a reference that can be passed to functions that ask for a RNG but doesn't actually use it +RandomNumberGenerator & NullRNG(); + +class WaitObjectContainer; + +//! interface for objects that you can wait for + +class Waitable +{ +public: + //! maximum number of wait objects that this object can return + virtual unsigned int GetMaxWaitObjectCount() const =0; + //! put wait objects into container + virtual void GetWaitObjects(WaitObjectContainer &container) =0; + //! wait on this object + /*! same as creating an empty container, calling GetWaitObjects(), and calling Wait() on the container */ + bool Wait(unsigned long milliseconds); +}; + +//! interface for buffered transformations + +/*! BufferedTransformation is a generalization of BlockTransformation, + StreamTransformation, and HashTransformation. + + A buffered transformation is an object that takes a stream of bytes + as input (this may be done in stages), does some computation on them, and + then places the result into an internal buffer for later retrieval. Any + partial result already in the output buffer is not modified by further + input. + + If a method takes a "blocking" parameter, and you + pass "false" for it, the method will return before all input has been processed if + the input cannot be processed without waiting (for network buffers to become available, for example). + In this case the method will return true + or a non-zero integer value. When this happens you must continue to call the method with the same + parameters until it returns false or zero, before calling any other method on it or + attached BufferedTransformation. The integer return value in this case is approximately + the number of bytes left to be processed, and can be used to implement a progress bar. + + For functions that take a "propagation" parameter, propagation != 0 means pass on the signal to attached + BufferedTransformation objects, with propagation decremented at each step until it reaches 0. + -1 means unlimited propagation. + + \nosubgrouping +*/ +class BufferedTransformation : public Algorithm, public Waitable +{ +public: + // placed up here for CW8 + static const std::string NULL_CHANNEL; // the empty string "" + + BufferedTransformation() : Algorithm(false) {} + + //! return a reference to this object + /*! This function is useful for passing a temporary BufferedTransformation object to a + function that takes a non-const reference. */ + BufferedTransformation& Ref() {return *this;} + + //! \name INPUT + //@{ + //! input a byte for processing + unsigned int Put(byte inByte, bool blocking=true) + {return Put(&inByte, 1, blocking);} + //! input multiple bytes + unsigned int Put(const byte *inString, unsigned int length, bool blocking=true) + {return Put2(inString, length, 0, blocking);} + + //! input a 16-bit word + unsigned int PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + //! input a 32-bit word + unsigned int PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + //! request space to write bytes into for processing + /*! \param size is requested size (as a hint) for input, and size of the returned space for output */ + virtual byte * CreatePutSpace(unsigned int &size) {size=0; return NULL;} + + virtual bool CanModifyInput() const {return false;} + + //! input multiple bytes that may be modified by callee + unsigned int PutModifiable(byte *inString, unsigned int length, bool blocking=true) + {return PutModifiable2(inString, length, 0, blocking);} + + bool MessageEnd(int propagation=-1, bool blocking=true) + {return !!Put2(NULL, 0, propagation < 0 ? -1 : propagation+1, blocking);} + unsigned int PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1, bool blocking=true) + {return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + //! input multiple bytes for blocking or non-blocking processing + /*! \param messageEnd means how many filters to signal MessageEnd to, including this one */ + virtual unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) =0; + //! input multiple bytes that may be modified by callee for blocking or non-blocking processing + /*! \param messageEnd means how many filters to signal MessageEnd to, including this one */ + virtual unsigned int PutModifiable2(byte *inString, unsigned int length, int messageEnd, bool blocking) + {return Put2(inString, length, messageEnd, blocking);} + + //! thrown by objects that have not implemented nonblocking input processing + struct BlockingInputOnly : public NotImplemented + {BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}}; + //@} + + //! \name WAITING + //@{ + unsigned int GetMaxWaitObjectCount() const; + void GetWaitObjects(WaitObjectContainer &container); + //@} + + //! \name SIGNALS + //@{ + virtual void IsolatedInitialize(const NameValuePairs ¶meters) {throw NotImplemented("BufferedTransformation: this object can't be reinitialized");} + virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0; + virtual bool IsolatedMessageSeriesEnd(bool blocking) {return false;} + + //! initialize or reinitialize this object + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + //! flush buffered input and/or output + /*! \param hardFlush is used to indicate whether all data should be flushed + \note Hard flushes must be used with care. It means try to process and output everything, even if + there may not be enough data to complete the action. For example, hard flushing a HexDecoder would + cause an error if you do it after inputing an odd number of hex encoded characters. + For some types of filters, for example ZlibDecompressor, hard flushes can only + be done at "synchronization points". These synchronization points are positions in the data + stream that are created by hard flushes on the corresponding reverse filters, in this + example ZlibCompressor. This is useful when zlib compressed data is moved across a + network in packets and compression state is preserved across packets, as in the ssh2 protocol. + */ + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + //! mark end of a series of messages + /*! There should be a MessageEnd immediately before MessageSeriesEnd. */ + virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + //! set propagation of automatically generated and transfered signals + /*! propagation == 0 means do not automaticly generate signals */ + virtual void SetAutoSignalPropagation(int propagation) {} + + //! + virtual int GetAutoSignalPropagation() const {return 0;} +public: + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + void Close() {MessageEnd();} +#endif + //@} + + //! \name RETRIEVAL OF ONE MESSAGE + //@{ + //! returns number of bytes that is currently ready for retrieval + /*! All retrieval functions return the actual number of bytes + retrieved, which is the lesser of the request number and + MaxRetrievable(). */ + virtual unsigned long MaxRetrievable() const; + + //! returns whether any bytes are currently ready for retrieval + virtual bool AnyRetrievable() const; + + //! try to retrieve a single byte + virtual unsigned int Get(byte &outByte); + //! try to retrieve multiple bytes + virtual unsigned int Get(byte *outString, unsigned int getMax); + + //! peek at the next byte without removing it from the output buffer + virtual unsigned int Peek(byte &outByte) const; + //! peek at multiple bytes without removing them from the output buffer + virtual unsigned int Peek(byte *outString, unsigned int peekMax) const; + + //! try to retrieve a 16-bit word + unsigned int GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER); + //! try to retrieve a 32-bit word + unsigned int GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + //! try to peek at a 16-bit word + unsigned int PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER); + //! try to peek at a 32-bit word + unsigned int PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + //! move transferMax bytes of the buffered output to target as input + unsigned long TransferTo(BufferedTransformation &target, unsigned long transferMax=ULONG_MAX, const std::string &channel=NULL_CHANNEL) + {TransferTo2(target, transferMax, channel); return transferMax;} + + //! discard skipMax bytes from the output buffer + virtual unsigned long Skip(unsigned long skipMax=ULONG_MAX); + + //! copy copyMax bytes of the buffered output to target as input + unsigned long CopyTo(BufferedTransformation &target, unsigned long copyMax=ULONG_MAX, const std::string &channel=NULL_CHANNEL) const + {return CopyRangeTo(target, 0, copyMax, channel);} + + //! copy copyMax bytes of the buffered output, starting at position (relative to current position), to target as input + unsigned long CopyRangeTo(BufferedTransformation &target, unsigned long position, unsigned long copyMax=ULONG_MAX, const std::string &channel=NULL_CHANNEL) const + {unsigned long i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;} + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + unsigned long MaxRetrieveable() const {return MaxRetrievable();} +#endif + //@} + + //! \name RETRIEVAL OF MULTIPLE MESSAGES + //@{ + //! + virtual unsigned long TotalBytesRetrievable() const; + //! number of times MessageEnd() has been received minus messages retrieved or skipped + virtual unsigned int NumberOfMessages() const; + //! returns true if NumberOfMessages() > 0 + virtual bool AnyMessages() const; + //! start retrieving the next message + /*! + Returns false if no more messages exist or this message + is not completely retrieved. + */ + virtual bool GetNextMessage(); + //! skip count number of messages + virtual unsigned int SkipMessages(unsigned int count=UINT_MAX); + //! + unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=NULL_CHANNEL) + {TransferMessagesTo2(target, count, channel); return count;} + //! + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=NULL_CHANNEL) const; + + //! + virtual void SkipAll(); + //! + void TransferAllTo(BufferedTransformation &target, const std::string &channel=NULL_CHANNEL) + {TransferAllTo2(target, channel);} + //! + void CopyAllTo(BufferedTransformation &target, const std::string &channel=NULL_CHANNEL) const; + + virtual bool GetNextMessageSeries() {return false;} + virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();} + virtual unsigned int NumberOfMessageSeries() const {return 0;} + //@} + + //! \name NON-BLOCKING TRANSFER OF OUTPUT + //@{ + //! . + virtual unsigned int TransferTo2(BufferedTransformation &target, unsigned long &byteCount, const std::string &channel=NULL_CHANNEL, bool blocking=true) =0; + virtual unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const =0; + unsigned int TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int TransferAllTo2(BufferedTransformation &target, const std::string &channel=NULL_CHANNEL, bool blocking=true); + //@} + + //! \name CHANNELS + //@{ + struct NoChannelSupport : public NotImplemented + {NoChannelSupport() : NotImplemented("BufferedTransformation: this object doesn't support multiple channels") {}}; + + unsigned int ChannelPut(const std::string &channel, byte inByte, bool blocking=true) + {return ChannelPut(channel, &inByte, 1, blocking);} + unsigned int ChannelPut(const std::string &channel, const byte *inString, unsigned int length, bool blocking=true) + {return ChannelPut2(channel, inString, length, 0, blocking);} + + unsigned int ChannelPutModifiable(const std::string &channel, byte *inString, unsigned int length, bool blocking=true) + {return ChannelPutModifiable2(channel, inString, length, 0, blocking);} + + unsigned int ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + unsigned int ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return !!ChannelPut2(channel, NULL, 0, propagation < 0 ? -1 : propagation+1, blocking);} + unsigned int ChannelPutMessageEnd(const std::string &channel, const byte *inString, unsigned int length, int propagation=-1, bool blocking=true) + {return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + virtual byte * ChannelCreatePutSpace(const std::string &channel, unsigned int &size); + + virtual unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking); + virtual unsigned int ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking); + + virtual void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true); + virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + virtual void SetRetrievalChannel(const std::string &channel); + //@} + + //! \name ATTACHMENT + /*! Some BufferedTransformation objects (e.g. Filter objects) + allow other BufferedTransformation objects to be attached. When + this is done, the first object instead of buffering its output, + sents that output to the attached object as input. The entire + attachment chain is deleted when the anchor object is destructed. + */ + //@{ + //! returns whether this object allows attachment + virtual bool Attachable() {return false;} + //! returns the object immediately attached to this object or NULL for no attachment + virtual BufferedTransformation *AttachedTransformation() {assert(!Attachable()); return 0;} + //! + virtual const BufferedTransformation *AttachedTransformation() const + {return const_cast<BufferedTransformation *>(this)->AttachedTransformation();} + //! delete the current attachment chain and replace it with newAttachment + virtual void Detach(BufferedTransformation *newAttachment = 0) + {assert(!Attachable()); throw NotImplemented("BufferedTransformation: this object is not attachable");} + //! add newAttachment to the end of attachment chain + virtual void Attach(BufferedTransformation *newAttachment); + //@} + +protected: + static int DecrementPropagation(int propagation) + {return propagation != 0 ? propagation - 1 : 0;} +}; + +//! returns a reference to a BufferedTransformation object that discards all input +BufferedTransformation & TheBitBucket(); + +//! interface for crypto material, such as public and private keys, and crypto parameters + +class CryptoMaterial : public NameValuePairs +{ +public: + //! exception thrown when invalid crypto material is detected + class InvalidMaterial : public InvalidDataFormat + { + public: + explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {} + }; + + //! assign values from source to this object + /*! \note This function can be used to create a public key from a private key. */ + virtual void AssignFrom(const NameValuePairs &source) =0; + + //! check this object for errors + /*! \param level denotes the level of thoroughness: + 0 - using this object won't cause a crash or exception (rng is ignored) + 1 - this object will probably function (encrypt, sign, etc.) correctly (but may not check for weak keys and such) + 2 - make sure this object will function correctly, and do reasonable security checks + 3 - do checks that may take a long time + \return true if the tests pass */ + virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0; + + //! throws InvalidMaterial if this object fails Validate() test + virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const + {if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");} + +// virtual std::vector<std::string> GetSupportedFormats(bool includeSaveOnly=false, bool includeLoadOnly=false); + + //! save key into a BufferedTransformation + virtual void Save(BufferedTransformation &bt) const + {throw NotImplemented("CryptoMaterial: this object does not support saving");} + + //! load key from a BufferedTransformation + /*! \throws KeyingErr if decode fails + \note Generally does not check that the key is valid. + Call ValidateKey() or ThrowIfInvalidKey() to check that. */ + virtual void Load(BufferedTransformation &bt) + {throw NotImplemented("CryptoMaterial: this object does not support loading");} + + //! \return whether this object supports precomputation + virtual bool SupportsPrecomputation() const {return false;} + //! do precomputation + /*! The exact semantics of Precompute() is varies, but + typically it means calculate a table of n objects + that can be used later to speed up computation. */ + virtual void Precompute(unsigned int n) + {assert(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + //! retrieve previously saved precomputation + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {assert(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + //! save precomputation for later use + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {assert(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + // for internal library use + void DoQuickSanityCheck() const {ThrowIfInvalid(NullRNG(), 0);} +}; + +//! interface for generatable crypto material, such as private keys and crypto parameters + +class GeneratableCryptoMaterial : virtual public CryptoMaterial +{ +public: + //! generate a random key or crypto parameters + /*! \throws KeyingErr if algorithm parameters are invalid, or if a key can't be generated + (e.g., if this is a public key object) */ + virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) + {throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation");} + + //! calls the above function with a NameValuePairs object that just specifies "KeySize" + void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize); +}; + +//! interface for public keys + +class PublicKey : virtual public CryptoMaterial +{ +}; + +//! interface for private keys + +class PrivateKey : public GeneratableCryptoMaterial +{ +}; + +//! interface for crypto prameters + +class CryptoParameters : public GeneratableCryptoMaterial +{ +}; + +//! interface for asymmetric algorithms + +class AsymmetricAlgorithm : public Algorithm +{ +public: + //! returns a reference to the crypto material used by this object + virtual CryptoMaterial & AccessMaterial() =0; + //! returns a const reference to the crypto material used by this object + virtual const CryptoMaterial & GetMaterial() const =0; + + //! for backwards compatibility, calls AccessMaterial().Load(bt) + void BERDecode(BufferedTransformation &bt) + {AccessMaterial().Load(bt);} + //! for backwards compatibility, calls GetMaterial().Save(bt) + void DEREncode(BufferedTransformation &bt) const + {GetMaterial().Save(bt);} +}; + +//! interface for asymmetric algorithms using public keys + +class PublicKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + // VC60 workaround: no co-variant return type + CryptoMaterial & AccessMaterial() {return AccessPublicKey();} + const CryptoMaterial & GetMaterial() const {return GetPublicKey();} + + virtual PublicKey & AccessPublicKey() =0; + virtual const PublicKey & GetPublicKey() const {return const_cast<PublicKeyAlgorithm *>(this)->AccessPublicKey();} +}; + +//! interface for asymmetric algorithms using private keys + +class PrivateKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + CryptoMaterial & AccessMaterial() {return AccessPrivateKey();} + const CryptoMaterial & GetMaterial() const {return GetPrivateKey();} + + virtual PrivateKey & AccessPrivateKey() =0; + virtual const PrivateKey & GetPrivateKey() const {return const_cast<PrivateKeyAlgorithm *>(this)->AccessPrivateKey();} +}; + +//! interface for key agreement algorithms + +class KeyAgreementAlgorithm : public AsymmetricAlgorithm +{ +public: + CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();} + const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();} + + virtual CryptoParameters & AccessCryptoParameters() =0; + virtual const CryptoParameters & GetCryptoParameters() const {return const_cast<KeyAgreementAlgorithm *>(this)->AccessCryptoParameters();} +}; + +//! interface for public-key encryptors and decryptors + +/*! This class provides an interface common to encryptors and decryptors + for querying their plaintext and ciphertext lengths. +*/ +class PK_CryptoSystem +{ +public: + virtual ~PK_CryptoSystem() {} + + //! maximum length of plaintext for a given ciphertext length + /*! \note This function returns 0 if cipherTextLength is not valid (too long or too short). */ + virtual unsigned int MaxPlaintextLength(unsigned int cipherTextLength) const =0; + + //! calculate length of ciphertext given length of plaintext + /*! \note This function returns 0 if plainTextLength is not valid (too long). */ + virtual unsigned int CiphertextLength(unsigned int plainTextLength) const =0; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + unsigned int MaxPlainTextLength(unsigned int cipherTextLength) const {return MaxPlaintextLength(cipherTextLength);} + unsigned int CipherTextLength(unsigned int plainTextLength) const {return CiphertextLength(plainTextLength);} +#endif +}; + +//! interface for public-key encryptors + +class PK_Encryptor : virtual public PK_CryptoSystem, public PublicKeyAlgorithm +{ +public: + //! . + class InvalidPlaintextLength : public Exception + { + public: + InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {} + }; + + //! encrypt a byte string + /*! \pre CipherTextLength(plainTextLength) != 0 (i.e., plainText isn't too long) + \pre size of cipherText == CipherTextLength(plainTextLength) + */ + virtual void Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const =0; + + //! create a new encryption filter + /*! \note caller is responsible for deleting the returned pointer + */ + virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng, BufferedTransformation *attachment=NULL) const; +}; + +//! interface for public-key decryptors + +class PK_Decryptor : virtual public PK_CryptoSystem, public PrivateKeyAlgorithm +{ +public: + //! decrypt a byte string, and return the length of plaintext + /*! \pre size of plainText == MaxPlainTextLength(cipherTextLength) bytes. + \return the actual length of the plaintext, or 0 if decryption fails. + */ + virtual DecodingResult Decrypt(const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const =0; + + //! create a new decryption filter + /*! \note caller is responsible for deleting the returned pointer + */ + virtual BufferedTransformation * CreateDecryptionFilter(BufferedTransformation *attachment=NULL) const; +}; + +//! interface for encryptors and decryptors with fixed length ciphertext + +/*! A simplified interface is provided for crypto systems (such + as RSA) whose ciphertext length and maximum plaintext length + depend only on the key. +*/ +class PK_FixedLengthCryptoSystem : virtual public PK_CryptoSystem +{ +public: + //! + virtual unsigned int FixedMaxPlaintextLength() const =0; + //! + virtual unsigned int FixedCiphertextLength() const =0; + + unsigned int MaxPlaintextLength(unsigned int cipherTextLength) const; + unsigned int CiphertextLength(unsigned int plainTextLength) const; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + unsigned int MaxPlainTextLength(unsigned int cipherTextLength) const {return MaxPlaintextLength(cipherTextLength);} + unsigned int CipherTextLength(unsigned int plainTextLength) const {return CiphertextLength(plainTextLength);} + unsigned int MaxPlainTextLength() const {return FixedMaxPlaintextLength();} + unsigned int CipherTextLength() const {return FixedCiphertextLength();} +#endif +}; + +//! interface for encryptors with fixed length ciphertext + +class PK_FixedLengthEncryptor : public PK_Encryptor, virtual public PK_FixedLengthCryptoSystem +{ +}; + +//! interface for decryptors with fixed length ciphertext + +class PK_FixedLengthDecryptor : public PK_Decryptor, virtual public PK_FixedLengthCryptoSystem +{ +public: + //! decrypt a byte string, and return the length of plaintext + /*! \pre length of cipherText == CipherTextLength() + \pre size of plainText == MaxPlainTextLength() + \return the actual length of the plaintext, or 0 if decryption fails. + */ + virtual DecodingResult FixedLengthDecrypt(const byte *cipherText, byte *plainText) const =0; + + DecodingResult Decrypt(const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + DecodingResult Decrypt(const byte *cipherText, byte *plainText) const {return FixedLengthDecrypt(cipherText, plainText);} +#endif +}; + +//! interface for public-key signers and verifiers + +/*! This class provides an interface common to signers and verifiers + for querying their signature lengths and creating message + accumulators. +*/ +class PK_SignatureScheme +{ +public: + virtual ~PK_SignatureScheme() {} + + //! signature length support by this object (as either input or output) + virtual unsigned int SignatureLength() const =0; + + //! deprecated, please use PK_Signer::NewSignatureAccumulator or PK_Verifier::NewVerificationAccumulator instead + virtual HashTransformation * NewMessageAccumulator() const =0; +}; + +//! interface for public-key signers + +class PK_Signer : virtual public PK_SignatureScheme, public PrivateKeyAlgorithm +{ +public: + //! key too short exception, may be thrown by Sign() or SignMessage() + class KeyTooShort : public Exception + { + public: + KeyTooShort() : Exception(OTHER_ERROR, "PK_Signer: key too short") {} + }; + + //! sign and delete messageAccumulator (even in case of exception thrown) + /*! \pre messageAccumulator was obtained by calling NewSignatureAccumulator() + \pre HashTransformation::Final() has not been called on messageAccumulator + \pre size of signature == SignatureLength() + */ + virtual void Sign(RandomNumberGenerator &rng, HashTransformation *messageAccumulator, byte *signature) const; + + //! sign and restart messageAccumulator + virtual void SignAndRestart(RandomNumberGenerator &rng, HashTransformation &messageAccumulator, byte *signature) const =0; + + //! sign a message + /*! \pre size of signature == SignatureLength() */ + virtual void SignMessage(RandomNumberGenerator &rng, const byte *message, unsigned int messageLen, byte *signature) const; + + //! create a new HashTransformation to accumulate the message to be signed + virtual HashTransformation * NewSignatureAccumulator() const + {return NewMessageAccumulator();} +}; + +//! interface for public-key signature verifiers + +class PK_Verifier : virtual public PK_SignatureScheme, public PublicKeyAlgorithm +{ +public: + /*! If this function returns true, you must input the signature when + calling NewVerificationAccumulator(). Otherwise, you must input the signature + when calling Verify(). */ + virtual bool SignatureUpfrontForVerification() const {return false;} + + //! create a new HashTransformation to accumulate the message to be verified + /*! \param signature is ignored if SignatureUpfrontForVerification() == false + \param signature may be NULL to indicate that the signature is not available yet + */ + virtual HashTransformation * NewVerificationAccumulator(const byte *signature=NULL) const + {return NewMessageAccumulator();} + + //! check whether sig is a valid signature for messageAccumulator, and delete messageAccumulator (even in case of exception thrown) + /*! \pre messageAccumulator was obtained by calling NewVerificationAccumulator() + \pre HashTransformation::Final() has not been called on messageAccumulator + \pre length of signature == SignatureLength() + \param signature is ignored if SignatureUpfrontForVerification() == true + */ + virtual bool Verify(HashTransformation *messageAccumulator, const byte *signature=NULL) const; + + //! check whether sig is a valid signature for messageAccumulator, and restart messageAccumulator + /*! \note depending on SignatureUpfrontForVerification(), signature is either the current or the next signature + \param signature may be NULL to indicate that the next signature is not available yet + */ + virtual bool VerifyAndRestart(HashTransformation &messageAccumulator, const byte *signature) const =0; + + //! only useful if SignatureUpfrontForVerification() == true + virtual void InitializeVerificationAccumulator(HashTransformation &messageAccumulator, const byte *signature) const {} + + //! check whether sig is a valid signature for message + /*! \pre size of signature == SignatureLength() */ + virtual bool VerifyMessage(const byte *message, unsigned int messageLen, const byte *signature) const; +}; + +//! interface for public-key signers and verifiers with recovery + +/*! In a signature scheme with recovery, a verifier is able to extract + a message from its valid signature. +*/ +class PK_SignatureSchemeWithRecovery : virtual public PK_SignatureScheme +{ +public: + //! length of longest message that can be fully recovered + virtual unsigned int MaximumRecoverableLength() const =0; + + //! whether or not messages longer than MaximumRecoverableLength() can be signed + /*! If this function returns false, any message longer than + MaximumRecoverableLength() will be truncated for signature + and will fail verification. + */ + virtual bool AllowLeftoverMessage() const =0; +}; + +//! interface for public-key signers with recovery + +class PK_SignerWithRecovery : virtual public PK_SignatureSchemeWithRecovery, virtual public PK_Signer +{ +}; + +//! interface for public-key verifiers with recovery + +/*! A PK_VerifierWithRecovery can also be used the same way as a PK_Verifier, + where the signature and the entire message is given to Verify() or + VerifyMessage() as input. +*/ +class PK_VerifierWithRecovery : virtual public PK_SignatureSchemeWithRecovery, virtual public PK_Verifier +{ +public: + /*! If this function returns true, you must input the signature when + calling NewRecoveryAccumulator(). Otherwise, you must input the signature + when calling Recover(). */ + virtual bool SignatureUpfrontForRecovery() const =0; + + //! create a new HashTransformation to accumulate leftover message + virtual HashTransformation * NewRecoveryAccumulator(const byte *signature=NULL) const =0; + + //! recover a message from its signature + /*! \pre leftoverMessageAccumulator was obtained by calling NewLeftoverMessageAccumulator(signature) + \pre HashTransformation::Final() has not been called on leftoverMessageAccumulator + \pre length of signature == SignatureLength() + \pre size of recoveredMessage == MaximumRecoverableLength() + */ + virtual DecodingResult Recover(byte *recoveredMessage, HashTransformation *recoveryAccumulator, const byte *signature=NULL) const =0; + + //! recover a message from its signature + /*! depending on SignatureUpfrontForRecovery(), signature is either the current or the next signature */ + // TODO: uncomment this and implement + // virtual unsigned int RecoverAndRestart(byte *recoveredMessage, HashTransformation &recoveryAccumulator, const byte *signature) const =0; + + //! recover a message from its signature + /*! \note This function should be equivalent to Recover(recoveredMessage, NewRecoveryAccumulator(signature), signature) + \pre length of signature == SignatureLength() + \pre size of recoveredMessage == MaximumRecoverableLength() + */ + virtual DecodingResult RecoverMessage(byte *recoveredMessage, const byte *message, unsigned int messageLen, const byte *signature) const + {return Recover(recoveredMessage, NewRecoveryAccumulator(signature), signature);} +}; + +//! interface for domains of simple key agreement protocols + +/*! A key agreement domain is a set of parameters that must be shared + by two parties in a key agreement protocol, along with the algorithms + for generating key pairs and deriving agreed values. +*/ +class SimpleKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + //! return length of agreed value produced + virtual unsigned int AgreedValueLength() const =0; + //! return length of private keys in this domain + virtual unsigned int PrivateKeyLength() const =0; + //! return length of public keys in this domain + virtual unsigned int PublicKeyLength() const =0; + //! generate private key + /*! \pre size of privateKey == PrivateKeyLength() */ + virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + //! generate public key + /*! \pre size of publicKey == PublicKeyLength() */ + virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + //! generate private/public key pair + /*! \note equivalent to calling GeneratePrivateKey() and then GeneratePublicKey() */ + virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + //! derive agreed value from your private key and couterparty's public key, return false in case of failure + /*! \note If you have previously validated the public key, use validateOtherPublicKey=false to save time. + /*! \pre size of agreedValue == AgreedValueLength() + \pre length of privateKey == PrivateKeyLength() + \pre length of otherPublicKey == PublicKeyLength() + */ + virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} +#endif +}; + +//! interface for domains of authenticated key agreement protocols + +/*! In an authenticated key agreement protocol, each party has two + key pairs. The long-lived key pair is called the static key pair, + and the short-lived key pair is called the ephemeral key pair. +*/ +class AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + //! return length of agreed value produced + virtual unsigned int AgreedValueLength() const =0; + + //! return length of static private keys in this domain + virtual unsigned int StaticPrivateKeyLength() const =0; + //! return length of static public keys in this domain + virtual unsigned int StaticPublicKeyLength() const =0; + //! generate static private key + /*! \pre size of privateKey == PrivateStaticKeyLength() */ + virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + //! generate static public key + /*! \pre size of publicKey == PublicStaticKeyLength() */ + virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + //! generate private/public key pair + /*! \note equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey() */ + virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + //! return length of ephemeral private keys in this domain + virtual unsigned int EphemeralPrivateKeyLength() const =0; + //! return length of ephemeral public keys in this domain + virtual unsigned int EphemeralPublicKeyLength() const =0; + //! generate ephemeral private key + /*! \pre size of privateKey == PrivateEphemeralKeyLength() */ + virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + //! generate ephemeral public key + /*! \pre size of publicKey == PublicEphemeralKeyLength() */ + virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + //! generate private/public key pair + /*! \note equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey() */ + virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + //! derive agreed value from your private keys and couterparty's public keys, return false in case of failure + /*! \note The ephemeral public key will always be validated. + If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time. + \pre size of agreedValue == AgreedValueLength() + \pre length of staticPrivateKey == StaticPrivateKeyLength() + \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength() + \pre length of staticOtherPublicKey == StaticPublicKeyLength() + \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength() + */ + virtual bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const =0; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} +#endif +}; + +// interface for password authenticated key agreement protocols, not implemented yet +#if 0 +//! interface for protocol sessions +/*! The methods should be called in the following order: + + InitializeSession(rng, parameters); // or call initialize method in derived class + while (true) + { + if (OutgoingMessageAvailable()) + { + length = GetOutgoingMessageLength(); + GetOutgoingMessage(message); + ; // send outgoing message + } + + if (LastMessageProcessed()) + break; + + ; // receive incoming message + ProcessIncomingMessage(message); + } + ; // call methods in derived class to obtain result of protocol session +*/ +class ProtocolSession +{ +public: + //! exception thrown when an invalid protocol message is processed + class ProtocolError : public Exception + { + public: + ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {} + }; + + //! exception thrown when a function is called unexpectedly + /*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */ + class UnexpectedMethodCall : public Exception + { + public: + UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {} + }; + + ProtocolSession() : m_rng(NULL), m_throwOnProtocolError(true), m_validState(false) {} + virtual ~ProtocolSession() {} + + virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs ¶meters) =0; + + bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;} + void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;} + + bool HasValidState() const {return m_validState;} + + virtual bool OutgoingMessageAvailable() const =0; + virtual unsigned int GetOutgoingMessageLength() const =0; + virtual void GetOutgoingMessage(byte *message) =0; + + virtual bool LastMessageProcessed() const =0; + virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0; + +protected: + void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const; + void CheckAndHandleInvalidState() const; + void SetValidState(bool valid) {m_validState = valid;} + + RandomNumberGenerator *m_rng; + +private: + bool m_throwOnProtocolError, m_validState; +}; + +class KeyAgreementSession : public ProtocolSession +{ +public: + virtual unsigned int GetAgreedValueLength() const =0; + virtual void GetAgreedValue(byte *agreedValue) const =0; +}; + +class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession +{ +public: + void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng, + const byte *myId, unsigned int myIdLength, + const byte *counterPartyId, unsigned int counterPartyIdLength, + const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength); +}; + +class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + //! return whether the domain parameters stored in this object are valid + virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} + + virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0; + virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0; + + enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8}; + + virtual bool IsValidRole(unsigned int role) =0; + virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0; +}; +#endif + +//! BER Decode Exception Class, may be thrown during an ASN1 BER decode operation +class BERDecodeErr : public InvalidArgument +{ +public: + BERDecodeErr() : InvalidArgument("BER decode error") {} + BERDecodeErr(const std::string &s) : InvalidArgument(s) {} +}; + +//! interface for encoding and decoding ASN1 objects +class ASN1Object +{ +public: + virtual ~ASN1Object() {} + //! decode this object from a BufferedTransformation, using BER (Basic Encoding Rules) + virtual void BERDecode(BufferedTransformation &bt) =0; + //! encode this object into a BufferedTransformation, using DER (Distinguished Encoding Rules) + virtual void DEREncode(BufferedTransformation &bt) const =0; + //! encode this object into a BufferedTransformation, using BER + /*! this may be useful if DEREncode() would be too inefficient */ + virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);} +}; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY +typedef PK_SignatureScheme PK_SignatureSystem +typedef PK_SignatureSchemeWithRecovery PK_SignatureSystemWithRecovery +typedef SimpleKeyAgreementDomain PK_SimpleKeyAgreementDomain +typedef AuthenticatedKeyAgreementDomain PK_AuthenticatedKeyAgreementDomain +typedef WithPrecomputation PK_WithPrecomputation +#endif + +NAMESPACE_END + +#endif diff --git a/default.cpp b/default.cpp new file mode 100644 index 0000000..ca99414 --- /dev/null +++ b/default.cpp @@ -0,0 +1,258 @@ +// default.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "default.h" +#include "queue.h" +#include <time.h> +#include <memory> + +NAMESPACE_BEGIN(CryptoPP) + +static const unsigned int MASH_ITERATIONS = 200; +static const unsigned int SALTLENGTH = 8; +static const unsigned int BLOCKSIZE = Default_BlockCipher::Encryption::BLOCKSIZE; +static const unsigned int KEYLENGTH = Default_BlockCipher::Encryption::DEFAULT_KEYLENGTH; + +// The purpose of this function Mash() is to take an arbitrary length input +// string and *deterministicly* produce an arbitrary length output string such +// that (1) it looks random, (2) no information about the input is +// deducible from it, and (3) it contains as much entropy as it can hold, or +// the amount of entropy in the input string, whichever is smaller. + +static void Mash(const byte *in, word16 inLen, byte *out, word16 outLen, int iterations) +{ + unsigned int bufSize = (outLen-1+DefaultHashModule::DIGESTSIZE-((outLen-1)%DefaultHashModule::DIGESTSIZE)); + + // ASSERT: bufSize == (the smallest multiple of DIGESTSIZE that is >= outLen) + + byte b[2]; + SecByteBlock buf(bufSize); + SecByteBlock outBuf(bufSize); + DefaultHashModule hash; + + unsigned int i; + for(i=0; i<outLen; i+=DefaultHashModule::DIGESTSIZE) + { + b[0] = (byte) i >> 8; + b[1] = (byte) i; + hash.Update(b, 2); + hash.Update(in, inLen); + hash.Final(outBuf+i); + } + + while (iterations-- > 1) + { + memcpy(buf, outBuf, bufSize); + for (i=0; i<bufSize; i+=DefaultHashModule::DIGESTSIZE) + { + b[0] = (byte) i >> 8; + b[1] = (byte) i; + hash.Update(b, 2); + hash.Update(buf, bufSize); + hash.Final(outBuf+i); + } + } + + memcpy(out, outBuf, outLen); +} + +static void GenerateKeyIV(const byte *passphrase, unsigned int passphraseLength, const byte *salt, unsigned int saltLength, byte *key, byte *IV) +{ + SecByteBlock temp(passphraseLength+saltLength); + memcpy(temp, passphrase, passphraseLength); + memcpy(temp+passphraseLength, salt, saltLength); + SecByteBlock keyIV(KEYLENGTH+BLOCKSIZE); + Mash(temp, passphraseLength + saltLength, keyIV, KEYLENGTH+BLOCKSIZE, MASH_ITERATIONS); + memcpy(key, keyIV, KEYLENGTH); + memcpy(IV, keyIV+KEYLENGTH, BLOCKSIZE); +} + +// ******************************************************** + +DefaultEncryptor::DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment) + : ProxyFilter(NULL, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase)) +{ +} + +DefaultEncryptor::DefaultEncryptor(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment) + : ProxyFilter(NULL, 0, 0, attachment), m_passphrase(passphrase, passphraseLength) +{ +} + + +void DefaultEncryptor::FirstPut(const byte *) +{ + // VC60 workaround: __LINE__ expansion bug + CRYPTOPP_COMPILE_ASSERT_INSTANCE(SALTLENGTH <= DefaultHashModule::DIGESTSIZE, 1); + CRYPTOPP_COMPILE_ASSERT_INSTANCE(BLOCKSIZE <= DefaultHashModule::DIGESTSIZE, 2); + + SecByteBlock salt(DefaultHashModule::DIGESTSIZE), keyCheck(DefaultHashModule::DIGESTSIZE); + DefaultHashModule hash; + + // use hash(passphrase | time | clock) as salt + hash.Update(m_passphrase, m_passphrase.size()); + time_t t=time(0); + hash.Update((byte *)&t, sizeof(t)); + clock_t c=clock(); + hash.Update((byte *)&c, sizeof(c)); + hash.Final(salt); + + // use hash(passphrase | salt) as key check + hash.Update(m_passphrase, m_passphrase.size()); + hash.Update(salt, SALTLENGTH); + hash.Final(keyCheck); + + AttachedTransformation()->Put(salt, SALTLENGTH); + + // mash passphrase and salt together into key and IV + SecByteBlock key(KEYLENGTH); + SecByteBlock IV(BLOCKSIZE); + GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, key, IV); + + m_cipher.SetKeyWithIV(key, key.size(), IV); + SetFilter(new StreamTransformationFilter(m_cipher)); + + m_filter->Put(keyCheck, BLOCKSIZE); +} + +void DefaultEncryptor::LastPut(const byte *inString, unsigned int length) +{ + m_filter->MessageEnd(); +} + +// ******************************************************** + +DefaultDecryptor::DefaultDecryptor(const char *p, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment) + , m_state(WAITING_FOR_KEYCHECK) + , m_passphrase((const byte *)p, strlen(p)) + , m_throwException(throwException) +{ +} + +DefaultDecryptor::DefaultDecryptor(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment) + , m_state(WAITING_FOR_KEYCHECK) + , m_passphrase(passphrase, passphraseLength) + , m_throwException(throwException) +{ +} + +void DefaultDecryptor::FirstPut(const byte *inString) +{ + CheckKey(inString, inString+SALTLENGTH); +} + +void DefaultDecryptor::LastPut(const byte *inString, unsigned int length) +{ + if (m_filter.get() == NULL) + { + m_state = KEY_BAD; + if (m_throwException) + throw KeyBadErr(); + } + else + { + m_filter->MessageEnd(); + m_state = WAITING_FOR_KEYCHECK; + } +} + +void DefaultDecryptor::CheckKey(const byte *salt, const byte *keyCheck) +{ + SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DefaultHashModule::DIGESTSIZE)); + + DefaultHashModule hash; + hash.Update(m_passphrase, m_passphrase.size()); + hash.Update(salt, SALTLENGTH); + hash.Final(check); + + SecByteBlock key(KEYLENGTH); + SecByteBlock IV(BLOCKSIZE); + GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, key, IV); + + m_cipher.SetKeyWithIV(key, key.size(), IV); + std::auto_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher)); + + decryptor->Put(keyCheck, BLOCKSIZE); + decryptor->ForceNextPut(); + decryptor->Get(check+BLOCKSIZE, BLOCKSIZE); + + SetFilter(decryptor.release()); + + if (memcmp(check, check+BLOCKSIZE, BLOCKSIZE)) + { + m_state = KEY_BAD; + if (m_throwException) + throw KeyBadErr(); + } + else + m_state = KEY_GOOD; +} + +// ******************************************************** + +static DefaultMAC * NewDefaultEncryptorMAC(const byte *passphrase, unsigned int passphraseLength) +{ + unsigned int macKeyLength = DefaultMAC::StaticGetValidKeyLength(16); + SecByteBlock macKey(macKeyLength); + // since the MAC is encrypted there is no reason to mash the passphrase for many iterations + Mash(passphrase, passphraseLength, macKey, macKeyLength, 1); + return new DefaultMAC(macKey, macKeyLength); +} + +DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment) + : ProxyFilter(NULL, 0, 0, attachment) + , m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase))) +{ + SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase), true)); +} + +DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment) + : ProxyFilter(NULL, 0, 0, attachment) + , m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength)) +{ + SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase, passphraseLength), true)); +} + +void DefaultEncryptorWithMAC::LastPut(const byte *inString, unsigned int length) +{ + m_filter->MessageEnd(); +} + +// ******************************************************** + +DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULL, 0, 0, attachment) + , m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase))) + , m_throwException(throwException) +{ + SetFilter(new DefaultDecryptor(passphrase, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException)); +} + +DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULL, 0, 0, attachment) + , m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength)) + , m_throwException(throwException) +{ + SetFilter(new DefaultDecryptor(passphrase, passphraseLength, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException)); +} + +DefaultDecryptor::State DefaultDecryptorWithMAC::CurrentState() const +{ + return static_cast<const DefaultDecryptor *>(m_filter.get())->CurrentState(); +} + +bool DefaultDecryptorWithMAC::CheckLastMAC() const +{ + return m_hashVerifier->GetLastResult(); +} + +void DefaultDecryptorWithMAC::LastPut(const byte *inString, unsigned int length) +{ + m_filter->MessageEnd(); + if (m_throwException && !CheckLastMAC()) + throw MACBadErr(); +} + +NAMESPACE_END diff --git a/default.h b/default.h new file mode 100644 index 0000000..ce3739d --- /dev/null +++ b/default.h @@ -0,0 +1,104 @@ +#ifndef CRYPTOPP_DEFAULT_H +#define CRYPTOPP_DEFAULT_H + +#include "sha.h" +#include "hmac.h" +#include "des.h" +#include "filters.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +typedef DES_EDE2 Default_BlockCipher; +typedef SHA DefaultHashModule; +typedef HMAC<DefaultHashModule> DefaultMAC; + +//! Password-Based Encryptor using DES-EDE2 +class DefaultEncryptor : public ProxyFilter +{ +public: + DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment = NULL); + DefaultEncryptor(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment = NULL); + +protected: + void FirstPut(const byte *); + void LastPut(const byte *inString, unsigned int length); + +private: + SecByteBlock m_passphrase; + CBC_Mode<Default_BlockCipher>::Encryption m_cipher; +}; + +//! Password-Based Decryptor using DES-EDE2 +class DefaultDecryptor : public ProxyFilter +{ +public: + DefaultDecryptor(const char *passphrase, BufferedTransformation *attachment = NULL, bool throwException=true); + DefaultDecryptor(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment = NULL, bool throwException=true); + + class Err : public Exception + { + public: + Err(const std::string &s) + : Exception(DATA_INTEGRITY_CHECK_FAILED, s) {} + }; + class KeyBadErr : public Err {public: KeyBadErr() : Err("DefaultDecryptor: cannot decrypt message with this passphrase") {}}; + + enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD}; + State CurrentState() const {return m_state;} + +protected: + void FirstPut(const byte *inString); + void LastPut(const byte *inString, unsigned int length); + + State m_state; + +private: + void CheckKey(const byte *salt, const byte *keyCheck); + + SecByteBlock m_passphrase; + CBC_Mode<Default_BlockCipher>::Decryption m_cipher; + member_ptr<FilterWithBufferedInput> m_decryptor; + bool m_throwException; +}; + +//! Password-Based Encryptor using DES-EDE2 and HMAC/SHA-1 +class DefaultEncryptorWithMAC : public ProxyFilter +{ +public: + DefaultEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULL); + DefaultEncryptorWithMAC(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment = NULL); + +protected: + void FirstPut(const byte *inString) {} + void LastPut(const byte *inString, unsigned int length); + +private: + member_ptr<DefaultMAC> m_mac; +}; + +//! Password-Based Decryptor using DES-EDE2 and HMAC/SHA-1 +class DefaultDecryptorWithMAC : public ProxyFilter +{ +public: + class MACBadErr : public DefaultDecryptor::Err {public: MACBadErr() : DefaultDecryptor::Err("DefaultDecryptorWithMAC: MAC check failed") {}}; + + DefaultDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULL, bool throwException=true); + DefaultDecryptorWithMAC(const byte *passphrase, unsigned int passphraseLength, BufferedTransformation *attachment = NULL, bool throwException=true); + + DefaultDecryptor::State CurrentState() const; + bool CheckLastMAC() const; + +protected: + void FirstPut(const byte *inString) {} + void LastPut(const byte *inString, unsigned int length); + +private: + member_ptr<DefaultMAC> m_mac; + HashVerifier *m_hashVerifier; + bool m_throwException; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,464 @@ +// des.cpp - modified by Wei Dai from Phil Karn's des.c +// The original code and all modifications are in the public domain. + +/* + * This is a major rewrite of my old public domain DES code written + * circa 1987, which in turn borrowed heavily from Jim Gillogly's 1977 + * public domain code. I pretty much kept my key scheduling code, but + * the actual encrypt/decrypt routines are taken from from Richard + * Outerbridge's DES code as printed in Schneier's "Applied Cryptography." + * + * This code is in the public domain. I would appreciate bug reports and + * enhancements. + * + * Phil Karn KA9Q, karn@unix.ka9q.ampr.org, August 1994. + */ + +#include "pch.h" +#include "misc.h" +#include "des.h" + +NAMESPACE_BEGIN(CryptoPP) + +static inline bool CheckParity(byte b) +{ + unsigned int a = b ^ (b >> 4); + return ((a ^ (a>>1) ^ (a>>2) ^ (a>>3)) & 1) == 1; +} + +bool DES::CheckKeyParityBits(const byte *key) +{ + for (unsigned int i=0; i<8; i++) + if (!CheckParity(key[i])) + return false; + return true; +} + +void DES::CorrectKeyParityBits(byte *key) +{ + for (unsigned int i=0; i<8; i++) + if (!CheckParity(key[i])) + key[i] ^= 1; +} + +/* Tables defined in the Data Encryption Standard documents + * Three of these tables, the initial permutation, the final + * permutation and the expansion operator, are regular enough that + * for speed, we hard-code them. They're here for reference only. + * Also, the S and P boxes are used by a separate program, gensp.c, + * to build the combined SP box, Spbox[]. They're also here just + * for reference. + */ +#ifdef notdef +/* initial permutation IP */ +static byte ip[] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +/* final permutation IP^-1 */ +static byte fp[] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; +/* expansion operation matrix */ +static byte ei[] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; +/* The (in)famous S-boxes */ +static byte sbox[8][64] = { + /* S1 */ + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + + /* S2 */ + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + + /* S3 */ + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + + /* S4 */ + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + + /* S5 */ + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + + /* S6 */ + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + + /* S7 */ + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + + /* S8 */ + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 +}; + +/* 32-bit permutation function P used on the output of the S-boxes */ +static byte p32i[] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; +#endif + +/* permuted choice table (key) */ +static const byte pc1[] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +/* number left rotations of pc1 */ +static const byte totrot[] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 +}; + +/* permuted choice key (table) */ +static const byte pc2[] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +/* End of DES-defined tables */ + +/* bit 0 is left-most in byte */ +static const int bytebit[] = { + 0200,0100,040,020,010,04,02,01 +}; + +/* Set key (initialize key schedule array) */ +void DES::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length) +{ + AssertValidKeyLength(length); + + SecByteBlock buffer(56+56+8); + byte *const pc1m=buffer; /* place to modify pc1 into */ + byte *const pcr=pc1m+56; /* place to rotate pc1 into */ + byte *const ks=pcr+56; + register int i,j,l; + int m; + + for (j=0; j<56; j++) { /* convert pc1 to bits of key */ + l=pc1[j]-1; /* integer bit location */ + m = l & 07; /* find bit */ + pc1m[j]=(key[l>>3] & /* find which key byte l is in */ + bytebit[m]) /* and which bit of that byte */ + ? 1 : 0; /* and store 1-bit result */ + } + for (i=0; i<16; i++) { /* key chunk for each iteration */ + memset(ks,0,8); /* Clear key schedule */ + for (j=0; j<56; j++) /* rotate pc1 the right amount */ + pcr[j] = pc1m[(l=j+totrot[i])<(j<28? 28 : 56) ? l: l-28]; + /* rotate left and right halves independently */ + for (j=0; j<48; j++){ /* select bits individually */ + /* check bit that goes to ks[j] */ + if (pcr[pc2[j]-1]){ + /* mask it in if it's there */ + l= j % 6; + ks[j/6] |= bytebit[l] >> 2; + } + } + /* Now convert to odd/even interleaved form for use in F */ + k[2*i] = ((word32)ks[0] << 24) + | ((word32)ks[2] << 16) + | ((word32)ks[4] << 8) + | ((word32)ks[6]); + k[2*i+1] = ((word32)ks[1] << 24) + | ((word32)ks[3] << 16) + | ((word32)ks[5] << 8) + | ((word32)ks[7]); + } + + if (dir==DECRYPTION) // reverse key schedule order + for (i=0; i<16; i+=2) + { + std::swap(k[i], k[32-2-i]); + std::swap(k[i+1], k[32-1-i]); + } +} + +// Richard Outerbridge's initial permutation algorithm +/* +inline void IPERM(word32 &left, word32 &right) +{ + word32 work; + + work = ((left >> 4) ^ right) & 0x0f0f0f0f; + right ^= work; + left ^= work << 4; + work = ((left >> 16) ^ right) & 0xffff; + right ^= work; + left ^= work << 16; + work = ((right >> 2) ^ left) & 0x33333333; + left ^= work; + right ^= (work << 2); + work = ((right >> 8) ^ left) & 0xff00ff; + left ^= work; + right ^= (work << 8); + right = rotl(right, 1); + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = rotl(left, 1); +} +inline void FPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotr(right, 1); + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = rotr(left, 1); + work = ((left >> 8) ^ right) & 0xff00ff; + right ^= work; + left ^= work << 8; + work = ((left >> 2) ^ right) & 0x33333333; + right ^= work; + left ^= work << 2; + work = ((right >> 16) ^ left) & 0xffff; + left ^= work; + right ^= work << 16; + work = ((right >> 4) ^ left) & 0x0f0f0f0f; + left ^= work; + right ^= work << 4; +} +*/ + +// Wei Dai's modification to Richard Outerbridge's initial permutation +// algorithm, this one is faster if you have access to rotate instructions +// (like in MSVC) +static inline void IPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotlFixed(right, 4U); + work = (left ^ right) & 0xf0f0f0f0; + left ^= work; + right = rotrFixed(right^work, 20U); + work = (left ^ right) & 0xffff0000; + left ^= work; + right = rotrFixed(right^work, 18U); + work = (left ^ right) & 0x33333333; + left ^= work; + right = rotrFixed(right^work, 6U); + work = (left ^ right) & 0x00ff00ff; + left ^= work; + right = rotlFixed(right^work, 9U); + work = (left ^ right) & 0xaaaaaaaa; + left = rotlFixed(left^work, 1U); + right ^= work; +} + +static inline void FPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotrFixed(right, 1U); + work = (left ^ right) & 0xaaaaaaaa; + right ^= work; + left = rotrFixed(left^work, 9U); + work = (left ^ right) & 0x00ff00ff; + right ^= work; + left = rotlFixed(left^work, 6U); + work = (left ^ right) & 0x33333333; + right ^= work; + left = rotlFixed(left^work, 18U); + work = (left ^ right) & 0xffff0000; + right ^= work; + left = rotlFixed(left^work, 20U); + work = (left ^ right) & 0xf0f0f0f0; + right ^= work; + left = rotrFixed(left^work, 4U); +} + +void DES::Base::RawProcessBlock(word32 &l_, word32 &r_) const +{ + word32 l = l_, r = r_; + const word32 *kptr=k; + + for (unsigned i=0; i<8; i++) + { + word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrFixed(l, 4U) ^ kptr[4*i+2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + l_ = l; r_ = r; +} + +typedef BlockGetAndPut<word32, BigEndian> Block; + +// Encrypt or decrypt a block of data in ECB mode +void DES::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + + const word32 *kptr=k; + + for (unsigned i=0; i<8; i++) + { + word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrFixed(l, 4U) ^ kptr[4*i+2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +void DES_EDE2::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length) +{ + AssertValidKeyLength(length); + + m_des1.UncheckedSetKey(dir, key); + m_des2.UncheckedSetKey(ReverseCipherDir(dir), key+8); +} + +void DES_EDE2::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + m_des1.RawProcessBlock(l, r); + m_des2.RawProcessBlock(r, l); + m_des1.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +void DES_EDE3::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length) +{ + AssertValidKeyLength(length); + + m_des1.UncheckedSetKey(dir, key+(dir==ENCRYPTION?0:2*8)); + m_des2.UncheckedSetKey(ReverseCipherDir(dir), key+8); + m_des3.UncheckedSetKey(dir, key+(dir==DECRYPTION?0:2*8)); +} + +void DES_EDE3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + m_des1.RawProcessBlock(l, r); + m_des2.RawProcessBlock(r, l); + m_des3.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +void DES_XEX3::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length) +{ + AssertValidKeyLength(length); + + memcpy(m_x1, key+(dir==ENCRYPTION?0:2*8), BLOCKSIZE); + m_des.UncheckedSetKey(dir, key+8); + memcpy(m_x3, key+(dir==DECRYPTION?0:2*8), BLOCKSIZE); +} + +void DES_XEX3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + xorbuf(outBlock, inBlock, m_x1, BLOCKSIZE); + m_des.ProcessAndXorBlock(outBlock, xorBlock, outBlock); + xorbuf(outBlock, m_x3, BLOCKSIZE); +} + +NAMESPACE_END @@ -0,0 +1,133 @@ +#ifndef CRYPTOPP_DES_H +#define CRYPTOPP_DES_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct DES_Info : public FixedBlockSize<8>, public FixedKeyLength<8> +{ + static const char *StaticAlgorithmName() {return "DES";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#DES">DES</a> +/*! The DES implementation in Crypto++ ignores the parity bits + (the least significant bits of each byte) in the key. However + you can use CheckKeyParityBits() and CorrectKeyParityBits() to + check or correct the parity bits if you wish. */ +class DES : public DES_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<DES_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length = 8); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + // exposed for faster Triple-DES + void RawProcessBlock(word32 &l, word32 &r) const; + + protected: + static const word32 Spbox[8][64]; + + FixedSizeSecBlock<word32, 32> k; + }; + +public: + //! check DES key parity bits + static bool CheckKeyParityBits(const byte *key); + //! correct DES key parity bits + static void CorrectKeyParityBits(byte *key); + + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + static const char *StaticAlgorithmName() {return "DES-EDE2";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#DESede">DES-EDE2</a> +class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<DES_EDE2_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + DES::Encryption m_des1, m_des2; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + static const char *StaticAlgorithmName() {return "DES-EDE3";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#DESede">DES-EDE3</a> +class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<DES_EDE3_Info> + { + public: + void UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + DES::Encryption m_des1, m_des2, m_des3; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + static const char *StaticAlgorithmName() {return "DES-XEX3";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#DESX">DES-XEX3</a>, AKA DESX +class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<DES_XEX3_Info> + { + public: + void UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock<byte, BLOCKSIZE> m_x1, m_x3; + DES::Encryption m_des; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +typedef DES::Encryption DESEncryption; +typedef DES::Decryption DESDecryption; + +typedef DES_EDE2::Encryption DES_EDE2_Encryption; +typedef DES_EDE2::Decryption DES_EDE2_Decryption; + +typedef DES_EDE3::Encryption DES_EDE3_Encryption; +typedef DES_EDE3::Decryption DES_EDE3_Decryption; + +typedef DES_XEX3::Encryption DES_XEX3_Encryption; +typedef DES_XEX3::Decryption DES_XEX3_Decryption; + +NAMESPACE_END + +#endif diff --git a/descert.dat b/descert.dat new file mode 100644 index 0000000..5d3ddc7 --- /dev/null +++ b/descert.dat @@ -0,0 +1,171 @@ +0101010101010101 95F8A5E5DD31D900 8000000000000000 +0101010101010101 DD7F121CA5015619 4000000000000000 +0101010101010101 2E8653104F3834EA 2000000000000000 +0101010101010101 4BD388FF6CD81D4F 1000000000000000 +0101010101010101 20B9E767B2FB1456 0800000000000000 +0101010101010101 55579380D77138EF 0400000000000000 +0101010101010101 6CC5DEFAAF04512F 0200000000000000 +0101010101010101 0D9F279BA5D87260 0100000000000000 +0101010101010101 D9031B0271BD5A0A 0080000000000000 +0101010101010101 424250B37C3DD951 0040000000000000 +0101010101010101 B8061B7ECD9A21E5 0020000000000000 +0101010101010101 F15D0F286B65BD28 0010000000000000 +0101010101010101 ADD0CC8D6E5DEBA1 0008000000000000 +0101010101010101 E6D5F82752AD63D1 0004000000000000 +0101010101010101 ECBFE3BD3F591A5E 0002000000000000 +0101010101010101 F356834379D165CD 0001000000000000 +0101010101010101 2B9F982F20037FA9 0000800000000000 +0101010101010101 889DE068A16F0BE6 0000400000000000 +0101010101010101 E19E275D846A1298 0000200000000000 +0101010101010101 329A8ED523D71AEC 0000100000000000 +0101010101010101 E7FCE22557D23C97 0000080000000000 +0101010101010101 12A9F5817FF2D65D 0000040000000000 +0101010101010101 A484C3AD38DC9C19 0000020000000000 +0101010101010101 FBE00A8A1EF8AD72 0000010000000000 +0101010101010101 750D079407521363 0000008000000000 +0101010101010101 64FEED9C724C2FAF 0000004000000000 +0101010101010101 F02B263B328E2B60 0000002000000000 +0101010101010101 9D64555A9A10B852 0000001000000000 +0101010101010101 D106FF0BED5255D7 0000000800000000 +0101010101010101 E1652C6B138C64A5 0000000400000000 +0101010101010101 E428581186EC8F46 0000000200000000 +0101010101010101 AEB5F5EDE22D1A36 0000000100000000 +0101010101010101 E943D7568AEC0C5C 0000000080000000 +0101010101010101 DF98C8276F54B04B 0000000040000000 +0101010101010101 B160E4680F6C696F 0000000020000000 +0101010101010101 FA0752B07D9C4AB8 0000000010000000 +0101010101010101 CA3A2B036DBC8502 0000000008000000 +0101010101010101 5E0905517BB59BCF 0000000004000000 +0101010101010101 814EEB3B91D90726 0000000002000000 +0101010101010101 4D49DB1532919C9F 0000000001000000 +0101010101010101 25EB5FC3F8CF0621 0000000000800000 +0101010101010101 AB6A20C0620D1C6F 0000000000400000 +0101010101010101 79E90DBC98F92CCA 0000000000200000 +0101010101010101 866ECEDD8072BB0E 0000000000100000 +0101010101010101 8B54536F2F3E64A8 0000000000080000 +0101010101010101 EA51D3975595B86B 0000000000040000 +0101010101010101 CAFFC6AC4542DE31 0000000000020000 +0101010101010101 8DD45A2DDF90796C 0000000000010000 +0101010101010101 1029D55E880EC2D0 0000000000008000 +0101010101010101 5D86CB23639DBEA9 0000000000004000 +0101010101010101 1D1CA853AE7C0C5F 0000000000002000 +0101010101010101 CE332329248F3228 0000000000001000 +0101010101010101 8405D1ABE24FB942 0000000000000800 +0101010101010101 E643D78090CA4207 0000000000000400 +0101010101010101 48221B9937748A23 0000000000000200 +0101010101010101 DD7C0BBD61FAFD54 0000000000000100 +0101010101010101 2FBC291A570DB5C4 0000000000000080 +0101010101010101 E07C30D7E4E26E12 0000000000000040 +0101010101010101 0953E2258E8E90A1 0000000000000020 +0101010101010101 5B711BC4CEEBF2EE 0000000000000010 +0101010101010101 CC083F1E6D9E85F6 0000000000000008 +0101010101010101 D2FD8867D50D2DFE 0000000000000004 +0101010101010101 06E7EA22CE92708F 0000000000000002 +0101010101010101 166B40B44ABA4BD6 0000000000000001 +8001010101010101 0000000000000000 95A8D72813DAA94D +4001010101010101 0000000000000000 0EEC1487DD8C26D5 +2001010101010101 0000000000000000 7AD16FFB79C45926 +1001010101010101 0000000000000000 D3746294CA6A6CF3 +0801010101010101 0000000000000000 809F5F873C1FD761 +0401010101010101 0000000000000000 C02FAFFEC989D1FC +0201010101010101 0000000000000000 4615AA1D33E72F10 +0180010101010101 0000000000000000 2055123350C00858 +0140010101010101 0000000000000000 DF3B99D6577397C8 +0120010101010101 0000000000000000 31FE17369B5288C9 +0110010101010101 0000000000000000 DFDD3CC64DAE1642 +0108010101010101 0000000000000000 178C83CE2B399D94 +0104010101010101 0000000000000000 50F636324A9B7F80 +0102010101010101 0000000000000000 A8468EE3BC18F06D +0101800101010101 0000000000000000 A2DC9E92FD3CDE92 +0101400101010101 0000000000000000 CAC09F797D031287 +0101200101010101 0000000000000000 90BA680B22AEB525 +0101100101010101 0000000000000000 CE7A24F350E280B6 +0101080101010101 0000000000000000 882BFF0AA01A0B87 +0101040101010101 0000000000000000 25610288924511C2 +0101020101010101 0000000000000000 C71516C29C75D170 +0101018001010101 0000000000000000 5199C29A52C9F059 +0101014001010101 0000000000000000 C22F0A294A71F29F +0101012001010101 0000000000000000 EE371483714C02EA +0101011001010101 0000000000000000 A81FBD448F9E522F +0101010801010101 0000000000000000 4F644C92E192DFED +0101010401010101 0000000000000000 1AFA9A66A6DF92AE +0101010201010101 0000000000000000 B3C1CC715CB879D8 +0101010180010101 0000000000000000 19D032E64AB0BD8B +0101010140010101 0000000000000000 3CFAA7A7DC8720DC +0101010120010101 0000000000000000 B7265F7F447AC6F3 +0101010110010101 0000000000000000 9DB73B3C0D163F54 +0101010108010101 0000000000000000 8181B65BABF4A975 +0101010104010101 0000000000000000 93C9B64042EAA240 +0101010102010101 0000000000000000 5570530829705592 +0101010101800101 0000000000000000 8638809E878787A0 +0101010101400101 0000000000000000 41B9A79AF79AC208 +0101010101200101 0000000000000000 7A9BE42F2009A892 +0101010101100101 0000000000000000 29038D56BA6D2745 +0101010101080101 0000000000000000 5495C6ABF1E5DF51 +0101010101040101 0000000000000000 AE13DBD561488933 +0101010101020101 0000000000000000 024D1FFA8904E389 +0101010101018001 0000000000000000 D1399712F99BF02E +0101010101014001 0000000000000000 14C1D7C1CFFEC79E +0101010101012001 0000000000000000 1DE5279DAE3BED6F +0101010101011001 0000000000000000 E941A33F85501303 +0101010101010801 0000000000000000 DA99DBBC9A03F379 +0101010101010401 0000000000000000 B7FC92F91D8E92E9 +0101010101010201 0000000000000000 AE8E5CAA3CA04E85 +0101010101010180 0000000000000000 9CC62DF43B6EED74 +0101010101010140 0000000000000000 D863DBB5C59A91A0 +0101010101010120 0000000000000000 A1AB2190545B91D7 +0101010101010110 0000000000000000 0875041E64C570F7 +0101010101010108 0000000000000000 5A594528BEBEF1CC +0101010101010104 0000000000000000 FCDB3291DE21F0C0 +0101010101010102 0000000000000000 869EFD7F9F265A09 +1046913489980131 0000000000000000 88D55E54F54C97B4 +1007103489988020 0000000000000000 0C0CC00C83EA48FD +10071034C8980120 0000000000000000 83BC8EF3A6570183 +1046103489988020 0000000000000000 DF725DCAD94EA2E9 +1086911519190101 0000000000000000 E652B53B550BE8B0 +1086911519580101 0000000000000000 AF527120C485CBB0 +5107B01519580101 0000000000000000 0F04CE393DB926D5 +1007B01519190101 0000000000000000 C9F00FFC74079067 +3107915498080101 0000000000000000 7CFD82A593252B4E +3107919498080101 0000000000000000 CB49A2F9E91363E3 +10079115B9080140 0000000000000000 00B588BE70D23F56 +3107911598090140 0000000000000000 406A9A6AB43399AE +1007D01589980101 0000000000000000 6CB773611DCA9ADA +9107911589980101 0000000000000000 67FD21C17DBB5D70 +9107D01589190101 0000000000000000 9592CB4110430787 +1007D01598980120 0000000000000000 A6B7FF68A318DDD3 +1007940498190101 0000000000000000 4D102196C914CA16 +0107910491190401 0000000000000000 2DFA9F4573594965 +0107910491190101 0000000000000000 B46604816C0E0774 +0107940491190401 0000000000000000 6E7E6221A4F34E87 +19079210981A0101 0000000000000000 AA85E74643233199 +1007911998190801 0000000000000000 2E5A19DB4D1962D6 +10079119981A0801 0000000000000000 23A866A809D30894 +1007921098190101 0000000000000000 D812D961F017D320 +100791159819010B 0000000000000000 055605816E58608F +1004801598190101 0000000000000000 ABD88E8B1B7716F1 +1004801598190102 0000000000000000 537AC95BE69DA1E1 +1004801598190108 0000000000000000 AED0F6AE3C25CDD8 +1002911598100104 0000000000000000 B3E35A5EE53E7B8D +1002911598190104 0000000000000000 61C79C71921A2EF8 +1002911598100201 0000000000000000 E2F5728F0995013C +1002911698100101 0000000000000000 1AEAC39A61F0A464 +7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B +0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271 +07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A +3849674C2602319E 51454B582DDF440A 7178876E01F19B2A +04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095 +0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B +0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09 +43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A +07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F +04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088 +37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77 +1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A +584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56 +025816164629B007 480D39006EE762F2 A1F9915541020B56 +49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556 +4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC +49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A +018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41 +1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793 diff --git a/dessp.cpp b/dessp.cpp new file mode 100644 index 0000000..1f7a951 --- /dev/null +++ b/dessp.cpp @@ -0,0 +1,90 @@ +// This file is mostly generated by Phil Karn's gensp.c + +#include "pch.h" +#include "des.h" + +NAMESPACE_BEGIN(CryptoPP) + +// VC60 workaround: gives a C4786 warning without this function +// when runtime lib is set to multithread debug DLL +// even though warning 4786 is disabled! +void DES_VC60Workaround() +{ +} + +const word32 DES::Base::Spbox[8][64] = { +{ +0x01010400,0x00000000,0x00010000,0x01010404, 0x01010004,0x00010404,0x00000004,0x00010000, +0x00000400,0x01010400,0x01010404,0x00000400, 0x01000404,0x01010004,0x01000000,0x00000004, +0x00000404,0x01000400,0x01000400,0x00010400, 0x00010400,0x01010000,0x01010000,0x01000404, +0x00010004,0x01000004,0x01000004,0x00010004, 0x00000000,0x00000404,0x00010404,0x01000000, +0x00010000,0x01010404,0x00000004,0x01010000, 0x01010400,0x01000000,0x01000000,0x00000400, +0x01010004,0x00010000,0x00010400,0x01000004, 0x00000400,0x00000004,0x01000404,0x00010404, +0x01010404,0x00010004,0x01010000,0x01000404, 0x01000004,0x00000404,0x00010404,0x01010400, +0x00000404,0x01000400,0x01000400,0x00000000, 0x00010004,0x00010400,0x00000000,0x01010004}, +{ +0x80108020,0x80008000,0x00008000,0x00108020, 0x00100000,0x00000020,0x80100020,0x80008020, +0x80000020,0x80108020,0x80108000,0x80000000, 0x80008000,0x00100000,0x00000020,0x80100020, +0x00108000,0x00100020,0x80008020,0x00000000, 0x80000000,0x00008000,0x00108020,0x80100000, +0x00100020,0x80000020,0x00000000,0x00108000, 0x00008020,0x80108000,0x80100000,0x00008020, +0x00000000,0x00108020,0x80100020,0x00100000, 0x80008020,0x80100000,0x80108000,0x00008000, +0x80100000,0x80008000,0x00000020,0x80108020, 0x00108020,0x00000020,0x00008000,0x80000000, +0x00008020,0x80108000,0x00100000,0x80000020, 0x00100020,0x80008020,0x80000020,0x00100020, +0x00108000,0x00000000,0x80008000,0x00008020, 0x80000000,0x80100020,0x80108020,0x00108000}, +{ +0x00000208,0x08020200,0x00000000,0x08020008, 0x08000200,0x00000000,0x00020208,0x08000200, +0x00020008,0x08000008,0x08000008,0x00020000, 0x08020208,0x00020008,0x08020000,0x00000208, +0x08000000,0x00000008,0x08020200,0x00000200, 0x00020200,0x08020000,0x08020008,0x00020208, +0x08000208,0x00020200,0x00020000,0x08000208, 0x00000008,0x08020208,0x00000200,0x08000000, +0x08020200,0x08000000,0x00020008,0x00000208, 0x00020000,0x08020200,0x08000200,0x00000000, +0x00000200,0x00020008,0x08020208,0x08000200, 0x08000008,0x00000200,0x00000000,0x08020008, +0x08000208,0x00020000,0x08000000,0x08020208, 0x00000008,0x00020208,0x00020200,0x08000008, +0x08020000,0x08000208,0x00000208,0x08020000, 0x00020208,0x00000008,0x08020008,0x00020200}, +{ +0x00802001,0x00002081,0x00002081,0x00000080, 0x00802080,0x00800081,0x00800001,0x00002001, +0x00000000,0x00802000,0x00802000,0x00802081, 0x00000081,0x00000000,0x00800080,0x00800001, +0x00000001,0x00002000,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002001,0x00002080, +0x00800081,0x00000001,0x00002080,0x00800080, 0x00002000,0x00802080,0x00802081,0x00000081, +0x00800080,0x00800001,0x00802000,0x00802081, 0x00000081,0x00000000,0x00000000,0x00802000, +0x00002080,0x00800080,0x00800081,0x00000001, 0x00802001,0x00002081,0x00002081,0x00000080, +0x00802081,0x00000081,0x00000001,0x00002000, 0x00800001,0x00002001,0x00802080,0x00800081, +0x00002001,0x00002080,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002000,0x00802080}, +{ +0x00000100,0x02080100,0x02080000,0x42000100, 0x00080000,0x00000100,0x40000000,0x02080000, +0x40080100,0x00080000,0x02000100,0x40080100, 0x42000100,0x42080000,0x00080100,0x40000000, +0x02000000,0x40080000,0x40080000,0x00000000, 0x40000100,0x42080100,0x42080100,0x02000100, +0x42080000,0x40000100,0x00000000,0x42000000, 0x02080100,0x02000000,0x42000000,0x00080100, +0x00080000,0x42000100,0x00000100,0x02000000, 0x40000000,0x02080000,0x42000100,0x40080100, +0x02000100,0x40000000,0x42080000,0x02080100, 0x40080100,0x00000100,0x02000000,0x42080000, +0x42080100,0x00080100,0x42000000,0x42080100, 0x02080000,0x00000000,0x40080000,0x42000000, +0x00080100,0x02000100,0x40000100,0x00080000, 0x00000000,0x40080000,0x02080100,0x40000100}, +{ +0x20000010,0x20400000,0x00004000,0x20404010, 0x20400000,0x00000010,0x20404010,0x00400000, +0x20004000,0x00404010,0x00400000,0x20000010, 0x00400010,0x20004000,0x20000000,0x00004010, +0x00000000,0x00400010,0x20004010,0x00004000, 0x00404000,0x20004010,0x00000010,0x20400010, +0x20400010,0x00000000,0x00404010,0x20404000, 0x00004010,0x00404000,0x20404000,0x20000000, +0x20004000,0x00000010,0x20400010,0x00404000, 0x20404010,0x00400000,0x00004010,0x20000010, +0x00400000,0x20004000,0x20000000,0x00004010, 0x20000010,0x20404010,0x00404000,0x20400000, +0x00404010,0x20404000,0x00000000,0x20400010, 0x00000010,0x00004000,0x20400000,0x00404010, +0x00004000,0x00400010,0x20004010,0x00000000, 0x20404000,0x20000000,0x00400010,0x20004010}, +{ +0x00200000,0x04200002,0x04000802,0x00000000, 0x00000800,0x04000802,0x00200802,0x04200800, +0x04200802,0x00200000,0x00000000,0x04000002, 0x00000002,0x04000000,0x04200002,0x00000802, +0x04000800,0x00200802,0x00200002,0x04000800, 0x04000002,0x04200000,0x04200800,0x00200002, +0x04200000,0x00000800,0x00000802,0x04200802, 0x00200800,0x00000002,0x04000000,0x00200800, +0x04000000,0x00200800,0x00200000,0x04000802, 0x04000802,0x04200002,0x04200002,0x00000002, +0x00200002,0x04000000,0x04000800,0x00200000, 0x04200800,0x00000802,0x00200802,0x04200800, +0x00000802,0x04000002,0x04200802,0x04200000, 0x00200800,0x00000000,0x00000002,0x04200802, +0x00000000,0x00200802,0x04200000,0x00000800, 0x04000002,0x04000800,0x00000800,0x00200002}, +{ +0x10001040,0x00001000,0x00040000,0x10041040, 0x10000000,0x10001040,0x00000040,0x10000000, +0x00040040,0x10040000,0x10041040,0x00041000, 0x10041000,0x00041040,0x00001000,0x00000040, +0x10040000,0x10000040,0x10001000,0x00001040, 0x00041000,0x00040040,0x10040040,0x10041000, +0x00001040,0x00000000,0x00000000,0x10040040, 0x10000040,0x10001000,0x00041040,0x00040000, +0x00041040,0x00040000,0x10041000,0x00001000, 0x00000040,0x10040040,0x00001000,0x00041040, +0x10001000,0x00000040,0x10000040,0x10040000, 0x10040040,0x10000000,0x00040000,0x10001040, +0x00000000,0x10041040,0x00040040,0x10000040, 0x10040000,0x10001000,0x10001040,0x00000000, +0x10041040,0x00041000,0x00041000,0x00001040, 0x00001040,0x00040040,0x10000000,0x10041000} +}; + +NAMESPACE_END @@ -0,0 +1,14 @@ +// dh.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "dh.h" + +NAMESPACE_BEGIN(CryptoPP) + +void DH_TestInstantiations() +{ + DH dh1; + DH dh2(NullRNG(), 10); +} + +NAMESPACE_END @@ -0,0 +1,93 @@ +#ifndef CRYPTOPP_DH_H +#define CRYPTOPP_DH_H + +/** \file +*/ + +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! , +template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption> +class DH_Domain : public DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element> +{ + typedef DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element> Base; + +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef DL_KeyAgreementAlgorithm_DH<Element, COFACTOR_OPTION> KeyAgreementAlgorithm; + typedef DH_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain; + + DH_Domain() {} + + DH_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + DH_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + template <class T2> + DH_Domain(RandomNumberGenerator &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + template <class T2, class T3> + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T2 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + template <class T2, class T3, class T4> + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + template <class T1, class T2> + DH_Domain(const T1 &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + template <class T1, class T2, class T3> + DH_Domain(const T1 &v1, const T2 &v2, const T2 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + template <class T1, class T2, class T3, class T4> + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + Base::GeneratePublicKey(rng, privateKey, publicKey); + + if (FIPS_140_2_ComplianceEnabled()) + { + SecByteBlock privateKey2(PrivateKeyLength()); + GeneratePrivateKey(rng, privateKey2); + + SecByteBlock publicKey2(PublicKeyLength()); + Base::GeneratePublicKey(rng, privateKey2, publicKey2); + + SecByteBlock agreedValue(AgreedValueLength()), agreedValue2(AgreedValueLength()); + Agree(agreedValue, privateKey, publicKey2); + Agree(agreedValue2, privateKey2, publicKey); + + if (agreedValue != agreedValue2) + throw SelfTestFailure(AlgorithmName() + ": pairwise consistency test failed"); + } + } + +private: + const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const + {static KeyAgreementAlgorithm a; return a;} + DL_GroupParameters<Element> & AccessAbstractGroupParameters() + {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +//! <a href="http://www.weidai.com/scan-mirror/ka.html#DH">Diffie-Hellman</a> in GF(p) with key validation +typedef DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime> DH; + +NAMESPACE_END + +#endif diff --git a/dh1024.dat b/dh1024.dat new file mode 100644 index 0000000..86a9551 --- /dev/null +++ b/dh1024.dat @@ -0,0 +1 @@ +30818702818100DA9A18547FF03B385CC16508C173A7EF4EB61CB40EF8FEF3B31F145051676166BCDC3FE6B799FC394D08C26385F9413F896E09117E46209D6923602683CEA100924A6EE695281775C619DAA94EA8CB3691B4275B0183F1D39639EBC92995FE645D6C1BC28D409E585549BBD2C5DCDD6C208B04EADD8B7A6D997F72CBAD88390F020102
\ No newline at end of file @@ -0,0 +1,17 @@ +// dh2.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "dh2.h" + +NAMESPACE_BEGIN(CryptoPP) + +bool DH2::Agree(byte *agreedValue, + const byte *staticSecretKey, const byte *ephemeralSecretKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey) const +{ + return d1.Agree(agreedValue, staticSecretKey, staticOtherPublicKey, validateStaticOtherPublicKey) + && d2.Agree(agreedValue+d1.AgreedValueLength(), ephemeralSecretKey, ephemeralOtherPublicKey, true); +} + +NAMESPACE_END @@ -0,0 +1,56 @@ +#ifndef CRYPTOPP_DH2_H +#define CRYPTOPP_DH2_H + +/** \file +*/ + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/ka.html#DH2">Unified Diffie-Hellman</a> +class DH2 : public AuthenticatedKeyAgreementDomain +{ +public: + DH2(const SimpleKeyAgreementDomain &domain) + : d1(domain), d2(domain) {} + DH2(const SimpleKeyAgreementDomain &staticDomain, const SimpleKeyAgreementDomain &ephemeralDomain) + : d1(staticDomain), d2(ephemeralDomain) {} + + unsigned int AgreedValueLength() const + {return d1.AgreedValueLength() + d2.AgreedValueLength();} + + unsigned int StaticPrivateKeyLength() const + {return d1.PrivateKeyLength();} + unsigned int StaticPublicKeyLength() const + {return d1.PublicKeyLength();} + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d1.GeneratePrivateKey(rng, privateKey);} + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d1.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d1.GenerateKeyPair(rng, privateKey, publicKey);} + + unsigned int EphemeralPrivateKeyLength() const + {return d2.PrivateKeyLength();} + unsigned int EphemeralPublicKeyLength() const + {return d2.PublicKeyLength();} + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d2.GeneratePrivateKey(rng, privateKey);} + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d2.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d2.GenerateKeyPair(rng, privateKey, publicKey);} + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const; + +protected: + const SimpleKeyAgreementDomain &d1, &d2; +}; + +NAMESPACE_END + +#endif diff --git a/dh2048.dat b/dh2048.dat new file mode 100644 index 0000000..bd5255f --- /dev/null +++ b/dh2048.dat @@ -0,0 +1 @@ +308201080282010100EB60DBD494AAFBCD2EAC6A36DB8E7DD4A2A64512A5BBB15B9BFB581C7C1CAFB647D4612973C3770C2166D75EEA695F67EA8261557591DB78BCF5A886AA5294F3AEE4D25B57C8EE8C7FE8DBF70C132CD7FFCB6F89426F807F552C5DAE2FB1F329E340094E4B30D8EF6265AB4D350E9837B151C86AC524DE4E1FC04746C668BE318275E420D51AEDDFBDF887D435CDEEF6AC81293DB45287132F8236A43AD8F4D6642D7CA6732DA06A1DE008259008C9D74403B68ADAC788CF8AB5BEFFC310DCCCD32901D1F290E5B7A993D2CF6A652AF81B6DA0FD2E70678D1AE086150E41444522F20621195AD2A1F0975652B4AF7DE5261A9FD46B9EA8B443641F3BBA695B9B020103
\ No newline at end of file diff --git a/diamond.cpp b/diamond.cpp new file mode 100644 index 0000000..6e68cf4 --- /dev/null +++ b/diamond.cpp @@ -0,0 +1,572 @@ +// diamond.cpp - modified by Wei Dai from: + +/* diamond2.c - Encryption designed to exceed DES in security. + This file and the Diamond2 and Diamond2 Lite Block Ciphers + described herein are hereby dedicated to the Public Domain by the + author and inventor, Michael Paul Johnson. Feel free to use these + for any purpose that is legally and morally right. The names + "Diamond2 Block Cipher" and "Diamond2 Lite Block Cipher" should only + be used to describe the algorithms described in this file, to avoid + confusion. + + Disclaimers: the following comes with no warranty, expressed or + implied. You, the user, must determine the suitability of this + information to your own uses. You must also find out what legal + requirements exist with respect to this data and programs using + it, and comply with whatever valid requirements exist. +*/ + +#include "pch.h" +#include "diamond.h" +#include "crc.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Diamond2SboxMaker +{ +public: + Diamond2SboxMaker(const byte *external_key, unsigned int key_size, + unsigned int rounds, bool lite); + + void MakeSbox(byte *sbox, CipherDir direction); + +private: + unsigned int keyrand(unsigned int max_value, const byte *prevSbox); + void makeonebox(byte *s, unsigned int i, unsigned int j); + + CRC32 crc; + const byte *const key; + const unsigned keysize; + unsigned keyindex; + const unsigned numrounds; + const unsigned roundsize; // Number of bytes in one round of substitution boxes + const unsigned blocksize; +}; + +Diamond2SboxMaker::Diamond2SboxMaker(const byte *external_key, unsigned int key_size, unsigned int rounds, + bool lite) + : key(external_key), + keysize(key_size), + keyindex(0), + numrounds(rounds), + roundsize(lite ? 2048 : 4096), + blocksize(lite ? 8 : 16) +{ + assert((rounds * blocksize) <= 255); +} + +// Returns uniformly distributed pseudorandom value based on key[], sized keysize +inline unsigned int Diamond2SboxMaker::keyrand(unsigned int max_value, const byte *prevSbox) +{ + assert(max_value <= 255); + + if (!max_value) return 0; + + unsigned int mask, prandvalue, i; + + // Create a mask to get the minimum number of + // bits to cover the range 0 to max_value. + for (i=max_value, mask=0; i > 0; i = i >> 1) + mask = (mask << 1) | 1; + + assert(i==0); + do + { + if (prevSbox) + crc.UpdateByte(prevSbox[key[keyindex++]]); + else + crc.UpdateByte(key[keyindex++]); + + if (keyindex >= keysize) + { + keyindex = 0; /* Recycle thru the key */ + crc.UpdateByte(byte(keysize)); + crc.UpdateByte(byte(keysize >> 8)); + } + prandvalue = crc.GetCrcByte(0) & mask; + if ((++i>97) && (prandvalue > max_value)) /* Don't loop forever. */ + prandvalue -= max_value; /* Introduce negligible bias. */ + } + while (prandvalue > max_value); /* Discard out of range values. */ + return prandvalue; +} + +void Diamond2SboxMaker::makeonebox(byte *s, unsigned int i, unsigned int j) +{ + bool filled[256]; + byte *sbox = s + (roundsize*i) + (256*j); + byte *prevSbox = (i||j) ? sbox-256 : 0; + + unsigned m; + for (m = 0; m < 256; m++) /* The filled array is used to make sure that */ + filled[m] = false; /* each byte of the array is filled only once. */ + for (int n = 255; n >= 0 ; n--) /* n counts the number of bytes left to fill */ + { + // pos is the position among the UNFILLED + // components of the s array that the number n should be placed. + unsigned pos = keyrand(n, prevSbox); + unsigned p=0; + while (filled[p]) p++; + for (m=0; m<pos; m++) + { + p++; + while (filled[p]) p++; + } + assert(p<256); + sbox[p] = n; + filled[p] = true; + } +} + +void Diamond2SboxMaker::MakeSbox(byte *s, CipherDir direction) +{ + unsigned int i, j, k; + + for (i = 0; i < numrounds; i++) + for (j = 0; j < blocksize; j++) + makeonebox(s, i, j); + + if (direction==DECRYPTION) + { + SecByteBlock si(numrounds * roundsize); + for (i = 0; i < numrounds; i++) + for (j = 0; j < blocksize; j++) + for (k = 0; k < 256; k++) + *(si + (roundsize * i) + (256 * j) + *(s + (roundsize * i) + (256 * j) + k)) = k; + memcpy(s, si, numrounds * roundsize); + } +} + +void Diamond2::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds) +{ + AssertValidKeyLength(length); + + numrounds = rounds; + s.New(numrounds * ROUNDSIZE); + + Diamond2SboxMaker m(userKey, length, rounds, false); + m.MakeSbox(s, direction); +} + +inline void Diamond2::Base::substitute(int round, byte *x, const byte *y) const +{ + const byte *sbox = s + (ROUNDSIZE*round); + x[0] = sbox[0*256+y[0]]; + x[1] = sbox[1*256+y[1]]; + x[2] = sbox[2*256+y[2]]; + x[3] = sbox[3*256+y[3]]; + x[4] = sbox[4*256+y[4]]; + x[5] = sbox[5*256+y[5]]; + x[6] = sbox[6*256+y[6]]; + x[7] = sbox[7*256+y[7]]; + x[8] = sbox[8*256+y[8]]; + x[9] = sbox[9*256+y[9]]; + x[10] = sbox[10*256+y[10]]; + x[11] = sbox[11*256+y[11]]; + x[12] = sbox[12*256+y[12]]; + x[13] = sbox[13*256+y[13]]; + x[14] = sbox[14*256+y[14]]; + x[15] = sbox[15*256+y[15]]; +} + +#ifdef DIAMOND_USE_PERMTABLE + +inline void Diamond2::Base::permute(byte *a) +{ +#ifdef IS_LITTLE_ENDIAN + word32 temp0 = (a[0] | (word32(a[10])<<24)) & 0x80000001; +#else + word32 temp0 = ((word32(a[0])<<24) | a[10]) & 0x01000080; +#endif + temp0 |= permtable[0][a[1]] | + permtable[1][a[2]] | permtable[2][a[3]] | + permtable[3][a[4]] | permtable[4][a[5]] | + permtable[5][a[6]] | permtable[6][a[7]] | + permtable[7][a[8]] | permtable[8][a[9]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp1 = (a[4] | (word32(a[14])<<24)) & 0x80000001; +#else + word32 temp1 = ((word32(a[4])<<24) | a[14]) & 0x01000080; +#endif + temp1 |= permtable[0][a[5]] | + permtable[1][a[6]] | permtable[2][a[7]] | + permtable[3][a[8]] | permtable[4][a[9]] | + permtable[5][a[10]] | permtable[6][a[11]] | + permtable[7][a[12]] | permtable[8][a[13]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp2 = (a[8] | (word32(a[2])<<24)) & 0x80000001; +#else + word32 temp2 = ((word32(a[8])<<24) | a[2]) & 0x01000080; +#endif + temp2 |= permtable[0][a[9]] | + permtable[1][a[10]] | permtable[2][a[11]] | + permtable[3][a[12]] | permtable[4][a[13]] | + permtable[5][a[14]] | permtable[6][a[15]] | + permtable[7][a[0]] | permtable[8][a[1]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp3 = (a[12] | (word32(a[6])<<24)) & 0x80000001; +#else + word32 temp3 = ((word32(a[12])<<24) | a[6]) & 0x01000080; +#endif + ((word32 *)a)[3] = temp3 | permtable[0][a[13]] | + permtable[1][a[14]] | permtable[2][a[15]] | + permtable[3][a[0]] | permtable[4][a[1]] | + permtable[5][a[2]] | permtable[6][a[3]] | + permtable[7][a[4]] | permtable[8][a[5]]; + + ((word32 *)a)[0] = temp0; + ((word32 *)a)[1] = temp1; + ((word32 *)a)[2] = temp2; +} + +inline void Diamond2::Base::ipermute(byte *a) +{ +#ifdef IS_LITTLE_ENDIAN + word32 temp0 = (a[9] | (word32(a[3])<<24)) & 0x01000080; +#else + word32 temp0 = ((word32(a[9])<<24) | a[3]) & 0x80000001; +#endif + temp0 |= ipermtable[0][a[2]] | + ipermtable[1][a[1]] | ipermtable[2][a[0]] | + ipermtable[3][a[15]] | ipermtable[4][a[14]] | + ipermtable[5][a[13]] | ipermtable[6][a[12]] | + ipermtable[7][a[11]] | ipermtable[8][a[10]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp1 = (a[13] | (word32(a[7])<<24)) & 0x01000080; +#else + word32 temp1 = ((word32(a[13])<<24) | a[7]) & 0x80000001; +#endif + temp1 |= ipermtable[0][a[6]] | + ipermtable[1][a[5]] | ipermtable[2][a[4]] | + ipermtable[3][a[3]] | ipermtable[4][a[2]] | + ipermtable[5][a[1]] | ipermtable[6][a[0]] | + ipermtable[7][a[15]] | ipermtable[8][a[14]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp2 = (a[1] | (word32(a[11])<<24)) & 0x01000080; +#else + word32 temp2 = ((word32(a[1])<<24) | a[11]) & 0x80000001; +#endif + temp2 |= ipermtable[0][a[10]] | + ipermtable[1][a[9]] | ipermtable[2][a[8]] | + ipermtable[3][a[7]] | ipermtable[4][a[6]] | + ipermtable[5][a[5]] | ipermtable[6][a[4]] | + ipermtable[7][a[3]] | ipermtable[8][a[2]]; + +#ifdef IS_LITTLE_ENDIAN + word32 temp3 = (a[5] | (word32(a[15])<<24)) & 0x01000080; +#else + word32 temp3 = ((word32(a[5])<<24) | a[15]) & 0x80000001; +#endif + ((word32 *)a)[3] = temp3 | ipermtable[0][a[14]] | + ipermtable[1][a[13]] | ipermtable[2][a[12]] | + ipermtable[3][a[11]] | ipermtable[4][a[10]] | + ipermtable[5][a[9]] | ipermtable[6][a[8]] | + ipermtable[7][a[7]] | ipermtable[8][a[6]]; + + ((word32 *)a)[0] = temp0; + ((word32 *)a)[1] = temp1; + ((word32 *)a)[2] = temp2; +} + +#else // DIAMOND_USE_PERMTABLE + +inline void Diamond2::Base::permute(byte *x) +{ + byte y[16]; + + y[0] = (x[0] & 1) | (x[1] & 2) | (x[2] & 4) | + (x[3] & 8) | (x[4] & 16) | (x[5] & 32) | + (x[6] & 64) | (x[7] & 128); + y[1] = (x[1] & 1) | (x[2] & 2) | (x[3] & 4) | + (x[4] & 8) | (x[5] & 16) | (x[6] & 32) | + (x[7] & 64) | (x[8] & 128); + y[2] = (x[2] & 1) | (x[3] & 2) | (x[4] & 4) | + (x[5] & 8) | (x[6] & 16) | (x[7] & 32) | + (x[8] & 64) | (x[9] & 128); + y[3] = (x[3] & 1) | (x[4] & 2) | (x[5] & 4) | + (x[6] & 8) | (x[7] & 16) | (x[8] & 32) | + (x[9] & 64) | (x[10] & 128); + y[4] = (x[4] & 1) | (x[5] & 2) | (x[6] & 4) | + (x[7] & 8) | (x[8] & 16) | (x[9] & 32) | + (x[10] & 64) | (x[11] & 128); + y[5] = (x[5] & 1) | (x[6] & 2) | (x[7] & 4) | + (x[8] & 8) | (x[9] & 16) | (x[10] & 32) | + (x[11] & 64) | (x[12] & 128); + y[6] = (x[6] & 1) | (x[7] & 2) | (x[8] & 4) | + (x[9] & 8) | (x[10] & 16) | (x[11] & 32) | + (x[12] & 64) | (x[13] & 128); + y[7] = (x[7] & 1) | (x[8] & 2) | (x[9] & 4) | + (x[10] & 8) | (x[11] & 16) | (x[12] & 32) | + (x[13] & 64) | (x[14] & 128); + y[8] = (x[8] & 1) | (x[9] & 2) | (x[10] & 4) | + (x[11] & 8) | (x[12] & 16) | (x[13] & 32) | + (x[14] & 64) | (x[15] & 128); + y[9] = (x[9] & 1) | (x[10] & 2) | (x[11] & 4) | + (x[12] & 8) | (x[13] & 16) | (x[14] & 32) | + (x[15] & 64) | (x[0] & 128); + y[10] = (x[10] & 1) | (x[11] & 2) | (x[12] & 4) | + (x[13] & 8) | (x[14] & 16) | (x[15] & 32) | + (x[0] & 64) | (x[1] & 128); + y[11] = (x[11] & 1) | (x[12] & 2) | (x[13] & 4) | + (x[14] & 8) | (x[15] & 16) | (x[0] & 32) | + (x[1] & 64) | (x[2] & 128); + y[12] = (x[12] & 1) | (x[13] & 2) | (x[14] & 4) | + (x[15] & 8) | (x[0] & 16) | (x[1] & 32) | + (x[2] & 64) | (x[3] & 128); + y[13] = (x[13] & 1) | (x[14] & 2) | (x[15] & 4) | + (x[0] & 8) | (x[1] & 16) | (x[2] & 32) | + (x[3] & 64) | (x[4] & 128); + y[14] = (x[14] & 1) | (x[15] & 2) | (x[0] & 4) | + (x[1] & 8) | (x[2] & 16) | (x[3] & 32) | + (x[4] & 64) | (x[5] & 128); + y[15] = (x[15] & 1) | (x[0] & 2) | (x[1] & 4) | + (x[2] & 8) | (x[3] & 16) | (x[4] & 32) | + (x[5] & 64) | (x[6] & 128); + + memcpy(x, y, 16); +} + +inline void Diamond2::Base::ipermute(byte *x) +{ + byte y[16]; + + y[0] = (x[0] & 1) | (x[15] & 2) | (x[14] & 4) | + (x[13] & 8) | (x[12] & 16) | (x[11] & 32) | + (x[10] & 64) | (x[9] & 128); + y[1] = (x[1] & 1) | (x[0] & 2) | (x[15] & 4) | + (x[14] & 8) | (x[13] & 16) | (x[12] & 32) | + (x[11] & 64) | (x[10] & 128); + y[2] = (x[2] & 1) | (x[1] & 2) | (x[0] & 4) | + (x[15] & 8) | (x[14] & 16) | (x[13] & 32) | + (x[12] & 64) | (x[11] & 128); + y[3] = (x[3] & 1) | (x[2] & 2) | (x[1] & 4) | + (x[0] & 8) | (x[15] & 16) | (x[14] & 32) | + (x[13] & 64) | (x[12] & 128); + y[4] = (x[4] & 1) | (x[3] & 2) | (x[2] & 4) | + (x[1] & 8) | (x[0] & 16) | (x[15] & 32) | + (x[14] & 64) | (x[13] & 128); + y[5] = (x[5] & 1) | (x[4] & 2) | (x[3] & 4) | + (x[2] & 8) | (x[1] & 16) | (x[0] & 32) | + (x[15] & 64) | (x[14] & 128); + y[6] = (x[6] & 1) | (x[5] & 2) | (x[4] & 4) | + (x[3] & 8) | (x[2] & 16) | (x[1] & 32) | + (x[0] & 64) | (x[15] & 128); + y[7] = (x[7] & 1) | (x[6] & 2) | (x[5] & 4) | + (x[4] & 8) | (x[3] & 16) | (x[2] & 32) | + (x[1] & 64) | (x[0] & 128); + y[8] = (x[8] & 1) | (x[7] & 2) | (x[6] & 4) | + (x[5] & 8) | (x[4] & 16) | (x[3] & 32) | + (x[2] & 64) | (x[1] & 128); + y[9] = (x[9] & 1) | (x[8] & 2) | (x[7] & 4) | + (x[6] & 8) | (x[5] & 16) | (x[4] & 32) | + (x[3] & 64) | (x[2] & 128); + y[10] = (x[10] & 1) | (x[9] & 2) | (x[8] & 4) | + (x[7] & 8) | (x[6] & 16) | (x[5] & 32) | + (x[4] & 64) | (x[3] & 128); + y[11] = (x[11] & 1) | (x[10] & 2) | (x[9] & 4) | + (x[8] & 8) | (x[7] & 16) | (x[6] & 32) | + (x[5] & 64) | (x[4] & 128); + y[12] = (x[12] & 1) | (x[11] & 2) | (x[10] & 4) | + (x[9] & 8) | (x[8] & 16) | (x[7] & 32) | + (x[6] & 64) | (x[5] & 128); + y[13] = (x[13] & 1) | (x[12] & 2) | (x[11] & 4) | + (x[10] & 8) | (x[9] & 16) | (x[8] & 32) | + (x[7] & 64) | (x[6] & 128); + y[14] = (x[14] & 1) | (x[13] & 2) | (x[12] & 4) | + (x[11] & 8) | (x[10] & 16) | (x[9] & 32) | + (x[8] & 64) | (x[7] & 128); + y[15] = (x[15] & 1) | (x[14] & 2) | (x[13] & 4) | + (x[12] & 8) | (x[11] & 16) | (x[10] & 32) | + (x[9] & 64) | (x[8] & 128); + + memcpy(x, y, 16); +} + +#endif // DIAMOND_USE_PERMTABLE + +void Diamond2::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const byte *x = inBlock; + byte y[16]; + + substitute(0, y, x); + for (int round=1; round < numrounds; round++) + { + permute(y); + substitute(round, y, y); + } + + if (xorBlock) + xorbuf(outBlock, xorBlock, y, BLOCKSIZE); + else + memcpy(outBlock, y, BLOCKSIZE); +} + +void Diamond2::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const byte *x = inBlock; + byte y[16]; + + substitute(numrounds-1, y, x); + for (int round=numrounds-2; round >= 0; round--) + { + ipermute(y); + substitute(round, y, y); + } + + if (xorBlock) + xorbuf(outBlock, xorBlock, y, BLOCKSIZE); + else + memcpy(outBlock, y, BLOCKSIZE); +} + +void Diamond2Lite::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds) +{ + AssertValidKeyLength(length); + + numrounds = rounds; + s.New(numrounds * ROUNDSIZE); + + Diamond2SboxMaker m(userKey, length, rounds, true); + m.MakeSbox(s, direction); +} + +inline void Diamond2Lite::Base::substitute(int round, byte *x, const byte *y) const +{ + const byte *sbox = s + (ROUNDSIZE*round); + x[0] = sbox[0*256+y[0]]; + x[1] = sbox[1*256+y[1]]; + x[2] = sbox[2*256+y[2]]; + x[3] = sbox[3*256+y[3]]; + x[4] = sbox[4*256+y[4]]; + x[5] = sbox[5*256+y[5]]; + x[6] = sbox[6*256+y[6]]; + x[7] = sbox[7*256+y[7]]; +} + +#ifdef DIAMOND_USE_PERMTABLE + +inline void Diamond2Lite::Base::permute(byte *a) +{ + word32 temp = permtable[0][a[0]] | permtable[1][a[1]] | + permtable[2][a[2]] | permtable[3][a[3]] | + permtable[4][a[4]] | permtable[5][a[5]] | + permtable[6][a[6]] | permtable[7][a[7]]; + + ((word32 *)a)[1] = permtable[0][a[4]] | permtable[1][a[5]] | + permtable[2][a[6]] | permtable[3][a[7]] | + permtable[4][a[0]] | permtable[5][a[1]] | + permtable[6][a[2]] | permtable[7][a[3]]; + + ((word32 *)a)[0] = temp; +} + +inline void Diamond2Lite::Base::ipermute(byte *a) +{ + word32 temp = ipermtable[0][a[0]] | ipermtable[1][a[1]] | + ipermtable[2][a[2]] | ipermtable[3][a[3]] | + ipermtable[4][a[4]] | ipermtable[5][a[5]] | + ipermtable[6][a[6]] | ipermtable[7][a[7]]; + + ((word32 *)a)[1] = ipermtable[0][a[4]] | ipermtable[1][a[5]] | + ipermtable[2][a[6]] | ipermtable[3][a[7]] | + ipermtable[4][a[0]] | ipermtable[5][a[1]] | + ipermtable[6][a[2]] | ipermtable[7][a[3]]; + + ((word32 *)a)[0] = temp; +} + +#else + +inline void Diamond2Lite::Base::permute(byte *a) +{ + byte b[8]; + + b[0] = (a[0] & 1) + (a[1] & 2) + (a[2] & 4) + (a[3] & 8) + (a[4] & 0x10) + + (a[5] & 0x20) + (a[6] & 0x40) + (a[7] & 0x80); + b[1] = (a[1] & 1) + (a[2] & 2) + (a[3] & 4) + (a[4] & 8) + (a[5] & 0x10) + + (a[6] & 0x20) + (a[7] & 0x40) + (a[0] & 0x80); + b[2] = (a[2] & 1) + (a[3] & 2) + (a[4] & 4) + (a[5] & 8) + (a[6] & 0x10) + + (a[7] & 0x20) + (a[0] & 0x40) + (a[1] & 0x80); + b[3] = (a[3] & 1) + (a[4] & 2) + (a[5] & 4) + (a[6] & 8) + (a[7] & 0x10) + + (a[0] & 0x20) + (a[1] & 0x40) + (a[2] & 0x80); + b[4] = (a[4] & 1) + (a[5] & 2) + (a[6] & 4) + (a[7] & 8) + (a[0] & 0x10) + + (a[1] & 0x20) + (a[2] & 0x40) + (a[3] & 0x80); + b[5] = (a[5] & 1) + (a[6] & 2) + (a[7] & 4) + (a[0] & 8) + (a[1] & 0x10) + + (a[2] & 0x20) + (a[3] & 0x40) + (a[4] & 0x80); + b[6] = (a[6] & 1) + (a[7] & 2) + (a[0] & 4) + (a[1] & 8) + (a[2] & 0x10) + + (a[3] & 0x20) + (a[4] & 0x40) + (a[5] & 0x80); + b[7] = (a[7] & 1) + (a[0] & 2) + (a[1] & 4) + (a[2] & 8) + (a[3] & 0x10) + + (a[4] & 0x20) + (a[5] & 0x40) + (a[6] & 0x80); + + memcpy(a, b, 8); +} + +inline void Diamond2Lite::Base::ipermute(byte *b) +{ + byte a[8]; + + a[0] = (b[0] & 1) + (b[7] & 2) + (b[6] & 4) + (b[5] & 8) + (b[4] & 0x10) + + (b[3] & 0x20) + (b[2] & 0x40) + (b[1] & 0x80); + a[1] = (b[1] & 1) + (b[0] & 2) + (b[7] & 4) + (b[6] & 8) + (b[5] & 0x10) + + (b[4] & 0x20) + (b[3] & 0x40) + (b[2] & 0x80); + a[2] = (b[2] & 1) + (b[1] & 2) + (b[0] & 4) + (b[7] & 8) + (b[6] & 0x10) + + (b[5] & 0x20) + (b[4] & 0x40) + (b[3] & 0x80); + a[3] = (b[3] & 1) + (b[2] & 2) + (b[1] & 4) + (b[0] & 8) + (b[7] & 0x10) + + (b[6] & 0x20) + (b[5] & 0x40) + (b[4] & 0x80); + a[4] = (b[4] & 1) + (b[3] & 2) + (b[2] & 4) + (b[1] & 8) + (b[0] & 0x10) + + (b[7] & 0x20) + (b[6] & 0x40) + (b[5] & 0x80); + a[5] = (b[5] & 1) + (b[4] & 2) + (b[3] & 4) + (b[2] & 8) + (b[1] & 0x10) + + (b[0] & 0x20) + (b[7] & 0x40) + (b[6] & 0x80); + a[6] = (b[6] & 1) + (b[5] & 2) + (b[4] & 4) + (b[3] & 8) + (b[2] & 0x10) + + (b[1] & 0x20) + (b[0] & 0x40) + (b[7] & 0x80); + a[7] = (b[7] & 1) + (b[6] & 2) + (b[5] & 4) + (b[4] & 8) + (b[3] & 0x10) + + (b[2] & 0x20) + (b[1] & 0x40) + (b[0] & 0x80); + + memcpy(b, a, 8); +} + +#endif // DIAMOND_USE_PERMTABLE + +void Diamond2Lite::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const byte *x = inBlock; + byte y[8]; + + substitute(0, y, x); + for (int round=1; round < numrounds; round++) + { + permute(y); + substitute(round, y, y); + } + + if (xorBlock) + xorbuf(outBlock, xorBlock, y, BLOCKSIZE); + else + memcpy(outBlock, y, BLOCKSIZE); +} + +void Diamond2Lite::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const byte *x = inBlock; + byte y[8]; + + substitute(numrounds-1, y, x); + for (int round=numrounds-2; round >= 0; round--) + { + ipermute(y); + substitute(round, y, y); + } + + if (xorBlock) + xorbuf(outBlock, xorBlock, y, BLOCKSIZE); + else + memcpy(outBlock, y, BLOCKSIZE); +} + +NAMESPACE_END diff --git a/diamond.dat b/diamond.dat new file mode 100644 index 0000000..ae3f064 --- /dev/null +++ b/diamond.dat @@ -0,0 +1,14 @@ +08 1E 20 E834FDB933C502923D92BC9E14368E70D41C66CBDF36155033A66E07E6CC6D8D + 5A8D872D31EEDDE6 2E69544D7723CBA0 +10 0F 20 E834FDB933C502923D92BC9E14368E70D41C66CBDF36155033A66E07E6CC6D8D + 5A8D872D31EEDDE63FC46F6C36456D8E 39B60490AEEF791A29015D74494AAA89 + +08 0B 11 599B02FBD0D321A789EB97B388BF77C663 + 56A25A87D40AB25A 3177400DE74099BB +10 0E 11 599B02FBD0D321A789EB97B388BF77C663 + 56A25A87D40AB25A1DD972A7D154F8A5 081420F230D5A85AB2B55453C43C7967 + +08 0A 08 3361066B2C297543 + 787699FCB627774F 06AD8CDF623D31F7 +10 09 08 3361066B2C297543 + 787699FCB627774FCF0F0D82462D6E7D CEB8B4F88C02DF34ADDAF431E7A7A07C diff --git a/diamond.h b/diamond.h new file mode 100644 index 0000000..1aae696 --- /dev/null +++ b/diamond.h @@ -0,0 +1,109 @@ +#ifndef CRYPTOPP_DIAMOND_H +#define CRYPTOPP_DIAMOND_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Diamond2_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 1, 256>, public VariableRounds<10> +{ + static const char *StaticAlgorithmName() {return "Diamond2";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Diamond2">Diamond2</a> +class Diamond2 : public Diamond2_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Diamond2_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds); + + protected: + enum {ROUNDSIZE=4096}; + inline void substitute(int round, byte *x, const byte *y) const; + + int numrounds; + SecByteBlock s; // Substitution boxes + + static inline void permute(byte *); + static inline void ipermute(byte *); +#ifdef DIAMOND_USE_PERMTABLE + static const word32 permtable[9][256]; + static const word32 ipermtable[9][256]; +#endif + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Diamond2::Encryption Diamond2Encryption; +typedef Diamond2::Decryption Diamond2Decryption; + +struct Diamond2Lite_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 256>, public VariableRounds<8> +{ + static const char *StaticAlgorithmName() {return "Diamond2Lite";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Diamond2">Diamond2Lite</a> +class Diamond2Lite : public Diamond2Lite_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Diamond2Lite_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds); + + protected: + enum {ROUNDSIZE=2048}; + inline void substitute(int round, byte *x, const byte *y) const; + int numrounds; + SecByteBlock s; // Substitution boxes + + static inline void permute(byte *); + static inline void ipermute(byte *); + #ifdef DIAMOND_USE_PERMTABLE + static const word32 permtable[8][256]; + static const word32 ipermtable[8][256]; + #endif + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Diamond2Lite::Encryption Diamond2LiteEncryption; +typedef Diamond2Lite::Decryption Diamond2LiteDecryption; + +NAMESPACE_END + +#endif diff --git a/diamondt.cpp b/diamondt.cpp new file mode 100644 index 0000000..d6277b0 --- /dev/null +++ b/diamondt.cpp @@ -0,0 +1,2270 @@ +#include "pch.h" +#include "diamond.h" + +#ifdef DIAMOND_USE_PERMTABLE + +NAMESPACE_BEGIN(CryptoPP) + +#ifndef IS_LITTLE_ENDIAN +const word32 Diamond2Lite::Base::permtable[8][256] = +{{0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020}, + +{0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040}, + +{0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180}, + +{0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201}, + +{0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402}, + +{0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010}}; +#else +const word32 Diamond2Lite::Base::permtable[8][256] = +{{0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001}, + +{0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102}, + +{0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204}, + +{0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408}, + +{0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810}, + +{0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080}}; +#endif + +#ifndef IS_LITTLE_ENDIAN +const word32 Diamond2Lite::Base::ipermtable[8][256] = +{{0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408}, + +{0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204, +0x80000000,0x80010000,0x80000200,0x80010200,0x80000004,0x80010004,0x80000204,0x80010204}, + +{0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x40000000,0x40000100,0x40000002,0x40000102,0x40000000,0x40000100,0x40000002,0x40000102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x800000,0x800100,0x800002,0x800102,0x800000,0x800100,0x800002,0x800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102, +0x40800000,0x40800100,0x40800002,0x40800102,0x40800000,0x40800100,0x40800002,0x40800102}, + +{0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x1, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001,0x20000000,0x20000001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x400000,0x400001,0x400000,0x400001,0x400000,0x400001,0x400000,0x400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001,0x20400000,0x20400001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x8000,0x8001,0x8000,0x8001,0x8000,0x8001,0x8000,0x8001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001,0x20008000,0x20008001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x408000,0x408001,0x408000,0x408001,0x408000,0x408001,0x408000,0x408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001, +0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001,0x20408000,0x20408001}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040}, + +{0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020}, + +{0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810}}; +#else +const word32 Diamond2Lite::Base::ipermtable[8][256] = +{{0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201}, + +{0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180, +0x80,0x180,0x20080,0x20180,0x4000080,0x4000180,0x4020080,0x4020180}, + +{0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x40,0x10040,0x2000040,0x2010040,0x40,0x10040,0x2000040,0x2010040, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8000,0x18000,0x2008000,0x2018000,0x8000,0x18000,0x2008000,0x2018000, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040, +0x8040,0x18040,0x2008040,0x2018040,0x8040,0x18040,0x2008040,0x2018040}, + +{0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x0,0x1000000,0x0,0x1000000,0x0,0x1000000,0x0,0x1000000, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x20,0x1000020,0x20,0x1000020,0x20,0x1000020,0x20,0x1000020, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000,0x4000,0x1004000, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020,0x4020,0x1004020, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000,0x800000,0x1800000, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020,0x800020,0x1800020, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000,0x804000,0x1804000, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020, +0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020,0x804020,0x1804020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008}, + +{0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804}, + +{0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402}}; +#endif + +#ifndef IS_LITTLE_ENDIAN +const word32 Diamond2::Base::permtable[9][256] = +{{0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000}, + +{0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100}, + +{0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201}, + +{0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402}, + +{0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040}}; +#else +const word32 Diamond2::Base::permtable[9][256] = +{{0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102}, + +{0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204}, + +{0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408}, + +{0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810}, + +{0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000}}; +#endif + +#ifndef IS_LITTLE_ENDIAN +const word32 Diamond2::Base::ipermtable[9][256] = +{{0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102, +0x0,0x100,0x2,0x102,0x0,0x100,0x2,0x102}, + +{0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204, +0x0,0x10000,0x200,0x10200,0x4,0x10004,0x204,0x10204}, + +{0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408, +0x0,0x1000000,0x20000,0x1020000,0x400,0x1000400,0x20400,0x1020400, +0x8,0x1000008,0x20008,0x1020008,0x408,0x1000408,0x20408,0x1020408}, + +{0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810, +0x0,0x0,0x2000000,0x2000000,0x40000,0x40000,0x2040000,0x2040000, +0x800,0x800,0x2000800,0x2000800,0x40800,0x40800,0x2040800,0x2040800, +0x10,0x10,0x2000010,0x2000010,0x40010,0x40010,0x2040010,0x2040010, +0x810,0x810,0x2000810,0x2000810,0x40810,0x40810,0x2040810,0x2040810}, + +{0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020, +0x0,0x0,0x0,0x0,0x4000000,0x4000000,0x4000000,0x4000000, +0x80000,0x80000,0x80000,0x80000,0x4080000,0x4080000,0x4080000,0x4080000, +0x1000,0x1000,0x1000,0x1000,0x4001000,0x4001000,0x4001000,0x4001000, +0x81000,0x81000,0x81000,0x81000,0x4081000,0x4081000,0x4081000,0x4081000, +0x20,0x20,0x20,0x20,0x4000020,0x4000020,0x4000020,0x4000020, +0x80020,0x80020,0x80020,0x80020,0x4080020,0x4080020,0x4080020,0x4080020, +0x1020,0x1020,0x1020,0x1020,0x4001020,0x4001020,0x4001020,0x4001020, +0x81020,0x81020,0x81020,0x81020,0x4081020,0x4081020,0x4081020,0x4081020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000, +0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000, +0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000,0x8100000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000,0x8002000, +0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000,0x102000, +0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000,0x8102000, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040,0x8000040, +0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040,0x100040, +0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040,0x8100040, +0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040,0x2040, +0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040,0x8002040, +0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040,0x102040, +0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040,0x8102040}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000,0x10200000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000,0x10004000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000,0x204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000,0x10204000, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080,0x10000080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080,0x200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080,0x10200080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080,0x4080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080,0x10004080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080,0x204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080, +0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080,0x10204080}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000,0x20400000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000,0x20008000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000,0x408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000, +0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000,0x20408000}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000, +0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000,0x40800000}}; +#else +const word32 Diamond2::Base::ipermtable[9][256] = +{{0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000, +0x0,0x10000,0x2000000,0x2010000,0x0,0x10000,0x2000000,0x2010000}, + +{0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100, +0x0,0x100,0x20000,0x20100,0x4000000,0x4000100,0x4020000,0x4020100}, + +{0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201, +0x0,0x1,0x200,0x201,0x40000,0x40001,0x40200,0x40201, +0x8000000,0x8000001,0x8000200,0x8000201,0x8040000,0x8040001,0x8040200,0x8040201}, + +{0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402, +0x0,0x0,0x2,0x2,0x400,0x400,0x402,0x402, +0x80000,0x80000,0x80002,0x80002,0x80400,0x80400,0x80402,0x80402, +0x10000000,0x10000000,0x10000002,0x10000002,0x10000400,0x10000400,0x10000402,0x10000402, +0x10080000,0x10080000,0x10080002,0x10080002,0x10080400,0x10080400,0x10080402,0x10080402}, + +{0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804, +0x0,0x0,0x0,0x0,0x4,0x4,0x4,0x4, +0x800,0x800,0x800,0x800,0x804,0x804,0x804,0x804, +0x100000,0x100000,0x100000,0x100000,0x100004,0x100004,0x100004,0x100004, +0x100800,0x100800,0x100800,0x100800,0x100804,0x100804,0x100804,0x100804, +0x20000000,0x20000000,0x20000000,0x20000000,0x20000004,0x20000004,0x20000004,0x20000004, +0x20000800,0x20000800,0x20000800,0x20000800,0x20000804,0x20000804,0x20000804,0x20000804, +0x20100000,0x20100000,0x20100000,0x20100000,0x20100004,0x20100004,0x20100004,0x20100004, +0x20100800,0x20100800,0x20100800,0x20100800,0x20100804,0x20100804,0x20100804,0x20100804}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, +0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008, +0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000, +0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008,0x200008, +0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000,0x201000, +0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008,0x201008, +0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000,0x40000000, +0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008,0x40000008, +0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000,0x40001000, +0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008,0x40001008, +0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000,0x40200000, +0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008,0x40200008, +0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000,0x40201000, +0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008,0x40201008}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010,0x2010, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010,0x400010, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000,0x402000, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010,0x402010, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010,0x80000010, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000,0x80002000, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010,0x80002010, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000,0x80400000, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010,0x80400010, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000,0x80402000, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010, +0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010,0x80402010}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020,0x4020, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020,0x800020, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000,0x804000, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020, +0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020,0x804020}, + +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040, +0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040,0x8040}}; +#endif + +NAMESPACE_END + +#endif // DIAMOND_USE_PERMTABLE diff --git a/dlie1024.dat b/dlie1024.dat new file mode 100644 index 0000000..547d494 --- /dev/null +++ b/dlie1024.dat @@ -0,0 +1 @@ +308201A40201003082011706072A8648CE3804013082010A028181008B333697371663F8869E3EC80A414E46BBAFE41F6D40E754A01ADA60FE7D12ACD16DE311C4115293114F6B92A54195909276380F04BCD4ED5CD993ED7F516DF7A752B928E5035E0D3A1A979A1CDE8387734338793C02001D59B662D4FC8F2BF0EABB1F553F9F46F57E74BCABCBA4E458812DB601FCD04609D435317181236B9702818045999B4B9B8B31FC434F1F640520A7235DD7F20FB6A073AA500D6D307F3E895668B6F188E208A94988A7B5C952A0CAC8493B1C07825E6A76AE6CC9F6BFA8B6FBD3A95C947281AF069D0D4BCD0E6F41C3B9A19C3C9E01000EACDB316A7E4795F8755D8FAA9FCFA37ABF3A5E55E5D2722C4096DB00FE682304EA1A98B8C091B5CB02010204818302818045999B4B9B8B31FC434F1F640520A7235DD7F20FB6A073AA500D6D307F3E895668B6F188E208A94988A7B5C952A0CAC8493B1C07825E6A76AE6CC9F6BFA8B6FBD3A95C947281AF069D0D4BCD0E6F41C3B9A19C3C9E01000EACDB316A7E4795F8755D8FAA9FCFA37ABF3A5E2958F40032EF29CB145C7481380458812D62F09287 diff --git a/dlie2048.dat b/dlie2048.dat new file mode 100644 index 0000000..36ab5e2 --- /dev/null +++ b/dlie2048.dat @@ -0,0 +1 @@ +308203280201003082021906072A8648CE3804013082020C0282010100A2D27D91489706E93358E6F57E7F85B986A972EFC2D5F2150B5981AE5C82AF3DCB99EB2B05EBDB4E3F7B7463536AD58AAE4E679E02B580E0A0952E88B3C5CEF73274C0458BD2CB0498E1431DF7EFC570F4D3A58686C498A3A0D404B1F68BDF1961A1160F4099EEC91CED5982B924610ECA12882F74B8CEDB49B5153E68B62ACE0ED93AD8019680CA333EF4B237AE43C1359C46281092A23DDAFFA915F639EDE93001D5D3C5CECF808B1FBC9D1FC941597137A811606DBCF643E73DF844532B540FD7A60566B5C859BC5B56C8CC5591D30E765E45CB33EFDF32322C29A843341AEA6E35348F5749E510783E8DAC70E7A646F6C8FEA25C7465DE8D58041F5CD8F30282010051693EC8A44B837499AC737ABF3FC2DCC354B977E16AF90A85ACC0D72E41579EE5CCF59582F5EDA71FBDBA31A9B56AC5572733CF015AC070504A974459E2E77B993A6022C5E965824C70A18EFBF7E2B87A69D2C343624C51D06A0258FB45EF8CB0D08B07A04CF7648E76ACC15C92308765094417BA5C676DA4DA8A9F345B1567076C9D6C00CB4065199F7A591BD721E09ACE23140849511EED7FD48AFB1CF6F49800EAE9E2E767C0458FDE4E8FE4A0ACB89BD408B036DE7B21F39EFC222995AA07EBD302B35AE42CDE2DAB64662AC8E9873B2F22E599F7EF99191614D4219A0D75371A9A47ABA4F2883C1F46D63873D3237B647F512E3A32EF46AC020FAE6C79020103048201040282010051693EC8A44B837499AC737ABF3FC2DCC354B977E16AF90A85ACC0D72E41579EE5CCF59582F5EDA71FBDBA31A9B56AC5572733CF015AC070504A974459E2E77B993A6022C5E965824C70A18EFBF7E2B87A69D2C343624C51D06A0258FB45EF8CB0D08B07A04CF7648E76ACC15C92308765094417BA5C676DA4DA8A9F345B1567076C9D6C00CB4065199F7A591BD721E09ACE23140849511EED7FD48AFB1CF6F49800EAE9E2E767C0458FDE4E8FE4A0ACB89BD408B036DE7B21F39EFC222995AA07EBD302B35AE42CDE2DAB64662AC8E9873B2F22E599F7EF99191614D4219A0D75371A943DF2A781AEF1E87084B0419C5988BF5EF581798F6CBFAD827CE75642 @@ -0,0 +1,90 @@ +#ifndef CRYPTOPP_DMAC_H +#define CRYPTOPP_DMAC_H + +#include "cbcmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +class DMAC_Base : public SameKeyLengthAs<T>, public MessageAuthenticationCode +{ +public: + static std::string StaticAlgorithmName() {return std::string("DMAC(") + T::StaticAlgorithmName() + ")";} + + enum {DIGESTSIZE=T::BLOCKSIZE}; + + DMAC_Base() {} + + void CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *mac, unsigned int size); + unsigned int DigestSize() const {return DIGESTSIZE;} + +private: + byte *GenerateSubKeys(const byte *key, unsigned int keylength); + + unsigned int m_subkeylength; + SecByteBlock m_subkeys; + CBC_MAC<T> m_mac1; + typename T::Encryption m_f2; + unsigned int m_counter; +}; + +//! DMAC +/*! Based on "CBC MAC for Real-Time Data Sources" by Erez Petrank + and Charles Rackoff. T should be BlockTransformation class. +*/ +template <class T> +class DMAC : public MessageAuthenticationCodeTemplate<DMAC_Base<T> > +{ +public: + DMAC() {} + DMAC(const byte *key, unsigned int length=DMAC_Base<T>::DEFAULT_KEYLENGTH) + {SetKey(key, length);} +}; + +template <class T> +void DMAC_Base<T>::CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_subkeylength = T::StaticGetValidKeyLength(T::BLOCKSIZE); + m_subkeys.resize(2*STDMAX((unsigned int)T::BLOCKSIZE, m_subkeylength)); + m_mac1.SetKey(GenerateSubKeys(key, length), m_subkeylength, params); + m_f2.SetKey(m_subkeys+m_subkeys.size()/2, m_subkeylength, params); + m_counter = 0; + m_subkeys.resize(0); +} + +template <class T> +void DMAC_Base<T>::Update(const byte *input, unsigned int length) +{ + m_mac1.Update(input, length); + m_counter = (m_counter + length) % T::BLOCKSIZE; +} + +template <class T> +void DMAC_Base<T>::TruncatedFinal(byte *mac, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte pad[T::BLOCKSIZE]; + byte padByte = byte(T::BLOCKSIZE-m_counter); + memset(pad, padByte, padByte); + m_mac1.Update(pad, padByte); + m_mac1.TruncatedFinal(mac, size); + m_f2.ProcessBlock(mac); +} + +template <class T> +byte *DMAC_Base<T>::GenerateSubKeys(const byte *key, unsigned int keylength) +{ + typename T::Encryption cipher(key, keylength); + memset(m_subkeys, 0, m_subkeys.size()); + cipher.ProcessBlock(m_subkeys); + m_subkeys[m_subkeys.size()/2 + T::BLOCKSIZE - 1] = 1; + cipher.ProcessBlock(m_subkeys+m_subkeys.size()/2); + return m_subkeys; +} + +NAMESPACE_END + +#endif @@ -0,0 +1,114 @@ +// dsa.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "dsa.h" +#include "nbtheory.h" + +NAMESPACE_BEGIN(CryptoPP) + +unsigned int DSAConvertSignatureFormat(byte *buffer, unsigned int bufferSize, DSASignatureFormat toFormat, const byte *signature, unsigned int signatureLen, DSASignatureFormat fromFormat) +{ + Integer r, s; + StringStore store(signature, signatureLen); + ArraySink sink(buffer, bufferSize); + + switch (fromFormat) + { + case DSA_P1363: + r.Decode(store, signatureLen/2); + s.Decode(store, signatureLen/2); + break; + case DSA_DER: + { + BERSequenceDecoder seq(store); + r.BERDecode(seq); + s.BERDecode(seq); + seq.MessageEnd(); + break; + } + case DSA_OPENPGP: + r.OpenPGPDecode(store); + s.OpenPGPDecode(store); + break; + } + + switch (toFormat) + { + case DSA_P1363: + r.Encode(sink, bufferSize/2); + s.Encode(sink, bufferSize/2); + break; + case DSA_DER: + { + DERSequenceEncoder seq(sink); + r.DEREncode(seq); + s.DEREncode(seq); + seq.MessageEnd(); + break; + } + case DSA_OPENPGP: + r.OpenPGPEncode(sink); + s.OpenPGPEncode(sink); + break; + } + + return sink.TotalPutLength(); +} + +bool DSA::GeneratePrimes(const byte *seedIn, unsigned int g, int &counter, + Integer &p, unsigned int L, Integer &q, bool useInputCounterValue) +{ + assert(g%8 == 0); + + SHA sha; + SecByteBlock seed(seedIn, g/8); + SecByteBlock U(SHA::DIGESTSIZE); + SecByteBlock temp(SHA::DIGESTSIZE); + SecByteBlock W(((L-1)/160+1) * SHA::DIGESTSIZE); + const int n = (L-1) / 160; + const int b = (L-1) % 160; + Integer X; + + sha.CalculateDigest(U, seed, g/8); + + for (int i=g/8-1, carry=true; i>=0 && carry; i--) + carry=!++seed[i]; + + sha.CalculateDigest(temp, seed, g/8); + xorbuf(U, temp, SHA::DIGESTSIZE); + + U[0] |= 0x80; + U[SHA::DIGESTSIZE-1] |= 1; + q.Decode(U, SHA::DIGESTSIZE); + + if (!IsPrime(q)) + return false; + + int counterEnd = useInputCounterValue ? counter+1 : 4096; + + for (int c = 0; c < counterEnd; c++) + { + for (int k=0; k<=n; k++) + { + for (int i=g/8-1, carry=true; i>=0 && carry; i--) + carry=!++seed[i]; + if (!useInputCounterValue || c == counter) + sha.CalculateDigest(W+(n-k)*SHA::DIGESTSIZE, seed, g/8); + } + if (!useInputCounterValue || c == counter) + { + W[SHA::DIGESTSIZE - 1 - b/8] |= 0x80; + X.Decode(W + SHA::DIGESTSIZE - 1 - b/8, L/8); + p = X-((X % (2*q))-1); + + if (p.GetBit(L-1) && IsPrime(p)) + { + counter = c; + return true; + } + } + } + return false; +} + +NAMESPACE_END @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_DSA_H +#define CRYPTOPP_DSA_H + +/** \file +*/ + +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +/*! The DSA signature format used by Crypto++ is as defined by IEEE P1363. + Java uses the DER format, and OpenPGP uses the OpenPGP format. */ +enum DSASignatureFormat {DSA_P1363, DSA_DER, DSA_OPENPGP}; +/** This function converts between these formats, and returns length of signature in the target format. + If toFormat == DSA_P1363, bufferSize must equal publicKey.SignatureLength() */ +unsigned int DSAConvertSignatureFormat(byte *buffer, unsigned int bufferSize, DSASignatureFormat toFormat, + const byte *signature, unsigned int signatureLen, DSASignatureFormat fromFormat); + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + +typedef DSA::Signer DSAPrivateKey; +typedef DSA::Verifier DSAPublicKey; + +const int MIN_DSA_PRIME_LENGTH = DSA::MIN_PRIME_LENGTH; +const int MAX_DSA_PRIME_LENGTH = DSA::MAX_PRIME_LENGTH; +const int DSA_PRIME_LENGTH_MULTIPLE = DSA::PRIME_LENGTH_MULTIPLE; + +bool GenerateDSAPrimes(const byte *seed, unsigned int seedLength, int &counter, Integer &p, unsigned int primeLength, Integer &q) + {return DSA::GeneratePrimes(seed, seedLength, counter, p, primeLength, q);} + +#endif + +NAMESPACE_END + +#endif diff --git a/dsa1024.dat b/dsa1024.dat new file mode 100644 index 0000000..8e59120 --- /dev/null +++ b/dsa1024.dat @@ -0,0 +1 @@ +3082014A0201003082012B06072A8648CE3804013082011E02818100F468699A6F6EBCC0120D3B34C8E007F125EC7D81F763B8D0F33869AE3BD6B9F2ECCC7DF34DF84C0307449E9B85D30D57194BCCEB310F48141914DD13A077AAF9B624A6CBE666BBA1D7EBEA95B5BA6F54417FD5D4E4220C601E071D316A24EA814E8B0122DBF47EE8AEEFD319EBB01DD95683F10DBB4FEB023F8262A07EAEB7FD02150082AD4E034DA6EEACDFDAE68C36F2BAD614F9E53B02818071AAF73361A26081529F7D84078ADAFCA48E031DB54AD57FB1A833ADBD8672328AABAA0C756247998D7A5B10DACA359D231332CE8120B483A784FE07D46EEBFF0D7D374A10691F78653E6DC29E27CCB1B174923960DFE5B959B919B2C3816C19251832AFD8E35D810E598F82877ABF7D40A041565168BD7F0E21E3FE2A8D8C1C0416021426EBA66E846E755169F84A1DA981D86502405DDF
\ No newline at end of file diff --git a/dsa1024b.dat b/dsa1024b.dat new file mode 100644 index 0000000..edfb808 --- /dev/null +++ b/dsa1024b.dat @@ -0,0 +1 @@ +308201B73082012B06072A8648CE3804013082011E02818100F468699A6F6EBCC0120D3B34C8E007F125EC7D81F763B8D0F33869AE3BD6B9F2ECCC7DF34DF84C0307449E9B85D30D57194BCCEB310F48141914DD13A077AAF9B624A6CBE666BBA1D7EBEA95B5BA6F54417FD5D4E4220C601E071D316A24EA814E8B0122DBF47EE8AEEFD319EBB01DD95683F10DBB4FEB023F8262A07EAEB7FD02150082AD4E034DA6EEACDFDAE68C36F2BAD614F9E53B02818071AAF73361A26081529F7D84078ADAFCA48E031DB54AD57FB1A833ADBD8672328AABAA0C756247998D7A5B10DACA359D231332CE8120B483A784FE07D46EEBFF0D7D374A10691F78653E6DC29E27CCB1B174923960DFE5B959B919B2C3816C19251832AFD8E35D810E598F82877ABF7D40A041565168BD7F0E21E3FE2A8D8C1C0381850002818100D30312B7179661DA4691EDE39A71CB961199CD792C50AED6EA7E1A24C53590B6BCD92F26509D3372B2849A17C99C0962FBE4A2606CA37E6DF10244805363450FFAA24A7C274DF0B5D24AE7F31A8319FD2AA6E98AC6E7E3364E7AEDE575A9993609B0DFA387084141EA0B5B2D59B6DE718C0DAB4F86BC59F0DBE8602AED933494
\ No newline at end of file diff --git a/dsa512.dat b/dsa512.dat new file mode 100644 index 0000000..0d63cfd --- /dev/null +++ b/dsa512.dat @@ -0,0 +1 @@ +3081C60201003081A806072A8648CE38040130819C0241008DF2A494492276AA3D25759BB06869CBEAC0D83AFB8D0CF7CBB8324F0D7882E5D0762FC5B7210EAFC2E9ADAC32AB7AAC49693DFBF83724C2EC0736EE31C80291021500C773218C737EC8EE993B4F2DED30F48EDACE915F0240626D027839EA0A13413163A55B4CB500299D5522956CEFCB3BFF10F399CE2C2E71CB9DE5FA24BABF58E5B79521925C9CC42E9F6F464B088CC572AF53E6D78802041602142070B3223DBA372FDE1C0FFC7B2E3B498B260614
\ No newline at end of file diff --git a/ec2n.cpp b/ec2n.cpp new file mode 100644 index 0000000..c6494ef --- /dev/null +++ b/ec2n.cpp @@ -0,0 +1,287 @@ +// ec2n.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "ec2n.h" +#include "asn.h" + +#include "algebra.cpp" +#include "eprecomp.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +EC2N::EC2N(BufferedTransformation &bt) + : m_field(BERDecodeGF2NP(bt)) +{ + BERSequenceDecoder seq(bt); + m_field->BERDecodeElement(seq, m_a); + m_field->BERDecodeElement(seq, m_b); + // skip optional seed + if (!seq.EndReached()) + BERDecodeOctetString(seq, TheBitBucket()); + seq.MessageEnd(); +} + +void EC2N::DEREncode(BufferedTransformation &bt) const +{ + m_field->DEREncode(bt); + DERSequenceEncoder seq(bt); + m_field->DEREncodeElement(seq, m_a); + m_field->DEREncodeElement(seq, m_b); + seq.MessageEnd(); +} + +bool EC2N::DecodePoint(EC2N::Point &P, const byte *encodedPoint, unsigned int encodedPointLen) const +{ + StringStore store(encodedPoint, encodedPointLen); + return DecodePoint(P, store, encodedPointLen); +} + +bool EC2N::DecodePoint(EC2N::Point &P, BufferedTransformation &bt, unsigned int encodedPointLen) const +{ + byte type; + if (encodedPointLen < 1 || !bt.Get(type)) + return false; + + switch (type) + { + case 0: + P.identity = true; + return true; + case 2: + case 3: + { + if (encodedPointLen != EncodedPointSize(true)) + return false; + + P.identity = false; + P.x.Decode(bt, m_field->MaxElementByteLength()); + + if (P.x.IsZero()) + { + P.y = m_field->SquareRoot(m_b); + return true; + } + + FieldElement z = m_field->Square(P.x); + assert(P.x == m_field->SquareRoot(z)); + P.y = m_field->Divide(m_field->Add(m_field->Multiply(z, m_field->Add(P.x, m_a)), m_b), z); + assert(P.x == m_field->Subtract(m_field->Divide(m_field->Subtract(m_field->Multiply(P.y, z), m_b), z), m_a)); + z = m_field->SolveQuadraticEquation(P.y); + assert(m_field->Add(m_field->Square(z), z) == P.y); + z.SetCoefficient(0, type & 1); + + P.y = m_field->Multiply(z, P.x); + return true; + } + case 4: + { + if (encodedPointLen != EncodedPointSize(false)) + return false; + + unsigned int len = m_field->MaxElementByteLength(); + P.identity = false; + P.x.Decode(bt, len); + P.y.Decode(bt, len); + return true; + } + default: + return false; + } +} + +void EC2N::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + if (P.identity) + NullStore().TransferTo(bt, EncodedPointSize(compressed)); + else if (compressed) + { + bt.Put(2 + (!P.x ? 0 : m_field->Divide(P.y, P.x).GetBit(0))); + P.x.Encode(bt, m_field->MaxElementByteLength()); + } + else + { + unsigned int len = m_field->MaxElementByteLength(); + bt.Put(4); // uncompressed + P.x.Encode(bt, len); + P.y.Encode(bt, len); + } +} + +void EC2N::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const +{ + ArraySink sink(encodedPoint, EncodedPointSize(compressed)); + EncodePoint(sink, P, compressed); + assert(sink.TotalPutLength() == EncodedPointSize(compressed)); +} + +EC2N::Point EC2N::BERDecodePoint(BufferedTransformation &bt) const +{ + SecByteBlock str; + BERDecodeOctetString(bt, str); + Point P; + if (!DecodePoint(P, str, str.size())) + BERDecodeError(); + return P; +} + +void EC2N::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + SecByteBlock str(EncodedPointSize(compressed)); + EncodePoint(str, P, compressed); + DEREncodeOctetString(bt, str); +} + +bool EC2N::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = !!m_b; + pass = pass && m_a.CoefficientCount() <= m_field->MaxElementBitLength(); + pass = pass && m_b.CoefficientCount() <= m_field->MaxElementBitLength(); + + if (level >= 1) + pass = pass && m_field->GetModulus().IsIrreducible(); + + return pass; +} + +bool EC2N::VerifyPoint(const Point &P) const +{ + const FieldElement &x = P.x, &y = P.y; + return P.identity || + (x.CoefficientCount() <= m_field->MaxElementBitLength() + && y.CoefficientCount() <= m_field->MaxElementBitLength() + && !(((x+m_a)*x*x+m_b-(x+y)*y)%m_field->GetModulus())); +} + +bool EC2N::Equal(const Point &P, const Point &Q) const +{ + if (P.identity && Q.identity) + return true; + + if (P.identity && !Q.identity) + return false; + + if (!P.identity && Q.identity) + return false; + + return (m_field->Equal(P.x,Q.x) && m_field->Equal(P.y,Q.y)); +} + +const EC2N::Point& EC2N::Identity() const +{ + static const Point zero; + return zero; +} + +const EC2N::Point& EC2N::Inverse(const Point &P) const +{ + if (P.identity) + return P; + else + { + m_R.identity = false; + m_R.y = m_field->Add(P.x, P.y); + m_R.x = P.x; + return m_R; + } +} + +const EC2N::Point& EC2N::Add(const Point &P, const Point &Q) const +{ + if (P.identity) return Q; + if (Q.identity) return P; + if (Equal(P, Q)) return Double(P); + if (m_field->Equal(P.x, Q.x) && m_field->Equal(P.y, m_field->Add(Q.x, Q.y))) return Identity(); + + FieldElement t = m_field->Add(P.y, Q.y); + t = m_field->Divide(t, m_field->Add(P.x, Q.x)); + FieldElement x = m_field->Square(t); + m_field->Accumulate(x, t); + m_field->Accumulate(x, Q.x); + m_field->Accumulate(x, m_a); + m_R.y = m_field->Add(P.y, m_field->Multiply(t, x)); + m_field->Accumulate(x, P.x); + m_field->Accumulate(m_R.y, x); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +const EC2N::Point& EC2N::Double(const Point &P) const +{ + if (P.identity) return P; + if (!m_field->IsUnit(P.x)) return Identity(); + + FieldElement t = m_field->Divide(P.y, P.x); + m_field->Accumulate(t, P.x); + m_R.y = m_field->Square(P.x); + m_R.x = m_field->Square(t); + m_field->Accumulate(m_R.x, t); + m_field->Accumulate(m_R.x, m_a); + m_field->Accumulate(m_R.y, m_field->Multiply(t, m_R.x)); + m_field->Accumulate(m_R.y, m_R.x); + + m_R.identity = false; + return m_R; +} + +// ******************************************************** + +/* +EcPrecomputation<EC2N>& EcPrecomputation<EC2N>::operator=(const EcPrecomputation<EC2N> &rhs) +{ + m_ec = rhs.m_ec; + m_ep = rhs.m_ep; + m_ep.m_group = m_ec.get(); + return *this; +} + +void EcPrecomputation<EC2N>::SetCurveAndBase(const EC2N &ec, const EC2N::Point &base) +{ + m_ec.reset(new EC2N(ec)); + m_ep.SetGroupAndBase(*m_ec, base); +} + +void EcPrecomputation<EC2N>::Precompute(unsigned int maxExpBits, unsigned int storage) +{ + m_ep.Precompute(maxExpBits, storage); +} + +void EcPrecomputation<EC2N>::Load(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1); + m_ep.m_exponentBase.BERDecode(seq); + m_ep.m_windowSize = m_ep.m_exponentBase.BitCount() - 1; + m_ep.m_bases.clear(); + while (!seq.EndReached()) + m_ep.m_bases.push_back(m_ec->BERDecodePoint(seq)); + seq.MessageEnd(); +} + +void EcPrecomputation<EC2N>::Save(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned<word32>(seq, 1); // version + m_ep.m_exponentBase.DEREncode(seq); + for (unsigned i=0; i<m_ep.m_bases.size(); i++) + m_ec->DEREncodePoint(seq, m_ep.m_bases[i]); + seq.MessageEnd(); +} + +EC2N::Point EcPrecomputation<EC2N>::Exponentiate(const Integer &exponent) const +{ + return m_ep.Exponentiate(exponent); +} + +EC2N::Point EcPrecomputation<EC2N>::CascadeExponentiate(const Integer &exponent, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const +{ + return m_ep.CascadeExponentiate(exponent, static_cast<const EcPrecomputation<EC2N> &>(pc2).m_ep, exponent2); +} +*/ + +template class AbstractGroup<EC2N::Point>; +template class DL_FixedBasePrecomputationImpl<EC2N::Point>; + +NAMESPACE_END @@ -0,0 +1,105 @@ +#ifndef CRYPTOPP_EC2N_H +#define CRYPTOPP_EC2N_H + +#include "gf2n.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Elliptic Curve Point +struct EC2NPoint +{ + EC2NPoint() : identity(true) {} + EC2NPoint(const PolynomialMod2 &x, const PolynomialMod2 &y) + : identity(false), x(x), y(y) {} + + bool operator==(const EC2NPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + bool operator< (const EC2NPoint &t) const + {return identity ? !t.identity : (!t.identity && (x<t.x || (x==t.x && y<t.y)));} + + bool identity; + PolynomialMod2 x, y; +}; + +//! Elliptic Curve over GF(2^n) +class EC2N : public AbstractGroup<EC2NPoint> +{ +public: + typedef GF2NP Field; + typedef Field::Element FieldElement; + typedef EC2NPoint Point; + + EC2N() {} + EC2N(const Field &field, const Field::Element &a, const Field::Element &b) + : m_field(field), m_a(a), m_b(b) {} + // construct from BER encoded parameters + // this constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters + EC2N(BufferedTransformation &bt); + + // encode the fields fieldID and curve of the sequence ECParameters + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*m_field->MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, unsigned int len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, unsigned int len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return Integer::Power2(m_field->MaxElementBitLength());} + const Field & GetField() const {return *m_field;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + +private: + clonable_ptr<Field> m_field; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +template <class T> class EcPrecomputation; + +//! . +template<> class EcPrecomputation<EC2N> : public DL_GroupPrecomputation<EC2N::Point> +{ +public: + typedef EC2N EllipticCurve; + + // DL_GroupPrecomputation + const AbstractGroup<Element> & GetGroup() const {return m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec.BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec.DEREncodePoint(bt, v, false);} + + // non-inherited + void SetCurve(const EC2N &ec) {m_ec = ec;} + const EC2N & GetCurve() const {return m_ec;} + +private: + EC2N m_ec; +}; + +NAMESPACE_END + +#endif diff --git a/eccrypto.cpp b/eccrypto.cpp new file mode 100644 index 0000000..28110b7 --- /dev/null +++ b/eccrypto.cpp @@ -0,0 +1,639 @@ +#include "pch.h" +#include "eccrypto.h" +#include "ec2n.h" +#include "ecp.h" +#include "nbtheory.h" +#include "oids.h" +#include "hex.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +static void ECDSA_TestInstantiations() +{ + ECDSA<EC2N>::Signer t1; + ECDSA<EC2N>::Verifier t2(t1); + ECNR<ECP>::Signer t3; + ECNR<ECP>::Verifier t4(t3); + ECIES<ECP>::Encryptor t5; + ECIES<EC2N>::Decryptor t6; + ECDH<ECP>::Domain t7; + ECMQV<ECP>::Domain t8; +} + +// VC60 workaround: complains when these functions are put into an anonymous namespace +static Integer ConvertToInteger(const PolynomialMod2 &x) +{ + unsigned int l = x.ByteCount(); + SecByteBlock temp(l); + x.Encode(temp, l); + return Integer(temp, l); +} + +static inline Integer ConvertToInteger(const Integer &x) +{ + return x; +} + +static bool CheckMOVCondition(const Integer &q, const Integer &r) +{ + Integer t=1; + unsigned int n=q.BitCount(), m=r.BitCount(); + + for (unsigned int i=n; DiscreteLogWorkFactor(i)<m/2; i+=n) + { + t = (t*q)%r; + if (t == 1) + return false; + } + return true; +} + +// ****************************************************************** + +template <class T> struct EcRecommendedParameters; + +template<> struct EcRecommendedParameters<EC2N> +{ + EcRecommendedParameters(const OID &oid, unsigned int t2, unsigned int t3, unsigned int t4, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), t0(0), t1(0), t2(t2), t3(t3), t4(t4), a(a), b(b), g(g), n(n), h(h) {} + EcRecommendedParameters(const OID &oid, unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), t0(t0), t1(t1), t2(t2), t3(t3), t4(t4), a(a), b(b), g(g), n(n), h(h) {} + EC2N *NewEC() const + { + StringSource ssA(a, true, new HexDecoder); + StringSource ssB(b, true, new HexDecoder); + if (t0 == 0) + return new EC2N(GF2NT(t2, t3, t4), EC2N::FieldElement(ssA, ssA.MaxRetrievable()), EC2N::FieldElement(ssB, ssB.MaxRetrievable())); + else + return new EC2N(GF2NPP(t0, t1, t2, t3, t4), EC2N::FieldElement(ssA, ssA.MaxRetrievable()), EC2N::FieldElement(ssB, ssB.MaxRetrievable())); + }; + + OID oid; + unsigned int t0, t1, t2, t3, t4; + const char *a, *b, *g, *n; + unsigned int h; +}; + +template<> struct EcRecommendedParameters<ECP> +{ + EcRecommendedParameters(const OID &oid, const char *p, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), p(p), a(a), b(b), g(g), n(n), h(h) {} + ECP *NewEC() const + { + StringSource ssP(p, true, new HexDecoder); + StringSource ssA(a, true, new HexDecoder); + StringSource ssB(b, true, new HexDecoder); + return new ECP(Integer(ssP, ssP.MaxRetrievable()), ECP::FieldElement(ssA, ssA.MaxRetrievable()), ECP::FieldElement(ssB, ssB.MaxRetrievable())); + }; + + OID oid; + const char *p; + const char *a, *b, *g, *n; + unsigned int h; +}; + +struct OIDLessThan +{ + template <typename T> + inline bool operator()(const EcRecommendedParameters<T>& a, const OID& b) {return a.oid < b;} + template <typename T> + inline bool operator()(const OID& a, const EcRecommendedParameters<T>& b) {return a < b.oid;} +}; + +static void GetRecommendedParameters(const EcRecommendedParameters<EC2N> *&begin, const EcRecommendedParameters<EC2N> *&end) +{ + // this array must be sorted by OID + static const EcRecommendedParameters<EC2N> rec[] = { + EcRecommendedParameters<EC2N>(ASN1::sect163k1(), + 163, 7, 6, 3, 0, + "000000000000000000000000000000000000000001", + "000000000000000000000000000000000000000001", + "0402FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE80289070FB05D38FF58321F2E800536D538CCDAA3D9", + "04000000000000000000020108A2E0CC0D99F8A5EF", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect163r1(), + 163, 7, 6, 3, 0, + "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", + "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", + "040369979697AB43897789566789567F787A7876A65400435EDB42EFAFB2989D51FEFCE3C80988F41FF883", + "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect239k1(), + 239, 158, 0, + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "0429A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", + "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", + 4), + EcRecommendedParameters<EC2N>(ASN1::sect113r1(), + 113, 9, 0, + "003088250CA6E7C7FE649CE85820F7", + "00E8BEE4D3E2260744188BE0E9C723", + "04009D73616F35F4AB1407D73562C10F00A52830277958EE84D1315ED31886", + "0100000000000000D9CCEC8A39E56F", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect113r2(), + 113, 9, 0, + "00689918DBEC7E5A0DD6DFC0AA55C7", + "0095E9A9EC9B297BD4BF36E059184F", + "0401A57A6A7B26CA5EF52FCDB816479700B3ADC94ED1FE674C06E695BABA1D", + "010000000000000108789B2496AF93", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect163r2(), + 163, 7, 6, 3, 0, + "000000000000000000000000000000000000000001", + "020A601907B8C953CA1481EB10512F78744A3205FD", + "0403F0EBA16286A2D57EA0991168D4994637E8343E3600D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", + "040000000000000000000292FE77E70C12A4234C33", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect283k1(), + 283, 12, 7, 5, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000001", + "040503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC245849283601CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", + 4), + EcRecommendedParameters<EC2N>(ASN1::sect283r1(), + 283, 12, 7, 5, 0, + "000000000000000000000000000000000000000000000000000000000000000000000001", + "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", + "0405F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B1205303676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect131r1(), + 131, 8, 3, 2, 0, + "07A11B09A76B562144418FF3FF8C2570B8", + "0217C05610884B63B9C6C7291678F9D341", + "040081BAF91FDF9833C40F9C181343638399078C6E7EA38C001F73C8134B1B4EF9E150", + "0400000000000000023123953A9464B54D", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect131r2(), + 131, 8, 3, 2, 0, + "03E5A88919D7CAFCBF415F07C2176573B2", + "04B8266A46C55657AC734CE38F018F2192", + "040356DCD8F2F95031AD652D23951BB366A80648F06D867940A5366D9E265DE9EB240F", + "0400000000000000016954A233049BA98F", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect193r1(), + 193, 15, 0, + "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", + "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", + "0401F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E10025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", + "01000000000000000000000000C7F34A778F443ACC920EBA49", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect193r2(), + 193, 15, 0, + "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", + "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", + "0400D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", + "010000000000000000000000015AAB561B005413CCD4EE99D5", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect233k1(), + 233, 74, 0, + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "04017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD612601DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", + "8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", + 4), + EcRecommendedParameters<EC2N>(ASN1::sect233r1(), + 233, 74, 0, + "000000000000000000000000000000000000000000000000000000000001", + "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", + "0400FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", + "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect409k1(), + 409, 87, 0, + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "040060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE902374601E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", + 4), + EcRecommendedParameters<EC2N>(ASN1::sect409r1(), + 409, 87, 0, + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", + "04015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A70061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", + "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", + 2), + EcRecommendedParameters<EC2N>(ASN1::sect571k1(), + 571, 10, 5, 2, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "04026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C89720349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", + "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", + 4), + EcRecommendedParameters<EC2N>(ASN1::sect571r1(), + 571, 10, 5, 2, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", + "040303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", + 2), + }; + begin = rec; + end = rec + sizeof(rec)/sizeof(rec[0]); +} + +static void GetRecommendedParameters(const EcRecommendedParameters<ECP> *&begin, const EcRecommendedParameters<ECP> *&end) +{ + // this array must be sorted by OID + static const EcRecommendedParameters<ECP> rec[] = { + EcRecommendedParameters<ECP>(ASN1::secp192r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "04188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + 1), + EcRecommendedParameters<ECP>(ASN1::secp256r1(), + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + 1), + EcRecommendedParameters<ECP>(ASN1::secp112r1(), + "DB7C2ABF62E35E668076BEAD208B", + "DB7C2ABF62E35E668076BEAD2088", + "659EF8BA043916EEDE8911702B22", + "0409487239995A5EE76B55F9C2F098A89CE5AF8724C0A23E0E0FF77500", + "DB7C2ABF62E35E7628DFAC6561C5", + 1), + EcRecommendedParameters<ECP>(ASN1::secp112r2(), + "DB7C2ABF62E35E668076BEAD208B", + "6127C24C05F38A0AAAF65C0EF02C", + "51DEF1815DB5ED74FCC34C85D709", + "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97", + "36DF0AAFD8B8D7597CA10520D04B", + 4), + EcRecommendedParameters<ECP>(ASN1::secp160r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "044A96B5688EF573284664698968C38BB913CBFC8223A628553168947D59DCC912042351377AC5FB32", + "0100000000000000000001F4C8F927AED3CA752257", + 1), + EcRecommendedParameters<ECP>(ASN1::secp160k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0000000000000000000000000000000000000000", + "0000000000000000000000000000000000000007", + "043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE", + "0100000000000000000001B8FA16DFAB9ACA16B6B3", + 1), + EcRecommendedParameters<ECP>(ASN1::secp256k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000007", + "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + 1), + EcRecommendedParameters<ECP>(ASN1::secp128r1(), + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", + "E87579C11079F43DD824993C2CEE5ED3", + "04161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83", + "FFFFFFFE0000000075A30D1B9038A115", + 1), + EcRecommendedParameters<ECP>(ASN1::secp128r2(), + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "D6031998D1B3BBFEBF59CC9BBFF9AEE1", + "5EEEFCA380D02919DC2C6558BB6D8A5D", + "047B6AA5D85E572983E6FB32A7CDEBC14027B6916A894D3AEE7106FE805FC34B44", + "3FFFFFFF7FFFFFFFBE0024720613B5A3", + 4), + EcRecommendedParameters<ECP>(ASN1::secp160r2(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", + "B4E134D3FB59EB8BAB57274904664D5AF50388BA", + "0452DCB034293A117E1F4FF11B30F7199D3144CE6DFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", + "0100000000000000000000351EE786A818F3A1A16B", + 1), + EcRecommendedParameters<ECP>(ASN1::secp192k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", + "000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000003", + "04DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", + 1), + EcRecommendedParameters<ECP>(ASN1::secp224k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", + "00000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000005", + "04A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", + "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", + 1), + EcRecommendedParameters<ECP>(ASN1::secp224r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + 1), + EcRecommendedParameters<ECP>(ASN1::secp384r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + 1), + EcRecommendedParameters<ECP>(ASN1::secp521r1(), + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + 1), + }; + begin = rec; + end = rec + sizeof(rec)/sizeof(rec[0]); +} + +template <class EC> OID DL_GroupParameters_EC<EC>::GetNextRecommendedParametersOID(const OID &oid) +{ + const EcRecommendedParameters<EllipticCurve> *begin, *end; + GetRecommendedParameters(begin, end); + const EcRecommendedParameters<EllipticCurve> *it = std::upper_bound(begin, end, oid, OIDLessThan()); + return (it == end ? OID() : it->oid); +} + +template <class EC> void DL_GroupParameters_EC<EC>::Initialize(const OID &oid) +{ + const EcRecommendedParameters<EllipticCurve> *begin, *end; + GetRecommendedParameters(begin, end); + const EcRecommendedParameters<EllipticCurve> *it = std::lower_bound(begin, end, oid, OIDLessThan()); + if (it == end || it->oid != oid) + throw UnknownOID(); + + const EcRecommendedParameters<EllipticCurve> ¶m = *it; + m_oid = oid; + std::auto_ptr<EllipticCurve> ec(param.NewEC()); + m_groupPrecomputation.SetCurve(*ec); + + StringSource ssG(param.g, true, new HexDecoder); + Element G; + bool result = GetCurve().DecodePoint(G, ssG, ssG.MaxRetrievable()); + SetSubgroupGenerator(G); + assert(result); + + StringSource ssN(param.n, true, new HexDecoder); + m_n.Decode(ssN, ssN.MaxRetrievable()); + m_k = param.h; +} + +template <class EC> +bool DL_GroupParameters_EC<EC>::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (strcmp(name, Name::GroupOID()) == 0) + { + if (m_oid.m_values.empty()) + return false; + + ThrowIfTypeMismatch(name, typeid(OID), valueType); + *reinterpret_cast<OID *>(pValue) = m_oid; + return true; + } + else + return GetValueHelper<DL_GroupParameters<Element> >(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Curve); +} + +template <class EC> +void DL_GroupParameters_EC<EC>::AssignFrom(const NameValuePairs &source) +{ + OID oid; + if (source.GetValue(Name::GroupOID(), oid)) + Initialize(oid); + else + { + EllipticCurve ec; + Point G; + Integer n; + + source.GetRequiredParameter("DL_GroupParameters_EC<EC>", Name::Curve(), ec); + source.GetRequiredParameter("DL_GroupParameters_EC<EC>", Name::SubgroupGenerator(), G); + source.GetRequiredParameter("DL_GroupParameters_EC<EC>", Name::SubgroupOrder(), n); + Integer k = source.GetValueWithDefault(Name::Cofactor(), Integer::Zero()); + + Initialize(ec, G, n, k); + } +} + +template <class EC> +void DL_GroupParameters_EC<EC>::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + try + { + AssignFrom(alg); + } + catch (InvalidArgument &) + { + throw NotImplemented("DL_GroupParameters_EC<EC>: curve generation is not implemented yet"); + } +} + +template <class EC> +void DL_GroupParameters_EC<EC>::BERDecode(BufferedTransformation &bt) +{ + byte b; + if (!bt.Peek(b)) + BERDecodeError(); + if (b == OBJECT_IDENTIFIER) + Initialize(OID(bt)); + else + { + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1); // check version + EllipticCurve ec(seq); + Point G = ec.BERDecodePoint(seq); + Integer n(seq); + Integer k; + bool cofactorPresent = !seq.EndReached(); + if (cofactorPresent) + k.BERDecode(seq); + else + k = Integer::Zero(); + seq.MessageEnd(); + + Initialize(ec, G, n, k); + } +} + +template <class EC> +void DL_GroupParameters_EC<EC>::DEREncode(BufferedTransformation &bt) const +{ + if (m_encodeAsOID && !m_oid.m_values.empty()) + m_oid.DEREncode(bt); + else + { + DERSequenceEncoder seq(bt); + DEREncodeUnsigned<word32>(seq, 1); // version + GetCurve().DEREncode(seq); + GetCurve().DEREncodePoint(seq, GetSubgroupGenerator(), m_compress); + m_n.DEREncode(seq); + if (m_k.NotZero()) + m_k.DEREncode(seq); + seq.MessageEnd(); + } +} + +template <class EC> +Integer DL_GroupParameters_EC<EC>::GetCofactor() const +{ + if (!m_k) + { + Integer q = GetCurve().FieldSize(); + Integer qSqrt = q.SquareRoot(); + m_k = (q+2*qSqrt+1)/m_n; + } + + return m_k; +} + +template <class EC> +Integer DL_GroupParameters_EC<EC>::ConvertElementToInteger(const Element &element) const +{ + return ConvertToInteger(element.x); +}; + +template <class EC> +bool DL_GroupParameters_EC<EC>::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = GetCurve().ValidateParameters(rng, level); + + Integer q = GetCurve().FieldSize(); + pass = pass && m_n!=q; + + if (level >= 2) + { + Integer qSqrt = q.SquareRoot(); + pass = pass && m_n>4*qSqrt; + pass = pass && VerifyPrime(rng, m_n, level-2); + pass = pass && (m_k.IsZero() || m_k == (q+2*qSqrt+1)/m_n); + pass = pass && CheckMOVCondition(q, m_n); + } + + return pass; +} + +template <class EC> +bool DL_GroupParameters_EC<EC>::ValidateElement(unsigned int level, const Element &g, const DL_FixedBasePrecomputation<Element> *gpc) const +{ + bool pass = !IsIdentity(g) && GetCurve().VerifyPoint(g); + if (level >= 1) + { + if (gpc) + pass = pass && gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g; + } + if (level >= 2) + { + const Integer &q = GetSubgroupOrder(); + pass = pass && IsIdentity(gpc ? gpc->Exponentiate(GetGroupPrecomputation(), q) : ExponentiateElement(g, q)); + } + return pass; +} + +template <class EC> +void DL_GroupParameters_EC<EC>::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + GetCurve().SimultaneousMultiply(results, base, exponents, exponentsCount); +} + +template <class EC> +DL_GroupParameters_EC<EC>::Element DL_GroupParameters_EC<EC>::MultiplyElements(const Element &a, const Element &b) const +{ + return GetCurve().Add(a, b); +} + +template <class EC> +DL_GroupParameters_EC<EC>::Element DL_GroupParameters_EC<EC>::CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const +{ + return GetCurve().CascadeMultiply(exponent1, element1, exponent2, element2); +} + +template <class EC> +OID DL_GroupParameters_EC<EC>::GetAlgorithmID() const +{ + return ASN1::id_ecPublicKey(); +} + +// ****************************************************************** + +template <class EC> +void DL_PublicKey_EC<EC>::BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size) +{ + typename EC::Point P; + if (!GetGroupParameters().GetCurve().DecodePoint(P, bt, size)) + BERDecodeError(); + SetPublicElement(P); +} + +template <class EC> +void DL_PublicKey_EC<EC>::DEREncodeKey(BufferedTransformation &bt) const +{ + GetGroupParameters().GetCurve().EncodePoint(bt, GetPublicElement(), GetGroupParameters().GetPointCompression()); +} + +// ****************************************************************** + +template <class EC> +void DL_PrivateKey_EC<EC>::BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1); // check version + + BERGeneralDecoder dec(seq, OCTET_STRING); + if (!dec.IsDefiniteLength()) + BERDecodeError(); + Integer x; + x.Decode(dec, dec.RemainingLength()); + dec.MessageEnd(); + if (!parametersPresent && seq.PeekByte() != (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + BERDecodeError(); + if (!seq.EndReached() && seq.PeekByte() == (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + { + BERGeneralDecoder parameters(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 0); + AccessGroupParameters().BERDecode(parameters); + parameters.MessageEnd(); + } + if (!seq.EndReached()) + { + // skip over the public element + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERGeneralDecoder publicKey(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + BERDecodeBitString(publicKey, subjectPublicKey, unusedBits); + publicKey.MessageEnd(); + Element Q; + if (!(unusedBits == 0 && GetGroupParameters().GetCurve().DecodePoint(Q, subjectPublicKey, subjectPublicKey.size()))) + BERDecodeError(); + } + seq.MessageEnd(); + + SetPrivateExponent(x); +} + +template <class EC> +void DL_PrivateKey_EC<EC>::DEREncodeKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + DEREncodeUnsigned<word32>(privateKey, 1); // version + // SEC 1 ver 1.0 says privateKey (m_d) has the same length as order of the curve + // this will be changed to order of base point in a future version + GetPrivateExponent().DEREncodeAsOctetString(privateKey, GetGroupParameters().GetSubgroupOrder().ByteCount()); + privateKey.MessageEnd(); +} + +// ****************************************************************** + +template class DL_GroupParameters_EC<EC2N>; +template class DL_GroupParameters_EC<ECP>; +template class DL_PublicKey_EC<EC2N>; +template class DL_PublicKey_EC<ECP>; +template class DL_PrivateKey_EC<EC2N>; +template class DL_PrivateKey_EC<ECP>; + +NAMESPACE_END diff --git a/eccrypto.h b/eccrypto.h new file mode 100644 index 0000000..9706b7f --- /dev/null +++ b/eccrypto.h @@ -0,0 +1,253 @@ +#ifndef CRYPTOPP_ECCRYPTO_H +#define CRYPTOPP_ECCRTPTO_H + +/*! \file +*/ + +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "hmac.h" +#include "sha.h" +#include "gfpcrypt.h" +#include "dh.h" +#include "mqv.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> class EcPrecomputation; + +//! Elliptic Curve Parameters +/*! This class corresponds to the ASN.1 sequence of the same name + in ANSI X9.62 (also SEC 1). +*/ +template <class EC> +class DL_GroupParameters_EC : public DL_GroupParametersImpl<EcPrecomputation<EC> > +{ + typedef DL_GroupParameters_EC<EC> ThisClass; + +public: + typedef EC EllipticCurve; + typedef typename EllipticCurve::Point Point; + typedef Point Element; + typedef IncompatibleCofactorMultiplication DefaultCofactorOption; + + DL_GroupParameters_EC() : m_compress(false), m_encodeAsOID(false) {} + DL_GroupParameters_EC(const OID &oid) + : m_compress(false), m_encodeAsOID(false) {Initialize(oid);} + DL_GroupParameters_EC(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + : m_compress(false), m_encodeAsOID(false) {Initialize(ec, G, n, k);} + DL_GroupParameters_EC(BufferedTransformation &bt) + : m_compress(false), m_encodeAsOID(false) {BERDecode(bt);} + + void Initialize(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + { + m_groupPrecomputation.SetCurve(ec); + SetSubgroupGenerator(G); + m_n = n; + m_k = k; + } + void Initialize(const OID &oid); + + // NameValuePairs + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GeneratibleCryptoMaterial interface + //! this implementation doesn't actually generate a curve, it just initializes the parameters with existing values + /*! parameters: (Curve, SubgroupGenerator, SubgroupOrder, Cofactor (optional)), or (GroupOID) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // DL_GroupParameters + const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const {return m_gpc;} + DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() {return m_gpc;} + const Integer & GetSubgroupOrder() const {return m_n;} + Integer GetCofactor() const; + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation<Element> *precomp) const; + bool FastSubgroupCheckAvailable() const {return false;} + void EncodeElement(bool reversible, const Element &element, byte *encoded) const + { + if (reversible) + GetCurve().EncodePoint(encoded, element, m_compress); + else + element.x.Encode(encoded, GetEncodedElementSize(false)); + } + unsigned int GetEncodedElementSize(bool reversible) const + { + if (reversible) + return GetCurve().EncodedPointSize(m_compress); + else + return GetCurve().GetField().MaxElementByteLength(); + } + Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const + { + Point result; + if (!GetCurve().DecodePoint(result, encoded, GetEncodedElementSize(true))) + throw DL_BadElement(); + if (checkForGroupMembership && !ValidateElement(1, result, NULL)) + throw DL_BadElement(); + return result; + } + Integer ConvertElementToInteger(const Element &element) const; + Integer GetMaxExponent() const {return GetSubgroupOrder()-1;} + bool IsIdentity(const Element &element) const {return element.identity;} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + // ASN1Key + OID GetAlgorithmID() const; + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + + // non-inherited + + // enumerate OIDs for recommended parameters, use OID() to get first one + static OID GetNextRecommendedParametersOID(const OID &oid); + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void SetPointCompression(bool compress) {m_compress = compress;} + bool GetPointCompression() const {return m_compress;} + + void SetEncodeAsOID(bool encodeAsOID) {m_encodeAsOID = encodeAsOID;} + bool GetEncodeAsOID() const {return m_encodeAsOID;} + + const EllipticCurve& GetCurve() const {return m_groupPrecomputation.GetCurve();} + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY + const Point& GetBasePoint() const {return GetSubgroupGenerator();} + const Integer& GetBasePointOrder() const {return GetSubgroupOrder();} + void LoadRecommendedParameters(const OID &oid) {Initialize(oid);} +#endif + +protected: + unsigned int FieldElementLength() const {return GetCurve().GetField().MaxElementByteLength();} + unsigned int ExponentLength() const {return m_n.ByteCount();} + + OID m_oid; // set if parameters loaded from a recommended curve + Integer m_n; // order of base point + bool m_compress, m_encodeAsOID; + mutable Integer m_k; // cofactor +}; + +//! . +template <class EC> +class DL_PublicKey_EC : public DL_PublicKeyImpl<DL_GroupParameters_EC<EC> > +{ +public: + typedef typename EC::Point Element; + + void Initialize(const DL_GroupParameters_EC<EC> ¶ms, const Element &Q) + {AccessGroupParameters() = params; SetPublicElement(Q);} + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {AccessGroupParameters().Initialize(ec, G, n); SetPublicElement(Q);} + + // X509PublicKey + void BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size); + void DEREncodeKey(BufferedTransformation &bt) const; +}; + +//! . +template <class EC> +class DL_PrivateKey_EC : public DL_PrivateKeyImpl<DL_GroupParameters_EC<EC> > +{ +public: + typedef typename EC::Point Element; + + void Initialize(const DL_GroupParameters_EC<EC> ¶ms, const Integer &x) + {AccessGroupParameters() = params; SetPrivateExponent(x);} + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + {AccessGroupParameters().Initialize(ec, G, n); SetPrivateExponent(x);} + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC<EC> ¶ms) + {GenerateRandom(rng, params);} + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {GenerateRandom(rng, DL_GroupParameters_EC<EC>(ec, G, n));} + + // PKCS8PrivateKey + void BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size); + void DEREncodeKey(BufferedTransformation &bt) const; +}; + +//! Elliptic Curve Diffie-Hellman, AKA <a href="http://www.weidai.com/scan-mirror/ka.html#ECDH">ECDH</a> +template <class EC, class COFACTOR_OPTION = DL_GroupParameters_EC<EC>::DefaultCofactorOption> +struct ECDH +{ + typedef DH_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION> Domain; +}; + +/// Elliptic Curve Menezes-Qu-Vanstone, AKA <a href="http://www.weidai.com/scan-mirror/ka.html#ECMQV">ECMQV</a> +template <class EC, class COFACTOR_OPTION = DL_GroupParameters_EC<EC>::DefaultCofactorOption> +struct ECMQV +{ + typedef MQV_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION> Domain; +}; + +//! . +template <class EC> +struct DL_Keys_EC +{ + typedef DL_PublicKey_EC<EC> PublicKey; + typedef DL_PrivateKey_EC<EC> PrivateKey; +}; + +template <class EC, class H = SHA> +struct ECDSA; + +//! . +template <class EC> +struct DL_Keys_ECDSA +{ + typedef DL_PublicKey_EC<EC> PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC>, ECDSA<EC> > PrivateKey; +}; + +//! . +template <class EC> +class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point> +{ +public: + static const char * StaticAlgorithmName() {return "ECDSA";} +}; + +//! . +template <class EC> +class DL_Algorithm_ECNR : public DL_Algorithm_NR<typename EC::Point> +{ +public: + static const char * StaticAlgorithmName() {return "ECNR";} +}; + +//! <a href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a> +template <class EC, class H> +struct ECDSA : public DL_SSA<DL_Keys_ECDSA<EC>, DL_Algorithm_ECDSA<EC>, H> +{ +}; + +//! ECNR +template <class EC, class H = SHA> +struct ECNR : public DL_SSA<DL_Keys_EC<EC>, DL_Algorithm_ECNR<EC>, H> +{ +}; + +//! Elliptic Curve Integrated Encryption Scheme, AKA <a href="http://www.weidai.com/scan-mirror/ca.html#ECIES">ECIES</a> +/*! Default to (NoCofactorMultiplication and DHAES_MODE = false) for compatibilty with SEC1 and Crypto++ 4.2. + The combination of (IncompatibleCofactorMultiplication and DHAES_MODE = true) is recommended for best + efficiency and security. */ +template <class EC, class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = false> +struct ECIES + : public DL_ES< + DL_Keys_EC<EC>, + DL_KeyAgreementAlgorithm_DH<typename EC::Point, COFACTOR_OPTION>, + DL_KeyDerivationAlgorithm_P1363<typename EC::Point, DHAES_MODE, P1363_KDF2<SHA1> >, + DL_EncryptionAlgorithm_Xor<HMAC<SHA1>, DHAES_MODE>, + ECIES<EC> > +{ + static std::string StaticAlgorithmName() {return "ECIES";} // TODO: fix this after name is standardized +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,477 @@ +// ecp.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "ecp.h" +#include "asn.h" +#include "nbtheory.h" + +#include "algebra.cpp" +#include "eprecomp.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +ANONYMOUS_NAMESPACE_BEGIN +static inline ECP::Point ToMontgomery(const ModularArithmetic &mr, const ECP::Point &P) +{ + return P.identity ? P : ECP::Point(mr.ConvertIn(P.x), mr.ConvertIn(P.y)); +} + +static inline ECP::Point FromMontgomery(const ModularArithmetic &mr, const ECP::Point &P) +{ + return P.identity ? P : ECP::Point(mr.ConvertOut(P.x), mr.ConvertOut(P.y)); +} +NAMESPACE_END + +ECP::ECP(const ECP &ecp, bool convertToMontgomeryRepresentation) +{ + if (convertToMontgomeryRepresentation && !ecp.GetField().IsMontgomeryRepresentation()) + { + m_fieldPtr.reset(new MontgomeryRepresentation(ecp.GetField().GetModulus())); + m_a = GetField().ConvertIn(ecp.m_a); + m_b = GetField().ConvertIn(ecp.m_b); + } + else + operator=(ecp); +} + +ECP::ECP(BufferedTransformation &bt) + : m_fieldPtr(new Field(bt)) +{ + BERSequenceDecoder seq(bt); + GetField().BERDecodeElement(seq, m_a); + GetField().BERDecodeElement(seq, m_b); + // skip optional seed + if (!seq.EndReached()) + BERDecodeOctetString(seq, TheBitBucket()); + seq.MessageEnd(); +} + +void ECP::DEREncode(BufferedTransformation &bt) const +{ + GetField().DEREncode(bt); + DERSequenceEncoder seq(bt); + GetField().DEREncodeElement(seq, m_a); + GetField().DEREncodeElement(seq, m_b); + seq.MessageEnd(); +} + +bool ECP::DecodePoint(ECP::Point &P, const byte *encodedPoint, unsigned int encodedPointLen) const +{ + StringStore store(encodedPoint, encodedPointLen); + return DecodePoint(P, store, encodedPointLen); +} + +bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, unsigned int encodedPointLen) const +{ + byte type; + if (encodedPointLen < 1 || !bt.Get(type)) + return false; + + switch (type) + { + case 0: + P.identity = true; + return true; + case 2: + case 3: + { + if (encodedPointLen != EncodedPointSize(true)) + return false; + + Integer p = FieldSize(); + + P.identity = false; + P.x.Decode(bt, GetField().MaxElementByteLength()); + P.y = ((P.x*P.x+m_a)*P.x+m_b) % p; + + if (Jacobi(P.y, p) !=1) + return false; + + P.y = ModularSquareRoot(P.y, p); + + if ((type & 1) != P.y.GetBit(0)) + P.y = p-P.y; + + return true; + } + case 4: + { + if (encodedPointLen != EncodedPointSize(false)) + return false; + + unsigned int len = GetField().MaxElementByteLength(); + P.identity = false; + P.x.Decode(bt, len); + P.y.Decode(bt, len); + return true; + } + default: + return false; + } +} + +void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + if (P.identity) + NullStore().TransferTo(bt, EncodedPointSize(compressed)); + else if (compressed) + { + bt.Put(2 + P.y.GetBit(0)); + P.x.Encode(bt, GetField().MaxElementByteLength()); + } + else + { + unsigned int len = GetField().MaxElementByteLength(); + bt.Put(4); // uncompressed + P.x.Encode(bt, len); + P.y.Encode(bt, len); + } +} + +void ECP::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const +{ + ArraySink sink(encodedPoint, EncodedPointSize(compressed)); + EncodePoint(sink, P, compressed); + assert(sink.TotalPutLength() == EncodedPointSize(compressed)); +} + +ECP::Point ECP::BERDecodePoint(BufferedTransformation &bt) const +{ + SecByteBlock str; + BERDecodeOctetString(bt, str); + Point P; + if (!DecodePoint(P, str, str.size())) + BERDecodeError(); + return P; +} + +void ECP::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + SecByteBlock str(EncodedPointSize(compressed)); + EncodePoint(str, P, compressed); + DEREncodeOctetString(bt, str); +} + +bool ECP::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const +{ + Integer p = FieldSize(); + + bool pass = p.IsOdd(); + pass = pass && !m_a.IsNegative() && m_a<p && !m_b.IsNegative() && m_b<p; + + if (level >= 1) + pass = pass && ((4*m_a*m_a*m_a+27*m_b*m_b)%p).IsPositive(); + + if (level >= 2) + pass = pass && VerifyPrime(rng, p); + + return pass; +} + +bool ECP::VerifyPoint(const Point &P) const +{ + const FieldElement &x = P.x, &y = P.y; + Integer p = FieldSize(); + return P.identity || + (!x.IsNegative() && x<p && !y.IsNegative() && y<p + && !(((x*x+m_a)*x+m_b-y*y)%p)); +} + +bool ECP::Equal(const Point &P, const Point &Q) const +{ + if (P.identity && Q.identity) + return true; + + if (P.identity && !Q.identity) + return false; + + if (!P.identity && Q.identity) + return false; + + return (GetField().Equal(P.x,Q.x) && GetField().Equal(P.y,Q.y)); +} + +const ECP::Point& ECP::Identity() const +{ + static const Point zero; + return zero; +} + +const ECP::Point& ECP::Inverse(const Point &P) const +{ + if (P.identity) + return P; + else + { + m_R.identity = false; + m_R.x = P.x; + m_R.y = GetField().Inverse(P.y); + return m_R; + } +} + +const ECP::Point& ECP::Add(const Point &P, const Point &Q) const +{ + if (P.identity) return Q; + if (Q.identity) return P; + if (GetField().Equal(P.x, Q.x)) + return GetField().Equal(P.y, Q.y) ? Double(P) : Identity(); + + FieldElement t = GetField().Subtract(Q.y, P.y); + t = GetField().Divide(t, GetField().Subtract(Q.x, P.x)); + FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), Q.x); + m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +const ECP::Point& ECP::Double(const Point &P) const +{ + if (P.identity || P.y==GetField().Identity()) return Identity(); + + FieldElement t = GetField().Square(P.x); + t = GetField().Add(GetField().Add(GetField().Double(t), t), m_a); + t = GetField().Divide(t, GetField().Double(P.y)); + FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), P.x); + m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +template <class T, class Iterator> void ParallelInvert(const AbstractRing<T> &ring, Iterator begin, Iterator end) +{ + unsigned int n = end-begin; + if (n == 1) + *begin = ring.MultiplicativeInverse(*begin); + else if (n > 1) + { + std::vector<T> vec((n+1)/2); + unsigned int i; + Iterator it; + + for (i=0, it=begin; i<n/2; i++, it+=2) + vec[i] = ring.Multiply(*it, *(it+1)); + if (n%2 == 1) + vec[n/2] = *it; + + ParallelInvert(ring, vec.begin(), vec.end()); + + for (i=0, it=begin; i<n/2; i++, it+=2) + { + if (!vec[i]) + { + *it = ring.MultiplicativeInverse(*it); + *(it+1) = ring.MultiplicativeInverse(*(it+1)); + } + else + { + std::swap(*it, *(it+1)); + *it = ring.Multiply(*it, vec[i]); + *(it+1) = ring.Multiply(*(it+1), vec[i]); + } + } + if (n%2 == 1) + *it = vec[n/2]; + } +} + +struct ProjectivePoint +{ + ProjectivePoint() {} + ProjectivePoint(const Integer &x, const Integer &y, const Integer &z) + : x(x), y(y), z(z) {} + + Integer x,y,z; +}; + +class ProjectiveDoubling +{ +public: + ProjectiveDoubling(const ModularArithmetic &mr, const Integer &m_a, const Integer &m_b, const ECPPoint &Q) + : mr(mr), firstDoubling(true), negated(false) + { + if (Q.identity) + { + sixteenY4 = P.x = P.y = mr.MultiplicativeIdentity(); + aZ4 = P.z = mr.Identity(); + } + else + { + P.x = Q.x; + P.y = Q.y; + sixteenY4 = P.z = mr.MultiplicativeIdentity(); + aZ4 = m_a; + } + } + + void Double() + { + twoY = mr.Double(P.y); + P.z = mr.Multiply(P.z, twoY); + fourY2 = mr.Square(twoY); + S = mr.Multiply(fourY2, P.x); + aZ4 = mr.Multiply(aZ4, sixteenY4); + M = mr.Square(P.x); + M = mr.Add(mr.Add(mr.Double(M), M), aZ4); + P.x = mr.Square(M); + mr.Reduce(P.x, S); + mr.Reduce(P.x, S); + mr.Reduce(S, P.x); + P.y = mr.Multiply(M, S); + sixteenY4 = mr.Square(fourY2); + mr.Reduce(P.y, mr.Half(sixteenY4)); + } + + const ModularArithmetic &mr; + ProjectivePoint P; + bool firstDoubling, negated; + Integer sixteenY4, aZ4, twoY, fourY2, S, M; +}; + +struct ZIterator +{ + ZIterator() {} + ZIterator(std::vector<ProjectivePoint>::iterator it) : it(it) {} + Integer& operator*() {return it->z;} + int operator-(ZIterator it2) {return it-it2.it;} + ZIterator operator+(int i) {return ZIterator(it+i);} + ZIterator& operator+=(int i) {it+=i; return *this;} + std::vector<ProjectivePoint>::iterator it; +}; + +ECP::Point ECP::ScalarMultiply(const Point &P, const Integer &k) const +{ + Element result; + if (k.BitCount() <= 5) + AbstractGroup<ECPPoint>::SimultaneousMultiply(&result, P, &k, 1); + else + ECP::SimultaneousMultiply(&result, P, &k, 1); + return result; +} + +void ECP::SimultaneousMultiply(ECP::Point *results, const ECP::Point &P, const Integer *expBegin, unsigned int expCount) const +{ + if (!GetField().IsMontgomeryRepresentation()) + { + ECP ecpmr(*this, true); + const ModularArithmetic &mr = ecpmr.GetField(); + ecpmr.SimultaneousMultiply(results, ToMontgomery(mr, P), expBegin, expCount); + for (unsigned int i=0; i<expCount; i++) + results[i] = FromMontgomery(mr, results[i]); + return; + } + + ProjectiveDoubling rd(GetField(), m_a, m_b, P); + std::vector<ProjectivePoint> bases; + std::vector<WindowSlider> exponents; + exponents.reserve(expCount); + std::vector<std::vector<unsigned int> > baseIndices(expCount); + std::vector<std::vector<bool> > negateBase(expCount); + std::vector<std::vector<unsigned int> > exponentWindows(expCount); + unsigned int i; + + for (i=0; i<expCount; i++) + { + assert(expBegin->NotNegative()); + exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 5)); + exponents[i].FindNextWindow(); + } + + unsigned int expBitPosition = 0; + bool notDone = true; + + while (notDone) + { + notDone = false; + bool baseAdded = false; + for (i=0; i<expCount; i++) + { + if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin) + { + if (!baseAdded) + { + bases.push_back(rd.P); + baseAdded =true; + } + + exponentWindows[i].push_back(exponents[i].expWindow); + baseIndices[i].push_back(bases.size()-1); + negateBase[i].push_back(exponents[i].negateNext); + + exponents[i].FindNextWindow(); + } + notDone = notDone || !exponents[i].finished; + } + + if (notDone) + { + rd.Double(); + expBitPosition++; + } + } + + // convert from projective to affine coordinates + ParallelInvert(GetField(), ZIterator(bases.begin()), ZIterator(bases.end())); + for (i=0; i<bases.size(); i++) + { + if (bases[i].z.NotZero()) + { + bases[i].y = GetField().Multiply(bases[i].y, bases[i].z); + bases[i].z = GetField().Square(bases[i].z); + bases[i].x = GetField().Multiply(bases[i].x, bases[i].z); + bases[i].y = GetField().Multiply(bases[i].y, bases[i].z); + } + } + + std::vector<BaseAndExponent<Point, word> > finalCascade; + for (i=0; i<expCount; i++) + { + finalCascade.resize(baseIndices[i].size()); + for (unsigned int j=0; j<baseIndices[i].size(); j++) + { + ProjectivePoint &base = bases[baseIndices[i][j]]; + if (base.z.IsZero()) + finalCascade[j].base.identity = true; + else + { + finalCascade[j].base.identity = false; + finalCascade[j].base.x = base.x; + if (negateBase[i][j]) + finalCascade[j].base.y = GetField().Inverse(base.y); + else + finalCascade[j].base.y = base.y; + } + finalCascade[j].exponent = exponentWindows[i][j]; + } + results[i] = GeneralCascadeMultiplication(*this, finalCascade.begin(), finalCascade.end()); + } +} + +ECP::Point ECP::CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const +{ + if (!GetField().IsMontgomeryRepresentation()) + { + ECP ecpmr(*this, true); + const ModularArithmetic &mr = ecpmr.GetField(); + return FromMontgomery(mr, ecpmr.CascadeScalarMultiply(ToMontgomery(mr, P), k1, ToMontgomery(mr, Q), k2)); + } + else + return AbstractGroup<Point>::CascadeScalarMultiply(P, k1, Q, k2); +} + +// ******************************************************** + +void EcPrecomputation<ECP>::SetCurve(const ECP &ec) +{ + m_ec.reset(new ECP(ec, true)); + m_ecOriginal = ec; +} + +template class AbstractGroup<ECP::Point>; +template class DL_FixedBasePrecomputationImpl<ECP::Point>; + +NAMESPACE_END @@ -0,0 +1,114 @@ +#ifndef CRYPTOPP_ECP_H +#define CRYPTOPP_ECP_H + +#include "modarith.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Elliptical Curve Point +struct ECPPoint +{ + ECPPoint() : identity(true) {} + ECPPoint(const Integer &x, const Integer &y) + : identity(false), x(x), y(y) {} + + bool operator==(const ECPPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + bool operator< (const ECPPoint &t) const + {return identity ? !t.identity : (!t.identity && (x<t.x || (x==t.x && y<t.y)));} + + bool identity; + Integer x, y; +}; + +//! Elliptic Curve over GF(p), where p is prime +class ECP : public AbstractGroup<ECPPoint> +{ +public: + typedef ModularArithmetic Field; + typedef Integer FieldElement; + typedef ECPPoint Point; + + ECP() {} + ECP(const ECP &ecp, bool convertToMontgomeryRepresentation = false); + ECP(const Integer &modulus, const FieldElement &a, const FieldElement &b) + : m_fieldPtr(new Field(modulus)), m_a(a.IsNegative() ? modulus+a : a), m_b(b) {} + // construct from BER encoded parameters + // this constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters + ECP(BufferedTransformation &bt); + + // encode the fields fieldID and curve of the sequence ECParameters + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + Point ScalarMultiply(const Point &P, const Integer &k) const; + Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const; + void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*GetField().MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, unsigned int len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, unsigned int len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return GetField().GetModulus();} + const Field & GetField() const {return *m_fieldPtr;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + +private: + clonable_ptr<Field> m_fieldPtr; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +template <class T> class EcPrecomputation; + +//! . +template<> class EcPrecomputation<ECP> : public DL_GroupPrecomputation<ECP::Point> +{ +public: + typedef ECP EllipticCurve; + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));}; + Element ConvertOut(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));} + const AbstractGroup<Element> & GetGroup() const {return *m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec->BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec->DEREncodePoint(bt, v, false);} + + // non-inherited + void SetCurve(const ECP &ec); + const ECP & GetCurve() const {return *m_ecOriginal;} + +private: + value_ptr<ECP> m_ec, m_ecOriginal; +}; + +NAMESPACE_END + +#endif diff --git a/elgamal.cpp b/elgamal.cpp new file mode 100644 index 0000000..b58fe7c --- /dev/null +++ b/elgamal.cpp @@ -0,0 +1,17 @@ +// elgamal.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "elgamal.h" +#include "asn.h" +#include "nbtheory.h" + +NAMESPACE_BEGIN(CryptoPP) + +void ElGamal_TestInstantiations() +{ + ElGamalEncryptor test1(1, 1, 1); + ElGamalDecryptor test2(NullRNG(), 123); + ElGamalEncryptor test3(test2); +} + +NAMESPACE_END diff --git a/elgamal.h b/elgamal.h new file mode 100644 index 0000000..a2f6ffb --- /dev/null +++ b/elgamal.h @@ -0,0 +1,137 @@ +#ifndef CRYPTOPP_ELGAMAL_H +#define CRYPTOPP_ELGAMAL_H + +#include "modexppc.h" +#include "dsa.h" + +NAMESPACE_BEGIN(CryptoPP) + +class ElGamalBase : public DL_KeyAgreementAlgorithm_DH<Integer, NoCofactorMultiplication>, + public DL_KeyDerivationAlgorithm<Integer>, + public DL_SymmetricEncryptionAlgorithm +{ +public: + void Derive(const DL_GroupParameters<Integer> ¶ms, byte *derivedKey, unsigned int derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey) const + { + agreedElement.Encode(derivedKey, derivedLength); + } + + unsigned int GetSymmetricKeyLength(unsigned int plainTextLength) const + { + return GetGroupParameters().GetModulus().ByteCount(); + } + + unsigned int GetSymmetricCiphertextLength(unsigned int plainTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (plainTextLength <= GetMaxSymmetricPlaintextLength(len)) + return len; + else + return 0; + } + + unsigned int GetMaxSymmetricPlaintextLength(unsigned int cipherTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (cipherTextLength == len) + return STDMIN(255U, len-3); + else + return 0; + } + + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const + { + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + SecByteBlock block(modulusLen-1); + rng.GenerateBlock(block, modulusLen-2-plainTextLength); + memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength); + block[modulusLen-2] = plainTextLength; + + a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen); + } + + DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const + { + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + if (cipherTextLength != modulusLen) + return DecodingResult(); + + Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p); + + m.Encode(plainText, 1); + unsigned int plainTextLength = plainText[0]; + if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen)) + return DecodingResult(); + m >>= 8; + m.Encode(plainText, plainTextLength); + return DecodingResult(plainTextLength); + } + + virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0; +}; + +template <class BASE, class SCHEME_OPTIONS, class KEY> +class ElGamalObjectImpl : public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY>, public ElGamalBase +{ +public: + unsigned int FixedMaxPlaintextLength() const {return MaxPlaintextLength(FixedCiphertextLength());} + unsigned int FixedCiphertextLength() const {return CiphertextLength(0);} + + const DL_GroupParameters_GFP & GetGroupParameters() const {return GetKey().GetGroupParameters();} + + DecodingResult FixedLengthDecrypt(const byte *cipherText, byte *plainText) const + {return Decrypt(cipherText, FixedCiphertextLength(), plainText);} + +protected: + const DL_KeyAgreementAlgorithm<Integer> & GetKeyAgreementAlgorithm() const {return *this;} + const DL_KeyDerivationAlgorithm<Integer> & GetKeyDerivationAlgorithm() const {return *this;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;} +}; + +struct ElGamalKeys +{ + typedef DL_CryptoKeys_GFP::GroupParameters GroupParameters; + typedef DL_PrivateKey_GFP_OldFormat<DL_CryptoKeys_GFP::PrivateKey> PrivateKey; + typedef DL_PublicKey_GFP_OldFormat<DL_CryptoKeys_GFP::PublicKey> PublicKey; +}; + +//! ElGamal encryption scheme with non-standard padding +struct ElGamal +{ + typedef DL_CryptoSchemeOptions<ElGamal, ElGamalKeys, int, int, int> SchemeOptions; + + static const char * StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";} + + class EncryptorImpl : public ElGamalObjectImpl<DL_EncryptorBase<Integer, PK_FixedLengthEncryptor>, SchemeOptions, SchemeOptions::PublicKey>, public PublicKeyCopier<SchemeOptions> + { + public: + void CopyKeyInto(SchemeOptions::PublicKey &key) const + {key = GetKey();} + }; + + class DecryptorImpl : public ElGamalObjectImpl<DL_DecryptorBase<Integer, PK_FixedLengthDecryptor>, SchemeOptions, SchemeOptions::PrivateKey>, public PrivateKeyCopier<SchemeOptions> + { + public: + void CopyKeyInto(SchemeOptions::PublicKey &key) const + {GetKey().MakePublicKey(key);} + void CopyKeyInto(SchemeOptions::PrivateKey &key) const + {key = GetKey();} + }; + + typedef SchemeOptions::GroupParameters GroupParameters; + //! implements PK_Encryptor interface + typedef PK_FinalTemplate<EncryptorImpl> Encryptor; + //! implements PK_Decryptor interface + typedef PK_FinalTemplate<DecryptorImpl> Decryptor; +}; + +typedef ElGamal::Encryptor ElGamalEncryptor; +typedef ElGamal::Decryptor ElGamalDecryptor; + +NAMESPACE_END + +#endif diff --git a/elgc1024.dat b/elgc1024.dat new file mode 100644 index 0000000..37518b6 --- /dev/null +++ b/elgc1024.dat @@ -0,0 +1 @@ +3082018E028181008B333697371663F8869E3EC80A414E46BBAFE41F6D40E754A01ADA60FE7D12ACD16DE311C4115293114F6B92A54195909276380F04BCD4ED5CD993ED7F516DF7A752B928E5035E0D3A1A979A1CDE8387734338793C02001D59B662D4FC8F2BF0EABB1F553F9F46F57E74BCABCBA4E458812DB601FCD04609D435317181236B9702010202818038FBC56751763146BC107ECC59E9BAD3852EBC38799B41B40EF5745810BCF9DCC6D569B7E61063EA358B0DF2A194910029B72A9CFD11AD240681D3F976EDCB18D79C0530AB2944DC1E314C2B520BE23066C802754C19BF2EC15DE0439E2663383CEA5163DC857B6A5F91079F54FB47C9B33F23A9EB6B3FCBA8581524B3EC5C75028181008B333697371663F8869E3EC80A414E46BBAFE41F6D40E754A01ADA60FE7D12ACD16DE311C4115293114F6B92A54195909276380F04BCD4ED5CD993ED7F516DF7A752B928E5035E0D3A1A979A1CDE8387734338793C02001D59B662D4FC8F2BF0EABB1F553F9F46F57E74BC7F3EC6725F2FC0A6155ADCA43CEE7319E623824852
\ No newline at end of file diff --git a/eprecomp.cpp b/eprecomp.cpp new file mode 100644 index 0000000..f9878b9 --- /dev/null +++ b/eprecomp.cpp @@ -0,0 +1,107 @@ +// eprecomp.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "eprecomp.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> void DL_FixedBasePrecomputationImpl<T>::SetBase(const DL_GroupPrecomputation<Element> &group, const Element &i_base) +{ + m_base = group.NeedConversions() ? group.ConvertIn(i_base) : i_base; + + if (m_bases.empty() || !(m_base == m_bases[0])) + { + m_bases.resize(1); + m_bases[0] = m_base; + } + + if (group.NeedConversions()) + m_base = i_base; +} + +template <class T> void DL_FixedBasePrecomputationImpl<T>::Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage) +{ + assert(m_bases.size() > 0); + assert(storage <= maxExpBits); + + if (storage > 1) + { + m_windowSize = (maxExpBits+storage-1)/storage; + m_exponentBase = Integer::Power2(m_windowSize); + } + + m_bases.resize(storage); + for (unsigned i=1; i<storage; i++) + m_bases[i] = group.GetGroup().ScalarMultiply(m_bases[i-1], m_exponentBase); +} + +template <class T> void DL_FixedBasePrecomputationImpl<T>::Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1); + m_exponentBase.BERDecode(seq); + m_windowSize = m_exponentBase.BitCount() - 1; + m_bases.clear(); + while (!seq.EndReached()) + m_bases.push_back(group.BERDecodeElement(seq)); + if (!m_bases.empty() && group.NeedConversions()) + m_base = group.ConvertOut(m_bases[0]); + seq.MessageEnd(); +} + +template <class T> void DL_FixedBasePrecomputationImpl<T>::Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned<word32>(seq, 1); // version + m_exponentBase.DEREncode(seq); + for (unsigned i=0; i<m_bases.size(); i++) + group.DEREncodeElement(seq, m_bases[i]); + seq.MessageEnd(); +} + +template <class T> void DL_FixedBasePrecomputationImpl<T>::PrepareCascade(const DL_GroupPrecomputation<Element> &i_group, std::vector<BaseAndExponent<Element> > &eb, const Integer &exponent) const +{ + const AbstractGroup<T> &group = i_group.GetGroup(); + + Integer r, q, e = exponent; + bool fastNegate = group.InversionIsFast() && m_windowSize > 1; + unsigned int i; + + for (i=0; i+1<m_bases.size(); i++) + { + Integer::DivideByPowerOf2(r, q, e, m_windowSize); + std::swap(q, e); + if (fastNegate && r.GetBit(m_windowSize-1)) + { + ++e; + eb.push_back(BaseAndExponent<Element>(group.Inverse(m_bases[i]), m_exponentBase - r)); + } + else + eb.push_back(BaseAndExponent<Element>(m_bases[i], r)); + } + eb.push_back(BaseAndExponent<Element>(m_bases[i], e)); +} + +template <class T> T DL_FixedBasePrecomputationImpl<T>::Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const +{ + std::vector<BaseAndExponent<Element> > eb; // array of segments of the exponent and precalculated bases + eb.reserve(m_bases.size()); + PrepareCascade(group, eb, exponent); + return group.ConvertOut(GeneralCascadeMultiplication<Element>(group.GetGroup(), eb.begin(), eb.end())); +} + +template <class T> T + DL_FixedBasePrecomputationImpl<T>::CascadeExponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent, + const DL_FixedBasePrecomputation<T> &i_pc2, const Integer &exponent2) const +{ + std::vector<BaseAndExponent<Element> > eb; // array of segments of the exponent and precalculated bases + const DL_FixedBasePrecomputationImpl<T> &pc2 = static_cast<const DL_FixedBasePrecomputationImpl<T> &>(i_pc2); + eb.reserve(m_bases.size() + pc2.m_bases.size()); + PrepareCascade(group, eb, exponent); + pc2.PrepareCascade(group, eb, exponent2); + return group.ConvertOut(GeneralCascadeMultiplication<Element>(group.GetGroup(), eb.begin(), eb.end())); +} + +NAMESPACE_END diff --git a/eprecomp.h b/eprecomp.h new file mode 100644 index 0000000..ae38c9c --- /dev/null +++ b/eprecomp.h @@ -0,0 +1,69 @@ +#ifndef CRYPTOPP_EPRECOMP_H +#define CRYPTOPP_EPRECOMP_H + +#include "integer.h" +#include "algebra.h" +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +class DL_GroupPrecomputation +{ +public: + typedef T Element; + + virtual bool NeedConversions() const {return false;} + virtual Element ConvertIn(const Element &v) const {return v;} + virtual Element ConvertOut(const Element &v) const {return v;} + virtual const AbstractGroup<Element> & GetGroup() const =0; + virtual Element BERDecodeElement(BufferedTransformation &bt) const =0; + virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0; +}; + +template <class T> +class DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual bool IsInitialized() const =0; + virtual void SetBase(const DL_GroupPrecomputation<Element> &group, const Element &base) =0; + virtual const Element & GetBase(const DL_GroupPrecomputation<Element> &group) const =0; + virtual void Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage) =0; + virtual void Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) =0; + virtual void Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) const =0; + virtual Element Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const =0; + virtual Element CascadeExponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const =0; +}; + +template <class T> +class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation<T> +{ +public: + typedef T Element; + + // DL_FixedBasePrecomputation + bool IsInitialized() const + {return !m_bases.empty();} + void SetBase(const DL_GroupPrecomputation<Element> &group, const Element &base); + const Element & GetBase(const DL_GroupPrecomputation<Element> &group) const + {return group.NeedConversions() ? m_base : m_bases[0];} + void Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage); + void Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation); + void Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) const; + Element Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const; + Element CascadeExponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const; + +private: + void PrepareCascade(const DL_GroupPrecomputation<Element> &group, std::vector<BaseAndExponent<Element> > &eb, const Integer &exponent) const; + + Element m_base; + unsigned int m_windowSize; + Integer m_exponentBase; // what base to represent the exponent in + std::vector<Element> m_bases; // precalculated bases +}; + +NAMESPACE_END + +#endif diff --git a/esig1023.dat b/esig1023.dat new file mode 100644 index 0000000..4e43ad4 --- /dev/null +++ b/esig1023.dat @@ -0,0 +1 @@ +3081E00281807040653BA4FCD5C66E3318B31E82654C5A62957F68D2EE6AE10BD6678D7A14EEF8EBF0C85F28FE22056C12B2A2DD4E9C897EB2FF06D57DB03B872C049ED2806DC3E4D86F2947D134065AC642F233F95FBCB55C533274FA91FFDC0CEB9E71B8795B71A977C7956001FC19E28DE18A80B20E4AE8F775B952CEEA0DEFEAE8E93D7F020120022B1EC74E9FC5EEA090E8DDF4BDB64861C7DC3F8EC7E64286EC2FE39DA55B4763C582DB48146521BDEF0146D5022B1E559EB15755298408E4E4C6F4791BF075C7A8C9B3C7F5B7FA3E8C322BA0A160C09A9DB6BBC4974BE0F877
\ No newline at end of file diff --git a/esig1536.dat b/esig1536.dat new file mode 100644 index 0000000..8e10d13 --- /dev/null +++ b/esig1536.dat @@ -0,0 +1 @@ +3082014D0281C100E2A6788AB3CC986AEC06C51690143D3677141645D0628165EE924B9AFB7E6EDD52D90145B2F6031522C7A6CEC05E358F42B7837DACEA589F868F8DCA1C0F5FD8E5EDB8BBBAFCFF6D64CFCFBE68F46FBA6EFF45BC9D0CBB4F7F6075F5FFC2049C2F304B51C417764E18D182926E02D4116CE5C5C010E3D0AA6872A49B0D1FF4B37D54689C31F5821D04E9D4DB34D7536EE7F88B8C481B0EC1F93193A0B70567E6FD76E9FAC4F67BB47DACD356D0C8015261E068DDF8C34C0CAFCF3FA775577FEB020120024100FAF0F292EE96D4F449024F86C0A104E0633C722586EC00AD33E0234629825D2081BA337597889CAC55DC6BEBDD8F13FE3AA2133D6371601A37D195DA7BC45EF3024100EBE16F88887A425AA08E271467CC2220DC44012AB24ED4FF3512A96E8CB600C8BBCB771459FF0EE63D4B6786952A83A7143A775073F0A1D69B6D0B5817755673
\ No newline at end of file diff --git a/esig2046.dat b/esig2046.dat new file mode 100644 index 0000000..1c31854 --- /dev/null +++ b/esig2046.dat @@ -0,0 +1 @@ +308201B70282010028B1F9CDF87EF6D74F3AC2EA83C17CE376215FB2B3B4817145F1A137FB86B0F7BF0F9BA1BDCF7CC15DF1884DD1B150A983279B90F7A1E4392CB3C16390771DA5668E68621C3898DF66BD254F3787ECFB64B3435E707D5C237A6C09F407D8CD618CC3BBFBAB3DEBA38A0D1A88B2A4E09AE32FF2064EF1896348D5B83047EC2E079D85662EED4A66FBB9C159A617EE3C333BAED66989740F54C3CB336C0EF71130786E70648F2698F4F4192DA06C1578FDB065F8E320EFB63049E4BA664F215924B3E89F69131C5987F357C54593BE173A7AED2D37BE69F90CB574EF83AD49145EB15950FADE9E848DA83BC2CACBEDCAFC4A3B31BFFBBFC4DD03B8E47A218A51410201200256033F9C3F8BDDC021503A687BEC90438F38FF9C0E4C050DD95E46BACA370F478B843611A94BC37B5E838AABFD4ECCCE757BAC967DF8A7DD219B3A71A4DA64D54AB367622B7EB9B4282E898755F02036E91D2A12C81F41025603DB3DE2AE2B52889148C98D68F2B7606B0E5112E60E6A6FF5FD98E5D74143C000B43BEC77082F17C1EF4C82127010B12438D498AAFE8521E21EE6391627D464B54D1BE31F57FFF18C27EC38F08093EA65139A61A2C1
\ No newline at end of file diff --git a/esign.cpp b/esign.cpp new file mode 100644 index 0000000..5858830 --- /dev/null +++ b/esign.cpp @@ -0,0 +1,210 @@ +// esign.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "esign.h" +#include "asn.h" +#include "modarith.h" +#include "nbtheory.h" +#include "sha.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +void ESIGN_TestInstantiations() +{ + ESIGN<SHA>::Verifier x1(1, 1); + ESIGN<SHA>::Signer x2(NullRNG(), 1); + ESIGN<SHA>::Verifier x3(x2); + ESIGN<SHA>::Verifier x4(x2.GetKey()); + ESIGN<SHA>::Verifier x5(x3); + ESIGN<SHA>::Signer x6 = x2; + + x6 = x2; + x3 = ESIGN<SHA>::Verifier(x2); + x4 = x2.GetKey(); +} + +void ESIGNFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_e.BERDecode(seq); + seq.MessageEnd(); +} + +void ESIGNFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + seq.MessageEnd(); +} + +Integer ESIGNFunction::ApplyFunction(const Integer &x) const +{ + DoQuickSanityCheck(); + return STDMIN(a_exp_b_mod_c(x, m_e, m_n) >> (2*GetK()+2), MaxImage()); +} + +bool ESIGNFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + pass = pass && m_e >= 8 && m_e < m_n; + return pass; +} + +bool ESIGNFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void ESIGNFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** + +void InvertibleESIGNFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶m) +{ + int modulusSize = 1023*2; + param.GetIntValue("ModulusSize", modulusSize) || param.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 24) + throw InvalidArgument("InvertibleESIGNFunction: specified modulus size is too small"); + + if (modulusSize % 3 != 0) + throw InvalidArgument("InvertibleESIGNFunction: modulus size must be divisible by 3"); + + m_e = param.GetValueWithDefault("PublicExponent", Integer(32)); + + if (m_e < 8) + throw InvalidArgument("InvertibleESIGNFunction: public exponents less than 8 may not be secure"); + + // VC70 workaround: putting these after primeParam causes overlapped stack allocation + ConstByteArrayParameter seedParam; + SecByteBlock seed; + + const Integer minP = Integer(204) << (modulusSize/3-8); + const Integer maxP = Integer::Power2(modulusSize/3)-1; + const NameValuePairs &primeParam = MakeParameters("Min", minP)("Max", maxP)("RandomNumberType", Integer::PRIME); + + if (param.GetValue("Seed", seedParam)) + { + seed.resize(seedParam.size() + 4); + memcpy(seed + 4, seedParam.begin(), seedParam.size()); + + UnalignedPutWord(BIG_ENDIAN_ORDER, seed, (word32)0); + m_p.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("Seed", ConstByteArrayParameter(seed)))); + UnalignedPutWord(BIG_ENDIAN_ORDER, seed, (word32)1); + m_q.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("Seed", ConstByteArrayParameter(seed)))); + } + else + { + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + } + + m_n = m_p * m_p * m_q; + + assert(m_n.BitCount() == modulusSize); +} + +void InvertibleESIGNFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKey(bt); + m_n.BERDecode(privateKey); + m_e.BERDecode(privateKey); + m_p.BERDecode(privateKey); + m_q.BERDecode(privateKey); + privateKey.MessageEnd(); +} + +void InvertibleESIGNFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + m_n.DEREncode(privateKey); + m_e.DEREncode(privateKey); + m_p.DEREncode(privateKey); + m_q.DEREncode(privateKey); + privateKey.MessageEnd(); +} + +Integer InvertibleESIGNFunction::CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + DoQuickSanityCheck(); + + Integer pq = m_p * m_q; + Integer p2 = m_p * m_p; + Integer r, z, re, a, w0, w1; + + do + { + r.Randomize(rng, Integer::Zero(), pq); + z = x << (2*GetK()+2); + re = a_exp_b_mod_c(r, m_e, m_n); + a = (z - re) % m_n; + Integer::Divide(w1, w0, a, pq); + if (w1.NotZero()) + { + ++w0; + w1 = pq - w1; + } + } + while ((w1 >> 2*GetK()+1).IsPositive()); + + ModularArithmetic modp(m_p); + Integer t = modp.Divide(w0 * r % m_p, m_e * re % m_p); + Integer s = r + t*pq; + assert(s < m_n); +/* + using namespace std; + cout << "f = " << x << endl; + cout << "r = " << r << endl; + cout << "z = " << z << endl; + cout << "a = " << a << endl; + cout << "w0 = " << w0 << endl; + cout << "w1 = " << w1 << endl; + cout << "t = " << t << endl; + cout << "s = " << s << endl; +*/ + return s; +} + +bool InvertibleESIGNFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = ESIGNFunction::Validate(rng, level); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + pass = pass && m_p.BitCount() == m_q.BitCount(); + if (level >= 1) + pass = pass && m_p * m_p * m_q == m_n; + if (level >= 2) + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + return pass; +} + +bool InvertibleESIGNFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<ESIGNFunction>(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + ; +} + +void InvertibleESIGNFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper<ESIGNFunction>(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + ; +} + +NAMESPACE_END @@ -0,0 +1,127 @@ +#ifndef CRYPTOPP_ESIGN_H +#define CRYPTOPP_ESIGN_H + +/** \file + This file contains classes that implement the + ESIGN signature schemes as defined in IEEE P1363a. +*/ + +#include "pubkey.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class ESIGNFunction : public TrapdoorFunction, public PublicKey, public ASN1CryptoMaterial +{ + typedef ESIGNFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return Integer::Power2(GetK());} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + unsigned int GetK() const {return m_n.BitCount()/3-1;} + + Integer m_n, m_e; +}; + +//! . +class InvertibleESIGNFunction : public ESIGNFunction, public RandomizedTrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleESIGNFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q) + {m_n = n; m_e = e; m_p = p; m_q = q;} + // generate a random private key + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + +protected: + Integer m_p, m_q; +}; + +//! . +template <class T> +class EMSA5Pad : public PK_NonreversiblePaddingAlgorithm +{ +public: + static const char *StaticAlgorithmName() {return "EMSA5";} + + unsigned int MaxUnpaddedLength(unsigned int paddedLength) const {return UINT_MAX;} + + void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedLength) const + { + unsigned int paddedByteLength = BitsToBytes(paddedLength); + memset(padded, 0, paddedByteLength); + T::GenerateAndMask(padded, paddedByteLength, raw, inputLength); + if (paddedLength % 8 != 0) + padded[0] = (byte)Crop(padded[0], paddedLength % 8); + } +}; + +//! EMSA5, for use with ESIGN +struct P1363_EMSA5 : public SignatureStandard +{ + template <class H> struct SignaturePaddingAlgorithm {typedef EMSA5Pad<P1363_MGF1<H> > type;}; + template <class H> struct DecoratedHashingAlgorithm {typedef H type;}; +}; + +template<> struct CryptoStandardTraits<P1363_EMSA5> : public P1363_EMSA5 {}; + +struct ESIGN_Keys +{ + static std::string StaticAlgorithmName() {return "ESIGN";} + typedef ESIGNFunction PublicKey; + typedef InvertibleESIGNFunction PrivateKey; +}; + +//! ESIGN, as defined in IEEE P1363a +template <class H, class STANDARD = P1363_EMSA5> +struct ESIGN : public TF_SSA<STANDARD, H, ESIGN_Keys> +{ +}; + +NAMESPACE_END + +#endif diff --git a/files.cpp b/files.cpp new file mode 100644 index 0000000..01028c6 --- /dev/null +++ b/files.cpp @@ -0,0 +1,188 @@ +// files.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "files.h" + +NAMESPACE_BEGIN(CryptoPP) + +using namespace std; + +void Files_TestInstantiations() +{ + FileStore f0; + FileSource f1; + FileSink f2; +} + +void FileStore::StoreInitialize(const NameValuePairs ¶meters) +{ + const char *fileName; + if (parameters.GetValue("InputFileName", fileName)) + { + ios::openmode binary = parameters.GetValueWithDefault("InputBinaryMode", true) ? ios::binary : ios::openmode(0); + m_file.open(fileName, ios::in | binary); + if (!m_file) + throw OpenErr(fileName); + m_stream = &m_file; + } + else + { + m_stream = NULL; + parameters.GetValue("InputStreamPointer", m_stream); + } + m_waiting = false; +} + +unsigned long FileStore::MaxRetrievable() const +{ + if (!m_stream) + return 0; + + streampos current = m_stream->tellg(); + streampos end = m_stream->seekg(0, ios::end).tellg(); + m_stream->seekg(current); + return end-current; +} + +unsigned int FileStore::Peek(byte &outByte) const +{ + if (!m_stream) + return 0; + + int result = m_stream->peek(); + if (result == EOF) // GCC workaround: 2.95.2 doesn't have char_traits<char>::eof() + return 0; + else + { + outByte = byte(result); + return 1; + } +} + +unsigned int FileStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + if (!m_stream) + { + transferBytes = 0; + return 0; + } + + unsigned long size=transferBytes; + transferBytes = 0; + + if (m_waiting) + goto output; + + while (size && m_stream->good()) + { + { + unsigned int spaceSize = 1024; + m_space = HelpCreatePutSpace(target, channel, 1, (unsigned int)STDMIN(size, (unsigned long)UINT_MAX), spaceSize); + + m_stream->read((char *)m_space, STDMIN(size, (unsigned long)spaceSize)); + } + m_len = m_stream->gcount(); + unsigned int blockedBytes; +output: + blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking); + m_waiting = blockedBytes > 0; + if (m_waiting) + return blockedBytes; + size -= m_len; + transferBytes += m_len; + } + + if (!m_stream->good() && !m_stream->eof()) + throw ReadErr(); + + return 0; +} + +unsigned int FileStore::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + if (!m_stream) + return 0; + + // TODO: figure out what happens on cin + streampos current = m_stream->tellg(); + streampos endPosition = m_stream->seekg(0, ios::end).tellg(); + streampos newPosition = current + (streamoff)begin; + + if (newPosition >= endPosition) + { + m_stream->seekg(current); + return 0; // don't try to seek beyond the end of file + } + m_stream->seekg(newPosition); + unsigned long total = 0; + try + { + assert(!m_waiting); + unsigned long copyMax = end-begin; + unsigned int blockedBytes = const_cast<FileStore *>(this)->TransferTo2(target, copyMax, channel, blocking); + begin += copyMax; + if (blockedBytes) + { + const_cast<FileStore *>(this)->m_waiting = false; + return blockedBytes; + } + } + catch(...) + { + m_stream->clear(); + m_stream->seekg(current); + throw; + } + m_stream->clear(); + m_stream->seekg(current); + + return 0; +} + +void FileSink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + const char *fileName; + if (parameters.GetValue("OutputFileName", fileName)) + { + ios::openmode binary = parameters.GetValueWithDefault("OutputBinaryMode", true) ? ios::binary : ios::openmode(0); + m_file.open(fileName, ios::out | ios::trunc | binary); + if (!m_file) + throw OpenErr(fileName); + m_stream = &m_file; + } + else + { + m_stream = NULL; + parameters.GetValue("OutputStreamPointer", m_stream); + } +} + +bool FileSink::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + m_stream->flush(); + if (!m_stream->good()) + throw WriteErr(); + + return false; +} + +unsigned int FileSink::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + m_stream->write((const char *)inString, length); + + if (messageEnd) + m_stream->flush(); + + if (!m_stream->good()) + throw WriteErr(); + + return 0; +} + +NAMESPACE_END @@ -0,0 +1,97 @@ +#ifndef CRYPTOPP_FILES_H +#define CRYPTOPP_FILES_H + +#include "cryptlib.h" +#include "filters.h" + +#include <iostream> +#include <fstream> + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class FileStore : public Store, private FilterPutSpaceHelper +{ +public: + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}}; + class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}}; + + FileStore() : m_stream(NULL) {} + FileStore(std::istream &in) + {StoreInitialize(MakeParameters("InputStreamPointer", &in));} + FileStore(const char *filename) + {StoreInitialize(MakeParameters("InputFileName", filename));} + + std::istream* GetStream() {return m_stream;} + + unsigned long MaxRetrievable() const; + unsigned int Peek(byte &outByte) const; + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + std::ifstream m_file; + std::istream *m_stream; + byte *m_space; + unsigned int m_len; + bool m_waiting; +}; + +//! . +class FileSource : public SourceTemplate<FileStore> +{ +public: + typedef FileStore::Err Err; + typedef FileStore::OpenErr OpenErr; + typedef FileStore::ReadErr ReadErr; + + FileSource(BufferedTransformation *attachment = NULL) + : SourceTemplate<FileStore>(attachment) {} + FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputStreamPointer", &in));} + FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULL, bool binary=true) + : SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputFileName", filename)("InputBinaryMode", binary));} + + std::istream* GetStream() {return m_store.GetStream();} +}; + +//! . +class FileSink : public Sink +{ +public: + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}}; + class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}}; + + FileSink() : m_stream(NULL) {} + FileSink(std::ostream &out) + {IsolatedInitialize(MakeParameters("OutputStreamPointer", &out));} + FileSink(const char *filename, bool binary=true) + {IsolatedInitialize(MakeParameters("OutputFileName", filename)("OutputBinaryMode", binary));} + + std::ostream* GetStream() {return m_stream;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +private: + std::ofstream m_file; + std::ostream *m_stream; +}; + +NAMESPACE_END + +#endif diff --git a/filters.cpp b/filters.cpp new file mode 100644 index 0000000..78e6b3c --- /dev/null +++ b/filters.cpp @@ -0,0 +1,898 @@ +// filters.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "filters.h" +#include "mqueue.h" +#include "fltrimpl.h" +#include "argnames.h" +#include <memory> +#include <functional> + +NAMESPACE_BEGIN(CryptoPP) + +Filter::Filter(BufferedTransformation *attachment) + : m_attachment(attachment), m_continueAt(0) +{ +} + +BufferedTransformation * Filter::NewDefaultAttachment() const +{ + return new MessageQueue; +} + +BufferedTransformation * Filter::AttachedTransformation() +{ + if (m_attachment.get() == NULL) + m_attachment.reset(NewDefaultAttachment()); + return m_attachment.get(); +} + +const BufferedTransformation *Filter::AttachedTransformation() const +{ + if (m_attachment.get() == NULL) + const_cast<Filter *>(this)->m_attachment.reset(NewDefaultAttachment()); + return m_attachment.get(); +} + +void Filter::Detach(BufferedTransformation *newOut) +{ + m_attachment.reset(newOut); + NotifyAttachmentChange(); +} + +void Filter::Insert(Filter *filter) +{ + filter->m_attachment.reset(m_attachment.release()); + m_attachment.reset(filter); + NotifyAttachmentChange(); +} + +unsigned int Filter::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + return AttachedTransformation()->CopyRangeTo2(target, begin, end, channel, blocking); +} + +unsigned int Filter::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + return AttachedTransformation()->TransferTo2(target, transferBytes, channel, blocking); +} + +void Filter::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_continueAt = 0; + IsolatedInitialize(parameters); + PropagateInitialize(parameters, propagation); +} + +bool Filter::Flush(bool hardFlush, int propagation, bool blocking) +{ + switch (m_continueAt) + { + case 0: + if (IsolatedFlush(hardFlush, blocking)) + return true; + case 1: + if (OutputFlush(1, hardFlush, propagation, blocking)) + return true; + } + return false; +} + +bool Filter::MessageSeriesEnd(int propagation, bool blocking) +{ + switch (m_continueAt) + { + case 0: + if (IsolatedMessageSeriesEnd(blocking)) + return true; + case 1: + if (ShouldPropagateMessageSeriesEnd() && OutputMessageSeriesEnd(1, propagation, blocking)) + return true; + } + return false; +} + +void Filter::PropagateInitialize(const NameValuePairs ¶meters, int propagation, const std::string &channel) +{ + if (propagation) + AttachedTransformation()->ChannelInitialize(channel, parameters, propagation-1); +} + +unsigned int Filter::Output(int outputSite, const byte *inString, unsigned int length, int messageEnd, bool blocking, const std::string &channel) +{ + if (messageEnd) + messageEnd--; + unsigned int result = AttachedTransformation()->Put2(inString, length, messageEnd, blocking); + m_continueAt = result ? outputSite : 0; + return result; +} + +bool Filter::OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel) +{ + if (propagation && AttachedTransformation()->ChannelFlush(channel, hardFlush, propagation-1, blocking)) + { + m_continueAt = outputSite; + return true; + } + m_continueAt = 0; + return false; +} + +bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel) +{ + if (propagation && AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation-1, blocking)) + { + m_continueAt = outputSite; + return true; + } + m_continueAt = 0; + return false; +} + +// ************************************************************* + +unsigned int MeterFilter::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + m_currentMessageBytes += length; + m_totalBytes += length; + + if (messageEnd) + { + m_currentMessageBytes = 0; + m_currentSeriesMessages++; + m_totalMessages++; + } + + FILTER_OUTPUT(1, begin, length, messageEnd); + FILTER_END; +} + +bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking) +{ + m_currentMessageBytes = 0; + m_currentSeriesMessages = 0; + m_totalMessageSeries++; + return false; +} + +// ************************************************************* + +void FilterWithBufferedInput::BlockQueue::ResetQueue(unsigned int blockSize, unsigned int maxBlocks) +{ + m_buffer.New(blockSize * maxBlocks); + m_blockSize = blockSize; + m_maxBlocks = maxBlocks; + m_size = 0; + m_begin = m_buffer; +} + +byte *FilterWithBufferedInput::BlockQueue::GetBlock() +{ + if (m_size >= m_blockSize) + { + byte *ptr = m_begin; + if ((m_begin+=m_blockSize) == m_buffer.end()) + m_begin = m_buffer; + m_size -= m_blockSize; + return ptr; + } + else + return NULL; +} + +byte *FilterWithBufferedInput::BlockQueue::GetContigousBlocks(unsigned int &numberOfBytes) +{ + numberOfBytes = STDMIN(numberOfBytes, STDMIN((unsigned int)(m_buffer.end()-m_begin), m_size)); + byte *ptr = m_begin; + m_begin += numberOfBytes; + m_size -= numberOfBytes; + if (m_size == 0 || m_begin == m_buffer.end()) + m_begin = m_buffer; + return ptr; +} + +unsigned int FilterWithBufferedInput::BlockQueue::GetAll(byte *outString) +{ + unsigned int size = m_size; + unsigned int numberOfBytes = m_maxBlocks*m_blockSize; + const byte *ptr = GetContigousBlocks(numberOfBytes); + memcpy(outString, ptr, numberOfBytes); + memcpy(outString+numberOfBytes, m_begin, m_size); + m_size = 0; + return size; +} + +void FilterWithBufferedInput::BlockQueue::Put(const byte *inString, unsigned int length) +{ + assert(m_size + length <= m_buffer.size()); + byte *end = (m_size < (unsigned int)(m_buffer.end()-m_begin)) ? m_begin + m_size : m_begin + m_size - m_buffer.size(); + unsigned int len = STDMIN(length, (unsigned int)(m_buffer.end()-end)); + memcpy(end, inString, len); + if (len < length) + memcpy(m_buffer, inString+len, length-len); + m_size += length; +} + +FilterWithBufferedInput::FilterWithBufferedInput(BufferedTransformation *attachment) + : Filter(attachment) +{ +} + +FilterWithBufferedInput::FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation *attachment) + : Filter(attachment), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize) + , m_firstInputDone(false) +{ + if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0) + throw InvalidArgument("FilterWithBufferedInput: invalid buffer size"); + + m_queue.ResetQueue(1, m_firstSize); +} + +void FilterWithBufferedInput::IsolatedInitialize(const NameValuePairs ¶meters) +{ + InitializeDerivedAndReturnNewSizes(parameters, m_firstSize, m_blockSize, m_lastSize); + if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0) + throw InvalidArgument("FilterWithBufferedInput: invalid buffer size"); + m_queue.ResetQueue(1, m_firstSize); + m_firstInputDone = false; +} + +bool FilterWithBufferedInput::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("FilterWithBufferedInput"); + + if (hardFlush) + ForceNextPut(); + FlushDerived(); + + return false; +} + +unsigned int FilterWithBufferedInput::PutMaybeModifiable(byte *inString, unsigned int length, int messageEnd, bool blocking, bool modifiable) +{ + if (!blocking) + throw BlockingInputOnly("FilterWithBufferedInput"); + + if (length != 0) + { + unsigned int newLength = m_queue.CurrentSize() + length; + + if (!m_firstInputDone && newLength >= m_firstSize) + { + unsigned int len = m_firstSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + FirstPut(m_queue.GetContigousBlocks(m_firstSize)); + assert(m_queue.CurrentSize() == 0); + m_queue.ResetQueue(m_blockSize, (2*m_blockSize+m_lastSize-2)/m_blockSize); + + inString += len; + newLength -= m_firstSize; + m_firstInputDone = true; + } + + if (m_firstInputDone) + { + if (m_blockSize == 1) + { + while (newLength > m_lastSize && m_queue.CurrentSize() > 0) + { + unsigned int len = newLength - m_lastSize; + byte *ptr = m_queue.GetContigousBlocks(len); + NextPutModifiable(ptr, len); + newLength -= len; + } + + if (newLength > m_lastSize) + { + unsigned int len = newLength - m_lastSize; + NextPutMaybeModifiable(inString, len, modifiable); + inString += len; + newLength -= len; + } + } + else + { + while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize) + { + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0) + { + assert(m_queue.CurrentSize() < m_blockSize); + unsigned int len = m_blockSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + inString += len; + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + if (newLength >= m_blockSize + m_lastSize) + { + unsigned int len = RoundDownToMultipleOf(newLength - m_lastSize, m_blockSize); + NextPutMaybeModifiable(inString, len, modifiable); + inString += len; + newLength -= len; + } + } + } + + m_queue.Put(inString, newLength - m_queue.CurrentSize()); + } + + if (messageEnd) + { + if (!m_firstInputDone && m_firstSize==0) + FirstPut(NULL); + + SecByteBlock temp(m_queue.CurrentSize()); + m_queue.GetAll(temp); + LastPut(temp, temp.size()); + + m_firstInputDone = false; + m_queue.ResetQueue(1, m_firstSize); + + Output(1, NULL, 0, messageEnd, blocking); + } + return 0; +} + +void FilterWithBufferedInput::ForceNextPut() +{ + if (!m_firstInputDone) + return; + + if (m_blockSize > 1) + { + while (m_queue.CurrentSize() >= m_blockSize) + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + } + else + { + unsigned int len; + while ((len = m_queue.CurrentSize()) > 0) + NextPutModifiable(m_queue.GetContigousBlocks(len), len); + } +} + +void FilterWithBufferedInput::NextPutMultiple(const byte *inString, unsigned int length) +{ + assert(m_blockSize > 1); // m_blockSize = 1 should always override this function + while (length > 0) + { + assert(length >= m_blockSize); + NextPutSingle(inString); + inString += m_blockSize; + length -= m_blockSize; + } +} + +// ************************************************************* + +void Redirector::ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters, int propagation) +{ + if (channel.empty()) + { + m_target = parameters.GetValueWithDefault("RedirectionTargetPointer", (BufferedTransformation*)NULL); + m_passSignal = parameters.GetValueWithDefault("PassSignal", true); + } + + if (m_target && m_passSignal) + m_target->ChannelInitialize(channel, parameters, propagation); +} + +// ************************************************************* + +ProxyFilter::ProxyFilter(BufferedTransformation *filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation *attachment) + : FilterWithBufferedInput(firstSize, 1, lastSize, attachment), m_filter(filter), m_proxy(NULL) +{ + if (m_filter.get()) + m_filter->Attach(m_proxy = new OutputProxy(*this, false)); +} + +void ProxyFilter::IsolatedFlush(bool completeFlush) +{ + if (m_filter.get()) + { + bool passSignal = m_proxy->GetPassSignal(); + m_proxy->SetPassSignal(false); + m_filter->Flush(completeFlush, -1); + m_proxy->SetPassSignal(passSignal); + } +} + +void ProxyFilter::SetFilter(Filter *filter) +{ + bool passSignal = m_proxy ? m_proxy->GetPassSignal() : false; + m_filter.reset(filter); + if (filter) + { + std::auto_ptr<OutputProxy> temp(m_proxy = new OutputProxy(*this, passSignal)); + m_filter->TransferAllTo(*m_proxy); + m_filter->Attach(temp.release()); + } + else + m_proxy=NULL; +} + +void ProxyFilter::NextPutMultiple(const byte *s, unsigned int len) +{ + if (m_filter.get()) + m_filter->Put(s, len); +} + +// ************************************************************* + +unsigned int ArraySink::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + memcpy(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total))); + m_total += length; + return 0; +} + +byte * ArraySink::CreatePutSpace(unsigned int &size) +{ + size = m_size - m_total; + return m_buf + m_total; +} + +void ArraySink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + ByteArrayParameter array; + if (!parameters.GetValue(Name::OutputBuffer(), array)) + throw InvalidArgument("ArraySink: missing OutputBuffer argument"); + m_buf = array.begin(); + m_size = array.size(); + m_total = 0; +} + +unsigned int ArrayXorSink::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + xorbuf(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total))); + m_total += length; + return 0; +} + +// ************************************************************* + +unsigned int StreamTransformationFilter::LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding) +{ + if (c.MinLastBlockSize() > 0) + return c.MinLastBlockSize(); + else if (c.MandatoryBlockSize() > 1 && !c.IsForwardTransformation() && padding != NO_PADDING && padding != ZEROS_PADDING) + return c.MandatoryBlockSize(); + else + return 0; +} + +StreamTransformationFilter::StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding) + : FilterWithBufferedInput(0, c.MandatoryBlockSize(), LastBlockSize(c, padding), attachment) + , m_cipher(c) +{ + assert(c.MinLastBlockSize() == 0 || c.MinLastBlockSize() > c.MandatoryBlockSize()); + + bool isBlockCipher = (c.MandatoryBlockSize() > 1 && c.MinLastBlockSize() == 0); + + if (padding == DEFAULT_PADDING) + { + if (isBlockCipher) + m_padding = PKCS_PADDING; + else + m_padding = NO_PADDING; + } + else + m_padding = padding; + + if (!isBlockCipher && (m_padding == PKCS_PADDING || m_padding == ONE_AND_ZEROS_PADDING)) + throw InvalidArgument("StreamTransformationFilter: PKCS_PADDING and ONE_AND_ZEROS_PADDING cannot be used with " + c.AlgorithmName()); +} + +void StreamTransformationFilter::FirstPut(const byte *inString) +{ + m_optimalBufferSize = m_cipher.OptimalBlockSize(); + m_optimalBufferSize = STDMAX(m_optimalBufferSize, RoundDownToMultipleOf(4096U, m_optimalBufferSize)); +} + +void StreamTransformationFilter::NextPutMultiple(const byte *inString, unsigned int length) +{ + if (!length) + return; + + unsigned int s = m_cipher.MandatoryBlockSize(); + + do + { + unsigned int len = m_optimalBufferSize; + byte *space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, s, length, len); + if (len < length) + { + if (len == m_optimalBufferSize) + len -= m_cipher.GetOptimalBlockSizeUsed(); + len = RoundDownToMultipleOf(len, s); + } + else + len = length; + m_cipher.ProcessString(space, inString, len); + AttachedTransformation()->PutModifiable(space, len); + inString += len; + length -= len; + } + while (length > 0); +} + +void StreamTransformationFilter::NextPutModifiable(byte *inString, unsigned int length) +{ + m_cipher.ProcessString(inString, length); + AttachedTransformation()->PutModifiable(inString, length); +} + +void StreamTransformationFilter::LastPut(const byte *inString, unsigned int length) +{ + byte *space = NULL; + + switch (m_padding) + { + case NO_PADDING: + case ZEROS_PADDING: + if (length > 0) + { + unsigned int minLastBlockSize = m_cipher.MinLastBlockSize(); + bool isForwardTransformation = m_cipher.IsForwardTransformation(); + + if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize)) + { + // do padding + unsigned int blockSize = STDMAX(minLastBlockSize, m_cipher.MandatoryBlockSize()); + space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, blockSize); + memcpy(space, inString, length); + memset(space + length, 0, blockSize - length); + m_cipher.ProcessLastBlock(space, space, blockSize); + AttachedTransformation()->Put(space, blockSize); + } + else + { + if (minLastBlockSize == 0) + { + if (isForwardTransformation) + throw InvalidDataFormat("StreamTransformationFilter: plaintext length is not a multiple of block size and NO_PADDING is specified"); + else + throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size"); + } + + space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, length, m_optimalBufferSize); + m_cipher.ProcessLastBlock(space, inString, length); + AttachedTransformation()->Put(space, length); + } + } + break; + + case PKCS_PADDING: + case ONE_AND_ZEROS_PADDING: + unsigned int s; + s = m_cipher.MandatoryBlockSize(); + assert(s > 1); + space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, s, m_optimalBufferSize); + if (m_cipher.IsForwardTransformation()) + { + assert(length < s); + memcpy(space, inString, length); + if (m_padding == PKCS_PADDING) + { + assert(s < 256); + byte pad = s-length; + memset(space+length, pad, s-length); + } + else + { + space[length] = 1; + memset(space+length+1, 0, s-length-1); + } + m_cipher.ProcessData(space, space, s); + AttachedTransformation()->Put(space, s); + } + else + { + if (length != s) + throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size"); + m_cipher.ProcessData(space, inString, s); + if (m_padding == PKCS_PADDING) + { + byte pad = space[s-1]; + if (pad < 1 || pad > s || std::find_if(space+s-pad, space+s, std::bind2nd(std::not_equal_to<byte>(), pad)) != space+s) + throw InvalidCiphertext("StreamTransformationFilter: invalid PKCS #7 block padding found"); + length = s-pad; + } + else + { + while (length > 1 && space[length-1] == '\0') + --length; + if (space[--length] != '\1') + throw InvalidCiphertext("StreamTransformationFilter: invalid ones-and-zeros padding found"); + } + AttachedTransformation()->Put(space, length); + } + break; + + default: + assert(false); + } +} + +// ************************************************************* + +void HashFilter::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false); + m_hashModule.Restart(); +} + +unsigned int HashFilter::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + m_hashModule.Update(inString, length); + if (m_putMessage) + FILTER_OUTPUT(1, inString, length, 0); + if (messageEnd) + { + { + unsigned int size, digestSize = m_hashModule.DigestSize(); + m_space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, digestSize, digestSize, size = digestSize); + m_hashModule.Final(m_space); + } + FILTER_OUTPUT(2, m_space, m_hashModule.DigestSize(), messageEnd); + } + FILTER_END_NO_MESSAGE_END; +} + +// ************************************************************* + +HashVerificationFilter::HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment, word32 flags) + : FilterWithBufferedInput(attachment) + , m_hashModule(hm) +{ + IsolatedInitialize(MakeParameters(Name::HashVerificationFilterFlags(), flags)); +} + +void HashVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize) +{ + m_flags = parameters.GetValueWithDefault(Name::HashVerificationFilterFlags(), (word32)DEFAULT_FLAGS); + m_hashModule.Restart(); + unsigned int size = m_hashModule.DigestSize(); + m_verified = false; + firstSize = m_flags & HASH_AT_BEGIN ? size : 0; + blockSize = 1; + lastSize = m_flags & HASH_AT_BEGIN ? 0 : size; +} + +void HashVerificationFilter::FirstPut(const byte *inString) +{ + if (m_flags & HASH_AT_BEGIN) + { + m_expectedHash.New(m_hashModule.DigestSize()); + memcpy(m_expectedHash, inString, m_expectedHash.size()); + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, m_expectedHash.size()); + } +} + +void HashVerificationFilter::NextPutMultiple(const byte *inString, unsigned int length) +{ + m_hashModule.Update(inString, length); + if (m_flags & PUT_MESSAGE) + AttachedTransformation()->Put(inString, length); +} + +void HashVerificationFilter::LastPut(const byte *inString, unsigned int length) +{ + if (m_flags & HASH_AT_BEGIN) + { + assert(length == 0); + m_verified = m_hashModule.Verify(m_expectedHash); + } + else + { + m_verified = (length==m_hashModule.DigestSize() && m_hashModule.Verify(inString)); + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, length); + } + + if (m_flags & PUT_RESULT) + AttachedTransformation()->Put(m_verified); + + if ((m_flags & THROW_EXCEPTION) && !m_verified) + throw HashVerificationFailed(); +} + +// ************************************************************* + +void SignerFilter::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false); + m_messageAccumulator.reset(m_signer.NewSignatureAccumulator()); +} + +unsigned int SignerFilter::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + m_messageAccumulator->Update(inString, length); + if (m_putMessage) + FILTER_OUTPUT(1, inString, length, 0); + if (messageEnd) + { + m_buf.New(m_signer.SignatureLength()); + m_signer.Sign(m_rng, m_messageAccumulator.release(), m_buf); + FILTER_OUTPUT(2, m_buf, m_buf.size(), messageEnd); + m_messageAccumulator.reset(m_signer.NewSignatureAccumulator()); + } + FILTER_END_NO_MESSAGE_END; +} + +SignatureVerificationFilter::SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment, word32 flags) + : FilterWithBufferedInput(attachment) + , m_verifier(verifier) +{ + IsolatedInitialize(MakeParameters(Name::SignatureVerificationFilterFlags(), flags)); +} + +void SignatureVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize) +{ + m_flags = parameters.GetValueWithDefault(Name::SignatureVerificationFilterFlags(), (word32)DEFAULT_FLAGS); + m_messageAccumulator.reset(m_verifier.NewVerificationAccumulator()); + unsigned int size = m_verifier.SignatureLength(); + m_verified = false; + firstSize = m_flags & SIGNATURE_AT_BEGIN ? size : 0; + blockSize = 1; + lastSize = m_flags & SIGNATURE_AT_BEGIN ? 0 : size; +} + +void SignatureVerificationFilter::FirstPut(const byte *inString) +{ + if (m_flags & SIGNATURE_AT_BEGIN) + { + if (m_verifier.SignatureUpfrontForVerification()) + m_verifier.InitializeVerificationAccumulator(*m_messageAccumulator, inString); + else + { + m_signature.New(m_verifier.SignatureLength()); + memcpy(m_signature, inString, m_signature.size()); + } + + if (m_flags & PUT_SIGNATURE) + AttachedTransformation()->Put(inString, m_signature.size()); + } + else + { + assert(!m_verifier.SignatureUpfrontForVerification()); + } +} + +void SignatureVerificationFilter::NextPutMultiple(const byte *inString, unsigned int length) +{ + m_messageAccumulator->Update(inString, length); + if (m_flags & PUT_MESSAGE) + AttachedTransformation()->Put(inString, length); +} + +void SignatureVerificationFilter::LastPut(const byte *inString, unsigned int length) +{ + if (m_flags & SIGNATURE_AT_BEGIN) + { + assert(length == 0); + m_verified = m_verifier.Verify(m_messageAccumulator.release(), m_signature); + } + else + { + m_verified = (length==m_verifier.SignatureLength() && m_verifier.Verify(m_messageAccumulator.release(), inString)); + if (m_flags & PUT_SIGNATURE) + AttachedTransformation()->Put(inString, length); + } + + if (m_flags & PUT_RESULT) + AttachedTransformation()->Put(m_verified); + + if ((m_flags & THROW_EXCEPTION) && !m_verified) + throw SignatureVerificationFailed(); +} + +// ************************************************************* + +unsigned int Source::PumpAll2(bool blocking) +{ + // TODO: switch length type + unsigned long i = UINT_MAX; + RETURN_IF_NONZERO(Pump2(i, blocking)); + unsigned int j = UINT_MAX; + return PumpMessages2(j, blocking); +} + +bool Store::GetNextMessage() +{ + if (!m_messageEnd && !AnyRetrievable()) + { + m_messageEnd=true; + return true; + } + else + return false; +} + +unsigned int Store::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + if (m_messageEnd || count == 0) + return 0; + else + { + CopyTo(target, ULONG_MAX, channel); + if (GetAutoSignalPropagation()) + target.ChannelMessageEnd(channel, GetAutoSignalPropagation()-1); + return 1; + } +} + +void StringStore::StoreInitialize(const NameValuePairs ¶meters) +{ + ConstByteArrayParameter array; + if (!parameters.GetValue(Name::InputBuffer(), array)) + throw InvalidArgument("StringStore: missing InputBuffer argument"); + m_store = array.begin(); + m_length = array.size(); + m_count = 0; +} + +unsigned int StringStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + unsigned long position = 0; + unsigned int blockedBytes = CopyRangeTo2(target, position, transferBytes, channel, blocking); + m_count += position; + transferBytes = position; + return blockedBytes; +} + +unsigned int StringStore::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + unsigned int i = (unsigned int)STDMIN((unsigned long)m_count+begin, (unsigned long)m_length); + unsigned int len = (unsigned int)STDMIN((unsigned long)m_length-i, end-begin); + unsigned int blockedBytes = target.ChannelPut2(channel, m_store+i, len, 0, blocking); + if (!blockedBytes) + begin += len; + return blockedBytes; +} + +unsigned int RandomNumberStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + if (!blocking) + throw NotImplemented("RandomNumberStore: nonblocking transfer is not implemented by this object"); + + unsigned long transferMax = transferBytes; + for (transferBytes = 0; transferBytes<transferMax && m_count < m_length; ++transferBytes, ++m_count) + target.ChannelPut(channel, m_rng.GenerateByte()); + return 0; +} + +unsigned int NullStore::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + static const byte nullBytes[128] = {0}; + while (begin < end) + { + unsigned int len = STDMIN(end-begin, 128UL); + unsigned int blockedBytes = target.ChannelPut2(channel, nullBytes, len, 0, blocking); + if (blockedBytes) + return blockedBytes; + begin += len; + } + return 0; +} + +unsigned int NullStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + unsigned long begin = 0; + unsigned int blockedBytes = NullStore::CopyRangeTo2(target, begin, transferBytes, channel, blocking); + transferBytes = begin; + m_size -= begin; + return blockedBytes; +} + +NAMESPACE_END diff --git a/filters.h b/filters.h new file mode 100644 index 0000000..2b11662 --- /dev/null +++ b/filters.h @@ -0,0 +1,682 @@ +#ifndef CRYPTOPP_FILTERS_H +#define CRYPTOPP_FILTERS_H + +#include "simple.h" +#include "secblock.h" +#include "misc.h" +#include "smartptr.h" +#include "queue.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// provides an implementation of BufferedTransformation's attachment interface +class Filter : public BufferedTransformation, public NotCopyable +{ +public: + Filter(BufferedTransformation *attachment); + + bool Attachable() {return true;} + BufferedTransformation *AttachedTransformation(); + const BufferedTransformation *AttachedTransformation() const; + void Detach(BufferedTransformation *newAttachment = NULL); + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + +protected: + virtual void NotifyAttachmentChange() {} + virtual BufferedTransformation * NewDefaultAttachment() const; + void Insert(Filter *nextFilter); // insert filter after this one + + virtual bool ShouldPropagateMessageEnd() const {return true;} + virtual bool ShouldPropagateMessageSeriesEnd() const {return true;} + + void PropagateInitialize(const NameValuePairs ¶meters, int propagation, const std::string &channel=NULL_CHANNEL); + + unsigned int Output(int outputSite, const byte *inString, unsigned int length, int messageEnd, bool blocking, const std::string &channel=NULL_CHANNEL); + bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=NULL_CHANNEL); + bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=NULL_CHANNEL); + bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=NULL_CHANNEL); + +private: + member_ptr<BufferedTransformation> m_attachment; + +protected: + unsigned int m_inputPosition; + int m_continueAt; +}; + +struct FilterPutSpaceHelper +{ + // desiredSize is how much to ask target, bufferSize is how much to allocate in m_tempSpace + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, unsigned int minSize, unsigned int desiredSize, unsigned int &bufferSize) + { + assert(desiredSize >= minSize && bufferSize >= minSize); + if (m_tempSpace.size() < minSize) + { + byte *result = target.ChannelCreatePutSpace(channel, desiredSize); + if (desiredSize >= minSize) + { + bufferSize = desiredSize; + return result; + } + m_tempSpace.New(bufferSize); + } + + bufferSize = m_tempSpace.size(); + return m_tempSpace.begin(); + } + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, unsigned int minSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);} + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, unsigned int minSize, unsigned int bufferSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);} + SecByteBlock m_tempSpace; +}; + +//! measure how many byte and messages pass through, also serves as valve +class MeterFilter : public Bufferless<Filter> +{ +public: + MeterFilter(BufferedTransformation *attachment=NULL, bool transparent=true) + : Bufferless<Filter>(attachment), m_transparent(transparent) {ResetMeter();} + + void SetTransparent(bool transparent) {m_transparent = transparent;} + void ResetMeter() {m_currentMessageBytes = m_totalBytes = m_currentSeriesMessages = m_totalMessages = m_totalMessageSeries = 0;} + + unsigned long GetCurrentMessageBytes() const {return m_currentMessageBytes;} + unsigned long GetTotalBytes() {return m_totalBytes;} + unsigned int GetCurrentSeriesMessages() {return m_currentSeriesMessages;} + unsigned int GetTotalMessages() {return m_totalMessages;} + unsigned int GetTotalMessageSeries() {return m_totalMessageSeries;} + + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + bool IsolatedMessageSeriesEnd(bool blocking); + +private: + bool ShouldPropagateMessageEnd() const {return m_transparent;} + bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;} + + bool m_transparent; + unsigned long m_currentMessageBytes, m_totalBytes; + unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries; +}; + +//! . +class TransparentFilter : public MeterFilter +{ +public: + TransparentFilter(BufferedTransformation *attachment=NULL) : MeterFilter(attachment, true) {} +}; + +//! . +class OpaqueFilter : public MeterFilter +{ +public: + OpaqueFilter(BufferedTransformation *attachment=NULL) : MeterFilter(attachment, false) {} +}; + +/*! FilterWithBufferedInput divides up the input stream into + a first block, a number of middle blocks, and a last block. + First and last blocks are optional, and middle blocks may + be a stream instead (i.e. blockSize == 1). +*/ +class FilterWithBufferedInput : public Filter +{ +public: + FilterWithBufferedInput(BufferedTransformation *attachment); + //! firstSize and lastSize may be 0, blockSize must be at least 1 + FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation *attachment); + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(const_cast<byte *>(inString), length, messageEnd, blocking, false); + } + unsigned int PutModifiable2(byte *inString, unsigned int length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(inString, length, messageEnd, blocking, true); + } + /*! calls ForceNextPut() if hardFlush is true */ + bool IsolatedFlush(bool hardFlush, bool blocking); + + /*! the input buffer may contain more than blockSize bytes if lastSize != 0 + ForceNextPut() forces a call to NextPut() if this is the case + */ + void ForceNextPut(); + +protected: + bool DidFirstPut() {return m_firstInputDone;} + + virtual void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize) + {InitializeDerived(parameters);} + virtual void InitializeDerived(const NameValuePairs ¶meters) {} + // FirstPut() is called if (firstSize != 0 and totalLength >= firstSize) + // or (firstSize == 0 and (totalLength > 0 or a MessageEnd() is received)) + virtual void FirstPut(const byte *inString) =0; + // NextPut() is called if totalLength >= firstSize+blockSize+lastSize + virtual void NextPutSingle(const byte *inString) {assert(false);} + // Same as NextPut() except length can be a multiple of blockSize + // Either NextPut() or NextPutMultiple() must be overriden + virtual void NextPutMultiple(const byte *inString, unsigned int length); + // Same as NextPutMultiple(), but inString can be modified + virtual void NextPutModifiable(byte *inString, unsigned int length) + {NextPutMultiple(inString, length);} + // LastPut() is always called + // if totalLength < firstSize then length == totalLength + // else if totalLength <= firstSize+lastSize then length == totalLength-firstSize + // else lastSize <= length < lastSize+blockSize + virtual void LastPut(const byte *inString, unsigned int length) =0; + virtual void FlushDerived() {} + +private: + unsigned int PutMaybeModifiable(byte *begin, unsigned int length, int messageEnd, bool blocking, bool modifiable); + void NextPutMaybeModifiable(byte *inString, unsigned int length, bool modifiable) + { + if (modifiable) NextPutModifiable(inString, length); + else NextPutMultiple(inString, length); + } + + // This function should no longer be used, put this here to cause a compiler error + // if someone tries to override NextPut(). + virtual int NextPut(const byte *inString, unsigned int length) {assert(false); return 0;} + + class BlockQueue + { + public: + void ResetQueue(unsigned int blockSize, unsigned int maxBlocks); + byte *GetBlock(); + byte *GetContigousBlocks(unsigned int &numberOfBytes); + unsigned int GetAll(byte *outString); + void Put(const byte *inString, unsigned int length); + unsigned int CurrentSize() const {return m_size;} + unsigned int MaxSize() const {return m_buffer.size();} + + private: + SecByteBlock m_buffer; + unsigned int m_blockSize, m_maxBlocks, m_size; + byte *m_begin; + }; + + unsigned int m_firstSize, m_blockSize, m_lastSize; + bool m_firstInputDone; + BlockQueue m_queue; +}; + +//! . +class FilterWithInputQueue : public Filter +{ +public: + FilterWithInputQueue(BufferedTransformation *attachment) : Filter(attachment) {} + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("FilterWithInputQueue"); + + m_inQueue.Put(inString, length); + if (messageEnd) + { + IsolatedMessageEnd(blocking); + Output(0, NULL, 0, messageEnd, blocking); + } + return 0; + } + +protected: + virtual bool IsolatedMessageEnd(bool blocking) =0; + void IsolatedInitialize(const NameValuePairs ¶meters) {m_inQueue.Clear();} + + ByteQueue m_inQueue; +}; + +//! Filter Wrapper for StreamTransformation +class StreamTransformationFilter : public FilterWithBufferedInput, private FilterPutSpaceHelper +{ +public: + enum BlockPaddingScheme {NO_PADDING, ZEROS_PADDING, PKCS_PADDING, ONE_AND_ZEROS_PADDING, DEFAULT_PADDING}; + /*! DEFAULT_PADDING means PKCS_PADDING if c.MandatoryBlockSize() > 1 && c.MinLastBlockSize() == 0 (e.g. ECB or CBC mode), + otherwise NO_PADDING (OFB, CFB, CTR, CBC-CTS modes) */ + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment = NULL, BlockPaddingScheme padding = DEFAULT_PADDING); + + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, unsigned int length); + void NextPutModifiable(byte *inString, unsigned int length); + void LastPut(const byte *inString, unsigned int length); +// byte * CreatePutSpace(unsigned int &size); + +protected: + static unsigned int LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding); + + StreamTransformation &m_cipher; + BlockPaddingScheme m_padding; + unsigned int m_optimalBufferSize; +}; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY +typedef StreamTransformationFilter StreamCipherFilter; +#endif + +//! Filter Wrapper for HashTransformation +class HashFilter : public Bufferless<Filter>, private FilterPutSpaceHelper +{ +public: + HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULL, bool putMessage=false) + : Bufferless<Filter>(attachment), m_hashModule(hm), m_putMessage(putMessage) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + + byte * CreatePutSpace(unsigned int &size) {return m_hashModule.CreateUpdateSpace(size);} + +private: + HashTransformation &m_hashModule; + bool m_putMessage; + byte *m_space; +}; + +//! Filter Wrapper for HashTransformation +class HashVerificationFilter : public FilterWithBufferedInput +{ +public: + class HashVerificationFailed : public Exception + { + public: + HashVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "HashVerifier: message hash not valid") {} + }; + + enum Flags {HASH_AT_BEGIN=1, PUT_MESSAGE=2, PUT_HASH=4, PUT_RESULT=8, THROW_EXCEPTION=16, DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT}; + HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment = NULL, word32 flags = DEFAULT_FLAGS); + + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, unsigned int length); + void LastPut(const byte *inString, unsigned int length); + +private: + static inline unsigned int FirstSize(word32 flags, HashTransformation &hm) {return flags & HASH_AT_BEGIN ? hm.DigestSize() : 0;} + static inline unsigned int LastSize(word32 flags, HashTransformation &hm) {return flags & HASH_AT_BEGIN ? 0 : hm.DigestSize();} + + HashTransformation &m_hashModule; + word32 m_flags; + SecByteBlock m_expectedHash; + bool m_verified; +}; + +typedef HashVerificationFilter HashVerifier; // for backwards compatibility + +//! Filter Wrapper for PK_Signer +class SignerFilter : public Unflushable<Filter> +{ +public: + SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULL, bool putMessage=false) + : Unflushable<Filter>(attachment), m_rng(rng), m_signer(signer), m_messageAccumulator(signer.NewSignatureAccumulator()), m_putMessage(putMessage) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator &m_rng; + const PK_Signer &m_signer; + member_ptr<HashTransformation> m_messageAccumulator; + bool m_putMessage; + SecByteBlock m_buf; +}; + +//! Filter Wrapper for PK_Verifier +class SignatureVerificationFilter : public FilterWithBufferedInput +{ +public: + class SignatureVerificationFailed : public Exception + { + public: + SignatureVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "VerifierFilter: digital signature not valid") {} + }; + + enum Flags {SIGNATURE_AT_BEGIN=1, PUT_MESSAGE=2, PUT_SIGNATURE=4, PUT_RESULT=8, THROW_EXCEPTION=16, DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT}; + SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment = NULL, word32 flags = DEFAULT_FLAGS); + + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, unsigned int length); + void LastPut(const byte *inString, unsigned int length); + +private: + const PK_Verifier &m_verifier; + member_ptr<HashTransformation> m_messageAccumulator; + word32 m_flags; + SecByteBlock m_signature; + bool m_verified; +}; + +typedef SignatureVerificationFilter VerifierFilter; // for backwards compatibility + +//! Redirect input to another BufferedTransformation without owning it +class Redirector : public CustomSignalPropagation<Sink> +{ +public: + Redirector() : m_target(NULL), m_passSignal(true) {} + Redirector(BufferedTransformation &target, bool passSignal=true) : m_target(&target), m_passSignal(passSignal) {} + + void Redirect(BufferedTransformation &target) {m_target = ⌖} + void StopRedirection() {m_target = NULL;} + bool GetPassSignal() const {return m_passSignal;} + void SetPassSignal(bool passSignal) {m_passSignal = passSignal;} + + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_target ? m_target->Put2(begin, length, m_passSignal ? messageEnd : 0, blocking) : 0;} + void Initialize(const NameValuePairs ¶meters, int propagation) + {ChannelInitialize(NULL_CHANNEL, parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_target && m_passSignal ? m_target->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_target && m_passSignal ? m_target->MessageSeriesEnd(propagation, blocking) : false;} + + void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking) : 0;} + unsigned int ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking) : 0;} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_target && m_passSignal ? m_target->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_target && m_passSignal ? m_target->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + +private: + BufferedTransformation *m_target; + bool m_passSignal; +}; + +// Used By ProxyFilter +class OutputProxy : public CustomSignalPropagation<Sink> +{ +public: + OutputProxy(BufferedTransformation &owner, bool passSignal) : m_owner(owner), m_passSignal(passSignal) {} + + bool GetPassSignal() const {return m_passSignal;} + void SetPassSignal(bool passSignal) {m_passSignal = passSignal;} + + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->Put2(begin, length, m_passSignal ? messageEnd : 0, blocking);} + unsigned int PutModifiable2(byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->PutModifiable2(begin, length, m_passSignal ? messageEnd : 0, blocking);} + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) + {if (m_passSignal) m_owner.AttachedTransformation()->Initialize(parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->MessageSeriesEnd(propagation, blocking) : false;} + + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + unsigned int ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters, int propagation=-1) + {if (m_passSignal) m_owner.AttachedTransformation()->ChannelInitialize(channel, parameters, propagation);} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + +private: + BufferedTransformation &m_owner; + bool m_passSignal; +}; + +//! Base class for Filter classes that are proxies for a chain of other filters. +class ProxyFilter : public FilterWithBufferedInput +{ +public: + ProxyFilter(BufferedTransformation *filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation *attachment); + + void IsolatedFlush(bool completeFlush); + + void SetFilter(Filter *filter); + void NextPutMultiple(const byte *s, unsigned int len); + +protected: + member_ptr<BufferedTransformation> m_filter; + OutputProxy *m_proxy; +}; + +//! simple proxy filter that doesn't modify the underlying filter's input or output +class SimpleProxyFilter : public ProxyFilter +{ +public: + SimpleProxyFilter(BufferedTransformation *filter, BufferedTransformation *attachment) + : ProxyFilter(filter, 0, 0, attachment) {} + + void FirstPut(const byte *) {} + void LastPut(const byte *, unsigned int) {m_filter->MessageEnd();} +}; + +//! proxy for the filter created by PK_Encryptor::CreateEncryptionFilter +/*! This class is here just to provide symmetry with VerifierFilter. */ +class PK_EncryptorFilter : public SimpleProxyFilter +{ +public: + PK_EncryptorFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment = NULL) + : SimpleProxyFilter(encryptor.CreateEncryptionFilter(rng), attachment) {} +}; + +//! proxy for the filter created by PK_Decryptor::CreateDecryptionFilter +/*! This class is here just to provide symmetry with SignerFilter. */ +class PK_DecryptorFilter : public SimpleProxyFilter +{ +public: + PK_DecryptorFilter(const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULL) + : SimpleProxyFilter(decryptor.CreateDecryptionFilter(), attachment) {} +}; + +//! Append input to a string object +template <class T> +class StringSinkTemplate : public Bufferless<Sink> +{ +public: + // VC60 workaround: no T::char_type + typedef typename T::traits_type::char_type char_type; + + StringSinkTemplate(T &output) + : m_output(&output) {assert(sizeof(output[0])==1);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {if (!parameters.GetValue("OutputStringPointer", m_output)) throw InvalidArgument("StringSink: OutputStringPointer not specified");} + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + { + m_output->append((const char_type *)begin, (const char_type *)begin+length); + return 0; + } + +private: + T *m_output; +}; + +//! Append input to an std::string +typedef StringSinkTemplate<std::string> StringSink; + +//! Copy input to a memory buffer +class ArraySink : public Bufferless<Sink> +{ +public: + ArraySink(const NameValuePairs ¶meters = g_nullNameValuePairs) {IsolatedInitialize(parameters);} + ArraySink(byte *buf, unsigned int size) : m_buf(buf), m_size(size), m_total(0) {} + + unsigned int AvailableSize() {return m_size - STDMIN(m_total, (unsigned long)m_size);} + unsigned long TotalPutLength() {return m_total;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(unsigned int &size); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + +protected: + byte *m_buf; + unsigned int m_size; + unsigned long m_total; +}; + +//! Xor input to a memory buffer +class ArrayXorSink : public ArraySink +{ +public: + ArrayXorSink(byte *buf, unsigned int size) + : ArraySink(buf, size) {} + + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + byte * CreatePutSpace(unsigned int &size) {return BufferedTransformation::CreatePutSpace(size);} +}; + +//! . +class StringStore : public Store +{ +public: + StringStore(const char *string = NULL) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + StringStore(const byte *string, unsigned int length) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + template <class T> StringStore(const T &string) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + const byte *m_store; + unsigned int m_length, m_count; +}; + +//! . +class RandomNumberStore : public Store +{ +public: + RandomNumberStore(RandomNumberGenerator &rng, unsigned long length) + : m_rng(rng), m_length(length), m_count(0) {} + + bool AnyRetrievable() const {return MaxRetrievable() != 0;} + unsigned long MaxRetrievable() const {return m_length-m_count;} + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const + { + throw NotImplemented("RandomNumberStore: CopyRangeTo2() is not supported by this store"); + } + +private: + void StoreInitialize(const NameValuePairs ¶meters) {m_count = 0;} + + RandomNumberGenerator &m_rng; + const unsigned long m_length; + unsigned long m_count; +}; + +//! . +class NullStore : public Store +{ +public: + NullStore(unsigned long size = ULONG_MAX) : m_size(size) {} + void StoreInitialize(const NameValuePairs ¶meters) {} + unsigned long MaxRetrievable() const {return m_size;} + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + +private: + unsigned long m_size; +}; + +//! A Filter that pumps data into its attachment as input +class Source : public InputRejecting<Filter> +{ +public: + Source(BufferedTransformation *attachment) + : InputRejecting<Filter>(attachment) {} + + unsigned long Pump(unsigned long pumpMax=ULONG_MAX) + {Pump2(pumpMax); return pumpMax;} + unsigned int PumpMessages(unsigned int count=UINT_MAX) + {PumpMessages2(count); return count;} + void PumpAll() + {PumpAll2();} + virtual unsigned int Pump2(unsigned long &byteCount, bool blocking=true) =0; + virtual unsigned int PumpMessages2(unsigned int &messageCount, bool blocking=true) =0; + virtual unsigned int PumpAll2(bool blocking=true); + virtual bool SourceExhausted() const =0; + +protected: + void SourceInitialize(bool pumpAll, const NameValuePairs ¶meters) + { + IsolatedInitialize(parameters); + if (pumpAll) + PumpAll(); + } +}; + +//! Turn a Store into a Source +template <class T> +class SourceTemplate : public Source +{ +public: + SourceTemplate<T>(BufferedTransformation *attachment) + : Source(attachment) {} + SourceTemplate<T>(BufferedTransformation *attachment, T store) + : Source(attachment), m_store(store) {} + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_store.IsolatedInitialize(parameters);} + unsigned int Pump2(unsigned long &byteCount, bool blocking=true) + {return m_store.TransferTo2(*AttachedTransformation(), byteCount, NULL_CHANNEL, blocking);} + unsigned int PumpMessages2(unsigned int &messageCount, bool blocking=true) + {return m_store.TransferMessagesTo2(*AttachedTransformation(), messageCount, NULL_CHANNEL, blocking);} + unsigned int PumpAll2(bool blocking=true) + {return m_store.TransferAllTo2(*AttachedTransformation(), NULL_CHANNEL, blocking);} + bool SourceExhausted() const + {return !m_store.AnyRetrievable() && !m_store.AnyMessages();} + void SetAutoSignalPropagation(int propagation) + {m_store.SetAutoSignalPropagation(propagation);} + int GetAutoSignalPropagation() const + {return m_store.GetAutoSignalPropagation();} + +protected: + T m_store; +}; + +//! . +class StringSource : public SourceTemplate<StringStore> +{ +public: + StringSource(BufferedTransformation *attachment = NULL) + : SourceTemplate<StringStore>(attachment) {} + StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + StringSource(const byte *string, unsigned int length, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + +#ifdef __MWERKS__ // CW60 workaround + StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULL) +#else + template <class T> StringSource(const T &string, bool pumpAll, BufferedTransformation *attachment = NULL) +#endif + : SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} +}; + +//! . +class RandomNumberSource : public SourceTemplate<RandomNumberStore> +{ +public: + RandomNumberSource(RandomNumberGenerator &rng, unsigned int length, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate<RandomNumberStore>(attachment, RandomNumberStore(rng, length)) {if (pumpAll) PumpAll();} +}; + +NAMESPACE_END + +#endif diff --git a/fips140.cpp b/fips140.cpp new file mode 100644 index 0000000..9a1a6f9 --- /dev/null +++ b/fips140.cpp @@ -0,0 +1,65 @@ +// fips140.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "fips140.h" +#include "trdlocal.h" // needs to be included last for cygwin + +NAMESPACE_BEGIN(CryptoPP) + +// Define this to 1 to turn on FIPS 140-2 compliance features, including additional tests during +// startup, random number generation, and key generation. These tests may affect performance. +#ifndef CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +#define CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 0 +#endif + +#if (CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 && !defined(THREADS_AVAILABLE)) +#error FIPS-140-2 compliance requires the availability of thread local storage. +#endif + +#if (CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 && !defined(OS_RNG_AVAILABLE)) +#error FIPS-140-2 compliance requires the availability of OS provided RNG. +#endif + +PowerUpSelfTestStatus g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_NOT_DONE; + +bool FIPS_140_2_ComplianceEnabled() +{ + return CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2; +} + +void SimulatePowerUpSelfTestFailure() +{ + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_FAILED; +} + +PowerUpSelfTestStatus GetPowerUpSelfTestStatus() +{ + return g_powerUpSelfTestStatus; +} + +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +ThreadLocalStorage & AccessPowerUpSelfTestInProgress() +{ + static ThreadLocalStorage selfTestInProgress; + return selfTestInProgress; +} +#endif + +bool PowerUpSelfTestInProgressOnThisThread() +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + return AccessPowerUpSelfTestInProgress().GetValue() != NULL; +#else + assert(false); // should not be called + return false; +#endif +} + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + AccessPowerUpSelfTestInProgress().SetValue((void *)inProgress); +#endif +} + +NAMESPACE_END diff --git a/fips140.h b/fips140.h new file mode 100644 index 0000000..e7e5d4a --- /dev/null +++ b/fips140.h @@ -0,0 +1,44 @@ +#ifndef CRYPTOPP_FIPS140_H +#define CRYPTOPP_FIPS140_H + +/*! \file + FIPS-140 related functions and classes. +*/ + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! exception thrown when a crypto algorithm is used after a self test fails +class SelfTestFailure : public Exception +{ +public: + explicit SelfTestFailure(const std::string &s) : Exception(OTHER_ERROR, s) {} +}; + +//! returns whether FIPS-140-2 compliance features were enabled at compile time +bool FIPS_140_2_ComplianceEnabled(); + +//! enum values representing status of the power-up self test +enum PowerUpSelfTestStatus {POWER_UP_SELF_TEST_NOT_DONE, POWER_UP_SELF_TEST_FAILED, POWER_UP_SELF_TEST_PASSED}; + +//! perform the power-up self test, and set the self test status +void DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleSha1Digest); + +//! set the power-up self test status to POWER_UP_SELF_TEST_FAILED +void SimulatePowerUpSelfTestFailure(); + +//! return the current power-up self test status +PowerUpSelfTestStatus GetPowerUpSelfTestStatus(); + +// this is used by Algorithm constructor to allow Algorithm objects to be constructed for the self test +bool PowerUpSelfTestInProgressOnThisThread(); + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress); + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); + +NAMESPACE_END + +#endif diff --git a/fipstest.cpp b/fipstest.cpp new file mode 100644 index 0000000..063ab6b --- /dev/null +++ b/fipstest.cpp @@ -0,0 +1,304 @@ +// fipstest.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "fips140.h" +#include "sha.h" +#include "files.h" +#include "hex.h" +#include "rsa.h" +#include "dsa.h" +#include "mqueue.h" +#include "channels.h" +#include "osrng.h" +#include "des.h" +#include "eccrypto.h" +#include "ec2n.h" +#include "ecp.h" +#include "modes.h" +#include "aes.h" +#include "skipjack.h" +#include "trdlocal.h" // needs to be included last for cygwin + +NAMESPACE_BEGIN(CryptoPP) + +extern PowerUpSelfTestStatus g_powerUpSelfTestStatus; + +void KnownAnswerTest(StreamTransformation &encryption, StreamTransformation &decryption, const char *plaintext, const char *ciphertext) +{ + EqualityComparisonFilter comparison; + + StringSource(plaintext, true, new HexDecoder(new StreamTransformationFilter(encryption, new ChannelSwitch(comparison, "0"), StreamTransformationFilter::NO_PADDING))); + StringSource(ciphertext, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + StringSource(ciphertext, true, new HexDecoder(new StreamTransformationFilter(decryption, new ChannelSwitch(comparison, "0"), StreamTransformationFilter::NO_PADDING))); + StringSource(plaintext, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +template <class CIPHER> +void SymmetricEncryptionKnownAnswerTest( + const char *key, + const char *hexIV, + const char *plaintext, + const char *ecb, + const char *cbc, + const char *cfb, + const char *ofb, + const char *ctr, + CIPHER *dummy = NULL) +{ + std::string decodedKey; + StringSource(key, true, new HexDecoder(new StringSink(decodedKey))); + + typename CIPHER::Encryption encryption((const byte *)decodedKey.data(), decodedKey.size()); + typename CIPHER::Decryption decryption((const byte *)decodedKey.data(), decodedKey.size()); + + SecByteBlock iv(encryption.BlockSize()); + StringSource(hexIV, true, new HexDecoder(new ArraySink(iv, iv.size()))); + + if (ecb) + KnownAnswerTest(ECB_Mode_ExternalCipher::Encryption(encryption).Ref(), ECB_Mode_ExternalCipher::Decryption(decryption).Ref(), plaintext, ecb); + if (cbc) + KnownAnswerTest(CBC_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CBC_Mode_ExternalCipher::Decryption(decryption, iv).Ref(), plaintext, cbc); + if (cfb) + KnownAnswerTest(CFB_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CFB_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, cfb); + if (ofb) + KnownAnswerTest(OFB_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), OFB_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, ofb); + if (ctr) + KnownAnswerTest(CTR_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CTR_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, ctr); +} + +void KnownAnswerTest(HashTransformation &hash, const char *message, const char *digest) +{ + EqualityComparisonFilter comparison; + StringSource(message, true, new HashFilter(hash, new ChannelSwitch(comparison, "0"))); + StringSource(digest, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +template <class HASH> +void SecureHashKnownAnswerTest(const char *message, const char *digest) +{ + HASH hash; + KnownAnswerTest(hash, message, digest); +} + +template <class MAC> +void MAC_KnownAnswerTest(const char *key, const char *message, const char *digest) +{ + std::string decodedKey; + StringSource(key, true, new HexDecoder(new StringSink(decodedKey))); + + MAC mac((const byte *)decodedKey.data(), decodedKey.size()); + KnownAnswerTest(mac, message, digest); +} + +template <class SCHEME> +void SignatureKnownAnswerTest(const char *key, const char *message, const char *signature, SCHEME *dummy = NULL) +{ + typename SCHEME::Signer signer(StringSource(key, true, new HexDecoder).Ref()); + typename SCHEME::Verifier verifier(signer); + + EqualityComparisonFilter comparison; + + StringSource(message, true, new SignerFilter(NullRNG(), signer, new ChannelSwitch(comparison, "0"))); + StringSource(signature, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); + + VerifierFilter verifierFilter(verifier, NULL, VerifierFilter::SIGNATURE_AT_BEGIN | VerifierFilter::THROW_EXCEPTION); + StringSource(signature, true, new HexDecoder(new Redirector(verifierFilter, false))); + StringSource(message, true, new Redirector(verifierFilter)); +} + +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor) +{ + try + { +#ifdef OS_RNG_AVAILABLE + AutoSeededX917RNG<DES_EDE3> rng; +#else + RandomNumberGenerator &rng = NullRNG(); +#endif + const char *testMessage ="test message"; + + EqualityComparisonFilter comparison; + comparison.ChannelPutMessageEnd("0", (const byte *)testMessage, strlen(testMessage)); + + StringSource( + testMessage, + true, + new PK_EncryptorFilter( + rng, + encryptor, + new PK_DecryptorFilter(decryptor, new ChannelSwitch(comparison, "1")))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); + } + catch (...) + { + throw SelfTestFailure(encryptor.AlgorithmName() + ": pairwise consistency test failed"); + } +} + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier) +{ + try + { +#ifdef OS_RNG_AVAILABLE + AutoSeededX917RNG<DES_EDE3> rng; +#else + RandomNumberGenerator &rng = NullRNG(); +#endif + + StringSource( + "test message", + true, + new SignerFilter( + rng, + signer, + new VerifierFilter(verifier, NULL, VerifierFilter::THROW_EXCEPTION), + true)); + } + catch (...) + { + throw SelfTestFailure(signer.AlgorithmName() + ": pairwise consistency test failed"); + } +} + +template <class SCHEME> +void SignaturePairwiseConsistencyTest(const char *key, SCHEME *dummy = NULL) +{ + typename SCHEME::Signer signer(StringSource(key, true, new HexDecoder).Ref()); + typename SCHEME::Verifier verifier(signer); + + SignaturePairwiseConsistencyTest(signer, verifier); +} + +void DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleSha1Digest) +{ + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_NOT_DONE; + SetPowerUpSelfTestInProgressOnThisThread(true); + + try + { + if (FIPS_140_2_ComplianceEnabled() || moduleFilename != NULL) + { + // integrity test + SHA1 sha; + HashVerifier verifier(sha); + verifier.Put(expectedModuleSha1Digest, sha.DigestSize()); + FileStore(moduleFilename).TransferAllTo(verifier); + if (!verifier.GetLastResult()) + { +#ifdef CRYPTOPP_WIN32_AVAILABLE + std::string actualDigest; + FileSource(moduleFilename, true, new HashFilter(sha, new HexEncoder(new StringSink(actualDigest)))); + OutputDebugString(("Crypto++ EDC test failed. Actual digest is: " + actualDigest + "\n").c_str()); +#endif + throw 0; // throw here so we break in the debugger, this will be caught right away + } + } + + // algorithm tests + + SymmetricEncryptionKnownAnswerTest<DES>( + "0123456789abcdef", // key + "1234567890abcdef", // IV + "4e6f77206973207468652074696d6520666f7220616c6c20", // plaintext + "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53", // ecb + "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6", // cbc + "F3096249C7F46E51A69E839B1A92F78403467133898EA622", // cfb + "f3096249c7f46e5135f24a242eeb3d3f3d6d5be3255af8c3", // ofb + "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75");// ctr + + SymmetricEncryptionKnownAnswerTest<DES_EDE3>( + "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E", + "C141B5FCCD28DC8A", + "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68", + "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4", + "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9", + "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B", + "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62", + "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371"); + + SymmetricEncryptionKnownAnswerTest<SKIPJACK>( + "1555E5531C3A169B2D65", + "6EC9795701F49864", + "00AFA48E9621E52E8CBDA312660184EDDB1F33D9DACDA8DA", + "DBEC73562EFCAEB56204EB8AE9557EBF77473FBB52D17CD1", + "0C7B0B74E21F99B8F2C8DF37879F6C044967F42A796DCA8B", + "79FDDA9724E36CC2E023E9A5C717A8A8A7FDA465CADCBF63", + "79FDDA9724E36CC26CACBD83C1ABC06EAF5B249BE5B1E040", + "79FDDA9724E36CC211B0AEC607B95A96BCDA318440B82F49"); + + SymmetricEncryptionKnownAnswerTest<AES>( + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", // plaintext + "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4", // ecb + "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7", // cbc + "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6", // cfb + "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e", // ofb + NULL); + + SymmetricEncryptionKnownAnswerTest<AES>( + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + NULL, + NULL, + NULL, + NULL, + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"); // ctr + + + SecureHashKnownAnswerTest<SHA>( + "abc", + "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + MAC_KnownAnswerTest<HMAC<SHA> >( + "303132333435363738393a3b3c3d3e3f40414243", + "Sample #2", + "0922d3405faa3d194f82a45830737d5cc6c75d24"); + + SignatureKnownAnswerTest<RSASSA<PKCS1v15, SHA> >( + "30820150020100300d06092a864886f70d01010105000482013a3082013602010002400a66791dc6988168de7ab77419bb7fb0" + "c001c62710270075142942e19a8d8c51d053b3e3782a1de5dc5af4ebe99468170114a1dfe67cdc9a9af55d655620bbab0203010001" + "02400123c5b61ba36edb1d3679904199a89ea80c09b9122e1400c09adcf7784676d01d23356a7d44d6bd8bd50e94bfc723fa" + "87d8862b75177691c11d757692df8881022033d48445c859e52340de704bcdda065fbb4058d740bd1d67d29e9c146c11cf61" + "0220335e8408866b0fd38dc7002d3f972c67389a65d5d8306566d5c4f2a5aa52628b0220045ec90071525325d3d46db79695e9af" + "acc4523964360e02b119baa366316241022015eb327360c7b60d12e5e2d16bdcd97981d17fba6b70db13b20b436e24eada590220" + "2ca6366d72781dfa24d34a9a24cbc2ae927a9958af426563ff63fb11658a461d", + "Everyone gets Friday off.", + "0610761F95FFD1B8F29DA34212947EC2AA0E358866A722F03CC3C41487ADC604A48FF54F5C6BEDB9FB7BD59F82D6E55D8F3174BA361B2214B2D74E8825E04E81"); + + SignaturePairwiseConsistencyTest<DSA>( + "3082014A0201003082012B06072A8648CE3804013082011E02818100F468699A6F6EBCC0120D3B34C8E007F125EC7D81F763B8D0F33869AE3BD6B9F2ECCC7DF34DF84C0307449E9B85D30D57194BCCEB310F48141914DD13A077AAF9B624A6CBE666BBA1D7EBEA95B5BA6F54417FD5D4E4220C601E071D316A24EA814E8B0122DBF47EE8AEEFD319EBB01DD95683F10DBB4FEB023F8262A07EAEB7FD02150082AD4E034DA6EEACDFDAE68C36F2BAD614F9E53B02818071AAF73361A26081529F7D84078ADAFCA48E031DB54AD57FB1A833ADBD8672328AABAA0C756247998D7A5B10DACA359D231332CE8120B483A784FE07D46EEBFF0D7D374A10691F78653E6DC29E27CCB1B174923960DFE5B959B919B2C3816C19251832AFD8E35D810E598F82877ABF7D40A041565168BD7F0E21E3FE2A8D8C1C0416021426EBA66E846E755169F84A1DA981D86502405DDF"); + + SignaturePairwiseConsistencyTest<ECDSA<EC2N, SHA> >( + "302D020100301006072A8648CE3D020106052B8104000404163014020101040F0070337065E1E196980A9D00E37211"); + + SignaturePairwiseConsistencyTest<ECDSA<ECP, SHA> >( + "3039020100301306072A8648CE3D020106082A8648CE3D030101041F301D02010104182BB8A13C8B867010BD9471D9E81FDB01ABD0538C64D6249A"); + } + catch (...) + { + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_FAILED; + goto done; + } + + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_PASSED; + +done: + SetPowerUpSelfTestInProgressOnThisThread(false); + return; +} + +NAMESPACE_END diff --git a/fltrimpl.h b/fltrimpl.h new file mode 100644 index 0000000..6c37bfa --- /dev/null +++ b/fltrimpl.h @@ -0,0 +1,40 @@ +#ifndef CRYPTOPP_FLTRIMPL_H +#define CRYPTOPP_FLTRIMPL_H + +#define FILTER_BEGIN \ + switch (m_continueAt) \ + { \ + case 0: \ + m_inputPosition = 0; + +#define FILTER_END_NO_MESSAGE_END_NO_RETURN \ + break; \ + default: \ + assert(false); \ + } + +#define FILTER_END_NO_MESSAGE_END \ + FILTER_END_NO_MESSAGE_END_NO_RETURN \ + return 0; + +#define FILTER_END \ + case -1: \ + if (Output(-1, NULL, 0, messageEnd, blocking)) \ + return 1; \ + FILTER_END_NO_MESSAGE_END + +#define FILTER_OUTPUT2(site, statement, output, length, messageEnd) \ + {\ + case site: \ + statement; \ + if (Output(site, output, length, messageEnd, blocking)) \ + return STDMAX(1U, (unsigned int)length-m_inputPosition);\ + } + +#define FILTER_OUTPUT(site, output, length, messageEnd) \ + FILTER_OUTPUT2(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT_BYTE(site, output) \ + FILTER_OUTPUT(site, &(const byte &)(byte)output, 1, 0) + +#endif diff --git a/gf256.cpp b/gf256.cpp new file mode 100644 index 0000000..72026d1 --- /dev/null +++ b/gf256.cpp @@ -0,0 +1,34 @@ +// gf256.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gf256.h" + +NAMESPACE_BEGIN(CryptoPP) + +GF256::Element GF256::Multiply(Element a, Element b) const +{ + word result = 0, t = b; + + for (unsigned int i=0; i<8; i++) + { + result <<= 1; + if (result & 0x100) + result ^= m_modulus; + + t <<= 1; + if (t & 0x100) + result ^= a; + } + + return (GF256::Element) result; +} + +GF256::Element GF256::MultiplicativeInverse(Element a) const +{ + Element result = a; + for (int i=1; i<7; i++) + result = Multiply(Square(result), a); + return Square(result); +} + +NAMESPACE_END @@ -0,0 +1,66 @@ +#ifndef CRYPTOPP_GF256_H +#define CRYPTOPP_GF256_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! GF(256) with polynomial basis +class GF256 +{ +public: + typedef byte Element; + typedef int RandomizationParameter; + + GF256(byte modulus) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {return rng.GenerateByte();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Zero() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {return 0;} + + Element One() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/gf2_32.cpp b/gf2_32.cpp new file mode 100644 index 0000000..fd2661b --- /dev/null +++ b/gf2_32.cpp @@ -0,0 +1,99 @@ +// gf2_32.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "misc.h" +#include "gf2_32.h" + +NAMESPACE_BEGIN(CryptoPP) + +GF2_32::Element GF2_32::Multiply(Element a, Element b) const +{ + word32 table[4]; + table[0] = 0; + table[1] = m_modulus; + if (a & 0x80000000) + { + table[2] = m_modulus ^ (a<<1); + table[3] = a<<1; + } + else + { + table[2] = a<<1; + table[3] = m_modulus ^ (a<<1); + } + +#ifdef FAST_ROTATE + b = rotrFixed(b, 30U); + word32 result = table[b&2]; + + for (int i=29; i>=0; --i) + { + b = rotlFixed(b, 1U); + result = (result<<1) ^ table[(b&2) + (result>>31)]; + } + + return (b&1) ? result ^ a : result; +#else + word32 result = table[(b>>30) & 2]; + + for (int i=29; i>=0; --i) + result = (result<<1) ^ table[((b>>i)&2) + (result>>31)]; + + return (b&1) ? result ^ a : result; +#endif +} + +GF2_32::Element GF2_32::MultiplicativeInverse(Element a) const +{ + if (a <= 1) // 1 is a special case + return a; + + // warning - don't try to adapt this algorithm for another situation + word32 g0=m_modulus, g1=a, g2=a; + word32 v0=0, v1=1, v2=1; + + assert(g1); + + while (!(g2 & 0x80000000)) + { + g2 <<= 1; + v2 <<= 1; + } + + g2 <<= 1; + v2 <<= 1; + + g0 ^= g2; + v0 ^= v2; + + while (g0 != 1) + { + if (g1 < g0 || ((g0^g1) < g0 && (g0^g1) < g1)) + { + assert(BitPrecision(g1) <= BitPrecision(g0)); + g2 = g1; + v2 = v1; + } + else + { + assert(BitPrecision(g1) > BitPrecision(g0)); + g2 = g0; g0 = g1; g1 = g2; + v2 = v0; v0 = v1; v1 = v2; + } + + while ((g0^g2) >= g2) + { + assert(BitPrecision(g0) > BitPrecision(g2)); + g2 <<= 1; + v2 <<= 1; + } + + assert(BitPrecision(g0) == BitPrecision(g2)); + g0 ^= g2; + v0 ^= v2; + } + + return v0; +} + +NAMESPACE_END diff --git a/gf2_32.h b/gf2_32.h new file mode 100644 index 0000000..31713f4 --- /dev/null +++ b/gf2_32.h @@ -0,0 +1,66 @@ +#ifndef CRYPTOPP_GF2_32_H +#define CRYPTOPP_GF2_32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! GF(2^32) with polynomial basis +class GF2_32 +{ +public: + typedef word32 Element; + typedef int RandomizationParameter; + + GF2_32(word32 modulus=0x0000008D) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {return rng.GenerateWord32();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Identity() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {return 0;} + + Element MultiplicativeIdentity() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word32 m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/gf2n.cpp b/gf2n.cpp new file mode 100644 index 0000000..3043075 --- /dev/null +++ b/gf2n.cpp @@ -0,0 +1,870 @@ +// gf2n.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gf2n.h" +#include "algebra.h" +#include "words.h" +#include "rng.h" +#include "asn.h" +#include "oids.h" + +#include <iostream> + +#include "algebra.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +PolynomialMod2::PolynomialMod2() +{ +} + +PolynomialMod2::PolynomialMod2(word value, unsigned int bitLength) + : reg(BitsToWords(bitLength)) +{ + assert(value==0 || reg.size()>0); + + if (reg.size() > 0) + { + reg[0] = value; + SetWords(reg+1, 0, reg.size()-1); + } +} + +PolynomialMod2::PolynomialMod2(const PolynomialMod2& t) + : reg(t.reg.size()) +{ + CopyWords(reg, t.reg, reg.size()); +} + +void PolynomialMod2::Randomize(RandomNumberGenerator &rng, unsigned int nbits) +{ + const unsigned int nbytes = nbits/8 + 1; + SecByteBlock buf(nbytes); + rng.GenerateBlock(buf, nbytes); + buf[0] = (byte)Crop(buf[0], nbits % 8); + Decode(buf, nbytes); +} + +PolynomialMod2 PolynomialMod2::AllOnes(unsigned int bitLength) +{ + PolynomialMod2 result((word)0, bitLength); + SetWords(result.reg, ~(word)0, result.reg.size()); + if (bitLength%WORD_BITS) + result.reg[result.reg.size()-1] = (word)Crop(result.reg[result.reg.size()-1], bitLength%WORD_BITS); + return result; +} + +void PolynomialMod2::SetBit(unsigned int n, int value) +{ + if (value) + { + reg.CleanGrow(n/WORD_BITS + 1); + reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS)); + } + else + { + if (n/WORD_BITS < reg.size()) + reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS)); + } +} + +byte PolynomialMod2::GetByte(unsigned int n) const +{ + if (n/WORD_SIZE >= reg.size()) + return 0; + else + return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); +} + +void PolynomialMod2::SetByte(unsigned int n, byte value) +{ + reg.CleanGrow(BytesToWords(n+1)); + reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); + reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); +} + +PolynomialMod2 PolynomialMod2::Monomial(unsigned i) +{ + PolynomialMod2 r((word)0, i+1); + r.SetBit(i); + return r; +} + +PolynomialMod2 PolynomialMod2::Trinomial(unsigned t0, unsigned t1, unsigned t2) +{ + PolynomialMod2 r((word)0, t0+1); + r.SetBit(t0); + r.SetBit(t1); + r.SetBit(t2); + return r; +} + +PolynomialMod2 PolynomialMod2::Pentanomial(unsigned t0, unsigned t1, unsigned t2, unsigned int t3, unsigned int t4) +{ + PolynomialMod2 r((word)0, t0+1); + r.SetBit(t0); + r.SetBit(t1); + r.SetBit(t2); + r.SetBit(t3); + r.SetBit(t4); + return r; +} + +const PolynomialMod2 &PolynomialMod2::Zero() +{ + static const PolynomialMod2 zero; + return zero; +} + +const PolynomialMod2 &PolynomialMod2::One() +{ + static const PolynomialMod2 one = 1; + return one; +} + +void PolynomialMod2::Decode(const byte *input, unsigned int inputLen) +{ + StringStore store(input, inputLen); + Decode(store, inputLen); +} + +unsigned int PolynomialMod2::Encode(byte *output, unsigned int outputLen) const +{ + ArraySink sink(output, outputLen); + return Encode(sink, outputLen); +} + +void PolynomialMod2::Decode(BufferedTransformation &bt, unsigned int inputLen) +{ + reg.CleanNew(BytesToWords(inputLen)); + + for (unsigned int i=inputLen; i > 0; i--) + { + byte b; + bt.Get(b); + reg[(i-1)/WORD_SIZE] |= b << ((i-1)%WORD_SIZE)*8; + } +} + +unsigned int PolynomialMod2::Encode(BufferedTransformation &bt, unsigned int outputLen) const +{ + for (unsigned int i=outputLen; i > 0; i--) + bt.Put(GetByte(i-1)); + return outputLen; +} + +void PolynomialMod2::DEREncodeAsOctetString(BufferedTransformation &bt, unsigned int length) const +{ + DERGeneralEncoder enc(bt, OCTET_STRING); + Encode(enc, length); + enc.MessageEnd(); +} + +void PolynomialMod2::BERDecodeAsOctetString(BufferedTransformation &bt, unsigned int length) +{ + BERGeneralDecoder dec(bt, OCTET_STRING); + if (!dec.IsDefiniteLength() || dec.RemainingLength() != length) + BERDecodeError(); + Decode(dec, length); + dec.MessageEnd(); +} + +unsigned int PolynomialMod2::WordCount() const +{ + return CountWords(reg, reg.size()); +} + +unsigned int PolynomialMod2::ByteCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int PolynomialMod2::BitCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int PolynomialMod2::Parity() const +{ + unsigned i; + word temp=0; + for (i=0; i<reg.size(); i++) + temp ^= reg[i]; + return CryptoPP::Parity(temp); +} + +PolynomialMod2& PolynomialMod2::operator=(const PolynomialMod2& t) +{ + reg.Assign(t.reg); + return *this; +} + +PolynomialMod2& PolynomialMod2::operator^=(const PolynomialMod2& t) +{ + reg.CleanGrow(t.reg.size()); + XorWords(reg, t.reg, t.reg.size()); + return *this; +} + +PolynomialMod2 PolynomialMod2::Xor(const PolynomialMod2 &b) const +{ + if (b.reg.size() >= reg.size()) + { + PolynomialMod2 result((word)0, b.reg.size()*WORD_BITS); + XorWords(result.reg, reg, b.reg, reg.size()); + CopyWords(result.reg+reg.size(), b.reg+reg.size(), b.reg.size()-reg.size()); + return result; + } + else + { + PolynomialMod2 result((word)0, reg.size()*WORD_BITS); + XorWords(result.reg, reg, b.reg, b.reg.size()); + CopyWords(result.reg+b.reg.size(), reg+b.reg.size(), reg.size()-b.reg.size()); + return result; + } +} + +PolynomialMod2 PolynomialMod2::And(const PolynomialMod2 &b) const +{ + PolynomialMod2 result((word)0, WORD_BITS*STDMIN(reg.size(), b.reg.size())); + AndWords(result.reg, reg, b.reg, result.reg.size()); + return result; +} + +PolynomialMod2 PolynomialMod2::Times(const PolynomialMod2 &b) const +{ + PolynomialMod2 result((word)0, BitCount() + b.BitCount()); + + for (int i=b.Degree(); i>=0; i--) + { + result <<= 1; + if (b[i]) + XorWords(result.reg, reg, reg.size()); + } + return result; +} + +PolynomialMod2 PolynomialMod2::Squared() const +{ + static const word map[16] = {0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}; + + PolynomialMod2 result((word)0, 2*reg.size()*WORD_BITS); + + for (unsigned i=0; i<reg.size(); i++) + { + unsigned j; + + for (j=0; j<WORD_BITS; j+=8) + result.reg[2*i] |= map[(reg[i] >> (j/2)) % 16] << j; + + for (j=0; j<WORD_BITS; j+=8) + result.reg[2*i+1] |= map[(reg[i] >> (j/2 + WORD_BITS/2)) % 16] << j; + } + + return result; +} + +void PolynomialMod2::Divide(PolynomialMod2 &remainder, PolynomialMod2 "ient, + const PolynomialMod2 ÷nd, const PolynomialMod2 &divisor) +{ + if (!divisor) + throw PolynomialMod2::DivideByZero(); + + int degree = divisor.Degree(); + remainder.reg.CleanNew(BitsToWords(degree+1)); + if (dividend.BitCount() >= divisor.BitCount()) + quotient.reg.CleanNew(BitsToWords(dividend.BitCount() - divisor.BitCount() + 1)); + else + quotient.reg.CleanNew(0); + + for (int i=dividend.Degree(); i>=0; i--) + { + remainder <<= 1; + remainder.reg[0] |= dividend[i]; + if (remainder[degree]) + { + remainder -= divisor; + quotient.SetBit(i); + } + } +} + +PolynomialMod2 PolynomialMod2::DividedBy(const PolynomialMod2 &b) const +{ + PolynomialMod2 remainder, quotient; + PolynomialMod2::Divide(remainder, quotient, *this, b); + return quotient; +} + +PolynomialMod2 PolynomialMod2::Modulo(const PolynomialMod2 &b) const +{ + PolynomialMod2 remainder, quotient; + PolynomialMod2::Divide(remainder, quotient, *this, b); + return remainder; +} + +PolynomialMod2& PolynomialMod2::operator<<=(unsigned int n) +{ + if (!reg.size()) + return *this; + + int i; + word u; + word carry=0; + word *r=reg; + + if (n==1) // special case code for most frequent case + { + i = reg.size(); + while (i--) + { + u = *r; + *r = (u << 1) | carry; + carry = u >> (WORD_BITS-1); + r++; + } + + if (carry) + { + reg.Grow(reg.size()+1); + reg[reg.size()-1] = carry; + } + + return *this; + } + + int shiftWords = n / WORD_BITS; + int shiftBits = n % WORD_BITS; + + if (shiftBits) + { + i = reg.size(); + while (i--) + { + u = *r; + *r = (u << shiftBits) | carry; + carry = u >> (WORD_BITS-shiftBits); + r++; + } + } + + if (carry) + { + reg.Grow(reg.size()+shiftWords+1); + reg[reg.size()-1] = carry; + } + else + reg.Grow(reg.size()+shiftWords); + + if (shiftWords) + { + for (i = reg.size()-1; i>=shiftWords; i--) + reg[i] = reg[i-shiftWords]; + for (; i>=0; i--) + reg[i] = 0; + } + + return *this; +} + +PolynomialMod2& PolynomialMod2::operator>>=(unsigned int n) +{ + if (!reg.size()) + return *this; + + int shiftWords = n / WORD_BITS; + int shiftBits = n % WORD_BITS; + + unsigned i; + word u; + word carry=0; + word *r=reg+reg.size()-1; + + if (shiftBits) + { + i = reg.size(); + while (i--) + { + u = *r; + *r = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + r--; + } + } + + if (shiftWords) + { + for (i=0; i<reg.size()-shiftWords; i++) + reg[i] = reg[i+shiftWords]; + for (; i<reg.size(); i++) + reg[i] = 0; + } + + return *this; +} + +PolynomialMod2 PolynomialMod2::operator<<(unsigned int n) const +{ + PolynomialMod2 result(*this); + return result<<=n; +} + +PolynomialMod2 PolynomialMod2::operator>>(unsigned int n) const +{ + PolynomialMod2 result(*this); + return result>>=n; +} + +bool PolynomialMod2::operator!() const +{ + for (unsigned i=0; i<reg.size(); i++) + if (reg[i]) return false; + return true; +} + +bool PolynomialMod2::Equals(const PolynomialMod2 &rhs) const +{ + unsigned i, smallerSize = STDMIN(reg.size(), rhs.reg.size()); + + for (i=0; i<smallerSize; i++) + if (reg[i] != rhs.reg[i]) return false; + + for (i=smallerSize; i<reg.size(); i++) + if (reg[i] != 0) return false; + + for (i=smallerSize; i<rhs.reg.size(); i++) + if (rhs.reg[i] != 0) return false; + + return true; +} + +std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a) +{ + // Get relevant conversion specifications from ostream. + long f = out.flags() & std::ios::basefield; // Get base digits. + int bits, block; + char suffix; + switch(f) + { + case std::ios::oct : + bits = 3; + block = 4; + suffix = 'o'; + break; + case std::ios::hex : + bits = 4; + block = 2; + suffix = 'h'; + break; + default : + bits = 1; + block = 8; + suffix = 'b'; + } + + if (!a) + return out << '0' << suffix; + + SecBlock<char> s(a.BitCount()/bits+1); + unsigned i; + const char vec[]="0123456789ABCDEF"; + + for (i=0; i*bits < a.BitCount(); i++) + { + int digit=0; + for (int j=0; j<bits; j++) + digit |= a[i*bits+j] << j; + s[i]=vec[digit]; + } + + while (i--) + { + out << s[i]; + if (i && (i%block)==0) + out << ','; + } + + return out << suffix; +} + +PolynomialMod2 PolynomialMod2::Gcd(const PolynomialMod2 &a, const PolynomialMod2 &b) +{ + return EuclideanDomainOf<PolynomialMod2>().Gcd(a, b); +} + +PolynomialMod2 PolynomialMod2::InverseMod(const PolynomialMod2 &modulus) const +{ + typedef EuclideanDomainOf<PolynomialMod2> Domain; + return QuotientRing<Domain>(Domain(), modulus).MultiplicativeInverse(*this); +} + +bool PolynomialMod2::IsIrreducible() const +{ + signed int d = Degree(); + if (d <= 0) + return false; + + PolynomialMod2 t(2), u(t); + for (int i=1; i<=d/2; i++) + { + u = u.Squared()%(*this); + if (!Gcd(u+t, *this).IsUnit()) + return false; + } + return true; +} + +// ******************************************************** + +GF2NP::GF2NP(const PolynomialMod2 &modulus) + : QuotientRing<EuclideanDomainOf<PolynomialMod2> >(EuclideanDomainOf<PolynomialMod2>(), modulus), m(modulus.Degree()) +{ +} + +GF2NP::Element GF2NP::SquareRoot(const Element &a) const +{ + Element r = a; + for (unsigned int i=1; i<m; i++) + r = Square(r); + return r; +} + +GF2NP::Element GF2NP::HalfTrace(const Element &a) const +{ + assert(m%2 == 1); + Element h = a; + for (unsigned int i=1; i<=(m-1)/2; i++) + h = Add(Square(Square(h)), a); + return h; +} + +GF2NP::Element GF2NP::SolveQuadraticEquation(const Element &a) const +{ + if (m%2 == 0) + { + Element z, w; + do + { + LC_RNG rng(11111); + Element p(rng, m); + z = PolynomialMod2::Zero(); + w = p; + for (unsigned int i=1; i<=m-1; i++) + { + w = Square(w); + z = Square(z); + Accumulate(z, Multiply(w, a)); + Accumulate(w, p); + } + } while (w.IsZero()); + return z; + } + else + return HalfTrace(a); +} + +// ******************************************************** + +GF2NT::GF2NT(unsigned int t0, unsigned int t1, unsigned int t2) + : GF2NP(PolynomialMod2::Trinomial(t0, t1, t2)) + , t0(t0), t1(t1) + , result((word)0, m) +{ + assert(t0 > t1 && t1 > t2 && t2==0); +} + +const GF2NT::Element& GF2NT::MultiplicativeInverse(const Element &a) const +{ + if (t0-t1 < WORD_BITS) + return GF2NP::MultiplicativeInverse(a); + + SecWordBlock T(m_modulus.reg.size() * 4); + word *b = T; + word *c = T+m_modulus.reg.size(); + word *f = T+2*m_modulus.reg.size(); + word *g = T+3*m_modulus.reg.size(); + unsigned int bcLen=1, fgLen=m_modulus.reg.size(); + unsigned int k=0; + + SetWords(T, 0, 3*m_modulus.reg.size()); + b[0]=1; + assert(a.reg.size() <= m_modulus.reg.size()); + CopyWords(f, a.reg, a.reg.size()); + CopyWords(g, m_modulus.reg, m_modulus.reg.size()); + + while (1) + { + word t=f[0]; + while (!t) + { + ShiftWordsRightByWords(f, fgLen, 1); + if (c[bcLen-1]) + bcLen++; + assert(bcLen <= m_modulus.reg.size()); + ShiftWordsLeftByWords(c, bcLen, 1); + k+=WORD_BITS; + t=f[0]; + } + + unsigned int i=0; + while (t%2 == 0) + { + t>>=1; + i++; + } + k+=i; + + if (t==1 && CountWords(f, fgLen)==1) + break; + + if (i==1) + { + ShiftWordsRightByBits(f, fgLen, 1); + t=ShiftWordsLeftByBits(c, bcLen, 1); + } + else + { + ShiftWordsRightByBits(f, fgLen, i); + t=ShiftWordsLeftByBits(c, bcLen, i); + } + if (t) + { + c[bcLen] = t; + bcLen++; + assert(bcLen <= m_modulus.reg.size()); + } + + if (f[fgLen-1]==0 && g[fgLen-1]==0) + fgLen--; + + if (f[fgLen-1] < g[fgLen-1]) + { + std::swap(f, g); + std::swap(b, c); + } + + XorWords(f, g, fgLen); + XorWords(b, c, bcLen); + } + + while (k >= WORD_BITS) + { + word temp = b[0]; + // right shift b + for (unsigned i=0; i+1<BitsToWords(m); i++) + b[i] = b[i+1]; + b[BitsToWords(m)-1] = 0; + + if (t1 < WORD_BITS) + for (unsigned int j=0; j<WORD_BITS-t1; j++) + temp ^= ((temp >> j) & 1) << (t1 + j); + else + b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; + + if (t1 % WORD_BITS) + b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); + + if (t0%WORD_BITS) + { + b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; + b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); + } + else + b[t0/WORD_BITS-1] ^= temp; + + k -= WORD_BITS; + } + + if (k) + { + word temp = b[0] << (WORD_BITS - k); + ShiftWordsRightByBits(b, BitsToWords(m), k); + + if (t1 < WORD_BITS) + for (unsigned int j=0; j<WORD_BITS-t1; j++) + temp ^= ((temp >> j) & 1) << (t1 + j); + else + b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; + + if (t1 % WORD_BITS) + b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); + + if (t0%WORD_BITS) + { + b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; + b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); + } + else + b[t0/WORD_BITS-1] ^= temp; + } + + CopyWords(result.reg.begin(), b, result.reg.size()); + return result; +} + +const GF2NT::Element& GF2NT::Multiply(const Element &a, const Element &b) const +{ + unsigned int aSize = STDMIN(a.reg.size(), result.reg.size()); + Element r((word)0, m); + + for (int i=m-1; i>=0; i--) + { + if (r[m-1]) + { + ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); + XorWords(r.reg.begin(), m_modulus.reg, r.reg.size()); + } + else + ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); + + if (b[i]) + XorWords(r.reg.begin(), a.reg, aSize); + } + + if (m%WORD_BITS) + r.reg.begin()[r.reg.size()-1] = (word)Crop(r.reg[r.reg.size()-1], m%WORD_BITS); + + CopyWords(result.reg.begin(), r.reg.begin(), result.reg.size()); + return result; +} + +const GF2NT::Element& GF2NT::Reduced(const Element &a) const +{ + if (t0-t1 < WORD_BITS) + return m_domain.Mod(a, m_modulus); + + SecWordBlock b(a.reg); + + unsigned i; + for (i=b.size()-1; i>=BitsToWords(t0); i--) + { + word temp = b[i]; + + if (t0%WORD_BITS) + { + b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; + b[i-t0/WORD_BITS-1] ^= temp << (WORD_BITS - t0%WORD_BITS); + } + else + b[i-t0/WORD_BITS] ^= temp; + + if ((t0-t1)%WORD_BITS) + { + b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; + b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); + } + else + b[i-(t0-t1)/WORD_BITS] ^= temp; + } + + if (i==BitsToWords(t0)-1 && t0%WORD_BITS) + { + word mask = ((word)1<<(t0%WORD_BITS))-1; + word temp = b[i] & ~mask; + b[i] &= mask; + + b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; + + if ((t0-t1)%WORD_BITS) + { + b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; + if ((t0-t1)%WORD_BITS > t0%WORD_BITS) + b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); + else + assert(temp << (WORD_BITS - (t0-t1)%WORD_BITS) == 0); + } + else + b[i-(t0-t1)/WORD_BITS] ^= temp; + } + + SetWords(result.reg.begin(), 0, result.reg.size()); + CopyWords(result.reg.begin(), b, STDMIN(b.size(), result.reg.size())); + return result; +} + +void GF2NP::DEREncodeElement(BufferedTransformation &out, const Element &a) const +{ + a.DEREncodeAsOctetString(out, MaxElementByteLength()); +} + +void GF2NP::BERDecodeElement(BufferedTransformation &in, Element &a) const +{ + a.BERDecodeAsOctetString(in, MaxElementByteLength()); +} + +void GF2NT::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::characteristic_two_field().DEREncode(seq); + DERSequenceEncoder parameters(seq); + DEREncodeUnsigned(parameters, m); + ASN1::tpBasis().DEREncode(parameters); + DEREncodeUnsigned(parameters, t1); + parameters.MessageEnd(); + seq.MessageEnd(); +} + +void GF2NPP::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::characteristic_two_field().DEREncode(seq); + DERSequenceEncoder parameters(seq); + DEREncodeUnsigned(parameters, m); + ASN1::ppBasis().DEREncode(parameters); + DERSequenceEncoder pentanomial(parameters); + DEREncodeUnsigned(pentanomial, t3); + DEREncodeUnsigned(pentanomial, t2); + DEREncodeUnsigned(pentanomial, t1); + pentanomial.MessageEnd(); + parameters.MessageEnd(); + seq.MessageEnd(); +} + +GF2NP * BERDecodeGF2NP(BufferedTransformation &bt) +{ + // VC60 workaround: auto_ptr lacks reset() + member_ptr<GF2NP> result; + + BERSequenceDecoder seq(bt); + if (OID(seq) != ASN1::characteristic_two_field()) + BERDecodeError(); + BERSequenceDecoder parameters(seq); + unsigned int m; + BERDecodeUnsigned(parameters, m); + OID oid(parameters); + if (oid == ASN1::tpBasis()) + { + unsigned int t1; + BERDecodeUnsigned(parameters, t1); + result.reset(new GF2NT(m, t1, 0)); + } + else if (oid == ASN1::ppBasis()) + { + unsigned int t1, t2, t3; + BERSequenceDecoder pentanomial(parameters); + BERDecodeUnsigned(pentanomial, t3); + BERDecodeUnsigned(pentanomial, t2); + BERDecodeUnsigned(pentanomial, t1); + pentanomial.MessageEnd(); + result.reset(new GF2NPP(m, t3, t2, t1, 0)); + } + else + { + BERDecodeError(); + return NULL; + } + parameters.MessageEnd(); + seq.MessageEnd(); + + return result.release(); +} + +NAMESPACE_END @@ -0,0 +1,359 @@ +#ifndef CRYPTOPP_GF2N_H +#define CRYPTOPP_GF2N_H + +/*! \file */ + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "algebra.h" + +#include <iosfwd> + +NAMESPACE_BEGIN(CryptoPP) + +//! Polynomial with Coefficients in GF(2) +/*! \nosubgrouping */ +class PolynomialMod2 +{ +public: + //! \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + //! divide by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialMod2: division by zero") {} + }; + + typedef unsigned int RandomizationParameter; + //@} + + //! \name CREATORS + //@{ + //! creates the zero polynomial + PolynomialMod2(); + //! copy constructor + PolynomialMod2(const PolynomialMod2& t); + + //! convert from word + /*! value should be encoded with the least significant bit as coefficient to x^0 + and most significant bit as coefficient to x^(WORD_BITS-1) + bitLength denotes how much memory to allocate initially + */ + PolynomialMod2(word value, unsigned int bitLength=WORD_BITS); + + //! convert from big-endian byte array + PolynomialMod2(const byte *encodedPoly, unsigned int byteCount) + {Decode(encodedPoly, byteCount);} + + //! convert from big-endian form stored in a BufferedTransformation + PolynomialMod2(BufferedTransformation &encodedPoly, unsigned int byteCount) + {Decode(encodedPoly, byteCount);} + + //! create a random polynomial uniformly distributed over all polynomials with degree less than bitcount + PolynomialMod2(RandomNumberGenerator &rng, unsigned int bitcount) + {Randomize(rng, bitcount);} + + //! return x^i + static PolynomialMod2 Monomial(unsigned i); + //! return x^t0 + x^t1 + x^t2 + static PolynomialMod2 Trinomial(unsigned t0, unsigned t1, unsigned t2); + //! return x^t0 + x^t1 + x^t2 + x^t3 + x^t4 + static PolynomialMod2 Pentanomial(unsigned t0, unsigned t1, unsigned t2, unsigned int t3, unsigned int t4); + //! return x^(n-1) + ... + x + 1 + static PolynomialMod2 AllOnes(unsigned n); + + //! + static const PolynomialMod2 &Zero(); + //! + static const PolynomialMod2 &One(); + //@} + + //! \name ENCODE/DECODE + //@{ + //! minimum number of bytes to encode this polynomial + /*! MinEncodedSize of 0 is 1 */ + unsigned int MinEncodedSize() const {return STDMAX(1U, ByteCount());} + + //! encode in big-endian format + /*! if outputLen < MinEncodedSize, the most significant bytes will be dropped + if outputLen > MinEncodedSize, the most significant bytes will be padded + */ + unsigned int Encode(byte *output, unsigned int outputLen) const; + //! + unsigned int Encode(BufferedTransformation &bt, unsigned int outputLen) const; + + //! + void Decode(const byte *input, unsigned int inputLen); + //! + //* Precondition: bt.MaxRetrievable() >= inputLen + void Decode(BufferedTransformation &bt, unsigned int inputLen); + + //! encode value as big-endian octet string + void DEREncodeAsOctetString(BufferedTransformation &bt, unsigned int length) const; + //! decode value as big-endian octet string + void BERDecodeAsOctetString(BufferedTransformation &bt, unsigned int length); + //@} + + //! \name ACCESSORS + //@{ + //! number of significant bits = Degree() + 1 + unsigned int BitCount() const; + //! number of significant bytes = ceiling(BitCount()/8) + unsigned int ByteCount() const; + //! number of significant words = ceiling(ByteCount()/sizeof(word)) + unsigned int WordCount() const; + + //! return the n-th bit, n=0 being the least significant bit + bool GetBit(unsigned int n) const {return GetCoefficient(n)!=0;} + //! return the n-th byte + byte GetByte(unsigned int n) const; + + //! the zero polynomial will return a degree of -1 + signed int Degree() const {return BitCount()-1;} + //! degree + 1 + unsigned int CoefficientCount() const {return BitCount();} + //! return coefficient for x^i + int GetCoefficient(unsigned int i) const + {return (i/WORD_BITS < reg.size()) ? int(reg[i/WORD_BITS] >> (i % WORD_BITS)) & 1 : 0;} + //! return coefficient for x^i + int operator[](unsigned int i) const {return GetCoefficient(i);} + + //! + bool IsZero() const {return !*this;} + //! + bool Equals(const PolynomialMod2 &rhs) const; + //@} + + //! \name MANIPULATORS + //@{ + //! + PolynomialMod2& operator=(const PolynomialMod2& t); + //! + PolynomialMod2& operator&=(const PolynomialMod2& t); + //! + PolynomialMod2& operator^=(const PolynomialMod2& t); + //! + PolynomialMod2& operator+=(const PolynomialMod2& t) {return *this ^= t;} + //! + PolynomialMod2& operator-=(const PolynomialMod2& t) {return *this ^= t;} + //! + PolynomialMod2& operator*=(const PolynomialMod2& t); + //! + PolynomialMod2& operator/=(const PolynomialMod2& t); + //! + PolynomialMod2& operator%=(const PolynomialMod2& t); + //! + PolynomialMod2& operator<<=(unsigned int); + //! + PolynomialMod2& operator>>=(unsigned int); + + //! + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); + + //! + void SetBit(unsigned int i, int value = 1); + //! set the n-th byte to value + void SetByte(unsigned int n, byte value); + + //! + void SetCoefficient(unsigned int i, int value) {SetBit(i, value);} + + //! + void swap(PolynomialMod2 &a) {reg.swap(a.reg);} + //@} + + //! \name UNARY OPERATORS + //@{ + //! + bool operator!() const; + //! + PolynomialMod2 operator+() const {return *this;} + //! + PolynomialMod2 operator-() const {return *this;} + //@} + + //! \name BINARY OPERATORS + //@{ + //! + PolynomialMod2 And(const PolynomialMod2 &b) const; + //! + PolynomialMod2 Xor(const PolynomialMod2 &b) const; + //! + PolynomialMod2 Plus(const PolynomialMod2 &b) const {return Xor(b);} + //! + PolynomialMod2 Minus(const PolynomialMod2 &b) const {return Xor(b);} + //! + PolynomialMod2 Times(const PolynomialMod2 &b) const; + //! + PolynomialMod2 DividedBy(const PolynomialMod2 &b) const; + //! + PolynomialMod2 Modulo(const PolynomialMod2 &b) const; + + //! + PolynomialMod2 operator>>(unsigned int n) const; + //! + PolynomialMod2 operator<<(unsigned int n) const; + //@} + + //! \name OTHER ARITHMETIC FUNCTIONS + //@{ + //! sum modulo 2 of all coefficients + unsigned int Parity() const; + + //! check for irreducibility + bool IsIrreducible() const; + + //! is always zero since we're working modulo 2 + PolynomialMod2 Doubled() const {return Zero();} + //! + PolynomialMod2 Squared() const; + + //! only 1 is a unit + bool IsUnit() const {return Equals(One());} + //! return inverse if *this is a unit, otherwise return 0 + PolynomialMod2 MultiplicativeInverse() const {return IsUnit() ? One() : Zero();} + + //! greatest common divisor + static PolynomialMod2 Gcd(const PolynomialMod2 &a, const PolynomialMod2 &n); + //! calculate multiplicative inverse of *this mod n + PolynomialMod2 InverseMod(const PolynomialMod2 &) const; + + //! calculate r and q such that (a == d*q + r) && (deg(r) < deg(d)) + static void Divide(PolynomialMod2 &r, PolynomialMod2 &q, const PolynomialMod2 &a, const PolynomialMod2 &d); + //@} + + //! \name INPUT/OUTPUT + //@{ + //! + friend std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a); + //@} + +private: + friend class GF2NT; + + SecWordBlock reg; +}; + +//! GF(2^n) with Polynomial Basis +class GF2NP : public QuotientRing<EuclideanDomainOf<PolynomialMod2> > +{ +public: + GF2NP(const PolynomialMod2 &modulus); + + virtual GF2NP * Clone() const {return new GF2NP(*this);} + virtual void DEREncode(BufferedTransformation &bt) const + {assert(false);} // no ASN.1 syntax yet for general polynomial basis + + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + bool Equal(const Element &a, const Element &b) const + {assert(a.Degree() < m_modulus.Degree() && b.Degree() < m_modulus.Degree()); return a.Equals(b);} + + bool IsUnit(const Element &a) const + {assert(a.Degree() < m_modulus.Degree()); return !!a;} + + unsigned int MaxElementBitLength() const + {return m;} + + unsigned int MaxElementByteLength() const + {return BitsToBytes(MaxElementBitLength());} + + Element SquareRoot(const Element &a) const; + + Element HalfTrace(const Element &a) const; + + // returns z such that z^2 + z == a + Element SolveQuadraticEquation(const Element &a) const; + +protected: + unsigned int m; +}; + +//! GF(2^n) with Trinomial Basis +class GF2NT : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2 + GF2NT(unsigned int t0, unsigned int t1, unsigned int t2); + + GF2NP * Clone() const {return new GF2NT(*this);} + void DEREncode(BufferedTransformation &bt) const; + + const Element& Multiply(const Element &a, const Element &b) const; + + const Element& Square(const Element &a) const + {return Reduced(a.Squared());} + + const Element& MultiplicativeInverse(const Element &a) const; + +private: + const Element& Reduced(const Element &a) const; + + unsigned int t0, t1; + mutable PolynomialMod2 result; +}; + +//! GF(2^n) with Pentanomial Basis +class GF2NPP : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2 + x^t3 + x^t4, t0 > t1 > t2 > t3 > t4 + GF2NPP(unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4) + : GF2NP(PolynomialMod2::Pentanomial(t0, t1, t2, t3, t4)), t0(t0), t1(t1), t2(t2), t3(t3) {} + + GF2NP * Clone() const {return new GF2NPP(*this);} + void DEREncode(BufferedTransformation &bt) const; + +private: + unsigned int t0, t1, t2, t3; +}; + +// construct new GF2NP from the ASN.1 sequence Characteristic-two +GF2NP * BERDecodeGF2NP(BufferedTransformation &bt); + +//! +inline bool operator==(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return a.Equals(b);} +//! +inline bool operator!=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return !(a==b);} +//! compares degree +inline bool operator> (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return a.Degree() > b.Degree();} +//! compares degree +inline bool operator>=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return a.Degree() >= b.Degree();} +//! compares degree +inline bool operator< (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return a.Degree() < b.Degree();} +//! compares degree +inline bool operator<=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) + {return a.Degree() <= b.Degree();} +//! +inline CryptoPP::PolynomialMod2 operator&(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.And(b);} +//! +inline CryptoPP::PolynomialMod2 operator^(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Xor(b);} +//! +inline CryptoPP::PolynomialMod2 operator+(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Plus(b);} +//! +inline CryptoPP::PolynomialMod2 operator-(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Minus(b);} +//! +inline CryptoPP::PolynomialMod2 operator*(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Times(b);} +//! +inline CryptoPP::PolynomialMod2 operator/(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.DividedBy(b);} +//! +inline CryptoPP::PolynomialMod2 operator%(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Modulo(b);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::PolynomialMod2 &a, CryptoPP::PolynomialMod2 &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/gfpcrypt.cpp b/gfpcrypt.cpp new file mode 100644 index 0000000..8d8b0bf --- /dev/null +++ b/gfpcrypt.cpp @@ -0,0 +1,249 @@ +// dsa.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gfpcrypt.h" +#include "asn.h" +#include "oids.h" +#include "nbtheory.h" + +NAMESPACE_BEGIN(CryptoPP) + +void TestInstantiations_gfpcrypt() +{ + GDSA<SHA>::Signer test; + GDSA<SHA>::Verifier test1; + DSA::Signer test5(NullRNG(), 100); + DSA::Signer test2(test5); + NR<SHA>::Signer test3; + NR<SHA>::Verifier test4; + DLIES<>::Encryptor test6; + DLIES<>::Decryptor test7; +} + +void DL_GroupParameters_DSA::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + Integer p, q, g; + + if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) + { + q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); + } + else + { + int modulusSize = 1024; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (!DSA::IsValidPrimeLength(modulusSize)) + throw InvalidArgument("DSA: not a valid prime length"); + + SecByteBlock seed(SHA::DIGESTSIZE); + Integer h; + int c; + + do + { + rng.GenerateBlock(seed, SHA::DIGESTSIZE); + } while (!DSA::GeneratePrimes(seed, SHA::DIGESTSIZE*8, c, p, modulusSize, q)); + + do + { + h.Randomize(rng, 2, p-2); + g = a_exp_b_mod_c(h, (p-1)/q, p); + } while (g <= 1); + } + + Initialize(p, q, g); +} + +bool DL_GroupParameters_DSA::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = DL_GroupParameters_GFP::ValidateGroup(rng, level); + pass = pass && DSA::IsValidPrimeLength(GetModulus().BitCount()); + pass = pass && GetSubgroupOrder().BitCount() == 160; + return pass; +} + +Integer NR_EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen) +{ + Integer h; + if (digestLen*8 < modulusBits) + h.Decode(digest, digestLen); + else + { + h.Decode(digest, BitsToBytes(modulusBits)); + h >>= BitsToBytes(modulusBits)*8 - modulusBits + 1; + } + return h; +} + +Integer DSA_EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen) +{ + Integer h; + if (digestLen*8 <= modulusBits) + h.Decode(digest, digestLen); + else + { + h.Decode(digest, BitsToBytes(modulusBits)); + h >>= BitsToBytes(modulusBits)*8 - modulusBits; + } + return h; +} + +bool DL_GroupParameters_IntegerBased::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + const Integer &p = GetModulus(), &q = GetSubgroupOrder(); + + bool pass = true; + pass = pass && p > Integer::One() && p.IsOdd(); + pass = pass && q > Integer::One() && q.IsOdd(); + + if (level >= 1) + pass = pass && GetCofactor() > Integer::One() && GetGroupOrder() % q == Integer::Zero(); + if (level >= 2) + pass = pass && VerifyPrime(rng, q, level-2) && VerifyPrime(rng, p, level-2); + + return pass; +} + +bool DL_GroupParameters_IntegerBased::ValidateElement(unsigned int level, const Integer &g, const DL_FixedBasePrecomputation<Integer> *gpc) const +{ + const Integer &p = GetModulus(), &q = GetSubgroupOrder(); + + bool pass = true; + pass = pass && GetFieldType() == 1 ? g.IsPositive() : g.NotNegative(); + pass = pass && g < p && !IsIdentity(g); + + if (level >= 1) + { + if (gpc) + pass = pass && gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g; + } + if (level >= 2) + { + if (GetFieldType() == 2) + pass = pass && Jacobi(g*g-4, p)==-1; + + // verifying that Lucas((p+1)/2, w, p)==2 is omitted because it's too costly + // and at most 1 bit is leaked if it's false + bool fullValidate = (GetFieldType() == 2 && level >= 3) || !FastSubgroupCheckAvailable(); + + if (fullValidate) + pass = pass && IsIdentity(gpc ? gpc->Exponentiate(GetGroupPrecomputation(), q) : ExponentiateElement(g, q)); + else if (GetFieldType() == 1) + pass = pass && Jacobi(g, p) == 1; + } + + return pass; +} + +void DL_GroupParameters_IntegerBased::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + Integer p, q, g; + + if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) + { + q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); + } + else + { + int modulusSize, subgroupOrderSize; + + if (!alg.GetIntValue("ModulusSize", modulusSize)) + modulusSize = alg.GetIntValueWithDefault("KeySize", 2048); + + if (!alg.GetIntValue("SubgroupOrderSize", subgroupOrderSize)) + subgroupOrderSize = GetDefaultSubgroupOrderSize(modulusSize); + + PrimeAndGenerator pg; + pg.Generate(GetFieldType() == 1 ? 1 : -1, rng, modulusSize, subgroupOrderSize); + p = pg.Prime(); + q = pg.SubPrime(); + g = pg.Generator(); + } + + Initialize(p, q, g); +} + +Integer DL_GroupParameters_IntegerBased::DecodeElement(const byte *encoded, bool checkForGroupMembership) const +{ + Integer g(encoded, GetModulus().ByteCount()); + if (!ValidateElement(1, g, NULL)) + throw DL_BadElement(); + return g; +} + +void DL_GroupParameters_IntegerBased::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder parameters(bt); + Integer p(parameters); + Integer q(parameters); + Integer g; + if (parameters.EndReached()) + { + g = q; + q = ComputeGroupOrder(p) / 2; + } + else + g.BERDecode(parameters); + parameters.MessageEnd(); + + SetModulusAndSubgroupGenerator(p, g); + SetSubgroupOrder(q); +} + +void DL_GroupParameters_IntegerBased::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder parameters(bt); + GetModulus().DEREncode(parameters); + m_q.DEREncode(parameters); + GetSubgroupGenerator().DEREncode(parameters); + parameters.MessageEnd(); +} + +bool DL_GroupParameters_IntegerBased::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<DL_GroupParameters<Element> >(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus); +} + +void DL_GroupParameters_IntegerBased::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY2(Modulus, SubgroupGenerator) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupOrder) + ; +} + +OID DL_GroupParameters_IntegerBased::GetAlgorithmID() const +{ + return ASN1::id_dsa(); +} + +void DL_GroupParameters_GFP::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + ModularArithmetic ma(GetModulus()); + ma.SimultaneousExponentiate(results, base, exponents, exponentsCount); +} + +DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::MultiplyElements(const Element &a, const Element &b) const +{ + return a_times_b_mod_c(a, b, GetModulus()); +} + +DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const +{ + ModularArithmetic ma(GetModulus()); + return ma.CascadeExponentiate(element1, exponent1, element2, exponent2); +} + +Integer DL_GroupParameters_IntegerBased::GetMaxExponent() const +{ + return STDMIN(GetSubgroupOrder()-1, Integer::Power2(2*DiscreteLogWorkFactor(GetFieldType()*GetModulus().BitCount()))); +} + +unsigned int DL_GroupParameters_IntegerBased::GetDefaultSubgroupOrderSize(unsigned int modulusSize) const +{ + return 2*DiscreteLogWorkFactor(GetFieldType()*modulusSize); +} + +NAMESPACE_END diff --git a/gfpcrypt.h b/gfpcrypt.h new file mode 100644 index 0000000..31db5a1 --- /dev/null +++ b/gfpcrypt.h @@ -0,0 +1,492 @@ +#ifndef CRYPTOPP_GFPCRYPT_H +#define CRYPTOPP_GFPCRYPT_H + +/** \file + Implementation of schemes based on DL over GF(p) +*/ + +#include "pubkey.h" +#include "modexppc.h" +#include "sha.h" +#include "algparam.h" +#include "asn.h" +#include "smartptr.h" +#include "hmac.h" + +#include <limits.h> + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class DL_GroupParameters_IntegerBased : public DL_GroupParameters<Integer>, public ASN1CryptoMaterial +{ + typedef DL_GroupParameters_IntegerBased ThisClass; + +public: + void Initialize(const DL_GroupParameters_IntegerBased ¶ms) + {Initialize(params.GetModulus(), params.GetSubgroupOrder(), params.GetSubgroupGenerator());} + void Initialize(RandomNumberGenerator &rng, unsigned int pbits) + {GenerateRandom(rng, MakeParameters("ModulusSize", (int)pbits));} + void Initialize(const Integer &p, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(ComputeGroupOrder(p)/2);} + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(q);} + + // ASN1Object interface + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // GeneratibleCryptoMaterial interface + /*! parameters: (ModulusSize, SubgroupOrderSize (optional)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // DL_GroupParameters + const Integer & GetSubgroupOrder() const {return m_q;} + Integer GetGroupOrder() const {return GetFieldType() == 1 ? GetModulus()-Integer::One() : GetModulus()+Integer::One();} + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Integer &element, const DL_FixedBasePrecomputation<Integer> *precomp) const; + bool FastSubgroupCheckAvailable() const {return GetCofactor() == 2;} + void EncodeElement(bool reversible, const Element &element, byte *encoded) const + {element.Encode(encoded, GetModulus().ByteCount());} + unsigned int GetEncodedElementSize(bool reversible) const {return GetModulus().ByteCount();} + Integer DecodeElement(const byte *encoded, bool checkForGroupMembership) const; + Integer ConvertElementToInteger(const Element &element) const + {return element;} + Integer GetMaxExponent() const; + + OID GetAlgorithmID() const; + + virtual const Integer & GetModulus() const =0; + virtual void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) =0; + + void SetSubgroupOrder(const Integer &q) + {m_q = q; ParametersChanged();} + +protected: + Integer ComputeGroupOrder(const Integer &modulus) const + {return modulus-(GetFieldType() == 1 ? 1 : -1);} + + // GF(p) = 1, GF(p^2) = 2 + virtual int GetFieldType() const =0; + virtual unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const; + +private: + Integer m_q; +}; + +//! . +template <class GROUP_PRECOMP, class BASE_PRECOMP = DL_FixedBasePrecomputationImpl<CPP_TYPENAME GROUP_PRECOMP::Element> > +class DL_GroupParameters_IntegerBasedImpl : public DL_GroupParametersImpl<GROUP_PRECOMP, BASE_PRECOMP, DL_GroupParameters_IntegerBased> +{ + typedef DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> ThisClass; + +public: + typedef typename GROUP_PRECOMP::Element Element; + + // GeneratibleCryptoMaterial interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + {return GetValueHelper<DL_GroupParameters_IntegerBased>(this, name, valueType, pValue).Assignable();} + + void AssignFrom(const NameValuePairs &source) + {AssignFromHelper<DL_GroupParameters_IntegerBased>(this, source);} + + // DL_GroupParameters + const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const {return m_gpc;} + DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() {return m_gpc;} + + // IntegerGroupParameters + const Integer & GetModulus() const {return m_groupPrecomputation.GetModulus();} + const Integer & GetGenerator() const {return m_gpc.GetBase(GetGroupPrecomputation());} + + void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) // these have to be set together + {m_groupPrecomputation.SetModulus(p); m_gpc.SetBase(GetGroupPrecomputation(), g); ParametersChanged();} + + // non-inherited + bool operator==(const DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> &rhs) const + {return GetModulus() == rhs.GetModulus() && GetGenerator() == rhs.GetGenerator() && GetSubgroupOrder() == rhs.GetSubgroupOrder();} + bool operator!=(const DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> &rhs) const + {return !operator==(rhs);} +}; + +//! . +class DL_GroupParameters_GFP : public DL_GroupParameters_IntegerBasedImpl<ModExpPrecomputation> +{ +public: + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::One();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper<DL_GroupParameters_IntegerBased>(this, name, valueType, pValue).Assignable(); + } + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + +protected: + int GetFieldType() const {return 1;} +}; + +//! . +class DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupParameters_GFP +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +//! . +template <class T> +class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T> +{ +public: + static const char * StaticAlgorithmName() {return "DSA-1363";} + + Integer EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen) const + { + return DSA_EncodeDigest(modulusBits, digest, digestLen); + } + + bool Sign(const DL_GroupParameters<T> ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r = params.ConvertElementToInteger(params.ExponentiateBase(k)) % q; + Integer kInv = k.InverseMod(q); + s = (kInv * (x*r + e)) % q; + return (!!r && !!s); + } + + bool Verify(const DL_GroupParameters<T> ¶ms, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q || s<1) + return false; + + Integer w = s.InverseMod(q); + Integer u1 = (e * w) % q; + Integer u2 = (r * w) % q; + // verify r == (g^u1 * y^u2 mod p) mod q + return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; + } +}; + +//! . +template <class T> +class DL_Algorithm_NR : public DL_ElgamalLikeSignatureAlgorithm<T> +{ +public: + static const char * StaticAlgorithmName() {return "NR";} + + Integer EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen) const + { + return NR_EncodeDigest(modulusBits, digest, digestLen); + } + + bool Sign(const DL_GroupParameters<T> ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r = (params.ConvertElementToInteger(params.ExponentiateBase(k)) + e) % q; + s = (k - x*r) % q; + return !!r; + } + + bool Verify(const DL_GroupParameters<T> ¶ms, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q) + return false; + + // check r == (m_g^s * m_y^r + m) mod m_q + return r == (params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(s, r)) + e) % q; + } +}; + +/*! DSA public key format is defined in 7.3.3 of RFC 2459. The + private key format is defined in 12.9 of PKCS #11 v2.10. */ +template <class GP> +class DL_PublicKey_GFP : public DL_PublicKeyImpl<GP> +{ +public: + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &y) + {AccessGroupParameters().Initialize(params); SetPublicElement(y);} + void Initialize(const Integer &p, const Integer &g, const Integer &y) + {AccessGroupParameters().Initialize(p, g); SetPublicElement(y);} + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &y) + {AccessGroupParameters().Initialize(p, q, g); SetPublicElement(y);} + + // X509PublicKey + void BERDecodeKey(BufferedTransformation &bt) + {SetPublicElement(Integer(bt));} + void DEREncodeKey(BufferedTransformation &bt) const + {GetPublicElement().DEREncode(bt);} +}; + +//! . +template <class GP> +class DL_PrivateKey_GFP : public DL_PrivateKeyImpl<GP> +{ +public: + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &g) + {GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupGenerator", g));} + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &q, const Integer &g) + {GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupOrder", q)("SubgroupGenerator", g));} + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &x) + {AccessGroupParameters().Initialize(params); SetPrivateExponent(x);} + void Initialize(const Integer &p, const Integer &g, const Integer &x) + {AccessGroupParameters().Initialize(p, g); SetPrivateExponent(x);} + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &x) + {AccessGroupParameters().Initialize(p, q, g); SetPrivateExponent(x);} +}; + +//! . +struct DL_SignatureKeys_GFP +{ + typedef DL_GroupParameters_GFP GroupParameters; + typedef DL_PublicKey_GFP<GroupParameters> PublicKey; + typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey; +}; + +//! . +struct DL_CryptoKeys_GFP +{ + typedef DL_GroupParameters_GFP_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP<GroupParameters> PublicKey; + typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey; +}; + +//! provided for backwards compatibility, this class uses the old non-standard Crypto++ key format +template <class BASE> +class DL_PublicKey_GFP_OldFormat : public BASE +{ +public: + void BERDecode(BufferedTransformation &bt) + { + BERSequenceDecoder seq(bt); + Integer v1(seq); + Integer v2(seq); + Integer v3(seq); + + if (seq.EndReached()) + { + AccessGroupParameters().Initialize(v1, v1/2, v2); + SetPublicElement(v3); + } + else + { + Integer v4(seq); + AccessGroupParameters().Initialize(v1, v2, v3); + SetPublicElement(v4); + } + + seq.MessageEnd(); + } + + void DEREncode(BufferedTransformation &bt) const + { + DERSequenceEncoder seq(bt); + GetGroupParameters().GetModulus().DEREncode(seq); + if (GetGroupParameters().GetCofactor() != 2) + GetGroupParameters().GetSubgroupOrder().DEREncode(seq); + GetGroupParameters().GetGenerator().DEREncode(seq); + GetPublicElement().DEREncode(seq); + seq.MessageEnd(); + } +}; + +//! provided for backwards compatibility, this class uses the old non-standard Crypto++ key format +template <class BASE> +class DL_PrivateKey_GFP_OldFormat : public BASE +{ +public: + void BERDecode(BufferedTransformation &bt) + { + BERSequenceDecoder seq(bt); + Integer v1(seq); + Integer v2(seq); + Integer v3(seq); + Integer v4(seq); + + if (seq.EndReached()) + { + AccessGroupParameters().Initialize(v1, v1/2, v2); + SetPrivateExponent(v4 % (v1/2)); // some old keys may have x >= q + } + else + { + Integer v5(seq); + AccessGroupParameters().Initialize(v1, v2, v3); + SetPrivateExponent(v5); + } + + seq.MessageEnd(); + } + + void DEREncode(BufferedTransformation &bt) const + { + DERSequenceEncoder seq(bt); + GetGroupParameters().GetModulus().DEREncode(seq); + if (GetGroupParameters().GetCofactor() != 2) + GetGroupParameters().GetSubgroupOrder().DEREncode(seq); + GetGroupParameters().GetGenerator().DEREncode(seq); + GetGroupParameters().ExponentiateBase(GetPrivateExponent()).DEREncode(seq); + GetPrivateExponent().DEREncode(seq); + seq.MessageEnd(); + } +}; + +//! <a href="http://www.weidai.com/scan-mirror/sig.html#DSA-1363">DSA-1363</a> +template <class H> +struct GDSA : public DL_SSA<DL_SignatureKeys_GFP, DL_Algorithm_GDSA<Integer>, H> +{ +}; + +//! <a href="http://www.weidai.com/scan-mirror/sig.html#NR">NR</a> +template <class H> +struct NR : public DL_SSA<DL_SignatureKeys_GFP, DL_Algorithm_NR<Integer>, H> +{ +}; + +//! . +class DL_GroupParameters_DSA : public DL_GroupParameters_GFP +{ +public: + /*! also checks that the lengths of p and q are allowed by the DSA standard */ + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + /*! parameters: (ModulusSize), or (Modulus, SubgroupOrder, SubgroupGenerator) */ + /*! ModulusSize must be between 512 and 1024, and divisible by 64 */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); +}; + +struct DSA; + +//! . +struct DL_Keys_DSA +{ + typedef DL_PublicKey_GFP<DL_GroupParameters_DSA> PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA> PrivateKey; +}; + +//! <a href="http://www.weidai.com/scan-mirror/sig.html#DSA">DSA</a> +struct DSA : public DL_SSA<DL_Keys_DSA, DL_Algorithm_GDSA<Integer>, SHA, DSA> +{ + static std::string StaticAlgorithmName() {return std::string("DSA");} + + //! Generate DSA primes according to NIST standard + /*! Both seedLength and primeLength are in bits, but seedLength should + be a multiple of 8. + If useInputCounterValue == true, the counter parameter is taken as input, otherwise it's used for output + */ + static bool GeneratePrimes(const byte *seed, unsigned int seedLength, int &counter, + Integer &p, unsigned int primeLength, Integer &q, bool useInputCounterValue = false); + + static bool IsValidPrimeLength(unsigned int pbits) + {return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;} + + enum { +#if (DSA_1024_BIT_MODULUS_ONLY) + MIN_PRIME_LENGTH = 1024, +#else + MIN_PRIME_LENGTH = 512, +#endif + MAX_PRIME_LENGTH = 1024, PRIME_LENGTH_MULTIPLE = 64}; +}; + +//! . +template <class MAC, bool DHAES_MODE> +class DL_EncryptionAlgorithm_Xor : public DL_SymmetricEncryptionAlgorithm +{ +public: + unsigned int GetSymmetricKeyLength(unsigned int plainTextLength) const + {return plainTextLength + MAC::DEFAULT_KEYLENGTH;} + unsigned int GetSymmetricCiphertextLength(unsigned int plainTextLength) const + {return plainTextLength + MAC::DIGESTSIZE;} + unsigned int GetMaxSymmetricPlaintextLength(unsigned int cipherTextLength) const + {return SaturatingSubtract(cipherTextLength, (unsigned int)MAC::DIGESTSIZE);} + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const + { + const byte *cipherKey, *macKey; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plainTextLength; + } + + xorbuf(cipherText, plainText, cipherKey, plainTextLength); + MAC(macKey).CalculateDigest(cipherText + plainTextLength, cipherText, plainTextLength); + } + DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const + { + unsigned int plainTextLength = GetMaxSymmetricPlaintextLength(cipherTextLength); + const byte *cipherKey, *macKey; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plainTextLength; + } + + if (!MAC(macKey).VerifyDigest(cipherText + plainTextLength, cipherText, plainTextLength)) + return DecodingResult(); + xorbuf(plainText, cipherText, cipherKey, plainTextLength); + return DecodingResult(plainTextLength); + } +}; + +//! . +template <class T, bool DHAES_MODE, class KDF> +class DL_KeyDerivationAlgorithm_P1363 : public DL_KeyDerivationAlgorithm<T> +{ +public: + void Derive(const DL_GroupParameters<T> ¶ms, byte *derivedKey, unsigned int derivedLength, const T &agreedElement, const T &ephemeralPublicKey) const + { + SecByteBlock agreedSecret; + if (DHAES_MODE) + { + agreedSecret.New(params.GetEncodedElementSize(true) + params.GetEncodedElementSize(false)); + params.EncodeElement(true, ephemeralPublicKey, agreedSecret); + params.EncodeElement(false, agreedElement, agreedSecret + params.GetEncodedElementSize(true)); + } + else + { + agreedSecret.New(params.GetEncodedElementSize(false)); + params.EncodeElement(false, agreedElement, agreedSecret); + } + + KDF::DeriveKey(derivedKey, derivedLength, agreedSecret, agreedSecret.size()); + } +}; + +//! Discrete Log Integrated Encryption Scheme, AKA <a href="http://www.weidai.com/scan-mirror/ca.html#DLIES">DLIES</a> +template <class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = true> +struct DLIES + : public DL_ES< + DL_CryptoKeys_GFP, + DL_KeyAgreementAlgorithm_DH<Integer, COFACTOR_OPTION>, + DL_KeyDerivationAlgorithm_P1363<Integer, DHAES_MODE, P1363_KDF2<SHA1> >, + DL_EncryptionAlgorithm_Xor<HMAC<SHA1>, DHAES_MODE>, + DLIES<> > +{ + static std::string StaticAlgorithmName() {return "DLIES";} // TODO: fix this after name is standardized +}; + +NAMESPACE_END + +#endif diff --git a/gost.cpp b/gost.cpp new file mode 100644 index 0000000..1dc2be4 --- /dev/null +++ b/gost.cpp @@ -0,0 +1,123 @@ +#include "pch.h" +#include "gost.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +// these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333 +const byte GOST::Base::sBox[8][16]={ + {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3}, + {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9}, + {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11}, + {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3}, + {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2}, + {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14}, + {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12}, + {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12}}; + +/* // these are the S-boxes given in the GOST source code listing in Applied + // Cryptography 2nd Ed., p. 644. they appear to be from the DES S-boxes + {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, + { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, + {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, + { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, + { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, + {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, + {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, + {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }}; +*/ + +bool GOST::Base::sTableCalculated = false; +word32 GOST::Base::sTable[4][256]; + +void GOST::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) +{ + AssertValidKeyLength(length); + + PrecalculateSTable(); + + GetUserKey(LITTLE_ENDIAN_ORDER, key.begin(), 8, userKey, KEYLENGTH); +} + +void GOST::Base::PrecalculateSTable() +{ + if (!sTableCalculated) + { + for (unsigned i = 0; i < 4; i++) + for (unsigned j = 0; j < 256; j++) + { + word32 temp = sBox[2*i][j%16] | (sBox[2*i+1][j/16] << 4); + sTable[i][j] = rotlMod(temp, 11+8*i); + } + + sTableCalculated=true; + } +} + +#define f(x) ( t=x, \ + sTable[3][GETBYTE(t, 3)] ^ sTable[2][GETBYTE(t, 2)] \ + ^ sTable[1][GETBYTE(t, 1)] ^ sTable[0][GETBYTE(t, 0)] ) + +typedef BlockGetAndPut<word32, LittleEndian> Block; + +void GOST::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 n1, n2, t; + + Block::Get(inBlock)(n1)(n2); + + for (unsigned int i=0; i<3; i++) + { + n2 ^= f(n1+key[0]); + n1 ^= f(n2+key[1]); + n2 ^= f(n1+key[2]); + n1 ^= f(n2+key[3]); + n2 ^= f(n1+key[4]); + n1 ^= f(n2+key[5]); + n2 ^= f(n1+key[6]); + n1 ^= f(n2+key[7]); + } + + n2 ^= f(n1+key[7]); + n1 ^= f(n2+key[6]); + n2 ^= f(n1+key[5]); + n1 ^= f(n2+key[4]); + n2 ^= f(n1+key[3]); + n1 ^= f(n2+key[2]); + n2 ^= f(n1+key[1]); + n1 ^= f(n2+key[0]); + + Block::Put(xorBlock, outBlock)(n2)(n1); +} + +void GOST::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 n1, n2, t; + + Block::Get(inBlock)(n1)(n2); + + n2 ^= f(n1+key[0]); + n1 ^= f(n2+key[1]); + n2 ^= f(n1+key[2]); + n1 ^= f(n2+key[3]); + n2 ^= f(n1+key[4]); + n1 ^= f(n2+key[5]); + n2 ^= f(n1+key[6]); + n1 ^= f(n2+key[7]); + + for (unsigned int i=0; i<3; i++) + { + n2 ^= f(n1+key[7]); + n1 ^= f(n2+key[6]); + n2 ^= f(n1+key[5]); + n1 ^= f(n2+key[4]); + n2 ^= f(n1+key[3]); + n1 ^= f(n2+key[2]); + n2 ^= f(n1+key[1]); + n1 ^= f(n2+key[0]); + } + + Block::Put(xorBlock, outBlock)(n2)(n1); +} + +NAMESPACE_END @@ -0,0 +1,57 @@ +#ifndef CRYPTOPP_GOST_H +#define CRYPTOPP_GOST_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct GOST_Info : public FixedBlockSize<8>, public FixedKeyLength<32> +{ + static const char *StaticAlgorithmName() {return "GOST";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#GOST">GOST</a> +class GOST : public GOST_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<GOST_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static void PrecalculateSTable(); + + static const byte sBox[8][16]; + static bool sTableCalculated; + static word32 sTable[4][256]; + + FixedSizeSecBlock<word32, 8> key; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef GOST::Encryption GOSTEncryption; +typedef GOST::Decryption GOSTDecryption; + +NAMESPACE_END + +#endif diff --git a/gostval.dat b/gostval.dat new file mode 100644 index 0000000..f89c98b --- /dev/null +++ b/gostval.dat @@ -0,0 +1,23 @@ +BE5EC2006CFF9DCF52354959F1FF0CBFE95061B5A648C10387069C25997C0672 +0DF82802B741A292 07F9027DF7F7DF89 + +B385272AC8D72A5A8B344BC80363AC4D09BF58F41F540624CBCB8FDCF55307D7 +1354EE9C0A11CD4C 4FB50536F960A7B1 + +AEE02F609A35660E4097E546FD3026B032CD107C7D459977ADF489BEF2652262 +6693D492C4B0CC39 670034AC0FA811B5 + +320E9D8422165D58911DFC7D8BBB1F81B0ECD924023BF94D9DF7DCF7801240E0 +99E2D13080928D79 8118FF9D3B3CFE7D + +C9F703BBBFC63691BFA3B7B87EA8FD5E8E8EF384EF733F1A61AEF68C8FFA265F +D1E787749C72814C A083826A790D3E0C + +728FEE32F04B4C654AD7F607D71C660C2C2670D7C999713233149A1C0C17A1F0 +D4C05323A4F7A7B5 4D1F2E6B0D9DE2CE + +35FC96402209500FCFDEF5352D1ABB038FE33FC0D9D58512E56370B22BAA133B +8742D9A05F6A3AF6 2F3BB84879D11E52 + +D416F630BE65B7FE150656183370E07018234EE5DA3D89C4CE9152A03E5BFB77 +F86506DA04E41CB8 96F0A5C77A04F5CE diff --git a/gzip.cpp b/gzip.cpp new file mode 100644 index 0000000..2cfee9c --- /dev/null +++ b/gzip.cpp @@ -0,0 +1,99 @@ +// gzip.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gzip.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Gzip::WritePrestreamHeader() +{ + m_totalLen = 0; + m_crc.Restart(); + + AttachedTransformation()->Put(MAGIC1); + AttachedTransformation()->Put(MAGIC2); + AttachedTransformation()->Put(DEFLATED); + AttachedTransformation()->Put(0); // general flag + AttachedTransformation()->PutWord32(0); // time stamp + byte extra = (GetDeflateLevel() == 1) ? FAST : ((GetDeflateLevel() == 9) ? SLOW : 0); + AttachedTransformation()->Put(extra); + AttachedTransformation()->Put(GZIP_OS_CODE); +} + +void Gzip::ProcessUncompressedData(const byte *inString, unsigned int length) +{ + m_crc.Update(inString, length); + m_totalLen += length; +} + +void Gzip::WritePoststreamTail() +{ + SecByteBlock crc(4); + m_crc.Final(crc); + AttachedTransformation()->Put(crc, 4); + AttachedTransformation()->PutWord32(m_totalLen, LITTLE_ENDIAN_ORDER); +} + +// ************************************************************* + +Gunzip::Gunzip(BufferedTransformation *attachment, bool repeat, int propagation) + : Inflator(attachment, repeat, propagation) +{ +} + +void Gunzip::ProcessPrestreamHeader() +{ + m_length = 0; + m_crc.Restart(); + + byte buf[6]; + byte b, flags; + + if (m_inQueue.Get(buf, 2)!=2) throw HeaderErr(); + if (buf[0] != MAGIC1 || buf[1] != MAGIC2) throw HeaderErr(); + if (!m_inQueue.Skip(1)) throw HeaderErr(); // skip extra flags + if (!m_inQueue.Get(flags)) throw HeaderErr(); + if (flags & (ENCRYPTED | CONTINUED)) throw HeaderErr(); + if (m_inQueue.Skip(6)!=6) throw HeaderErr(); // Skip file time, extra flags and OS type + + if (flags & EXTRA_FIELDS) // skip extra fields + { + word16 length; + if (m_inQueue.GetWord16(length, LITTLE_ENDIAN_ORDER) != 2) throw HeaderErr(); + if (m_inQueue.Skip(length)!=length) throw HeaderErr(); + } + + if (flags & FILENAME) // skip filename + do + if(!m_inQueue.Get(b)) throw HeaderErr(); + while (b); + + if (flags & COMMENTS) // skip comments + do + if(!m_inQueue.Get(b)) throw HeaderErr(); + while (b); +} + +void Gunzip::ProcessDecompressedData(const byte *inString, unsigned int length) +{ + AttachedTransformation()->Put(inString, length); + m_crc.Update(inString, length); + m_length += length; +} + +void Gunzip::ProcessPoststreamTail() +{ + SecByteBlock crc(4); + if (m_inQueue.Get(crc, 4) != 4) + throw TailErr(); + if (!m_crc.Verify(crc)) + throw CrcErr(); + + word32 lengthCheck; + if (m_inQueue.GetWord32(lengthCheck, LITTLE_ENDIAN_ORDER) != 4) + throw TailErr(); + if (lengthCheck != m_length) + throw LengthErr(); +} + +NAMESPACE_END @@ -0,0 +1,65 @@ +#ifndef CRYPTOPP_GZIP_H +#define CRYPTOPP_GZIP_H + +#include "zdeflate.h" +#include "zinflate.h" +#include "crc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// GZIP Compression (RFC 1952) +class Gzip : public Deflator +{ +public: + Gzip(BufferedTransformation *attachment=NULL, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE) + : Deflator(attachment, deflateLevel, log2WindowSize) {} + Gzip(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULL) + : Deflator(parameters, attachment) {} + +protected: + enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header + DEFLATED=8, FAST=4, SLOW=2}; + + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, unsigned int length); + void WritePoststreamTail(); + + unsigned long m_totalLen; + CRC32 m_crc; +}; + +/// GZIP Decompression (RFC 1952) +class Gunzip : public Inflator +{ +public: + typedef Inflator::Err Err; + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "Gunzip: header decoding error") {}}; + class TailErr : public Err {public: TailErr() : Err(INVALID_DATA_FORMAT, "Gunzip: tail too short") {}}; + class CrcErr : public Err {public: CrcErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: CRC check error") {}}; + class LengthErr : public Err {public: LengthErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: length check error") {}}; + + /*! \param repeat decompress multiple compressed streams in series + \param autoSignalPropagation 0 to turn off MessageEnd signal + */ + Gunzip(BufferedTransformation *attachment = NULL, bool repeat = false, int autoSignalPropagation = -1); + +protected: + enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header + DEFLATED=8}; + + enum FLAG_MASKS { + CONTINUED=2, EXTRA_FIELDS=4, FILENAME=8, COMMENTS=16, ENCRYPTED=32}; + + unsigned int MaxPrestreamHeaderSize() const {return 1024;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, unsigned int length); + unsigned int MaxPoststreamTailSize() const {return 8;} + void ProcessPoststreamTail(); + + unsigned long m_length; + CRC32 m_crc; +}; + +NAMESPACE_END + +#endif diff --git a/haval.cpp b/haval.cpp new file mode 100644 index 0000000..37a0bb0 --- /dev/null +++ b/haval.cpp @@ -0,0 +1,275 @@ +// haval.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "haval.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +HAVAL::HAVAL(unsigned int digestSize, unsigned int pass) + : IteratedHash<word32, LittleEndian, 128>(DIGESTSIZE) + , digestSize(digestSize), pass(pass) +{ + if (!(digestSize >= 16 && digestSize <= 32 && digestSize%4==0)) + throw InvalidArgument("HAVAL: invalid digest size"); + + if (!(pass >= 3 && pass <= 5)) + throw InvalidArgument("HAVAL: invalid number of passes"); + + Init(); +} + +void HAVAL::Init() +{ + m_digest[0] = 0x243F6A88; + m_digest[1] = 0x85A308D3; + m_digest[2] = 0x13198A2E; + m_digest[3] = 0x03707344; + m_digest[4] = 0xA4093822; + m_digest[5] = 0x299F31D0; + m_digest[6] = 0x082EFA98; + m_digest[7] = 0xEC4E6C89; +} + +inline void HAVAL::vTransform(const word32 *in) +{ + if (pass==3) + HAVAL3::Transform(m_digest, in); + else if (pass==4) + HAVAL4::Transform(m_digest, in); + else + HAVAL5::Transform(m_digest, in); +} + +void HAVAL::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(118, 1); // first byte of padding for HAVAL is 1 instead of 0x80 + CorrectEndianess(m_data, m_data, 120); + + m_data[29] &= 0xffff; + m_data[29] |= ((word32)digestSize<<25) | ((word32)pass<<19) | ((word32)HAVAL_VERSION<<16); + m_data[30] = GetBitCountLo(); + m_data[31] = GetBitCountHi(); + + vTransform(m_data); + Tailor(digestSize*8); + CorrectEndianess(m_digest, m_digest, digestSize); + memcpy(hash, m_digest, size); + + Restart(); // reinit for next use +} + +#define ROTR(x, y) rotrFixed(x, y##u) + +// fold digest down to desired size +void HAVAL::Tailor(unsigned int bitlen) +{ +#define EB(a, b, c) (m_digest[a] & (((~(word32)0) << b) & ((~(word32)0) >> (8*sizeof(word32)-b-c)))) +#define S(a, b) (a > b ? a - b : 32 + a - b) +#define T128(a, b, c, d, e) ROTR(EB(7, b, S(a,b)) | EB(6, c, S(b,c)) | EB(5, d, S(c,d)) | EB(4, e, S(d,e)), e) +#define T160(a, b, c, d) ROTR(EB(7, b, S(a,b)) | EB(6, c, S(b,c)) | EB(5, d, S(c,d)), d) +#define T192(a, b, c) ROTR(EB(7, b, S(a,b)) | EB(6, c, S(b,c)), c) +#define T224(a, b) ROTR(EB(7, b, S(a,b)), b) + + switch (bitlen) + { + case 128: + m_digest[0] += T128(8, 0, 24, 16, 8); + m_digest[1] += T128(16, 8, 0, 24, 16); + m_digest[2] += T128(24, 16, 8, 0, 24); + m_digest[3] += T128(0, 24, 16, 8, 0); + break; + + case 160: + m_digest[0] += T160(6, 0, 25, 19); + m_digest[1] += T160(12, 6, 0, 25); + m_digest[2] += T160(19, 12, 6, 0); + m_digest[3] += T160(25, 19, 12, 6); + m_digest[4] += T160(0, 25, 19, 12); + break; + + case 192: + m_digest[0] += T192(5, 0, 26); + m_digest[1] += T192(10, 5, 0); + m_digest[2] += T192(16, 10, 5); + m_digest[3] += T192(21, 16, 10); + m_digest[4] += T192(26, 21, 16); + m_digest[5] += T192(0, 26, 21); + break; + + case 224: + m_digest[0] += T224(0, 27); + m_digest[1] += T224(27, 22); + m_digest[2] += T224(22, 18); + m_digest[3] += T224(18, 13); + m_digest[4] += T224(13, 9); + m_digest[5] += T224(9, 4); + m_digest[6] += T224(4, 0); + break; + + case 256: + break; + + default: + assert(false); + } +} + +/* Nonlinear F functions */ + +/* #define F1(X6, X5, X4, X3, X2, X1, X0) \ + ((X1) & (X4) ^ (X2) & (X5) ^ (X3) & (X6) ^ (X0) & (X1) ^ (X0))*/ +#define F1(X6, X5, X4, X3, X2, X1, X0) \ + (((X1) & ((X4) ^ (X0))) ^ ((X2) & (X5)) ^ ((X3) & (X6)) ^ (X0)) + +/* #define F2(X6, X5, X4, X3, X2, X1, X0) \ + ((X1) & (X2) & (X3) ^ (X2) & (X4) & (X5) ^ \ + (X1) & (X2) ^ (X1) & (X4) ^ (X2) & (X6) ^ (X3) & (X5) ^ \ + (X4) & (X5) ^ (X0) & (X2) ^ (X0))*/ +#define F2(X6, X5, X4, X3, X2, X1, X0) \ + (((X2) & (((X1) & (~(X3))) ^ ((X4) & (X5)) ^ (X6) ^ (X0))) ^ \ + (((X4) & ((X1) ^ (X5))) ^ ((X3) & (X5)) ^ (X0))) + +/* #define F3(X6, X5, X4, X3, X2, X1, X0) \ + ((X1) & (X2) & (X3) ^ (X1) & (X4) ^ (X2) & (X5) ^ (X3) & (X6) ^ (X0) & +(X3) ^ (X0))*/ +#define F3(X6, X5, X4, X3, X2, X1, X0) \ + (((X3) & (((X1) & (X2)) ^ (X6) ^ (X0))) ^ ((X1) & (X4)) ^ \ + ((X2) & (X5)) ^ (X0)) + +/* #define F4(X6, X5, X4, X3, X2, X1, X0) \ + ((X1) & (X2) & (X3) ^ (X2) & (X4) & (X5) ^ (X3) & (X4) & (X6) ^ \ + (X1) & (X4) ^ (X2) & (X6) ^ (X3) & (X4) ^ (X3) & (X5) ^ \ + (X3) & (X6) ^ (X4) & (X5) ^ (X4) & (X6) ^ (X0) & (X4) ^(X0))*/ +#define F4(X6, X5, X4, X3, X2, X1, X0) \ + (((X4) & (((~(X2)) & (X5)) ^ ((X3) | (X6)) ^ (X1) ^ (X0))) ^ \ + ((X3) & (((X1) & (X2)) ^ (X5) ^ (X6))) ^ ((X2) & (X6)) ^ (X0)) + +/* #define F5(X6, X5, X4, X3, X2, X1, X0) \ + ((X1) & (X4) ^ (X2) & (X5) ^ (X3) & (X6) ^ \ + (X0) & (X1) & (X2) & (X3) ^ (X0) & (X5) ^ (X0))*/ +#define F5(X6, X5, X4, X3, X2, X1, X0) \ + (((X1) & ((X4) ^ ((X0) & (X2) & (X3)))) ^ \ + (((X2) ^ (X0)) & (X5)) ^ ((X3) & (X6)) ^ (X0)) + +#define p31(x) (x==0 ? 1 : (x==1 ? 0 : (x==2 ? 3 : (x==3 ? 5 : (x==4 ? 6 : (x==5 ? 2 : (x==6 ? 4 : 7))))))) +#define p41(x) (x==0 ? 2 : (x==1 ? 6 : (x==2 ? 1 : (x==3 ? 4 : (x==4 ? 5 : (x==5 ? 3 : (x==6 ? 0 : 7))))))) +#define p51(x) (x==0 ? 3 : (x==1 ? 4 : (x==2 ? 1 : (x==3 ? 0 : (x==4 ? 5 : (x==5 ? 2 : (x==6 ? 6 : 7))))))) +#define p32(x) (x==0 ? 4 : (x==1 ? 2 : (x==2 ? 1 : (x==3 ? 0 : (x==4 ? 5 : (x==5 ? 3 : (x==6 ? 6 : 7))))))) +#define p42(x) (x==0 ? 3 : (x==1 ? 5 : (x==2 ? 2 : (x==3 ? 0 : (x==4 ? 1 : (x==5 ? 6 : (x==6 ? 4 : 7))))))) +#define p52(x) (x==0 ? 6 : (x==1 ? 2 : (x==2 ? 1 : (x==3 ? 0 : (x==4 ? 3 : (x==5 ? 4 : (x==6 ? 5 : 7))))))) +#define p33(x) (x==0 ? 6 : (x==1 ? 1 : (x==2 ? 2 : (x==3 ? 3 : (x==4 ? 4 : (x==5 ? 5 : (x==6 ? 0 : 7))))))) +#define p43(x) (x==0 ? 1 : (x==1 ? 4 : (x==2 ? 3 : (x==3 ? 6 : (x==4 ? 0 : (x==5 ? 2 : (x==6 ? 5 : 7))))))) +#define p53(x) (x==0 ? 2 : (x==1 ? 6 : (x==2 ? 0 : (x==3 ? 4 : (x==4 ? 3 : (x==5 ? 1 : (x==6 ? 5 : 7))))))) +#define p44(x) (x==0 ? 6 : (x==1 ? 4 : (x==2 ? 0 : (x==3 ? 5 : (x==4 ? 2 : (x==5 ? 1 : (x==6 ? 3 : 7))))))) +#define p54(x) (x==0 ? 1 : (x==1 ? 5 : (x==2 ? 3 : (x==3 ? 2 : (x==4 ? 0 : (x==5 ? 4 : (x==6 ? 6 : 7))))))) +#define p55(x) (x==0 ? 2 : (x==1 ? 5 : (x==2 ? 0 : (x==3 ? 6 : (x==4 ? 4 : (x==5 ? 3 : (x==6 ? 1 : 7))))))) + +#define t(b,p,x,j) ((b&&((p(x)+8-j)%8<(8-j)))?E:T)[(p(x)+8-j)%8] + +#define FF(b, e, F, p, j, w, c) \ + T[7-j] = rotrFixed(F(t(b,p,0,j), t(b,p,1,j), t(b,p,2,j), t(b,p,3,j), t(b,p,4,j), t(b,p,5,j), t(b,p,6,j)), 7U) + rotrFixed(t(b,p,7,j), 11U) + w + c; \ + if (e) E[7-j] += T[7-j]; + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +// Doxygen can't handle these macros +#define Round1(t) +#define Round(t, n) +#else +#define Round1(t) \ + for (i=0; i<4; i++) \ + { \ + FF(i==0, 0, F1, p##t##1, 0, W[8*i+0], 0); \ + FF(i==0, 0, F1, p##t##1, 1, W[8*i+1], 0); \ + FF(i==0, 0, F1, p##t##1, 2, W[8*i+2], 0); \ + FF(i==0, 0, F1, p##t##1, 3, W[8*i+3], 0); \ + FF(i==0, 0, F1, p##t##1, 4, W[8*i+4], 0); \ + FF(i==0, 0, F1, p##t##1, 5, W[8*i+5], 0); \ + FF(i==0, 0, F1, p##t##1, 6, W[8*i+6], 0); \ + FF(i==0, 0, F1, p##t##1, 7, W[8*i+7], 0); \ + } +#define Round(t, n) \ + for (i=0; i<4; i++) \ + { \ + FF(0, t==n && i==3, F##n, p##t##n, 0, W[wi##n[8*i+0]], mc##n[8*i+0]); \ + FF(0, t==n && i==3, F##n, p##t##n, 1, W[wi##n[8*i+1]], mc##n[8*i+1]); \ + FF(0, t==n && i==3, F##n, p##t##n, 2, W[wi##n[8*i+2]], mc##n[8*i+2]); \ + FF(0, t==n && i==3, F##n, p##t##n, 3, W[wi##n[8*i+3]], mc##n[8*i+3]); \ + FF(0, t==n && i==3, F##n, p##t##n, 4, W[wi##n[8*i+4]], mc##n[8*i+4]); \ + FF(0, t==n && i==3, F##n, p##t##n, 5, W[wi##n[8*i+5]], mc##n[8*i+5]); \ + FF(0, t==n && i==3, F##n, p##t##n, 6, W[wi##n[8*i+6]], mc##n[8*i+6]); \ + FF(0, t==n && i==3, F##n, p##t##n, 7, W[wi##n[8*i+7]], mc##n[8*i+7]); \ + } +#endif + +const unsigned int HAVAL::wi2[32] = { 5,14,26,18,11,28, 7,16, 0,23,20,22, 1,10, 4, 8,30, 3,21, 9,17,24,29, 6,19,12,15,13, 2,25,31,27}; +const unsigned int HAVAL::wi3[32] = {19, 9, 4,20,28,17, 8,22,29,14,25,12,24,30,16,26,31,15, 7, 3, 1, 0,18,27,13, 6,21,10,23,11, 5, 2}; +const unsigned int HAVAL::wi4[32] = {24, 4, 0,14, 2, 7,28,23,26, 6,30,20,18,25,19, 3,22,11,31,21, 8,27,12, 9, 1,29, 5,15,17,10,16,13}; +const unsigned int HAVAL::wi5[32] = {27, 3,21,26,17,11,20,29,19, 0,12, 7,13, 8,31,10, 5, 9,14,30,18, 6,28,24, 2,23,16,22, 4, 1,25,15}; + +const word32 HAVAL::mc2[32] = { + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 +, 0x9216D5D9, 0x8979FB1B, 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96 +, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69 +, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5}; + +const word32 HAVAL::mc3[32] = { +0x9C30D539,0x2AF26013,0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E, +0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,0xE65525F3,0xAA55AB94, +0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993, +0xB3EE1411,0x636FBC2A,0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C}; + +const word32 HAVAL::mc4[32] = { +0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,0x61D809CC,0xFB21A991, +0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5, +0x0F6D6FF3,0x83F44239,0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A, +0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,0x6EEF0B6C,0x137A3BE4}; + +const word32 HAVAL::mc5[32] = { +0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4, +0x7D84A5C3,0x3B8B5EBE,0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706, +0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,0x075372C9,0x80991B7B, +0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4}; + +void HAVAL3::Transform(word32 *E, const word32 *W) +{ + word32 T[8]; + unsigned int i; + + Round1(3); + Round(3, 2); + Round(3, 3); + + memset(T, 0, sizeof(T)); +} + +void HAVAL4::Transform(word32 *E, const word32 *W) +{ + word32 T[8]; + unsigned int i; + + Round1(4); + Round(4, 2); + Round(4, 3); + Round(4, 4); + + memset(T, 0, sizeof(T)); +} + +void HAVAL5::Transform(word32 *E, const word32 *W) +{ + word32 T[8]; + unsigned int i; + + Round1(5); + Round(5, 2); + Round(5, 3); + Round(5, 4); + Round(5, 5); + + memset(T, 0, sizeof(T)); +} + +NAMESPACE_END @@ -0,0 +1,57 @@ +#ifndef CRYPTOPP_HAVAL_H +#define CRYPTOPP_HAVAL_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/md.html#HAVAL">HAVAL</a> +class HAVAL : public IteratedHash<word32, LittleEndian, 128> +{ +public: + enum {DIGESTSIZE = 32, HAVAL_VERSION = 1}; + + /// digestSize can be 16, 20, 24, 28, or 32 (Default=32)<br> + /// pass can be 3, 4 or 5 (Default=3) + HAVAL(unsigned int digestSize=DIGESTSIZE, unsigned int passes=3); + void TruncatedFinal(byte *hash, unsigned int size); + unsigned int DigestSize() const {return digestSize;} + +protected: + static const unsigned int wi2[32], wi3[32], wi4[32], wi5[32]; + static const word32 mc2[32], mc3[32], mc4[32], mc5[32]; + + void Init(); + void Tailor(unsigned int FPTLEN); + void vTransform(const word32 *in); + + const unsigned int digestSize, pass; +}; + +/// <a href="http://www.weidai.com/scan-mirror/md.html#HAVAL">HAVAL</a> with 3 passes +class HAVAL3 : public HAVAL +{ +public: + HAVAL3(unsigned int digestSize=DIGESTSIZE) : HAVAL(digestSize, 3) {} + static void Transform(word32 *buf, const word32 *in); +}; + +/// <a href="http://www.weidai.com/scan-mirror/md.html#HAVAL">HAVAL</a> with 4 passes +class HAVAL4 : public HAVAL +{ +public: + HAVAL4(unsigned int digestSize=DIGESTSIZE) : HAVAL(digestSize, 4) {} + static void Transform(word32 *buf, const word32 *in); +}; + +/// <a href="http://www.weidai.com/scan-mirror/md.html#HAVAL">HAVAL</a> with 5 passes +class HAVAL5 : public HAVAL +{ +public: + HAVAL5(unsigned int digestSize=DIGESTSIZE) : HAVAL(digestSize, 5) {} + static void Transform(word32 *buf, const word32 *in); +}; + +NAMESPACE_END + +#endif diff --git a/havalcer.dat b/havalcer.dat new file mode 100644 index 0000000..ab6a5a3 --- /dev/null +++ b/havalcer.dat @@ -0,0 +1,23 @@ +3 128 + +1BDC556B29AD02EC09AF8C66477F2A87 + +3 160 +a +5E1610FCED1D3ADB0BB18E92AC2B11F0BD99D8ED + +4 192 +HAVAL +74AA31182FF09BCCE453A7F71B5A7C5E80872FA90CD93AE4 + +4 224 +0123456789 +144CB2DE11F05DF7C356282A3B485796DA653F6B702868C7DCF4AE76 + +5 256 +abcdefghijklmnopqrstuvwxyz +1A1DC8099BDAA7F35B4DA4E805F1A28FEE909D8DEE920198185CBCAED8A10A8D + +5 256 +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +C5647FC6C1877FFF96742F27E9266B6874894F41A08F5913033D9D532AEDDB39 @@ -0,0 +1,32 @@ +// hex.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "hex.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const byte s_vecUpper[] = "0123456789ABCDEF"; +static const byte s_vecLower[] = "0123456789abcdef"; + +void HexEncoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool uppercase = parameters.GetValueWithDefault("Uppercase", true); + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters("EncodingLookupArray", uppercase ? &s_vecUpper[0] : &s_vecLower[0])("Log2Base", 4))); +} + +const int *HexDecoder::GetDecodingLookupArray() +{ + static bool s_initialized = false; + static int s_array[256]; + + if (!s_initialized) + { + InitializeDecodingLookupArray(s_array, s_vecUpper, 16, true); + s_initialized = true; + } + return s_array; +} + +NAMESPACE_END @@ -0,0 +1,36 @@ +#ifndef CRYPTOPP_HEX_H +#define CRYPTOPP_HEX_H + +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Converts given data to base 16 +class HexEncoder : public SimpleProxyFilter +{ +public: + HexEncoder(BufferedTransformation *attachment = NULL, bool uppercase = true, int outputGroupSize = 0, const std::string &seperator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters("Uppercase", uppercase)("GroupSize", outputGroupSize)("Seperator", ConstByteArrayParameter(seperator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +//! Decode 16 bit data back to bytes +class HexDecoder : public BaseN_Decoder +{ +public: + HexDecoder(BufferedTransformation *attachment = NULL) + : BaseN_Decoder(GetDecodingLookupArray(), 4, attachment) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) {} + +private: + static const int *GetDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,119 @@ +// hmac.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_HMAC_H +#define CRYPTOPP_HMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +class HMAC_Base : public VariableKeyLength<16, 0, UINT_MAX>, public MessageAuthenticationCode +{ +public: + static std::string StaticAlgorithmName() {return std::string("HMAC(") + T::StaticAlgorithmName() + ")";} + + // put enums here for Metrowerks 4 + enum {DIGESTSIZE=T::DIGESTSIZE, BLOCKSIZE=T::BLOCKSIZE}; + + HMAC_Base() : m_innerHashKeyed(false) {} + void UncheckedSetKey(const byte *userKey, unsigned int keylength); + + void Restart(); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *mac, unsigned int size); + unsigned int DigestSize() const {return DIGESTSIZE;} + +private: + void KeyInnerHash(); + + enum {IPAD=0x36, OPAD=0x5c}; + + FixedSizeSecBlock<byte, BLOCKSIZE> k_ipad, k_opad; + FixedSizeSecBlock<byte, DIGESTSIZE> m_innerHash; + T m_hash; + bool m_innerHashKeyed; +}; + +//! <a href="http://www.weidai.com/scan-mirror/mac.html#HMAC">HMAC</a> +/*! HMAC(K, text) = H(K XOR opad, H(K XOR ipad, text)) */ +template <class T> +class HMAC : public MessageAuthenticationCodeTemplate<HMAC_Base<T> > +{ +public: + HMAC() {} + HMAC(const byte *key, unsigned int length=HMAC_Base<T>::DEFAULT_KEYLENGTH) + {SetKey(key, length);} +}; + +template <class T> +void HMAC_Base<T>::UncheckedSetKey(const byte *userKey, unsigned int keylength) +{ + AssertValidKeyLength(keylength); + + Restart(); + + if (keylength <= T::BLOCKSIZE) + memcpy(k_ipad, userKey, keylength); + else + { + m_hash.CalculateDigest(k_ipad, userKey, keylength); + keylength = T::DIGESTSIZE; + } + + assert(keylength <= T::BLOCKSIZE); + memset(k_ipad+keylength, 0, T::BLOCKSIZE-keylength); + + for (unsigned int i=0; i<T::BLOCKSIZE; i++) + { + k_opad[i] = k_ipad[i] ^ OPAD; + k_ipad[i] ^= IPAD; + } +} + +template <class T> +void HMAC_Base<T>::KeyInnerHash() +{ + assert(!m_innerHashKeyed); + m_hash.Update(k_ipad, T::BLOCKSIZE); + m_innerHashKeyed = true; +} + +template <class T> +void HMAC_Base<T>::Restart() +{ + if (m_innerHashKeyed) + { + m_hash.Restart(); + m_innerHashKeyed = false; + } +} + +template <class T> +void HMAC_Base<T>::Update(const byte *input, unsigned int length) +{ + if (!m_innerHashKeyed) + KeyInnerHash(); + m_hash.Update(input, length); +} + +template <class T> +void HMAC_Base<T>::TruncatedFinal(byte *mac, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + if (!m_innerHashKeyed) + KeyInnerHash(); + m_hash.Final(m_innerHash); + + m_hash.Update(k_opad, T::BLOCKSIZE); + m_hash.Update(m_innerHash, DIGESTSIZE); + m_hash.TruncatedFinal(mac, size); + + m_innerHashKeyed = false; +} + +NAMESPACE_END + +#endif diff --git a/hrtimer.cpp b/hrtimer.cpp new file mode 100644 index 0000000..2dafbca --- /dev/null +++ b/hrtimer.cpp @@ -0,0 +1,75 @@ +// hrtimer.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "hrtimer.h" +#include <stddef.h> // for NULL + +#ifdef HIGHRES_TIMER_AVAILABLE + +#if defined(CRYPTOPP_WIN32_AVAILABLE) +#include <windows.h> +#elif defined(__unix__) +#include <sys/time.h> +#elif defined(macintosh) +#include <Timer.h> +#endif + +#include <assert.h> + +NAMESPACE_BEGIN(CryptoPP) + +word64 Timer::GetCurrentTimerValue() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) + FILETIME now; + GetSystemTimeAsFileTime(&now); + return now.dwLowDateTime + ((word64)now.dwHighDateTime << 32); +#elif defined(__unix__) + timeval now; + gettimeofday(&now, NULL); + return (word64)now.tv_sec * 1000000 + now.tv_usec; +#elif defined(macintosh) + UnsignedWide now; + Microseconds(&now); + return now.lo + ((word64)now.hi << 32); +#endif +} + +unsigned long Timer::ConvertTo(word64 t, Unit unit) +{ + switch (unit) + { + case SECONDS: + return (unsigned long)(t / (TicksPerMillisecond() * 1000)); + case MILLISECONDS: + return (unsigned long)(t / TicksPerMillisecond()); + case MICROSECONDS: + assert(TicksPerMillisecond() % 1000 == 0); + return (unsigned long)(t / (TicksPerMillisecond() / 1000)); + } + assert(false); + return 0; +} + +void Timer::StartTimer() +{ + m_start = GetCurrentTimerValue(); + m_started = true; +} + +unsigned long Timer::ElapsedTime() +{ + if (m_stuckAtZero) + return 0; + else if (m_started) + return ConvertTo(GetCurrentTimerValue() - m_start, m_timerUnit); + else + { + StartTimer(); + return 0; + } +} + +NAMESPACE_END + +#endif diff --git a/hrtimer.h b/hrtimer.h new file mode 100644 index 0000000..81d9fcd --- /dev/null +++ b/hrtimer.h @@ -0,0 +1,43 @@ +#ifndef CRYPTOPP_HRTIMER_H +#define CRYPTOPP_HRTIMER_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef HIGHRES_TIMER_AVAILABLE + +//! high resolution timer +class Timer +{ +public: + enum Unit {SECONDS, MILLISECONDS, MICROSECONDS}; + Timer(Unit unit, bool stuckAtZero = false) : m_timerUnit(unit), m_stuckAtZero(stuckAtZero), m_started(false) {} + + static word64 GetCurrentTimerValue(); // GetCurrentTime is a macro in MSVC 6.0 + static unsigned long ConvertTo(word64 t, Unit unit); + + // this is not the resolution, just a conversion factor into milliseconds + static inline unsigned int TicksPerMillisecond() + { +#if defined(CRYPTOPP_WIN32_AVAILABLE) + return 10000; +#elif defined(__unix__) || defined(macintosh) + return 1000; +#endif + } + + void StartTimer(); + unsigned long ElapsedTime(); + +private: + Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX + bool m_stuckAtZero, m_started; + word64 m_start; +}; + +#endif + +NAMESPACE_END + +#endif @@ -0,0 +1,425 @@ +// ida.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "ida.h" + +#include "algebra.h" +#include "gf2_32.h" +#include "polynomi.h" + +#include "polynomi.cpp" + +ANONYMOUS_NAMESPACE_BEGIN +static const CryptoPP::GF2_32 field; +NAMESPACE_END + +using namespace std; + +NAMESPACE_BEGIN(CryptoPP) + +void RawIDA::ChannelInitialize(const string &channel, const NameValuePairs ¶meters, int propagation) +{ + if (!channel.empty()) + throw NotImplemented("RawIDA: can't reinitialize a channel"); + + if (!parameters.GetIntValue("RecoveryThreshold", m_threshold)) + throw InvalidArgument("RawIDA: missing RecoveryThreshold argument"); + + if (m_threshold <= 0) + throw InvalidArgument("RawIDA: RecoveryThreshold must be greater than 0"); + + m_lastMapPosition = m_inputChannelMap.end(); + m_channelsReady = 0; + m_channelsFinished = 0; + m_w.New(m_threshold); + m_y.New(m_threshold); + m_inputQueues.reserve(m_threshold); + + m_outputChannelIds.clear(); + m_outputChannelIdStrings.clear(); + m_outputQueues.clear(); + + word32 outputChannelID; + if (parameters.GetValue("OutputChannelID", outputChannelID)) + AddOutputChannel(outputChannelID); + else + { + int nShares = parameters.GetIntValueWithDefault("NumberOfShares", m_threshold); + for (unsigned int i=0; i<nShares; i++) + AddOutputChannel(i); + } + + if (propagation) + for (unsigned int i=0; i<m_outputChannelIds.size(); i++) + AttachedTransformation()->ChannelInitialize(m_outputChannelIdStrings[i], parameters, propagation-1); +} + +unsigned int RawIDA::InsertInputChannel(word32 channelId) +{ + if (m_lastMapPosition != m_inputChannelMap.end()) + { + if (m_lastMapPosition->first == channelId) + goto skipFind; + ++m_lastMapPosition; + if (m_lastMapPosition != m_inputChannelMap.end() && m_lastMapPosition->first == channelId) + goto skipFind; + } + m_lastMapPosition = m_inputChannelMap.find(channelId); + +skipFind: + if (m_lastMapPosition == m_inputChannelMap.end()) + { + if (m_inputChannelIds.size() == m_threshold) + return m_threshold; + + m_lastMapPosition = m_inputChannelMap.insert(pair<const unsigned long, unsigned int>(channelId, m_inputChannelIds.size())).first; + m_inputQueues.push_back(MessageQueue()); + m_inputChannelIds.push_back(channelId); + + if (m_inputChannelIds.size() == m_threshold) + PrepareInterpolation(); + } + return m_lastMapPosition->second; +} + +unsigned int RawIDA::LookupInputChannel(word32 channelId) const +{ + map<word32, unsigned int>::const_iterator it = m_inputChannelMap.find(channelId); + if (it == m_inputChannelMap.end()) + return m_threshold; + else + return it->second; +} + +void RawIDA::ChannelData(word32 channelId, const byte *inString, unsigned int length, bool messageEnd) +{ + unsigned int i = InsertInputChannel(channelId); + if (i < m_threshold) + { + unsigned long size = m_inputQueues[i].MaxRetrievable(); + m_inputQueues[i].Put(inString, length); + if (size < 4 && size + length >= 4) + { + m_channelsReady++; + if (m_channelsReady == m_threshold) + ProcessInputQueues(); + } + + if (messageEnd) + { + m_inputQueues[i].MessageEnd(); + if (m_inputQueues[i].NumberOfMessages() == 1) + { + m_channelsFinished++; + if (m_channelsFinished == m_threshold) + { + m_channelsReady = 0; + for (i=0; i<m_threshold; i++) + m_channelsReady += m_inputQueues[i].AnyRetrievable(); + ProcessInputQueues(); + } + } + } + } +} + +unsigned int RawIDA::InputBuffered(word32 channelId) const +{ + unsigned int i = LookupInputChannel(channelId); + return i < m_threshold ? m_inputQueues[i].MaxRetrievable() : 0; +} + +void RawIDA::ComputeV(unsigned int i) +{ + if (i >= m_v.size()) + { + m_v.resize(i+1); + m_outputToInput.resize(i+1); + } + + m_outputToInput[i] = LookupInputChannel(m_outputChannelIds[i]); + if (m_outputToInput[i] == m_threshold && i * m_threshold <= 1000*1000) + { + m_v[i].resize(m_threshold); + PrepareBulkPolynomialInterpolationAt(field, m_v[i].begin(), m_outputChannelIds[i], &(m_inputChannelIds[0]), m_w.begin(), m_threshold); + } +} + +void RawIDA::AddOutputChannel(word32 channelId) +{ + m_outputChannelIds.push_back(channelId); + m_outputChannelIdStrings.push_back(WordToString(channelId)); + m_outputQueues.push_back(ByteQueue()); + if (m_inputChannelIds.size() == m_threshold) + ComputeV(m_outputChannelIds.size() - 1); +} + +void RawIDA::PrepareInterpolation() +{ + assert(m_inputChannelIds.size() == m_threshold); + PrepareBulkPolynomialInterpolation(field, m_w.begin(), &(m_inputChannelIds[0]), m_threshold); + for (unsigned int i=0; i<m_outputChannelIds.size(); i++) + ComputeV(i); +} + +void RawIDA::ProcessInputQueues() +{ + bool finished = (m_channelsFinished == m_threshold); + unsigned int i; + + while (finished ? m_channelsReady > 0 : m_channelsReady == m_threshold) + { + m_channelsReady = 0; + for (i=0; i<m_threshold; i++) + { + MessageQueue &queue = m_inputQueues[i]; + queue.GetWord32(m_y[i]); + + if (finished) + m_channelsReady += queue.AnyRetrievable(); + else + m_channelsReady += queue.NumberOfMessages() > 0 || queue.MaxRetrievable() >= 4; + } + + for (i=0; i<m_outputChannelIds.size(); i++) + { + if (m_outputToInput[i] != m_threshold) + m_outputQueues[i].PutWord32(m_y[m_outputToInput[i]]); + else if (m_v[i].size() == m_threshold) + m_outputQueues[i].PutWord32(BulkPolynomialInterpolateAt(field, m_y.begin(), m_v[i].begin(), m_threshold)); + else + { + m_u.resize(m_threshold); + PrepareBulkPolynomialInterpolationAt(field, m_u.begin(), m_outputChannelIds[i], &(m_inputChannelIds[0]), m_w.begin(), m_threshold); + m_outputQueues[i].PutWord32(BulkPolynomialInterpolateAt(field, m_y.begin(), m_u.begin(), m_threshold)); + } + } + } + + if (m_outputChannelIds.size() > 0 && m_outputQueues[0].AnyRetrievable()) + FlushOutputQueues(); + + if (finished) + { + OutputMessageEnds(); + + m_channelsReady = 0; + m_channelsFinished = 0; + m_v.clear(); + + vector<MessageQueue> inputQueues; + vector<word32> inputChannelIds; + + inputQueues.swap(m_inputQueues); + inputChannelIds.swap(m_inputChannelIds); + m_inputChannelMap.clear(); + m_lastMapPosition = m_inputChannelMap.end(); + + for (i=0; i<m_threshold; i++) + { + inputQueues[i].GetNextMessage(); + inputQueues[i].TransferAllTo(*AttachedTransformation(), WordToString(inputChannelIds[i])); + } + } +} + +void RawIDA::FlushOutputQueues() +{ + for (unsigned int i=0; i<m_outputChannelIds.size(); i++) + m_outputQueues[i].TransferAllTo(*AttachedTransformation(), m_outputChannelIdStrings[i]); +} + +void RawIDA::OutputMessageEnds() +{ + if (GetAutoSignalPropagation() != 0) + { + for (unsigned int i=0; i<m_outputChannelIds.size(); i++) + AttachedTransformation()->ChannelMessageEnd(m_outputChannelIdStrings[i], GetAutoSignalPropagation()-1); + } +} + +// **************************************************************** + +void SecretSharing::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_pad = parameters.GetValueWithDefault("AddPadding", true); + m_ida.Initialize(parameters, propagation); +} + +unsigned int SecretSharing::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("SecretSharing"); + + SecByteBlock buf(STDMIN(length, 256U)); + unsigned int threshold = m_ida.GetThreshold(); + while (length > 0) + { + unsigned int len = STDMIN(length, (unsigned int)buf.size()); + m_ida.ChannelData(0xffffffff, begin, len, false); + for (unsigned int i=0; i<threshold-1; i++) + { + m_rng.GenerateBlock(buf, len); + m_ida.ChannelData(i, buf, len, false); + } + length -= len; + begin += len; + } + + if (messageEnd) + { + m_ida.SetAutoSignalPropagation(messageEnd-1); + if (m_pad) + { + SecretSharing::Put(1); + while (m_ida.InputBuffered(0xffffffff) > 0) + SecretSharing::Put(0); + } + m_ida.ChannelData(0xffffffff, NULL, 0, true); + for (unsigned int i=0; i<m_ida.GetThreshold()-1; i++) + m_ida.ChannelData(i, NULL, 0, true); + } + + return 0; +} + +void SecretRecovery::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_pad = parameters.GetValueWithDefault("RemovePadding", true); + RawIDA::Initialize(CombinedNameValuePairs(parameters, MakeParameters("OutputChannelID", (word32)0xffffffff)), propagation); +} + +void SecretRecovery::FlushOutputQueues() +{ + if (m_pad) + m_outputQueues[0].TransferTo(*AttachedTransformation(), m_outputQueues[0].MaxRetrievable()-4); + else + m_outputQueues[0].TransferTo(*AttachedTransformation()); +} + +void SecretRecovery::OutputMessageEnds() +{ + if (m_pad) + { + PaddingRemover paddingRemover(new Redirector(*AttachedTransformation())); + m_outputQueues[0].TransferAllTo(paddingRemover); + } + + if (GetAutoSignalPropagation() != 0) + AttachedTransformation()->MessageEnd(GetAutoSignalPropagation()-1); +} + +// **************************************************************** + +void InformationDispersal::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_nextChannel = 0; + m_pad = parameters.GetValueWithDefault("AddPadding", true); + m_ida.Initialize(parameters, propagation); +} + +unsigned int InformationDispersal::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("InformationDispersal"); + + while (length--) + { + m_ida.ChannelData(m_nextChannel, begin, 1, false); + begin++; + m_nextChannel++; + if (m_nextChannel == m_ida.GetThreshold()) + m_nextChannel = 0; + } + + if (messageEnd) + { + m_ida.SetAutoSignalPropagation(messageEnd-1); + if (m_pad) + InformationDispersal::Put(1); + for (word32 i=0; i<m_ida.GetThreshold(); i++) + m_ida.ChannelData(i, NULL, 0, true); + } + + return 0; +} + +void InformationRecovery::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_pad = parameters.GetValueWithDefault("RemovePadding", true); + RawIDA::Initialize(parameters, propagation); +} + +void InformationRecovery::FlushOutputQueues() +{ + while (m_outputQueues[0].AnyRetrievable()) + { + for (unsigned int i=0; i<m_outputChannelIds.size(); i++) + m_outputQueues[i].TransferTo(m_queue, 1); + } + + if (m_pad) + m_queue.TransferTo(*AttachedTransformation(), m_queue.MaxRetrievable()-4*m_threshold); + else + m_queue.TransferTo(*AttachedTransformation()); +} + +void InformationRecovery::OutputMessageEnds() +{ + if (m_pad) + { + PaddingRemover paddingRemover(new Redirector(*AttachedTransformation())); + m_queue.TransferAllTo(paddingRemover); + } + + if (GetAutoSignalPropagation() != 0) + AttachedTransformation()->MessageEnd(GetAutoSignalPropagation()-1); +} + +unsigned int PaddingRemover::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("PaddingRemover"); + + const byte *const end = begin + length; + + if (m_possiblePadding) + { + unsigned int len = find_if(begin, end, bind2nd(not_equal_to<byte>(), 0)) - begin; + m_zeroCount += len; + begin += len; + if (begin == end) + return 0; + + AttachedTransformation()->Put(1); + while (m_zeroCount--) + AttachedTransformation()->Put(0); + AttachedTransformation()->Put(*begin++); + m_possiblePadding = false; + } + +#if defined(_MSC_VER) && !defined(__MWERKS__) + // VC60 workaround: built-in reverse_iterator has two template parameters, Dinkumware only has one + typedef reverse_bidirectional_iterator<const byte *, const byte> rit; +#else + typedef reverse_iterator<const byte *> rit; +#endif + const byte *x = find_if(rit(end), rit(begin), bind2nd(not_equal_to<byte>(), 0)).base(); + if (x != begin && *(x-1) == 1) + { + AttachedTransformation()->Put(begin, x-begin-1); + m_possiblePadding = true; + m_zeroCount = end - x; + } + else + AttachedTransformation()->Put(begin, end-begin); + + if (messageEnd) + { + m_possiblePadding = false; + Output(0, begin, length, messageEnd, blocking); + } + return 0; +} + +NAMESPACE_END @@ -0,0 +1,145 @@ +#ifndef CRYPTOPP_IDA_H +#define CRYPTOPP_IDA_H + +#include "mqueue.h" +#include "filters.h" +#include "channels.h" +#include <map> +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +/// base class for secret sharing and information dispersal +class RawIDA : public AutoSignaling<Unflushable<Multichannel<Filter> > > +{ +public: + RawIDA(BufferedTransformation *attachment=NULL) + : AutoSignaling<Unflushable<Multichannel<Filter> > >(attachment) {} + + unsigned int GetThreshold() const {return m_threshold;} + void AddOutputChannel(word32 channelId); + void ChannelData(word32 channelId, const byte *inString, unsigned int length, bool messageEnd); + unsigned int InputBuffered(word32 channelId) const; + + void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("RawIDA"); + ChannelData(StringToWord<word32>(channel), begin, length, messageEnd != 0); + return 0; + } + +protected: + virtual void FlushOutputQueues(); + virtual void OutputMessageEnds(); + + unsigned int InsertInputChannel(word32 channelId); + unsigned int LookupInputChannel(word32 channelId) const; + void ComputeV(unsigned int); + void PrepareInterpolation(); + void ProcessInputQueues(); + + std::map<word32, unsigned int> m_inputChannelMap; + std::map<word32, unsigned int>::iterator m_lastMapPosition; + std::vector<MessageQueue> m_inputQueues; + std::vector<word32> m_inputChannelIds, m_outputChannelIds, m_outputToInput; + std::vector<std::string> m_outputChannelIdStrings; + std::vector<ByteQueue> m_outputQueues; + int m_threshold; + unsigned int m_channelsReady, m_channelsFinished; + std::vector<SecBlock<word32> > m_v; + SecBlock<word32> m_u, m_w, m_y; +}; + +/// a variant of Shamir's Secret Sharing Algorithm +class SecretSharing : public CustomSignalPropagation<Filter> +{ +public: + SecretSharing(RandomNumberGenerator &rng, int threshold, int nShares, BufferedTransformation *attachment=NULL, bool addPadding=true) + : CustomSignalPropagation<Filter>(attachment), m_rng(rng), m_ida(new OutputProxy(*this, true)) + {Initialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding), 0);} + + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RandomNumberGenerator &m_rng; + RawIDA m_ida; + bool m_pad; +}; + +/// a variant of Shamir's Secret Sharing Algorithm +class SecretRecovery : public RawIDA +{ +public: + SecretRecovery(int threshold, BufferedTransformation *attachment=NULL, bool removePadding=true) + : RawIDA(attachment) + {Initialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding), 0);} + + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; +}; + +/// a variant of Rabin's Information Dispersal Algorithm +class InformationDispersal : public CustomSignalPropagation<Filter> +{ +public: + InformationDispersal(int threshold, int nShares, BufferedTransformation *attachment=NULL, bool addPadding=true) + : CustomSignalPropagation<Filter>(attachment), m_ida(new OutputProxy(*this, true)) + {Initialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding), 0);} + + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RawIDA m_ida; + bool m_pad; + unsigned int m_nextChannel; +}; + +/// a variant of Rabin's Information Dispersal Algorithm +class InformationRecovery : public RawIDA +{ +public: + InformationRecovery(int threshold, BufferedTransformation *attachment=NULL, bool removePadding=true) + : RawIDA(attachment) + {Initialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding), 0);} + + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; + ByteQueue m_queue; +}; + +class PaddingRemover : public Unflushable<Filter> +{ +public: + PaddingRemover(BufferedTransformation *attachment=NULL) + : Unflushable<Filter>(attachment), m_possiblePadding(false) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) {m_possiblePadding = false;} + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + + // GetPossiblePadding() == false at the end of a message indicates incorrect padding + bool GetPossiblePadding() const {return m_possiblePadding;} + +private: + bool m_possiblePadding; + unsigned long m_zeroCount; +}; + +NAMESPACE_END + +#endif diff --git a/idea.cpp b/idea.cpp new file mode 100644 index 0000000..e8d4bb8 --- /dev/null +++ b/idea.cpp @@ -0,0 +1,190 @@ +// idea.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "idea.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const int IDEA_KEYLEN=(6*IDEA::ROUNDS+4); // key schedule length in # of word16s + +#define low16(x) ((x)&0xffff) // compiler should be able to optimize this away if word is 16 bits +#define high16(x) ((x)>>16) + +// should use an inline function but macros are still faster in MSVC 4.0 +#define DirectMUL(a,b) \ +{ \ + assert(b <= 0xffff); \ + \ + word32 p=(word32)low16(a)*b; \ + \ + if (p) \ + { \ + p = low16(p) - high16(p); \ + a = (word)p - (word)high16(p); \ + } \ + else \ + a = 1-a-b; \ +} + +#ifdef IDEA_LARGECACHE +bool IDEA::Base::tablesBuilt = false; +word16 IDEA::Base::log[0x10000]; +word16 IDEA::Base::antilog[0x10000]; + +void IDEA::Base::BuildLogTables() +{ + if (tablesBuilt) + return; + else + { + tablesBuilt = true; + + word x=1; + word32 i; + + for (i=0; i<0x10000; i++) + { + antilog[i] = (word16)x; + DirectMUL(x, 3); + } + + for (i=0; i<0x10000; i++) + log[antilog[i]] = (word16)i; + } +} + +void IDEA::Base::LookupKeyLogs() +{ + word* Z=key; + int r=ROUNDS; + do + { + Z[0] = log[Z[0]]; + Z[3] = log[Z[3]]; + Z[4] = log[Z[4]]; + Z[5] = log[Z[5]]; + Z+=6; + } while (--r); + Z[0] = log[Z[0]]; + Z[3] = log[Z[3]]; +} + +inline void IDEA::Base::LookupMUL(word &a, word b) +{ + a = antilog[low16(log[low16(a)]+b)]; +} +#endif // IDEA_LARGECACHE + +void IDEA::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) +{ + AssertValidKeyLength(length); + +#ifdef IDEA_LARGECACHE + BuildLogTables(); +#endif + + EnKey(userKey); + + if (direction==DECRYPTION) + DeKey(); + +#ifdef IDEA_LARGECACHE + LookupKeyLogs(); +#endif +} + +void IDEA::Base::EnKey (const byte *userKey) +{ + unsigned int i; + + for (i=0; i<8; i++) + m_key[i] = ((word)userKey[2*i]<<8) | userKey[2*i+1]; + + for (; i<IDEA_KEYLEN; i++) + { + unsigned int j = RoundDownToMultipleOf(i,8U)-8; + m_key[i] = low16((m_key[j+(i+1)%8] << 9) | (m_key[j+(i+2)%8] >> 7)); + } +} + +static word MulInv(word x) +{ + word y=x; + for (unsigned i=0; i<15; i++) + { + DirectMUL(y,low16(y)); + DirectMUL(y,x); + } + return low16(y); +} + +static inline word AddInv(word x) +{ + return low16(0-x); +} + +void IDEA::Base::DeKey() +{ + FixedSizeSecBlock<word, 6*ROUNDS+4> tempkey; + unsigned int i; + + for (i=0; i<ROUNDS; i++) + { + tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]); + tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1+(i>0)]); + tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2-(i>0)]); + tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); + tempkey[i*6+4] = m_key[(ROUNDS-1-i)*6+4]; + tempkey[i*6+5] = m_key[(ROUNDS-1-i)*6+5]; + } + + tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]); + tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1]); + tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2]); + tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); + + m_key = tempkey; +} + +#ifdef IDEA_LARGECACHE +#define MUL(a,b) LookupMUL(a,b) +#else +#define MUL(a,b) DirectMUL(a,b) +#endif + +void IDEA::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut<word16, BigEndian> Block; + + const word *key = m_key; + word x0,x1,x2,x3,t0,t1; + Block::Get(inBlock)(x0)(x1)(x2)(x3); + + for (unsigned int i=0; i<ROUNDS; i++) + { + MUL(x0, key[i*6+0]); + x1 += key[i*6+1]; + x2 += key[i*6+2]; + MUL(x3, key[i*6+3]); + t0 = x0^x2; + MUL(t0, key[i*6+4]); + t1 = t0 + (x1^x3); + MUL(t1, key[i*6+5]); + t0 += t1; + x0 ^= t1; + x3 ^= t0; + t0 ^= x1; + x1 = x2^t1; + x2 = t0; + } + + MUL(x0, key[ROUNDS*6+0]); + x2 += key[ROUNDS*6+1]; + x1 += key[ROUNDS*6+2]; + MUL(x3, key[ROUNDS*6+3]); + + Block::Put(xorBlock, outBlock)(x0)(x2)(x1)(x3); +} + +NAMESPACE_END @@ -0,0 +1,52 @@ +#ifndef CRYPTOPP_IDEA_H +#define CRYPTOPP_IDEA_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct IDEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<8> +{ + static const char *StaticAlgorithmName() {return "IDEA";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#IDEA">IDEA</a> +class IDEA : public IDEA_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<IDEA_Info> + { + public: + unsigned int GetAlignment() const {return 2;} + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + private: + void EnKey(const byte *); + void DeKey(); + FixedSizeSecBlock<word, 6*ROUNDS+4> m_key; + + #ifdef IDEA_LARGECACHE + static inline void LookupMUL(word &a, word b); + void LookupKeyLogs(); + static void BuildLogTables(); + static bool tablesBuilt; + static word16 log[0x10000], antilog[0x10000]; + #endif + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Base> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Base> Decryption; +}; + +typedef IDEA::Encryption IDEAEncryption; +typedef IDEA::Decryption IDEADecryption; + +NAMESPACE_END + +#endif diff --git a/ideaval.dat b/ideaval.dat new file mode 100644 index 0000000..f7cd6fe --- /dev/null +++ b/ideaval.dat @@ -0,0 +1,11 @@ +00010002000300040005000600070008 0000000100020003 11FBED2B01986DE5 +00010002000300040005000600070008 0102030405060708 540E5FEA18C2F8B1 +00010002000300040005000600070008 0019324B647D96AF 9F0A0AB6E10CED78 +00010002000300040005000600070008 F5202D5B9C671B08 CF18FD7355E2C5C5 +00010002000300040005000600070008 FAE6D2BEAA96826E 85DF52005608193D +00010002000300040005000600070008 0A141E28323C4650 2F7DE750212FB734 +00010002000300040005000600070008 050A0F14191E2328 7B7314925DE59C09 +0005000A000F00140019001E00230028 0102030405060708 3EC04780BEFF6E20 +3A984E2000195DB32EE501C8C47CEA60 0102030405060708 97BCD8200780DA86 +006400C8012C019001F4025802BC0320 05320A6414C819FA 65BE87E7A2538AED +9D4075C103BC322AFB03E7BE6AB30006 0808080808080808 F5DB1AC45E5EF9F9 diff --git a/integer.cpp b/integer.cpp new file mode 100644 index 0000000..0df3540 --- /dev/null +++ b/integer.cpp @@ -0,0 +1,3983 @@ +// integer.cpp - written and placed in the public domain by Wei Dai +// contains public domain code contributed by Alister Lee and Leonard Janke + +#include "pch.h" +#include "integer.h" +#include "modarith.h" +#include "nbtheory.h" +#include "asn.h" +#include "oids.h" +#include "words.h" +#include "algparam.h" +#include "pubkey.h" // for P1363_KDF2 +#include "sha.h" + +#include <iostream> + +#ifdef SSE2_INTRINSICS_AVAILABLE +#include <emmintrin.h> +#endif + +#include "algebra.cpp" +#include "eprecomp.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef SSE2_INTRINSICS_AVAILABLE +template <class T> +AllocatorBase<T>::pointer AlignedAllocator<T>::allocate(size_type n, const void *) +{ + if (n < 4) + return new T[n]; + else + return (T *)_mm_malloc(sizeof(T)*n, 16); + +} + +template <class T> +void AlignedAllocator<T>::deallocate(void *p, size_type n) +{ + memset(p, 0, n*sizeof(T)); + if (n < 4) + delete [] p; + else + _mm_free(p); +} + +template class AlignedAllocator<word>; +#endif + +#define MAKE_DWORD(lowWord, highWord) ((dword(highWord)<<WORD_BITS) | (lowWord)) + +static int Compare(const word *A, const word *B, unsigned int N) +{ + while (N--) + if (A[N] > B[N]) + return 1; + else if (A[N] < B[N]) + return -1; + + return 0; +} + +static word Increment(word *A, unsigned int N, word B=1) +{ + assert(N); + word t = A[0]; + A[0] = t+B; + if (A[0] >= t) + return 0; + for (unsigned i=1; i<N; i++) + if (++A[i]) + return 0; + return 1; +} + +static word Decrement(word *A, unsigned int N, word B=1) +{ + assert(N); + word t = A[0]; + A[0] = t-B; + if (A[0] <= t) + return 0; + for (unsigned i=1; i<N; i++) + if (A[i]--) + return 0; + return 1; +} + +static void TwosComplement(word *A, unsigned int N) +{ + Decrement(A, N); + for (unsigned i=0; i<N; i++) + A[i] = ~A[i]; +} + +static word LinearMultiply(word *C, const word *A, word B, unsigned int N) +{ + word carry=0; + for(unsigned i=0; i<N; i++) + { + dword p = (dword)A[i] * B + carry; + C[i] = LOW_WORD(p); + carry = HIGH_WORD(p); + } + return carry; +} + +static void AtomicInverseModPower2(word *C, word A0, word A1) +{ + assert(A0%2==1); + + dword A=MAKE_DWORD(A0, A1), R=A0%8; + + for (unsigned i=3; i<2*WORD_BITS; i*=2) + R = R*(2-R*A); + + assert(R*A==1); + + C[0] = LOW_WORD(R); + C[1] = HIGH_WORD(R); +} + +// ******************************************************** + +class Portable +{ +public: + static word Add(word *C, const word *A, const word *B, unsigned int N); + static word Subtract(word *C, const word *A, const word *B, unsigned int N); + + static inline void Multiply2(word *C, const word *A, const word *B); + static inline word Multiply2Add(word *C, const word *A, const word *B); + static void Multiply4(word *C, const word *A, const word *B); + static void Multiply8(word *C, const word *A, const word *B); + static inline unsigned int MultiplyRecursionLimit() {return 8;} + + static inline void Multiply2Bottom(word *C, const word *A, const word *B); + static void Multiply4Bottom(word *C, const word *A, const word *B); + static void Multiply8Bottom(word *C, const word *A, const word *B); + static inline unsigned int MultiplyBottomRecursionLimit() {return 8;} + + static void Square2(word *R, const word *A); + static void Square4(word *R, const word *A); + static void Square8(word *R, const word *A) {assert(false);} + static inline unsigned int SquareRecursionLimit() {return 4;} +}; + +word Portable::Add(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + +#ifdef IS_LITTLE_ENDIAN + if (sizeof(dword) == sizeof(size_t)) // dword is only register size + { + dword carry = 0; + N >>= 1; + for (unsigned int i = 0; i < N; i++) + { + dword a = ((const dword *)A)[i] + carry; + dword c = a + ((const dword *)B)[i]; + ((dword *)C)[i] = c; + carry = (a < carry) | (c < a); + } + return (word)carry; + } + else +#endif + { + word carry = 0; + for (unsigned int i = 0; i < N; i+=2) + { + dword u = (dword) carry + A[i] + B[i]; + C[i] = LOW_WORD(u); + u = (dword) HIGH_WORD(u) + A[i+1] + B[i+1]; + C[i+1] = LOW_WORD(u); + carry = HIGH_WORD(u); + } + return carry; + } +} + +word Portable::Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + +#ifdef IS_LITTLE_ENDIAN + if (sizeof(dword) == sizeof(size_t)) // dword is only register size + { + dword borrow = 0; + N >>= 1; + for (unsigned int i = 0; i < N; i++) + { + dword a = ((const dword *)A)[i]; + dword b = a - borrow; + dword c = b - ((const dword *)B)[i]; + ((dword *)C)[i] = c; + borrow = (b > a) | (c > b); + } + return (word)borrow; + } + else +#endif + { + word borrow=0; + for (unsigned i = 0; i < N; i+=2) + { + dword u = (dword) A[i] - B[i] - borrow; + C[i] = LOW_WORD(u); + u = (dword) A[i+1] - B[i+1] - (word)(0-HIGH_WORD(u)); + C[i+1] = LOW_WORD(u); + borrow = 0-HIGH_WORD(u); + } + return borrow; + } +} + +void Portable::Multiply2(word *C, const word *A, const word *B) +{ +/* + word s; + dword d; + + if (A1 >= A0) + if (B0 >= B1) + { + s = 0; + d = (dword)(A1-A0)*(B0-B1); + } + else + { + s = (A1-A0); + d = (dword)s*(word)(B0-B1); + } + else + if (B0 > B1) + { + s = (B0-B1); + d = (word)(A1-A0)*(dword)s; + } + else + { + s = 0; + d = (dword)(A0-A1)*(B1-B0); + } +*/ + // this segment is the branchless equivalent of above + word D[4] = {A[1]-A[0], A[0]-A[1], B[0]-B[1], B[1]-B[0]}; + unsigned int ai = A[1] < A[0]; + unsigned int bi = B[0] < B[1]; + unsigned int di = ai & bi; + dword d = (dword)D[di]*D[di+2]; + D[1] = D[3] = 0; + unsigned int si = ai + !bi; + word s = D[si]; + + dword A0B0 = (dword)A[0]*B[0]; + C[0] = LOW_WORD(A0B0); + + dword A1B1 = (dword)A[1]*B[1]; + dword t = (dword) HIGH_WORD(A0B0) + LOW_WORD(A0B0) + LOW_WORD(d) + LOW_WORD(A1B1); + C[1] = LOW_WORD(t); + + t = A1B1 + HIGH_WORD(t) + HIGH_WORD(A0B0) + HIGH_WORD(d) + HIGH_WORD(A1B1) - s; + C[2] = LOW_WORD(t); + C[3] = HIGH_WORD(t); +} + +inline void Portable::Multiply2Bottom(word *C, const word *A, const word *B) +{ +#ifdef IS_LITTLE_ENDIAN + if (sizeof(dword) == sizeof(size_t)) + { + dword a = *(const dword *)A, b = *(const dword *)B; + ((dword *)C)[0] = a*b; + } + else +#endif + { + dword t = (dword)A[0]*B[0]; + C[0] = LOW_WORD(t); + C[1] = HIGH_WORD(t) + A[0]*B[1] + A[1]*B[0]; + } +} + +word Portable::Multiply2Add(word *C, const word *A, const word *B) +{ + word D[4] = {A[1]-A[0], A[0]-A[1], B[0]-B[1], B[1]-B[0]}; + unsigned int ai = A[1] < A[0]; + unsigned int bi = B[0] < B[1]; + unsigned int di = ai & bi; + dword d = (dword)D[di]*D[di+2]; + D[1] = D[3] = 0; + unsigned int si = ai + !bi; + word s = D[si]; + + dword A0B0 = (dword)A[0]*B[0]; + dword t = A0B0 + C[0]; + C[0] = LOW_WORD(t); + + dword A1B1 = (dword)A[1]*B[1]; + t = (dword) HIGH_WORD(t) + LOW_WORD(A0B0) + LOW_WORD(d) + LOW_WORD(A1B1) + C[1]; + C[1] = LOW_WORD(t); + + t = (dword) HIGH_WORD(t) + LOW_WORD(A1B1) + HIGH_WORD(A0B0) + HIGH_WORD(d) + HIGH_WORD(A1B1) - s + C[2]; + C[2] = LOW_WORD(t); + + t = (dword) HIGH_WORD(t) + HIGH_WORD(A1B1) + C[3]; + C[3] = LOW_WORD(t); + return HIGH_WORD(t); +} + +#define MulAcc(x, y) \ + p = (dword)A[x] * B[y] + c; \ + c = LOW_WORD(p); \ + p = (dword)d + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e += HIGH_WORD(p); + +#define SaveMulAcc(s, x, y) \ + R[s] = c; \ + p = (dword)A[x] * B[y] + d; \ + c = LOW_WORD(p); \ + p = (dword)e + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e = HIGH_WORD(p); + +#define SquAcc(x, y) \ + q = (dword)A[x] * A[y]; \ + p = q + c; \ + c = LOW_WORD(p); \ + p = (dword)d + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e += HIGH_WORD(p); \ + p = q + c; \ + c = LOW_WORD(p); \ + p = (dword)d + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e += HIGH_WORD(p); + +#define SaveSquAcc(s, x, y) \ + R[s] = c; \ + q = (dword)A[x] * A[y]; \ + p = q + d; \ + c = LOW_WORD(p); \ + p = (dword)e + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e = HIGH_WORD(p); \ + p = q + c; \ + c = LOW_WORD(p); \ + p = (dword)d + HIGH_WORD(p); \ + d = LOW_WORD(p); \ + e += HIGH_WORD(p); + +void Portable::Multiply4(word *R, const word *A, const word *B) +{ + dword p; + word c, d, e; + + p = (dword)A[0] * B[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 3, 1); + MulAcc(2, 2); + MulAcc(1, 3); + + SaveMulAcc(4, 2, 3); + MulAcc(3, 2); + + R[5] = c; + p = (dword)A[3] * B[3] + d; + R[6] = LOW_WORD(p); + R[7] = e + HIGH_WORD(p); +} + +void Portable::Square2(word *R, const word *A) +{ + dword p, q; + word c, d, e; + + p = (dword)A[0] * A[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + SquAcc(0, 1); + + R[1] = c; + p = (dword)A[1] * A[1] + d; + R[2] = LOW_WORD(p); + R[3] = e + HIGH_WORD(p); +} + +void Portable::Square4(word *R, const word *A) +{ + const word *B = A; + dword p, q; + word c, d, e; + + p = (dword)A[0] * A[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + SquAcc(0, 1); + + SaveSquAcc(1, 2, 0); + MulAcc(1, 1); + + SaveSquAcc(2, 0, 3); + SquAcc(1, 2); + + SaveSquAcc(3, 3, 1); + MulAcc(2, 2); + + SaveSquAcc(4, 2, 3); + + R[5] = c; + p = (dword)A[3] * A[3] + d; + R[6] = LOW_WORD(p); + R[7] = e + HIGH_WORD(p); +} + +void Portable::Multiply8(word *R, const word *A, const word *B) +{ + dword p; + word c, d, e; + + p = (dword)A[0] * B[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 0, 4); + MulAcc(1, 3); + MulAcc(2, 2); + MulAcc(3, 1); + MulAcc(4, 0); + + SaveMulAcc(4, 0, 5); + MulAcc(1, 4); + MulAcc(2, 3); + MulAcc(3, 2); + MulAcc(4, 1); + MulAcc(5, 0); + + SaveMulAcc(5, 0, 6); + MulAcc(1, 5); + MulAcc(2, 4); + MulAcc(3, 3); + MulAcc(4, 2); + MulAcc(5, 1); + MulAcc(6, 0); + + SaveMulAcc(6, 0, 7); + MulAcc(1, 6); + MulAcc(2, 5); + MulAcc(3, 4); + MulAcc(4, 3); + MulAcc(5, 2); + MulAcc(6, 1); + MulAcc(7, 0); + + SaveMulAcc(7, 1, 7); + MulAcc(2, 6); + MulAcc(3, 5); + MulAcc(4, 4); + MulAcc(5, 3); + MulAcc(6, 2); + MulAcc(7, 1); + + SaveMulAcc(8, 2, 7); + MulAcc(3, 6); + MulAcc(4, 5); + MulAcc(5, 4); + MulAcc(6, 3); + MulAcc(7, 2); + + SaveMulAcc(9, 3, 7); + MulAcc(4, 6); + MulAcc(5, 5); + MulAcc(6, 4); + MulAcc(7, 3); + + SaveMulAcc(10, 4, 7); + MulAcc(5, 6); + MulAcc(6, 5); + MulAcc(7, 4); + + SaveMulAcc(11, 5, 7); + MulAcc(6, 6); + MulAcc(7, 5); + + SaveMulAcc(12, 6, 7); + MulAcc(7, 6); + + R[13] = c; + p = (dword)A[7] * B[7] + d; + R[14] = LOW_WORD(p); + R[15] = e + HIGH_WORD(p); +} + +void Portable::Multiply4Bottom(word *R, const word *A, const word *B) +{ + dword p; + word c, d, e; + + p = (dword)A[0] * B[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + R[2] = c; + R[3] = d + A[0] * B[3] + A[1] * B[2] + A[2] * B[1] + A[3] * B[0]; +} + +void Portable::Multiply8Bottom(word *R, const word *A, const word *B) +{ + dword p; + word c, d, e; + + p = (dword)A[0] * B[0]; + R[0] = LOW_WORD(p); + c = HIGH_WORD(p); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 0, 4); + MulAcc(1, 3); + MulAcc(2, 2); + MulAcc(3, 1); + MulAcc(4, 0); + + SaveMulAcc(4, 0, 5); + MulAcc(1, 4); + MulAcc(2, 3); + MulAcc(3, 2); + MulAcc(4, 1); + MulAcc(5, 0); + + SaveMulAcc(5, 0, 6); + MulAcc(1, 5); + MulAcc(2, 4); + MulAcc(3, 3); + MulAcc(4, 2); + MulAcc(5, 1); + MulAcc(6, 0); + + R[6] = c; + R[7] = d + A[0] * B[7] + A[1] * B[6] + A[2] * B[5] + A[3] * B[4] + + A[4] * B[3] + A[5] * B[2] + A[6] * B[1] + A[7] * B[0]; +} + +#undef MulAcc +#undef SaveMulAcc +#undef SquAcc +#undef SaveSquAcc + +// CodeWarrior defines _MSC_VER +#if defined(_MSC_VER) && !defined(__MWERKS__) && defined(_M_IX86) && (_M_IX86<=700) + +class PentiumOptimized : public Portable +{ +public: + static word __fastcall Add(word *C, const word *A, const word *B, unsigned int N); + static word __fastcall Subtract(word *C, const word *A, const word *B, unsigned int N); + static inline void Square4(word *R, const word *A) + { + // VC60 workaround: MSVC 6.0 has an optimization bug that makes + // (dword)A*B where either A or B has been cast to a dword before + // very expensive. Revisit this function when this + // bug is fixed. + Multiply4(R, A, A); + } +}; + +typedef PentiumOptimized LowLevel; + +__declspec(naked) word __fastcall PentiumOptimized::Add(word *C, const word *A, const word *B, unsigned int N) +{ + __asm + { + push ebp + push ebx + push esi + push edi + + mov esi, [esp+24] ; N + mov ebx, [esp+20] ; B + + // now: ebx = B, ecx = C, edx = A, esi = N + + sub ecx, edx // hold the distance between C & A so we can add this to A to get C + xor eax, eax // clear eax + + sub eax, esi // eax is a negative index from end of B + lea ebx, [ebx+4*esi] // ebx is end of B + + sar eax, 1 // unit of eax is now dwords; this also clears the carry flag + jz loopend // if no dwords then nothing to do + +loopstart: + mov esi,[edx] // load lower word of A + mov ebp,[edx+4] // load higher word of A + + mov edi,[ebx+8*eax] // load lower word of B + lea edx,[edx+8] // advance A and C + + adc esi,edi // add lower words + mov edi,[ebx+8*eax+4] // load higher word of B + + adc ebp,edi // add higher words + inc eax // advance B + + mov [edx+ecx-8],esi // store lower word result + mov [edx+ecx-4],ebp // store higher word result + + jnz loopstart // loop until eax overflows and becomes zero + +loopend: + adc eax, 0 // store carry into eax (return result register) + pop edi + pop esi + pop ebx + pop ebp + ret 8 + } +} + +__declspec(naked) word __fastcall PentiumOptimized::Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + __asm + { + push ebp + push ebx + push esi + push edi + + mov esi, [esp+24] ; N + mov ebx, [esp+20] ; B + + sub ecx, edx + xor eax, eax + + sub eax, esi + lea ebx, [ebx+4*esi] + + sar eax, 1 + jz loopend + +loopstart: + mov esi,[edx] + mov ebp,[edx+4] + + mov edi,[ebx+8*eax] + lea edx,[edx+8] + + sbb esi,edi + mov edi,[ebx+8*eax+4] + + sbb ebp,edi + inc eax + + mov [edx+ecx-8],esi + mov [edx+ecx-4],ebp + + jnz loopstart + +loopend: + adc eax, 0 + pop edi + pop esi + pop ebx + pop ebp + ret 8 + } +} + +#ifdef SSE2_INTRINSICS_AVAILABLE + +static bool GetSSE2Capability() +{ + word32 b; + + __asm + { + mov eax, 1 + cpuid + mov b, edx + } + + return (b & (1 << 26)) != 0; +} + +bool g_sse2DetectionDone = false, g_sse2Detected, g_sse2Enabled = true; + +static inline bool HasSSE2() +{ + if (g_sse2Enabled && !g_sse2DetectionDone) + { + g_sse2Detected = GetSSE2Capability(); + g_sse2DetectionDone = true; + } + return g_sse2Enabled && g_sse2Detected; +} + +class P4Optimized : public PentiumOptimized +{ +public: + static word __fastcall Add(word *C, const word *A, const word *B, unsigned int N); + static word __fastcall Subtract(word *C, const word *A, const word *B, unsigned int N); + static void Multiply4(word *C, const word *A, const word *B); + static void Multiply8(word *C, const word *A, const word *B); + static inline void Square4(word *R, const word *A) + { + Multiply4(R, A, A); + } + static void Multiply8Bottom(word *C, const word *A, const word *B); +}; + +static void __fastcall P4_Mul(__m128i *C, const __m128i *A, const __m128i *B) +{ + __m128i a3210 = _mm_load_si128(A); + __m128i b3210 = _mm_load_si128(B); + + __m128i sum; + + __m128i z = _mm_setzero_si128(); + __m128i a2b2_a0b0 = _mm_mul_epu32(a3210, b3210); + C[0] = a2b2_a0b0; + + __m128i a3120 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(3, 1, 2, 0)); + __m128i b3021 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(3, 0, 2, 1)); + __m128i a1b0_a0b1 = _mm_mul_epu32(a3120, b3021); + __m128i a1b0 = _mm_unpackhi_epi32(a1b0_a0b1, z); + __m128i a0b1 = _mm_unpacklo_epi32(a1b0_a0b1, z); + C[1] = _mm_add_epi64(a1b0, a0b1); + + __m128i a31 = _mm_srli_epi64(a3210, 32); + __m128i b31 = _mm_srli_epi64(b3210, 32); + __m128i a3b3_a1b1 = _mm_mul_epu32(a31, b31); + C[6] = a3b3_a1b1; + + __m128i a1b1 = _mm_unpacklo_epi32(a3b3_a1b1, z); + __m128i b3012 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(3, 0, 1, 2)); + __m128i a2b0_a0b2 = _mm_mul_epu32(a3210, b3012); + __m128i a0b2 = _mm_unpacklo_epi32(a2b0_a0b2, z); + __m128i a2b0 = _mm_unpackhi_epi32(a2b0_a0b2, z); + sum = _mm_add_epi64(a1b1, a0b2); + C[2] = _mm_add_epi64(sum, a2b0); + + __m128i a2301 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i b2103 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(2, 1, 0, 3)); + __m128i a3b0_a1b2 = _mm_mul_epu32(a2301, b3012); + __m128i a2b1_a0b3 = _mm_mul_epu32(a3210, b2103); + __m128i a3b0 = _mm_unpackhi_epi32(a3b0_a1b2, z); + __m128i a1b2 = _mm_unpacklo_epi32(a3b0_a1b2, z); + __m128i a2b1 = _mm_unpackhi_epi32(a2b1_a0b3, z); + __m128i a0b3 = _mm_unpacklo_epi32(a2b1_a0b3, z); + __m128i sum1 = _mm_add_epi64(a3b0, a1b2); + sum = _mm_add_epi64(a2b1, a0b3); + C[3] = _mm_add_epi64(sum, sum1); + + __m128i a3b1_a1b3 = _mm_mul_epu32(a2301, b2103); + __m128i a2b2 = _mm_unpackhi_epi32(a2b2_a0b0, z); + __m128i a3b1 = _mm_unpackhi_epi32(a3b1_a1b3, z); + __m128i a1b3 = _mm_unpacklo_epi32(a3b1_a1b3, z); + sum = _mm_add_epi64(a2b2, a3b1); + C[4] = _mm_add_epi64(sum, a1b3); + + __m128i a1302 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(1, 3, 0, 2)); + __m128i b1203 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(1, 2, 0, 3)); + __m128i a3b2_a2b3 = _mm_mul_epu32(a1302, b1203); + __m128i a3b2 = _mm_unpackhi_epi32(a3b2_a2b3, z); + __m128i a2b3 = _mm_unpacklo_epi32(a3b2_a2b3, z); + C[5] = _mm_add_epi64(a3b2, a2b3); +} + +void P4Optimized::Multiply4(word *C, const word *A, const word *B) +{ + __m128i temp[7]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + C[0] = w[0]; + + __m64 s1, s2; + + __m64 w1 = _m_from_int(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _m_from_int(w[26]); + + s1 = _mm_add_si64(w1, w4); + C[1] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s2); + C[4] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w18, w20); + s1 = _mm_add_si64(s1, s2); + C[5] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w22, w26); + s1 = _mm_add_si64(s1, s2); + C[6] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + C[7] = _m_to_int(s1) + w[27]; + _mm_empty(); +} + +void P4Optimized::Multiply8(word *C, const word *A, const word *B) +{ + __m128i temp[28]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + const word *x = (word *)temp+7*4; + const __m64 *mx = (__m64 *)x; + const word *y = (word *)temp+7*4*2; + const __m64 *my = (__m64 *)y; + const word *z = (word *)temp+7*4*3; + const __m64 *mz = (__m64 *)z; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + P4_Mul(temp+7, (__m128i *)A+1, (__m128i *)B); + + P4_Mul(temp+14, (__m128i *)A, (__m128i *)B+1); + + P4_Mul(temp+21, (__m128i *)A+1, (__m128i *)B+1); + + C[0] = w[0]; + + __m64 s1, s2, s3, s4; + + __m64 w1 = _m_from_int(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _m_from_int(w[26]); + __m64 w27 = _m_from_int(w[27]); + + __m64 x0 = _m_from_int(x[0]); + __m64 x1 = _m_from_int(x[1]); + __m64 x4 = mx[2]; + __m64 x6 = mx[3]; + __m64 x8 = mx[4]; + __m64 x10 = mx[5]; + __m64 x12 = mx[6]; + __m64 x14 = mx[7]; + __m64 x16 = mx[8]; + __m64 x18 = mx[9]; + __m64 x20 = mx[10]; + __m64 x22 = mx[11]; + __m64 x26 = _m_from_int(x[26]); + __m64 x27 = _m_from_int(x[27]); + + __m64 y0 = _m_from_int(y[0]); + __m64 y1 = _m_from_int(y[1]); + __m64 y4 = my[2]; + __m64 y6 = my[3]; + __m64 y8 = my[4]; + __m64 y10 = my[5]; + __m64 y12 = my[6]; + __m64 y14 = my[7]; + __m64 y16 = my[8]; + __m64 y18 = my[9]; + __m64 y20 = my[10]; + __m64 y22 = my[11]; + __m64 y26 = _m_from_int(y[26]); + __m64 y27 = _m_from_int(y[27]); + + __m64 z0 = _m_from_int(z[0]); + __m64 z1 = _m_from_int(z[1]); + __m64 z4 = mz[2]; + __m64 z6 = mz[3]; + __m64 z8 = mz[4]; + __m64 z10 = mz[5]; + __m64 z12 = mz[6]; + __m64 z14 = mz[7]; + __m64 z16 = mz[8]; + __m64 z18 = mz[9]; + __m64 z20 = mz[10]; + __m64 z22 = mz[11]; + __m64 z26 = _m_from_int(z[26]); + + s1 = _mm_add_si64(w1, w4); + C[1] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x0, y0); + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s3); + s1 = _mm_add_si64(s1, s2); + C[4] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x1, y1); + s4 = _mm_add_si64(x4, y4); + s1 = _mm_add_si64(s1, w18); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w20); + s1 = _mm_add_si64(s1, s3); + C[5] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x6, y6); + s4 = _mm_add_si64(x8, y8); + s1 = _mm_add_si64(s1, w22); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w26); + s1 = _mm_add_si64(s1, s3); + C[6] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x10, y10); + s4 = _mm_add_si64(x12, y12); + s1 = _mm_add_si64(s1, w27); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, s3); + C[7] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x14, y14); + s4 = _mm_add_si64(x16, y16); + s1 = _mm_add_si64(s1, z0); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, s3); + C[8] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x18, y18); + s4 = _mm_add_si64(x20, y20); + s1 = _mm_add_si64(s1, z1); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, z4); + s1 = _mm_add_si64(s1, s3); + C[9] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x22, y22); + s4 = _mm_add_si64(x26, y26); + s1 = _mm_add_si64(s1, z6); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, z8); + s1 = _mm_add_si64(s1, s3); + C[10] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x27, y27); + s1 = _mm_add_si64(s1, z10); + s1 = _mm_add_si64(s1, z12); + s1 = _mm_add_si64(s1, s3); + C[11] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(z14, z16); + s1 = _mm_add_si64(s1, s3); + C[12] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(z18, z20); + s1 = _mm_add_si64(s1, s3); + C[13] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(z22, z26); + s1 = _mm_add_si64(s1, s3); + C[14] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + C[15] = z[27] + _m_to_int(s1); + _mm_empty(); +} + +void P4Optimized::Multiply8Bottom(word *C, const word *A, const word *B) +{ + __m128i temp[21]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + const word *x = (word *)temp+7*4; + const __m64 *mx = (__m64 *)x; + const word *y = (word *)temp+7*4*2; + const __m64 *my = (__m64 *)y; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + P4_Mul(temp+7, (__m128i *)A+1, (__m128i *)B); + + P4_Mul(temp+14, (__m128i *)A, (__m128i *)B+1); + + C[0] = w[0]; + + __m64 s1, s2, s3, s4; + + __m64 w1 = _m_from_int(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _m_from_int(w[26]); + + __m64 x0 = _m_from_int(x[0]); + __m64 x1 = _m_from_int(x[1]); + __m64 x4 = mx[2]; + __m64 x6 = mx[3]; + __m64 x8 = mx[4]; + + __m64 y0 = _m_from_int(y[0]); + __m64 y1 = _m_from_int(y[1]); + __m64 y4 = my[2]; + __m64 y6 = my[3]; + __m64 y8 = my[4]; + + s1 = _mm_add_si64(w1, w4); + C[1] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x0, y0); + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s3); + s1 = _mm_add_si64(s1, s2); + C[4] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x1, y1); + s4 = _mm_add_si64(x4, y4); + s1 = _mm_add_si64(s1, w18); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w20); + s1 = _mm_add_si64(s1, s3); + C[5] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + s3 = _mm_add_si64(x6, y6); + s4 = _mm_add_si64(x8, y8); + s1 = _mm_add_si64(s1, w22); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w26); + s1 = _mm_add_si64(s1, s3); + C[6] = _m_to_int(s1); + s1 = _m_psrlqi(s1, 32); + + C[7] = _m_to_int(s1) + w[27] + x[10] + y[10] + x[12] + y[12]; + _mm_empty(); +} + +__declspec(naked) word __fastcall P4Optimized::Add(word *C, const word *A, const word *B, unsigned int N) +{ + __asm + { + sub esp, 16 + xor eax, eax + mov [esp], edi + mov [esp+4], esi + mov [esp+8], ebx + mov [esp+12], ebp + + mov ebx, [esp+20] // B + mov esi, [esp+24] // N + + // now: ebx = B, ecx = C, edx = A, esi = N + + neg esi + jz loopend // if no dwords then nothing to do + + mov edi, [edx] + mov ebp, [ebx] + +loopstart: + add edi, eax + jc carry1 + + xor eax, eax + +carry1continue: + add edi, ebp + mov ebp, 1 + mov [ecx], edi + mov edi, [edx+4] + cmovc eax, ebp + mov ebp, [ebx+4] + lea ebx, [ebx+8] + add edi, eax + jc carry2 + + xor eax, eax + +carry2continue: + add edi, ebp + mov ebp, 1 + cmovc eax, ebp + mov [ecx+4], edi + add ecx, 8 + mov edi, [edx+8] + add edx, 8 + add esi, 2 + mov ebp, [ebx] + jnz loopstart + +loopend: + mov edi, [esp] + mov esi, [esp+4] + mov ebx, [esp+8] + mov ebp, [esp+12] + add esp, 16 + ret 8 + +carry1: + mov eax, 1 + jmp carry1continue + +carry2: + mov eax, 1 + jmp carry2continue + } +} + +__declspec(naked) word __fastcall P4Optimized::Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + __asm + { + sub esp, 16 + xor eax, eax + mov [esp], edi + mov [esp+4], esi + mov [esp+8], ebx + mov [esp+12], ebp + + mov ebx, [esp+20] // B + mov esi, [esp+24] // N + + // now: ebx = B, ecx = C, edx = A, esi = N + + neg esi + jz loopend // if no dwords then nothing to do + + mov edi, [edx] + mov ebp, [ebx] + +loopstart: + sub edi, eax + jc carry1 + + xor eax, eax + +carry1continue: + sub edi, ebp + mov ebp, 1 + mov [ecx], edi + mov edi, [edx+4] + cmovc eax, ebp + mov ebp, [ebx+4] + lea ebx, [ebx+8] + sub edi, eax + jc carry2 + + xor eax, eax + +carry2continue: + sub edi, ebp + mov ebp, 1 + cmovc eax, ebp + mov [ecx+4], edi + add ecx, 8 + mov edi, [edx+8] + add edx, 8 + add esi, 2 + mov ebp, [ebx] + jnz loopstart + +loopend: + mov edi, [esp] + mov esi, [esp+4] + mov ebx, [esp+8] + mov ebp, [esp+12] + add esp, 16 + ret 8 + +carry1: + mov eax, 1 + jmp carry1continue + +carry2: + mov eax, 1 + jmp carry2continue + } +} + +#endif // #ifdef SSE2_INTRINSICS_AVAILABLE + +#elif defined(__GNUC__) && defined(__i386__) + +class PentiumOptimized : public Portable +{ +public: + static word Add(word *C, const word *A, const word *B, unsigned int N); + static word Subtract(word *C, const word *A, const word *B, unsigned int N); + static void Square4(word *R, const word *A); + static void Multiply4(word *C, const word *A, const word *B); + static void Multiply8(word *C, const word *A, const word *B); +}; + +typedef PentiumOptimized LowLevel; + +// Add and Subtract assembly code originally contributed by Alister Lee + +__attribute__((regparm(3))) word PentiumOptimized::Add(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + + register word carry, temp; + + __asm__ __volatile__( + "push %%ebp;" + "sub %3, %2;" + "xor %0, %0;" + "sub %4, %0;" + "lea (%1,%4,4), %1;" + "sar $1, %0;" + "jz 1f;" + + "0:;" + "mov 0(%3), %4;" + "mov 4(%3), %%ebp;" + "mov (%1,%0,8), %5;" + "lea 8(%3), %3;" + "adc %5, %4;" + "mov 4(%1,%0,8), %5;" + "adc %5, %%ebp;" + "inc %0;" + "mov %4, -8(%3, %2);" + "mov %%ebp, -4(%3, %2);" + "jnz 0b;" + + "1:;" + "adc $0, %0;" + "pop %%ebp;" + + : "=aSD" (carry), "+r" (B), "+r" (C), "+r" (A), "+r" (N), "=r" (temp) + : : "cc", "memory"); + + return carry; +} + +__attribute__((regparm(3))) word PentiumOptimized::Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + + register word carry, temp; + + __asm__ __volatile__( + "push %%ebp;" + "sub %3, %2;" + "xor %0, %0;" + "sub %4, %0;" + "lea (%1,%4,4), %1;" + "sar $1, %0;" + "jz 1f;" + + "0:;" + "mov 0(%3), %4;" + "mov 4(%3), %%ebp;" + "mov (%1,%0,8), %5;" + "lea 8(%3), %3;" + "sbb %5, %4;" + "mov 4(%1,%0,8), %5;" + "sbb %5, %%ebp;" + "inc %0;" + "mov %4, -8(%3, %2);" + "mov %%ebp, -4(%3, %2);" + "jnz 0b;" + + "1:;" + "adc $0, %0;" + "pop %%ebp;" + + : "=aSD" (carry), "+r" (B), "+r" (C), "+r" (A), "+r" (N), "=r" (temp) + : : "cc", "memory"); + + return carry; +} + +// Comba square and multiply assembly code originally contributed by Leonard Janke + +#define SqrStartup \ + "push %%ebp\n\t" \ + "push %%esi\n\t" \ + "push %%ebx\n\t" \ + "xor %%ebp, %%ebp\n\t" \ + "xor %%ebx, %%ebx\n\t" \ + "xor %%ecx, %%ecx\n\t" + +#define SqrShiftCarry \ + "mov %%ebx, %%ebp\n\t" \ + "mov %%ecx, %%ebx\n\t" \ + "xor %%ecx, %%ecx\n\t" + +#define SqrAccumulate(i,j) \ + "mov 4*"#j"(%%esi), %%eax\n\t" \ + "mull 4*"#i"(%%esi)\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edx, %%ebx\n\t" \ + "adc %%ch, %%cl\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edx, %%ebx\n\t" \ + "adc %%ch, %%cl\n\t" + +#define SqrAccumulateCentre(i) \ + "mov 4*"#i"(%%esi), %%eax\n\t" \ + "mull 4*"#i"(%%esi)\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edx, %%ebx\n\t" \ + "adc %%ch, %%cl\n\t" + +#define SqrStoreDigit(X) \ + "mov %%ebp, 4*"#X"(%%edi)\n\t" \ + +#define SqrLastDiagonal(digits) \ + "mov 4*("#digits"-1)(%%esi), %%eax\n\t" \ + "mull 4*("#digits"-1)(%%esi)\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edx, %%ebx\n\t" \ + "mov %%ebp, 4*(2*"#digits"-2)(%%edi)\n\t" \ + "mov %%ebx, 4*(2*"#digits"-1)(%%edi)\n\t" + +#define SqrCleanup \ + "pop %%ebx\n\t" \ + "pop %%esi\n\t" \ + "pop %%ebp\n\t" + +void PentiumOptimized::Square4(word* Y, const word* X) +{ + __asm__ __volatile__( + SqrStartup + + SqrAccumulateCentre(0) + SqrStoreDigit(0) + SqrShiftCarry + + SqrAccumulate(1,0) + SqrStoreDigit(1) + SqrShiftCarry + + SqrAccumulate(2,0) + SqrAccumulateCentre(1) + SqrStoreDigit(2) + SqrShiftCarry + + SqrAccumulate(3,0) + SqrAccumulate(2,1) + SqrStoreDigit(3) + SqrShiftCarry + + SqrAccumulate(3,1) + SqrAccumulateCentre(2) + SqrStoreDigit(4) + SqrShiftCarry + + SqrAccumulate(3,2) + SqrStoreDigit(5) + SqrShiftCarry + + SqrLastDiagonal(4) + + SqrCleanup + + : + : "D" (Y), "S" (X) + : "eax", "ecx", "edx", "ebp", "memory" + ); +} + +#define MulStartup \ + "push %%ebp\n\t" \ + "push %%esi\n\t" \ + "push %%ebx\n\t" \ + "push %%edi\n\t" \ + "mov %%eax, %%ebx \n\t" \ + "xor %%ebp, %%ebp\n\t" \ + "xor %%edi, %%edi\n\t" \ + "xor %%ecx, %%ecx\n\t" + +#define MulShiftCarry \ + "mov %%edx, %%ebp\n\t" \ + "mov %%ecx, %%edi\n\t" \ + "xor %%ecx, %%ecx\n\t" + +#define MulAccumulate(i,j) \ + "mov 4*"#j"(%%ebx), %%eax\n\t" \ + "mull 4*"#i"(%%esi)\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edx, %%edi\n\t" \ + "adc %%ch, %%cl\n\t" + +#define MulStoreDigit(X) \ + "mov %%edi, %%edx \n\t" \ + "mov (%%esp), %%edi \n\t" \ + "mov %%ebp, 4*"#X"(%%edi)\n\t" \ + "mov %%edi, (%%esp)\n\t" + +#define MulLastDiagonal(digits) \ + "mov 4*("#digits"-1)(%%ebx), %%eax\n\t" \ + "mull 4*("#digits"-1)(%%esi)\n\t" \ + "add %%eax, %%ebp\n\t" \ + "adc %%edi, %%edx\n\t" \ + "mov (%%esp), %%edi\n\t" \ + "mov %%ebp, 4*(2*"#digits"-2)(%%edi)\n\t" \ + "mov %%edx, 4*(2*"#digits"-1)(%%edi)\n\t" + +#define MulCleanup \ + "pop %%edi\n\t" \ + "pop %%ebx\n\t" \ + "pop %%esi\n\t" \ + "pop %%ebp\n\t" + +void PentiumOptimized::Multiply4(word* Z, const word* X, const word* Y) +{ + __asm__ __volatile__( + MulStartup + MulAccumulate(0,0) + MulStoreDigit(0) + MulShiftCarry + + MulAccumulate(1,0) + MulAccumulate(0,1) + MulStoreDigit(1) + MulShiftCarry + + MulAccumulate(2,0) + MulAccumulate(1,1) + MulAccumulate(0,2) + MulStoreDigit(2) + MulShiftCarry + + MulAccumulate(3,0) + MulAccumulate(2,1) + MulAccumulate(1,2) + MulAccumulate(0,3) + MulStoreDigit(3) + MulShiftCarry + + MulAccumulate(3,1) + MulAccumulate(2,2) + MulAccumulate(1,3) + MulStoreDigit(4) + MulShiftCarry + + MulAccumulate(3,2) + MulAccumulate(2,3) + MulStoreDigit(5) + MulShiftCarry + + MulLastDiagonal(4) + + MulCleanup + + : + : "D" (Z), "S" (X), "a" (Y) + : "%ecx", "%edx", "memory" + ); +} + +void PentiumOptimized::Multiply8(word* Z, const word* X, const word* Y) +{ + __asm__ __volatile__( + MulStartup + MulAccumulate(0,0) + MulStoreDigit(0) + MulShiftCarry + + MulAccumulate(1,0) + MulAccumulate(0,1) + MulStoreDigit(1) + MulShiftCarry + + MulAccumulate(2,0) + MulAccumulate(1,1) + MulAccumulate(0,2) + MulStoreDigit(2) + MulShiftCarry + + MulAccumulate(3,0) + MulAccumulate(2,1) + MulAccumulate(1,2) + MulAccumulate(0,3) + MulStoreDigit(3) + MulShiftCarry + + MulAccumulate(4,0) + MulAccumulate(3,1) + MulAccumulate(2,2) + MulAccumulate(1,3) + MulAccumulate(0,4) + MulStoreDigit(4) + MulShiftCarry + + MulAccumulate(5,0) + MulAccumulate(4,1) + MulAccumulate(3,2) + MulAccumulate(2,3) + MulAccumulate(1,4) + MulAccumulate(0,5) + MulStoreDigit(5) + MulShiftCarry + + MulAccumulate(6,0) + MulAccumulate(5,1) + MulAccumulate(4,2) + MulAccumulate(3,3) + MulAccumulate(2,4) + MulAccumulate(1,5) + MulAccumulate(0,6) + MulStoreDigit(6) + MulShiftCarry + + MulAccumulate(7,0) + MulAccumulate(6,1) + MulAccumulate(5,2) + MulAccumulate(4,3) + MulAccumulate(3,4) + MulAccumulate(2,5) + MulAccumulate(1,6) + MulAccumulate(0,7) + MulStoreDigit(7) + MulShiftCarry + + MulAccumulate(7,1) + MulAccumulate(6,2) + MulAccumulate(5,3) + MulAccumulate(4,4) + MulAccumulate(3,5) + MulAccumulate(2,6) + MulAccumulate(1,7) + MulStoreDigit(8) + MulShiftCarry + + MulAccumulate(7,2) + MulAccumulate(6,3) + MulAccumulate(5,4) + MulAccumulate(4,5) + MulAccumulate(3,6) + MulAccumulate(2,7) + MulStoreDigit(9) + MulShiftCarry + + MulAccumulate(7,3) + MulAccumulate(6,4) + MulAccumulate(5,5) + MulAccumulate(4,6) + MulAccumulate(3,7) + MulStoreDigit(10) + MulShiftCarry + + MulAccumulate(7,4) + MulAccumulate(6,5) + MulAccumulate(5,6) + MulAccumulate(4,7) + MulStoreDigit(11) + MulShiftCarry + + MulAccumulate(7,5) + MulAccumulate(6,6) + MulAccumulate(5,7) + MulStoreDigit(12) + MulShiftCarry + + MulAccumulate(7,6) + MulAccumulate(6,7) + MulStoreDigit(13) + MulShiftCarry + + MulLastDiagonal(8) + + MulCleanup + + : + : "D" (Z), "S" (X), "a" (Y) + : "%ecx", "%edx", "memory" + ); +} + +#elif defined(__GNUC__) && defined(__alpha__) + +class AlphaOptimized : public Portable +{ +public: + static inline void Multiply2(word *C, const word *A, const word *B); + static inline word Multiply2Add(word *C, const word *A, const word *B); + static inline void Multiply4(word *C, const word *A, const word *B); + static inline unsigned int MultiplyRecursionLimit() {return 4;} + + static inline void Multiply4Bottom(word *C, const word *A, const word *B); + static inline unsigned int MultiplyBottomRecursionLimit() {return 4;} + + static inline void Square4(word *R, const word *A) + { + Multiply4(R, A, A); + } +}; + +typedef AlphaOptimized LowLevel; + +inline void AlphaOptimized::Multiply2(word *C, const word *A, const word *B) +{ + register dword c, a = *(const dword *)A, b = *(const dword *)B; + ((dword *)C)[0] = a*b; + __asm__("umulh %1,%2,%0" : "=r" (c) : "r" (a), "r" (b)); + ((dword *)C)[1] = c; +} + +inline word AlphaOptimized::Multiply2Add(word *C, const word *A, const word *B) +{ + register dword c, d, e, a = *(const dword *)A, b = *(const dword *)B; + c = ((dword *)C)[0]; + d = a*b + c; + __asm__("umulh %1,%2,%0" : "=r" (e) : "r" (a), "r" (b)); + ((dword *)C)[0] = d; + d = (d < c); + c = ((dword *)C)[1] + d; + d = (c < d); + c += e; + ((dword *)C)[1] = c; + d |= (c < e); + return d; +} + +inline void AlphaOptimized::Multiply4(word *R, const word *A, const word *B) +{ + Multiply2(R, A, B); + Multiply2(R+4, A+2, B+2); + word carry = Multiply2Add(R+2, A+0, B+2); + carry += Multiply2Add(R+2, A+2, B+0); + Increment(R+6, 2, carry); +} + +static inline void Multiply2BottomAdd(word *C, const word *A, const word *B) +{ + register dword a = *(const dword *)A, b = *(const dword *)B; + ((dword *)C)[0] = a*b + ((dword *)C)[0]; +} + +inline void AlphaOptimized::Multiply4Bottom(word *R, const word *A, const word *B) +{ + Multiply2(R, A, B); + Multiply2BottomAdd(R+2, A+0, B+2); + Multiply2BottomAdd(R+2, A+2, B+0); +} + +#else // no processor specific code available + +typedef Portable LowLevel; + +#endif + +// ******************************************************** + +#define A0 A +#define A1 (A+N2) +#define B0 B +#define B1 (B+N2) + +#define T0 T +#define T1 (T+N2) +#define T2 (T+N) +#define T3 (T+N+N2) + +#define R0 R +#define R1 (R+N2) +#define R2 (R+N) +#define R3 (R+N+N2) + +//VC60 workaround: compiler bug triggered without the extra dummy parameters + +// R[2*N] - result = A*B +// T[2*N] - temporary work space +// A[N] --- multiplier +// B[N] --- multiplicant + +template <class P> +void DoRecursiveMultiply(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL); + +template <class P> +inline void RecursiveMultiply(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL) +{ + assert(N>=2 && N%2==0); + + if (P::MultiplyRecursionLimit() >= 8 && N==8) + P::Multiply8(R, A, B); + else if (P::MultiplyRecursionLimit() >= 4 && N==4) + P::Multiply4(R, A, B); + else if (N==2) + P::Multiply2(R, A, B); + else + DoRecursiveMultiply<P>(R, T, A, B, N, NULL); // VC60 workaround: needs this NULL +} + +template <class P> +void DoRecursiveMultiply(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy) +{ + const unsigned int N2 = N/2; + int carry; + + int aComp = Compare(A0, A1, N2); + int bComp = Compare(B0, B1, N2); + + switch (2*aComp + aComp + bComp) + { + case -4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R0, N2); + carry = -1; + break; + case -2: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + P::Subtract(R0, A0, A1, N2); + P::Subtract(R1, B1, B0, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply<P>(R0, T2, A0, B0, N2); + RecursiveMultiply<P>(R2, T2, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1), R[01] holds A0*B0, R[23] holds A1*B1 + + carry += P::Add(T0, T0, R0, N); + carry += P::Add(T0, T0, R2, N); + carry += P::Add(R1, R1, T0, N); + + assert (carry >= 0 && carry <= 2); + Increment(R3, N2, carry); +} + +// R[2*N] - result = A*A +// T[2*N] - temporary work space +// A[N] --- number to be squared + +template <class P> +void DoRecursiveSquare(word *R, word *T, const word *A, unsigned int N, const P *dummy=NULL); + +template <class P> +inline void RecursiveSquare(word *R, word *T, const word *A, unsigned int N, const P *dummy=NULL) +{ + assert(N && N%2==0); + if (P::SquareRecursionLimit() >= 8 && N==8) + P::Square8(R, A); + if (P::SquareRecursionLimit() >= 4 && N==4) + P::Square4(R, A); + else if (N==2) + P::Square2(R, A); + else + DoRecursiveSquare<P>(R, T, A, N, NULL); // VC60 workaround: needs this NULL +} + +template <class P> +void DoRecursiveSquare(word *R, word *T, const word *A, unsigned int N, const P *dummy) +{ + const unsigned int N2 = N/2; + + RecursiveSquare<P>(R0, T2, A0, N2); + RecursiveSquare<P>(R2, T2, A1, N2); + RecursiveMultiply<P>(T0, T2, A0, A1, N2); + + word carry = P::Add(R1, R1, T0, N); + carry += P::Add(R1, R1, T0, N); + Increment(R3, N2, carry); +} + +// R[N] - bottom half of A*B +// T[N] - temporary work space +// A[N] - multiplier +// B[N] - multiplicant + +template <class P> +void DoRecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL); + +template <class P> +inline void RecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL) +{ + assert(N>=2 && N%2==0); + if (P::MultiplyBottomRecursionLimit() >= 8 && N==8) + P::Multiply8Bottom(R, A, B); + else if (P::MultiplyBottomRecursionLimit() >= 4 && N==4) + P::Multiply4Bottom(R, A, B); + else if (N==2) + P::Multiply2Bottom(R, A, B); + else + DoRecursiveMultiplyBottom<P>(R, T, A, B, N, NULL); +} + +template <class P> +void DoRecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy) +{ + const unsigned int N2 = N/2; + + RecursiveMultiply<P>(R, T, A0, B0, N2); + RecursiveMultiplyBottom<P>(T0, T1, A1, B0, N2); + P::Add(R1, R1, T0, N2); + RecursiveMultiplyBottom<P>(T0, T1, A0, B1, N2); + P::Add(R1, R1, T0, N2); +} + +// R[N] --- upper half of A*B +// T[2*N] - temporary work space +// L[N] --- lower half of A*B +// A[N] --- multiplier +// B[N] --- multiplicant + +template <class P> +void RecursiveMultiplyTop(word *R, word *T, const word *L, const word *A, const word *B, unsigned int N, const P *dummy=NULL) +{ + assert(N>=2 && N%2==0); + + if (N==4) + { + P::Multiply4(T, A, B); + ((dword *)R)[0] = ((dword *)T)[2]; + ((dword *)R)[1] = ((dword *)T)[3]; + } + else if (N==2) + { + P::Multiply2(T, A, B); + ((dword *)R)[0] = ((dword *)T)[1]; + } + else + { + const unsigned int N2 = N/2; + int carry; + + int aComp = Compare(A0, A1, N2); + int bComp = Compare(B0, B1, N2); + + switch (2*aComp + aComp + bComp) + { + case -4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R0, N2); + carry = -1; + break; + case -2: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + P::Subtract(R0, A0, A1, N2); + P::Subtract(R1, B1, B0, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply<P>(T2, R0, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1), T[23] holds A1*B1 + + word c2 = P::Subtract(R0, L+N2, L, N2); + c2 += P::Subtract(R0, R0, T0, N2); + word t = (Compare(R0, T2, N2) == -1); + + carry += t; + carry += Increment(R0, N2, c2+t); + carry += P::Add(R0, R0, T1, N2); + carry += P::Add(R0, R0, T3, N2); + assert (carry >= 0 && carry <= 2); + + CopyWords(R1, T3, N2); + Increment(R1, N2, carry); + } +} + +inline word Add(word *C, const word *A, const word *B, unsigned int N) +{ + return LowLevel::Add(C, A, B, N); +} + +inline word Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + return LowLevel::Subtract(C, A, B, N); +} + +inline void Multiply(word *R, word *T, const word *A, const word *B, unsigned int N) +{ +#ifdef SSE2_INTRINSICS_AVAILABLE + if (HasSSE2()) + RecursiveMultiply<P4Optimized>(R, T, A, B, N); + else +#endif + RecursiveMultiply<LowLevel>(R, T, A, B, N); +} + +inline void Square(word *R, word *T, const word *A, unsigned int N) +{ +#ifdef SSE2_INTRINSICS_AVAILABLE + if (HasSSE2()) + RecursiveSquare<P4Optimized>(R, T, A, N); + else +#endif + RecursiveSquare<LowLevel>(R, T, A, N); +} + +inline void MultiplyBottom(word *R, word *T, const word *A, const word *B, unsigned int N) +{ +#ifdef SSE2_INTRINSICS_AVAILABLE + if (HasSSE2()) + RecursiveMultiplyBottom<P4Optimized>(R, T, A, B, N); + else +#endif + RecursiveMultiplyBottom<LowLevel>(R, T, A, B, N); +} + +inline void MultiplyTop(word *R, word *T, const word *L, const word *A, const word *B, unsigned int N) +{ +#ifdef SSE2_INTRINSICS_AVAILABLE + if (HasSSE2()) + RecursiveMultiplyTop<P4Optimized>(R, T, L, A, B, N); + else +#endif + RecursiveMultiplyTop<LowLevel>(R, T, L, A, B, N); +} + +// R[NA+NB] - result = A*B +// T[NA+NB] - temporary work space +// A[NA] ---- multiplier +// B[NB] ---- multiplicant + +void AsymmetricMultiply(word *R, word *T, const word *A, unsigned int NA, const word *B, unsigned int NB) +{ + if (NA == NB) + { + if (A == B) + Square(R, T, A, NA); + else + Multiply(R, T, A, B, NA); + + return; + } + + if (NA > NB) + { + std::swap(A, B); + std::swap(NA, NB); + } + + assert(NB % NA == 0); + assert((NB/NA)%2 == 0); // NB is an even multiple of NA + + if (NA==2 && !A[1]) + { + switch (A[0]) + { + case 0: + SetWords(R, 0, NB+2); + return; + case 1: + CopyWords(R, B, NB); + R[NB] = R[NB+1] = 0; + return; + default: + R[NB] = LinearMultiply(R, B, A[0], NB); + R[NB+1] = 0; + return; + } + } + + Multiply(R, T, A, B, NA); + CopyWords(T+2*NA, R+NA, NA); + + unsigned i; + + for (i=2*NA; i<NB; i+=2*NA) + Multiply(T+NA+i, T, A, B+i, NA); + for (i=NA; i<NB; i+=2*NA) + Multiply(R+i, T, A, B+i, NA); + + if (Add(R+NA, R+NA, T+2*NA, NB-NA)) + Increment(R+NB, NA); +} + +// R[N] ----- result = A inverse mod 2**(WORD_BITS*N) +// T[3*N/2] - temporary work space +// A[N] ----- an odd number as input + +void RecursiveInverseModPower2(word *R, word *T, const word *A, unsigned int N) +{ + if (N==2) + AtomicInverseModPower2(R, A[0], A[1]); + else + { + const unsigned int N2 = N/2; + RecursiveInverseModPower2(R0, T0, A0, N2); + T0[0] = 1; + SetWords(T0+1, 0, N2-1); + MultiplyTop(R1, T1, T0, R0, A0, N2); + MultiplyBottom(T0, T1, R0, A1, N2); + Add(T0, R1, T0, N2); + TwosComplement(T0, N2); + MultiplyBottom(R1, T1, R0, T0, N2); + } +} + +// R[N] --- result = X/(2**(WORD_BITS*N)) mod M +// T[3*N] - temporary work space +// X[2*N] - number to be reduced +// M[N] --- modulus +// U[N] --- multiplicative inverse of M mod 2**(WORD_BITS*N) + +void MontgomeryReduce(word *R, word *T, const word *X, const word *M, const word *U, unsigned int N) +{ + MultiplyBottom(R, T, X, U, N); + MultiplyTop(T, T+N, X, R, M, N); + if (Subtract(R, X+N, T, N)) + { + word carry = Add(R, R, M, N); + assert(carry); + } +} + +// R[N] --- result = X/(2**(WORD_BITS*N/2)) mod M +// T[2*N] - temporary work space +// X[2*N] - number to be reduced +// M[N] --- modulus +// U[N/2] - multiplicative inverse of M mod 2**(WORD_BITS*N/2) +// V[N] --- 2**(WORD_BITS*3*N/2) mod M + +void HalfMontgomeryReduce(word *R, word *T, const word *X, const word *M, const word *U, const word *V, unsigned int N) +{ + assert(N%2==0 && N>=4); + +#define M0 M +#define M1 (M+N2) +#define V0 V +#define V1 (V+N2) + +#define X0 X +#define X1 (X+N2) +#define X2 (X+N) +#define X3 (X+N+N2) + + const unsigned int N2 = N/2; + Multiply(T0, T2, V0, X3, N2); + int c2 = Add(T0, T0, X0, N); + MultiplyBottom(T3, T2, T0, U, N2); + MultiplyTop(T2, R, T0, T3, M0, N2); + c2 -= Subtract(T2, T1, T2, N2); + Multiply(T0, R, T3, M1, N2); + c2 -= Subtract(T0, T2, T0, N2); + int c3 = -(int)Subtract(T1, X2, T1, N2); + Multiply(R0, T2, V1, X3, N2); + c3 += Add(R, R, T, N); + + if (c2>0) + c3 += Increment(R1, N2); + else if (c2<0) + c3 -= Decrement(R1, N2, -c2); + + assert(c3>=-1 && c3<=1); + if (c3>0) + Subtract(R, R, M, N); + else if (c3<0) + Add(R, R, M, N); + +#undef M0 +#undef M1 +#undef V0 +#undef V1 + +#undef X0 +#undef X1 +#undef X2 +#undef X3 +} + +#undef A0 +#undef A1 +#undef B0 +#undef B1 + +#undef T0 +#undef T1 +#undef T2 +#undef T3 + +#undef R0 +#undef R1 +#undef R2 +#undef R3 + +// do a 3 word by 2 word divide, returns quotient and leaves remainder in A +static word SubatomicDivide(word *A, word B0, word B1) +{ + // assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a word + assert(A[2] < B1 || (A[2]==B1 && A[1] < B0)); + + dword p, u; + word Q; + + // estimate the quotient: do a 2 word by 1 word divide + if (B1+1 == 0) + Q = A[2]; + else + Q = word(MAKE_DWORD(A[1], A[2]) / (B1+1)); + + // now subtract Q*B from A + p = (dword) B0*Q; + u = (dword) A[0] - LOW_WORD(p); + A[0] = LOW_WORD(u); + u = (dword) A[1] - HIGH_WORD(p) - (word)(0-HIGH_WORD(u)) - (dword)B1*Q; + A[1] = LOW_WORD(u); + A[2] += HIGH_WORD(u); + + // Q <= actual quotient, so fix it + while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) + { + u = (dword) A[0] - B0; + A[0] = LOW_WORD(u); + u = (dword) A[1] - B1 - (word)(0-HIGH_WORD(u)); + A[1] = LOW_WORD(u); + A[2] += HIGH_WORD(u); + Q++; + assert(Q); // shouldn't overflow + } + + return Q; +} + +// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1 +static inline void AtomicDivide(word *Q, const word *A, const word *B) +{ + if (!B[0] && !B[1]) // if divisor is 0, we assume divisor==2**(2*WORD_BITS) + { + Q[0] = A[2]; + Q[1] = A[3]; + } + else + { + word T[4]; + T[0] = A[0]; T[1] = A[1]; T[2] = A[2]; T[3] = A[3]; + Q[1] = SubatomicDivide(T+1, B[0], B[1]); + Q[0] = SubatomicDivide(T, B[0], B[1]); + +#ifndef NDEBUG + // multiply quotient and divisor and add remainder, make sure it equals dividend + assert(!T[2] && !T[3] && (T[1] < B[1] || (T[1]==B[1] && T[0]<B[0]))); + word P[4]; + LowLevel::Multiply2(P, Q, B); + Add(P, P, T, 4); + assert(memcmp(P, A, 4*WORD_SIZE)==0); +#endif + } +} + +// for use by Divide(), corrects the underestimated quotient {Q1,Q0} +static void CorrectQuotientEstimate(word *R, word *T, word *Q, const word *B, unsigned int N) +{ + assert(N && N%2==0); + + if (Q[1]) + { + T[N] = T[N+1] = 0; + unsigned i; + for (i=0; i<N; i+=4) + LowLevel::Multiply2(T+i, Q, B+i); + for (i=2; i<N; i+=4) + if (LowLevel::Multiply2Add(T+i, Q, B+i)) + T[i+5] += (++T[i+4]==0); + } + else + { + T[N] = LinearMultiply(T, B, Q[0], N); + T[N+1] = 0; + } + + word borrow = Subtract(R, R, T, N+2); + assert(!borrow && !R[N+1]); + + while (R[N] || Compare(R, B, N) >= 0) + { + R[N] -= Subtract(R, R, B, N); + Q[1] += (++Q[0]==0); + assert(Q[0] || Q[1]); // no overflow + } +} + +// R[NB] -------- remainder = A%B +// Q[NA-NB+2] --- quotient = A/B +// T[NA+2*NB+4] - temp work space +// A[NA] -------- dividend +// B[NB] -------- divisor + +void Divide(word *R, word *Q, word *T, const word *A, unsigned int NA, const word *B, unsigned int NB) +{ + assert(NA && NB && NA%2==0 && NB%2==0); + assert(B[NB-1] || B[NB-2]); + assert(NB <= NA); + + // set up temporary work space + word *const TA=T; + word *const TB=T+NA+2; + word *const TP=T+NA+2+NB; + + // copy B into TB and normalize it so that TB has highest bit set to 1 + unsigned shiftWords = (B[NB-1]==0); + TB[0] = TB[NB-1] = 0; + CopyWords(TB+shiftWords, B, NB-shiftWords); + unsigned shiftBits = WORD_BITS - BitPrecision(TB[NB-1]); + assert(shiftBits < WORD_BITS); + ShiftWordsLeftByBits(TB, NB, shiftBits); + + // copy A into TA and normalize it + TA[0] = TA[NA] = TA[NA+1] = 0; + CopyWords(TA+shiftWords, A, NA); + ShiftWordsLeftByBits(TA, NA+2, shiftBits); + + if (TA[NA+1]==0 && TA[NA] <= 1) + { + Q[NA-NB+1] = Q[NA-NB] = 0; + while (TA[NA] || Compare(TA+NA-NB, TB, NB) >= 0) + { + TA[NA] -= Subtract(TA+NA-NB, TA+NA-NB, TB, NB); + ++Q[NA-NB]; + } + } + else + { + NA+=2; + assert(Compare(TA+NA-NB, TB, NB) < 0); + } + + word BT[2]; + BT[0] = TB[NB-2] + 1; + BT[1] = TB[NB-1] + (BT[0]==0); + + // start reducing TA mod TB, 2 words at a time + for (unsigned i=NA-2; i>=NB; i-=2) + { + AtomicDivide(Q+i-NB, TA+i-2, BT); + CorrectQuotientEstimate(TA+i-NB, TP, Q+i-NB, TB, NB); + } + + // copy TA into R, and denormalize it + CopyWords(R, TA+shiftWords, NB); + ShiftWordsRightByBits(R, NB, shiftBits); +} + +static inline unsigned int EvenWordCount(const word *X, unsigned int N) +{ + while (N && X[N-2]==0 && X[N-1]==0) + N-=2; + return N; +} + +// return k +// R[N] --- result = A^(-1) * 2^k mod M +// T[4*N] - temporary work space +// A[NA] -- number to take inverse of +// M[N] --- modulus + +unsigned int AlmostInverse(word *R, word *T, const word *A, unsigned int NA, const word *M, unsigned int N) +{ + assert(NA<=N && N && N%2==0); + + word *b = T; + word *c = T+N; + word *f = T+2*N; + word *g = T+3*N; + unsigned int bcLen=2, fgLen=EvenWordCount(M, N); + unsigned int k=0, s=0; + + SetWords(T, 0, 3*N); + b[0]=1; + CopyWords(f, A, NA); + CopyWords(g, M, N); + + while (1) + { + word t=f[0]; + while (!t) + { + if (EvenWordCount(f, fgLen)==0) + { + SetWords(R, 0, N); + return 0; + } + + ShiftWordsRightByWords(f, fgLen, 1); + if (c[bcLen-1]) bcLen+=2; + assert(bcLen <= N); + ShiftWordsLeftByWords(c, bcLen, 1); + k+=WORD_BITS; + t=f[0]; + } + + unsigned int i=0; + while (t%2 == 0) + { + t>>=1; + i++; + } + k+=i; + + if (t==1 && f[1]==0 && EvenWordCount(f, fgLen)==2) + { + if (s%2==0) + CopyWords(R, b, N); + else + Subtract(R, M, b, N); + return k; + } + + ShiftWordsRightByBits(f, fgLen, i); + t=ShiftWordsLeftByBits(c, bcLen, i); + if (t) + { + c[bcLen] = t; + bcLen+=2; + assert(bcLen <= N); + } + + if (f[fgLen-2]==0 && g[fgLen-2]==0 && f[fgLen-1]==0 && g[fgLen-1]==0) + fgLen-=2; + + if (Compare(f, g, fgLen)==-1) + { + std::swap(f, g); + std::swap(b, c); + s++; + } + + Subtract(f, f, g, fgLen); + + if (Add(b, b, c, bcLen)) + { + b[bcLen] = 1; + bcLen+=2; + assert(bcLen <= N); + } + } +} + +// R[N] - result = A/(2^k) mod M +// A[N] - input +// M[N] - modulus + +void DivideByPower2Mod(word *R, const word *A, unsigned int k, const word *M, unsigned int N) +{ + CopyWords(R, A, N); + + while (k--) + { + if (R[0]%2==0) + ShiftWordsRightByBits(R, N, 1); + else + { + word carry = Add(R, R, M, N); + ShiftWordsRightByBits(R, N, 1); + R[N-1] += carry<<(WORD_BITS-1); + } + } +} + +// R[N] - result = A*(2^k) mod M +// A[N] - input +// M[N] - modulus + +void MultiplyByPower2Mod(word *R, const word *A, unsigned int k, const word *M, unsigned int N) +{ + CopyWords(R, A, N); + + while (k--) + if (ShiftWordsLeftByBits(R, N, 1) || Compare(R, M, N)>=0) + Subtract(R, R, M, N); +} + +// ****************************************************************** + +static const unsigned int RoundupSizeTable[] = {2, 2, 2, 4, 4, 8, 8, 8, 8}; + +static inline unsigned int RoundupSize(unsigned int n) +{ + if (n<=8) + return RoundupSizeTable[n]; + else if (n<=16) + return 16; + else if (n<=32) + return 32; + else if (n<=64) + return 64; + else return 1U << BitPrecision(n-1); +} + +Integer::Integer() + : reg(2), sign(POSITIVE) +{ + reg[0] = reg[1] = 0; +} + +Integer::Integer(const Integer& t) + : reg(RoundupSize(t.WordCount())), sign(t.sign) +{ + CopyWords(reg, t.reg, reg.size()); +} + +Integer::Integer(signed long value) + : reg(2) +{ + if (value >= 0) + sign = POSITIVE; + else + { + sign = NEGATIVE; + value = -value; + } + reg[0] = word(value); + reg[1] = word(SafeRightShift<WORD_BITS, unsigned long>(value)); +} + +bool Integer::IsConvertableToLong() const +{ + if (ByteCount() > sizeof(long)) + return false; + + unsigned long value = reg[0]; + value += SafeLeftShift<WORD_BITS, unsigned long>(reg[1]); + + if (sign==POSITIVE) + return (signed long)value >= 0; + else + return -(signed long)value < 0; +} + +signed long Integer::ConvertToLong() const +{ + assert(IsConvertableToLong()); + + unsigned long value = reg[0]; + value += SafeLeftShift<WORD_BITS, unsigned long>(reg[1]); + return sign==POSITIVE ? value : -(signed long)value; +} + +Integer::Integer(BufferedTransformation &encodedInteger, unsigned int byteCount, Signedness s) +{ + Decode(encodedInteger, byteCount, s); +} + +Integer::Integer(const byte *encodedInteger, unsigned int byteCount, Signedness s) +{ + Decode(encodedInteger, byteCount, s); +} + +Integer::Integer(BufferedTransformation &bt) +{ + BERDecode(bt); +} + +Integer::Integer(RandomNumberGenerator &rng, unsigned int bitcount) +{ + Randomize(rng, bitcount); +} + +Integer::Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod) +{ + if (!Randomize(rng, min, max, rnType, equiv, mod)) + throw Integer::RandomNumberNotFound(); +} + +Integer Integer::Power2(unsigned int e) +{ + Integer r((word)0, BitsToWords(e+1)); + r.SetBit(e); + return r; +} + +const Integer &Integer::Zero() +{ + static const Integer zero; + return zero; +} + +const Integer &Integer::One() +{ + static const Integer one(1,2); + return one; +} + +const Integer &Integer::Two() +{ + static const Integer two(2,2); + return two; +} + +bool Integer::operator!() const +{ + return IsNegative() ? false : (reg[0]==0 && WordCount()==0); +} + +Integer& Integer::operator=(const Integer& t) +{ + if (this != &t) + { + reg.New(RoundupSize(t.WordCount())); + CopyWords(reg, t.reg, reg.size()); + sign = t.sign; + } + return *this; +} + +bool Integer::GetBit(unsigned int n) const +{ + if (n/WORD_BITS >= reg.size()) + return 0; + else + return bool((reg[n/WORD_BITS] >> (n % WORD_BITS)) & 1); +} + +void Integer::SetBit(unsigned int n, bool value) +{ + if (value) + { + reg.CleanGrow(RoundupSize(BitsToWords(n+1))); + reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS)); + } + else + { + if (n/WORD_BITS < reg.size()) + reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS)); + } +} + +byte Integer::GetByte(unsigned int n) const +{ + if (n/WORD_SIZE >= reg.size()) + return 0; + else + return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); +} + +void Integer::SetByte(unsigned int n, byte value) +{ + reg.CleanGrow(RoundupSize(BytesToWords(n+1))); + reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); + reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); +} + +unsigned long Integer::GetBits(unsigned int i, unsigned int n) const +{ + assert(n <= sizeof(unsigned long)*8); + unsigned long v = 0; + for (unsigned int j=0; j<n; j++) + v |= GetBit(i+j) << j; + return v; +} + +Integer Integer::operator-() const +{ + Integer result(*this); + result.Negate(); + return result; +} + +Integer Integer::AbsoluteValue() const +{ + Integer result(*this); + result.sign = POSITIVE; + return result; +} + +void Integer::swap(Integer &a) +{ + reg.swap(a.reg); + std::swap(sign, a.sign); +} + +Integer::Integer(word value, unsigned int length) + : reg(RoundupSize(length)), sign(POSITIVE) +{ + reg[0] = value; + SetWords(reg+1, 0, reg.size()-1); +} + +template <class T> +static Integer StringToInteger(const T *str) +{ + word radix; +#if (defined(__GNUC__) && __GNUC__ <= 3) // GCC workaround + // std::char_traits doesn't exist in GCC 2.x + // std::char_traits<wchar_t>::length() not defined in GCC 3.2 + unsigned int length; + for (length = 0; str[length] != 0; length++) {} +#else + unsigned int length = std::char_traits<T>::length(str); +#endif + + Integer v; + + if (length == 0) + return v; + + switch (str[length-1]) + { + case 'h': + case 'H': + radix=16; + break; + case 'o': + case 'O': + radix=8; + break; + case 'b': + case 'B': + radix=2; + break; + default: + radix=10; + } + + if (length > 2 && str[0] == '0' && str[1] == 'x') + radix = 16; + + for (unsigned i=0; i<length; i++) + { + word digit; + + if (str[i] >= '0' && str[i] <= '9') + digit = str[i] - '0'; + else if (str[i] >= 'A' && str[i] <= 'F') + digit = str[i] - 'A' + 10; + else if (str[i] >= 'a' && str[i] <= 'f') + digit = str[i] - 'a' + 10; + else + digit = radix; + + if (digit < radix) + { + v *= radix; + v += digit; + } + } + + if (str[0] == '-') + v.Negate(); + + return v; +} + +Integer::Integer(const char *str) + : reg(2), sign(POSITIVE) +{ + *this = StringToInteger(str); +} + +Integer::Integer(const wchar_t *str) + : reg(2), sign(POSITIVE) +{ + *this = StringToInteger(str); +} + +unsigned int Integer::WordCount() const +{ + return CountWords(reg, reg.size()); +} + +unsigned int Integer::ByteCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int Integer::BitCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]); + else + return 0; +} + +void Integer::Decode(const byte *input, unsigned int inputLen, Signedness s) +{ + StringStore store(input, inputLen); + Decode(store, inputLen, s); +} + +void Integer::Decode(BufferedTransformation &bt, unsigned int inputLen, Signedness s) +{ + assert(bt.MaxRetrievable() >= inputLen); + + byte b; + bt.Peek(b); + sign = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; + + while (inputLen>0 && (sign==POSITIVE ? b==0 : b==0xff)) + { + bt.Skip(1); + inputLen--; + bt.Peek(b); + } + + reg.CleanNew(RoundupSize(BytesToWords(inputLen))); + + for (unsigned int i=inputLen; i > 0; i--) + { + bt.Get(b); + reg[(i-1)/WORD_SIZE] |= b << ((i-1)%WORD_SIZE)*8; + } + + if (sign == NEGATIVE) + { + for (unsigned i=inputLen; i<reg.size()*WORD_SIZE; i++) + reg[i/WORD_SIZE] |= 0xff << (i%WORD_SIZE)*8; + TwosComplement(reg, reg.size()); + } +} + +unsigned int Integer::MinEncodedSize(Signedness signedness) const +{ + unsigned int outputLen = STDMAX(1U, ByteCount()); + if (signedness == UNSIGNED) + return outputLen; + if (NotNegative() && (GetByte(outputLen-1) & 0x80)) + outputLen++; + if (IsNegative() && *this < -Power2(outputLen*8-1)) + outputLen++; + return outputLen; +} + +unsigned int Integer::Encode(byte *output, unsigned int outputLen, Signedness signedness) const +{ + ArraySink sink(output, outputLen); + return Encode(sink, outputLen, signedness); +} + +unsigned int Integer::Encode(BufferedTransformation &bt, unsigned int outputLen, Signedness signedness) const +{ + if (signedness == UNSIGNED || NotNegative()) + { + for (unsigned int i=outputLen; i > 0; i--) + bt.Put(GetByte(i-1)); + } + else + { + // take two's complement of *this + Integer temp = Integer::Power2(8*STDMAX(ByteCount(), outputLen)) + *this; + for (unsigned i=0; i<outputLen; i++) + bt.Put(temp.GetByte(outputLen-i-1)); + } + return outputLen; +} + +void Integer::DEREncode(BufferedTransformation &bt) const +{ + DERGeneralEncoder enc(bt, INTEGER); + Encode(enc, MinEncodedSize(SIGNED), SIGNED); + enc.MessageEnd(); +} + +void Integer::BERDecode(const byte *input, unsigned int len) +{ + StringStore store(input, len); + BERDecode(store); +} + +void Integer::BERDecode(BufferedTransformation &bt) +{ + BERGeneralDecoder dec(bt, INTEGER); + if (!dec.IsDefiniteLength() || dec.MaxRetrievable() < dec.RemainingLength()) + BERDecodeError(); + Decode(dec, dec.RemainingLength(), SIGNED); + dec.MessageEnd(); +} + +void Integer::DEREncodeAsOctetString(BufferedTransformation &bt, unsigned int length) const +{ + DERGeneralEncoder enc(bt, OCTET_STRING); + Encode(enc, length); + enc.MessageEnd(); +} + +void Integer::BERDecodeAsOctetString(BufferedTransformation &bt, unsigned int length) +{ + BERGeneralDecoder dec(bt, OCTET_STRING); + if (!dec.IsDefiniteLength() || dec.RemainingLength() != length) + BERDecodeError(); + Decode(dec, length); + dec.MessageEnd(); +} + +unsigned int Integer::OpenPGPEncode(byte *output, unsigned int len) const +{ + ArraySink sink(output, len); + return OpenPGPEncode(sink); +} + +unsigned int Integer::OpenPGPEncode(BufferedTransformation &bt) const +{ + word16 bitCount = BitCount(); + bt.PutWord16(bitCount); + return 2 + Encode(bt, BitsToBytes(bitCount)); +} + +void Integer::OpenPGPDecode(const byte *input, unsigned int len) +{ + StringStore store(input, len); + OpenPGPDecode(store); +} + +void Integer::OpenPGPDecode(BufferedTransformation &bt) +{ + word16 bitCount; + if (bt.GetWord16(bitCount) != 2 || bt.MaxRetrievable() < BitsToBytes(bitCount)) + throw OpenPGPDecodeErr(); + Decode(bt, BitsToBytes(bitCount)); +} + +void Integer::Randomize(RandomNumberGenerator &rng, unsigned int nbits) +{ + const unsigned int nbytes = nbits/8 + 1; + SecByteBlock buf(nbytes); + rng.GenerateBlock(buf, nbytes); + if (nbytes) + buf[0] = (byte)Crop(buf[0], nbits % 8); + Decode(buf, nbytes, UNSIGNED); +} + +void Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max) +{ + if (min > max) + throw InvalidArgument("Integer: Min must be no greater than Max"); + + Integer range = max - min; + const unsigned int nbits = range.BitCount(); + + do + { + Randomize(rng, nbits); + } + while (*this > range); + + *this += min; +} + +bool Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod) +{ + return GenerateRandomNoThrow(rng, MakeParameters("Min", min)("Max", max)("RandomNumberType", rnType)("EquivalentTo", equiv)("Mod", mod)); +} + +class KDF2_RNG : public RandomNumberGenerator +{ +public: + KDF2_RNG(const byte *seed, unsigned int seedSize) + : m_counter(0), m_counterAndSeed(seedSize + 4) + { + memcpy(m_counterAndSeed + 4, seed, seedSize); + } + + byte GenerateByte() + { + byte b; + GenerateBlock(&b, 1); + return b; + } + + void GenerateBlock(byte *output, unsigned int size) + { + UnalignedPutWord(BIG_ENDIAN_ORDER, m_counterAndSeed, m_counter); + ++m_counter; + P1363_KDF2<SHA1>::DeriveKey(output, size, m_counterAndSeed, m_counterAndSeed.size()); + } + +private: + word32 m_counter; + SecByteBlock m_counterAndSeed; +}; + +bool Integer::GenerateRandomNoThrow(RandomNumberGenerator &i_rng, const NameValuePairs ¶ms) +{ + Integer min = params.GetValueWithDefault("Min", Integer::Zero()); + Integer max; + if (!params.GetValue("Max", max)) + { + int bitLength; + if (params.GetIntValue("BitLength", bitLength)) + max = Integer::Power2(bitLength); + else + throw InvalidArgument("Integer: missing Max argument"); + } + if (min > max) + throw InvalidArgument("Integer: Min must be no greater than Max"); + + Integer equiv = params.GetValueWithDefault("EquivalentTo", Integer::Zero()); + Integer mod = params.GetValueWithDefault("Mod", Integer::One()); + + if (equiv.IsNegative() || equiv >= mod) + throw InvalidArgument("Integer: invalid EquivalentTo and/or Mod argument"); + + Integer::RandomNumberType rnType = params.GetValueWithDefault("RandomNumberType", Integer::ANY); + + member_ptr<KDF2_RNG> kdf2Rng; + ConstByteArrayParameter seed; + if (params.GetValue("Seed", seed)) + { + ByteQueue bq; + DERSequenceEncoder seq(bq); + min.DEREncode(seq); + max.DEREncode(seq); + equiv.DEREncode(seq); + mod.DEREncode(seq); + DEREncodeUnsigned(seq, rnType); + DEREncodeOctetString(seq, seed.begin(), seed.size()); + seq.MessageEnd(); + + SecByteBlock finalSeed(bq.MaxRetrievable()); + bq.Get(finalSeed, finalSeed.size()); + kdf2Rng.reset(new KDF2_RNG(finalSeed.begin(), finalSeed.size())); + } + RandomNumberGenerator &rng = kdf2Rng.get() ? (RandomNumberGenerator &)*kdf2Rng : i_rng; + + switch (rnType) + { + case ANY: + if (mod == One()) + Randomize(rng, min, max); + else + { + Integer min1 = min + (equiv-min)%mod; + if (max < min1) + return false; + Randomize(rng, Zero(), (max - min1) / mod); + *this *= mod; + *this += min1; + } + return true; + + case PRIME: + { + const PrimeSelector *pSelector = params.GetValueWithDefault("PointerToPrimeSelector", (const PrimeSelector *)NULL); + + int i; + i = 0; + while (1) + { + if (++i==16) + { + // check if there are any suitable primes in [min, max] + Integer first = min; + if (FirstPrime(first, max, equiv, mod, pSelector)) + { + // if there is only one suitable prime, we're done + *this = first; + if (!FirstPrime(first, max, equiv, mod, pSelector)) + return true; + } + else + return false; + } + + Randomize(rng, min, max); + if (FirstPrime(*this, STDMIN(*this+mod*PrimeSearchInterval(max), max), equiv, mod, pSelector)) + return true; + } + } + + default: + throw InvalidArgument("Integer: invalid RandomNumberType argument"); + } +} + +std::istream& operator>>(std::istream& in, Integer &a) +{ + char c; + unsigned int length = 0; + SecBlock<char> str(length + 16); + + std::ws(in); + + do + { + in.read(&c, 1); + str[length++] = c; + if (length >= str.size()) + str.Grow(length + 16); + } + while (in && (c=='-' || c=='x' || (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F') || c=='h' || c=='H' || c=='o' || c=='O' || c==',' || c=='.')); + + if (in.gcount()) + in.putback(c); + str[length-1] = '\0'; + a = Integer(str); + + return in; +} + +std::ostream& operator<<(std::ostream& out, const Integer &a) +{ + // Get relevant conversion specifications from ostream. + long f = out.flags() & std::ios::basefield; // Get base digits. + int base, block; + char suffix; + switch(f) + { + case std::ios::oct : + base = 8; + block = 8; + suffix = 'o'; + break; + case std::ios::hex : + base = 16; + block = 4; + suffix = 'h'; + break; + default : + base = 10; + block = 3; + suffix = '.'; + } + + SecBlock<char> s(a.BitCount() / (BitPrecision(base)-1) + 1); + Integer temp1=a, temp2; + unsigned i=0; + const char vec[]="0123456789ABCDEF"; + + if (a.IsNegative()) + { + out << '-'; + temp1.Negate(); + } + + if (!a) + out << '0'; + + while (!!temp1) + { + word digit; + Integer::Divide(digit, temp2, temp1, base); + s[i++]=vec[digit]; + temp1=temp2; + } + + while (i--) + { + out << s[i]; +// if (i && !(i%block)) +// out << ","; + } + return out << suffix; +} + +Integer& Integer::operator++() +{ + if (NotNegative()) + { + if (Increment(reg, reg.size())) + { + reg.CleanGrow(2*reg.size()); + reg[reg.size()/2]=1; + } + } + else + { + word borrow = Decrement(reg, reg.size()); + assert(!borrow); + if (WordCount()==0) + *this = Zero(); + } + return *this; +} + +Integer& Integer::operator--() +{ + if (IsNegative()) + { + if (Increment(reg, reg.size())) + { + reg.CleanGrow(2*reg.size()); + reg[reg.size()/2]=1; + } + } + else + { + if (Decrement(reg, reg.size())) + *this = -One(); + } + return *this; +} + +void PositiveAdd(Integer &sum, const Integer &a, const Integer& b) +{ + word carry; + if (a.reg.size() == b.reg.size()) + carry = Add(sum.reg, a.reg, b.reg, a.reg.size()); + else if (a.reg.size() > b.reg.size()) + { + carry = Add(sum.reg, a.reg, b.reg, b.reg.size()); + CopyWords(sum.reg+b.reg.size(), a.reg+b.reg.size(), a.reg.size()-b.reg.size()); + carry = Increment(sum.reg+b.reg.size(), a.reg.size()-b.reg.size(), carry); + } + else + { + carry = Add(sum.reg, a.reg, b.reg, a.reg.size()); + CopyWords(sum.reg+a.reg.size(), b.reg+a.reg.size(), b.reg.size()-a.reg.size()); + carry = Increment(sum.reg+a.reg.size(), b.reg.size()-a.reg.size(), carry); + } + + if (carry) + { + sum.reg.CleanGrow(2*sum.reg.size()); + sum.reg[sum.reg.size()/2] = 1; + } + sum.sign = Integer::POSITIVE; +} + +void PositiveSubtract(Integer &diff, const Integer &a, const Integer& b) +{ + unsigned aSize = a.WordCount(); + aSize += aSize%2; + unsigned bSize = b.WordCount(); + bSize += bSize%2; + + if (aSize == bSize) + { + if (Compare(a.reg, b.reg, aSize) >= 0) + { + Subtract(diff.reg, a.reg, b.reg, aSize); + diff.sign = Integer::POSITIVE; + } + else + { + Subtract(diff.reg, b.reg, a.reg, aSize); + diff.sign = Integer::NEGATIVE; + } + } + else if (aSize > bSize) + { + word borrow = Subtract(diff.reg, a.reg, b.reg, bSize); + CopyWords(diff.reg+bSize, a.reg+bSize, aSize-bSize); + borrow = Decrement(diff.reg+bSize, aSize-bSize, borrow); + assert(!borrow); + diff.sign = Integer::POSITIVE; + } + else + { + word borrow = Subtract(diff.reg, b.reg, a.reg, aSize); + CopyWords(diff.reg+aSize, b.reg+aSize, bSize-aSize); + borrow = Decrement(diff.reg+aSize, bSize-aSize, borrow); + assert(!borrow); + diff.sign = Integer::NEGATIVE; + } +} + +Integer Integer::Plus(const Integer& b) const +{ + Integer sum((word)0, STDMAX(reg.size(), b.reg.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveAdd(sum, *this, b); + else + PositiveSubtract(sum, *this, b); + } + else + { + if (b.NotNegative()) + PositiveSubtract(sum, b, *this); + else + { + PositiveAdd(sum, *this, b); + sum.sign = Integer::NEGATIVE; + } + } + return sum; +} + +Integer& Integer::operator+=(const Integer& t) +{ + reg.CleanGrow(t.reg.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveAdd(*this, *this, t); + else + PositiveSubtract(*this, *this, t); + } + else + { + if (t.NotNegative()) + PositiveSubtract(*this, t, *this); + else + { + PositiveAdd(*this, *this, t); + sign = Integer::NEGATIVE; + } + } + return *this; +} + +Integer Integer::Minus(const Integer& b) const +{ + Integer diff((word)0, STDMAX(reg.size(), b.reg.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveSubtract(diff, *this, b); + else + PositiveAdd(diff, *this, b); + } + else + { + if (b.NotNegative()) + { + PositiveAdd(diff, *this, b); + diff.sign = Integer::NEGATIVE; + } + else + PositiveSubtract(diff, b, *this); + } + return diff; +} + +Integer& Integer::operator-=(const Integer& t) +{ + reg.CleanGrow(t.reg.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveSubtract(*this, *this, t); + else + PositiveAdd(*this, *this, t); + } + else + { + if (t.NotNegative()) + { + PositiveAdd(*this, *this, t); + sign = Integer::NEGATIVE; + } + else + PositiveSubtract(*this, t, *this); + } + return *this; +} + +Integer& Integer::operator<<=(unsigned int n) +{ + const unsigned int wordCount = WordCount(); + const unsigned int shiftWords = n / WORD_BITS; + const unsigned int shiftBits = n % WORD_BITS; + + reg.CleanGrow(RoundupSize(wordCount+BitsToWords(n))); + ShiftWordsLeftByWords(reg, wordCount + shiftWords, shiftWords); + ShiftWordsLeftByBits(reg+shiftWords, wordCount+BitsToWords(shiftBits), shiftBits); + return *this; +} + +Integer& Integer::operator>>=(unsigned int n) +{ + const unsigned int wordCount = WordCount(); + const unsigned int shiftWords = n / WORD_BITS; + const unsigned int shiftBits = n % WORD_BITS; + + ShiftWordsRightByWords(reg, wordCount, shiftWords); + if (wordCount > shiftWords) + ShiftWordsRightByBits(reg, wordCount-shiftWords, shiftBits); + if (IsNegative() && WordCount()==0) // avoid -0 + *this = Zero(); + return *this; +} + +void PositiveMultiply(Integer &product, const Integer &a, const Integer &b) +{ + unsigned aSize = RoundupSize(a.WordCount()); + unsigned bSize = RoundupSize(b.WordCount()); + + product.reg.CleanNew(RoundupSize(aSize+bSize)); + product.sign = Integer::POSITIVE; + + SecAlignedWordBlock workspace(aSize + bSize); + AsymmetricMultiply(product.reg, workspace, a.reg, aSize, b.reg, bSize); +} + +void Multiply(Integer &product, const Integer &a, const Integer &b) +{ + PositiveMultiply(product, a, b); + + if (a.NotNegative() != b.NotNegative()) + product.Negate(); +} + +Integer Integer::Times(const Integer &b) const +{ + Integer product; + Multiply(product, *this, b); + return product; +} + +/* +void PositiveDivide(Integer &remainder, Integer "ient, + const Integer ÷nd, const Integer &divisor) +{ + remainder.reg.CleanNew(divisor.reg.size()); + remainder.sign = Integer::POSITIVE; + quotient.reg.New(0); + quotient.sign = Integer::POSITIVE; + unsigned i=dividend.BitCount(); + while (i--) + { + word overflow = ShiftWordsLeftByBits(remainder.reg, remainder.reg.size(), 1); + remainder.reg[0] |= dividend[i]; + if (overflow || remainder >= divisor) + { + Subtract(remainder.reg, remainder.reg, divisor.reg, remainder.reg.size()); + quotient.SetBit(i); + } + } +} +*/ + +void PositiveDivide(Integer &remainder, Integer "ient, + const Integer &a, const Integer &b) +{ + unsigned aSize = a.WordCount(); + unsigned bSize = b.WordCount(); + + if (!bSize) + throw Integer::DivideByZero(); + + if (a.PositiveCompare(b) == -1) + { + remainder = a; + remainder.sign = Integer::POSITIVE; + quotient = Integer::Zero(); + return; + } + + aSize += aSize%2; // round up to next even number + bSize += bSize%2; + + remainder.reg.CleanNew(RoundupSize(bSize)); + remainder.sign = Integer::POSITIVE; + quotient.reg.CleanNew(RoundupSize(aSize-bSize+2)); + quotient.sign = Integer::POSITIVE; + + SecAlignedWordBlock T(aSize+2*bSize+4); + Divide(remainder.reg, quotient.reg, T, a.reg, aSize, b.reg, bSize); +} + +void Integer::Divide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor) +{ + PositiveDivide(remainder, quotient, dividend, divisor); + + if (dividend.IsNegative()) + { + quotient.Negate(); + if (remainder.NotZero()) + { + --quotient; + remainder = divisor.AbsoluteValue() - remainder; + } + } + + if (divisor.IsNegative()) + quotient.Negate(); +} + +void Integer::DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n) +{ + q = a; + q >>= n; + + const unsigned int wordCount = BitsToWords(n); + if (wordCount <= a.WordCount()) + { + r.reg.resize(RoundupSize(wordCount)); + CopyWords(r.reg, a.reg, wordCount); + SetWords(r.reg+wordCount, 0, r.reg.size()-wordCount); + if (n % WORD_BITS != 0) + r.reg[wordCount-1] %= (1 << (n % WORD_BITS)); + } + else + { + r.reg.resize(RoundupSize(a.WordCount())); + CopyWords(r.reg, a.reg, r.reg.size()); + } + r.sign = POSITIVE; + + if (a.IsNegative() && r.NotZero()) + { + --q; + r = Power2(n) - r; + } +} + +Integer Integer::DividedBy(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +Integer Integer::Modulo(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return remainder; +} + +void Integer::Divide(word &remainder, Integer "ient, const Integer ÷nd, word divisor) +{ + if (!divisor) + throw Integer::DivideByZero(); + + assert(divisor); + + if ((divisor & (divisor-1)) == 0) // divisor is a power of 2 + { + quotient = dividend >> (BitPrecision(divisor)-1); + remainder = dividend.reg[0] & (divisor-1); + return; + } + + unsigned int i = dividend.WordCount(); + quotient.reg.CleanNew(RoundupSize(i)); + remainder = 0; + while (i--) + { + quotient.reg[i] = word(MAKE_DWORD(dividend.reg[i], remainder) / divisor); + remainder = word(MAKE_DWORD(dividend.reg[i], remainder) % divisor); + } + + if (dividend.NotNegative()) + quotient.sign = POSITIVE; + else + { + quotient.sign = NEGATIVE; + if (remainder) + { + --quotient; + remainder = divisor - remainder; + } + } +} + +Integer Integer::DividedBy(word b) const +{ + word remainder; + Integer quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +word Integer::Modulo(word divisor) const +{ + if (!divisor) + throw Integer::DivideByZero(); + + assert(divisor); + + word remainder; + + if ((divisor & (divisor-1)) == 0) // divisor is a power of 2 + remainder = reg[0] & (divisor-1); + else + { + unsigned int i = WordCount(); + + if (divisor <= 5) + { + dword sum=0; + while (i--) + sum += reg[i]; + remainder = word(sum%divisor); + } + else + { + remainder = 0; + while (i--) + remainder = word(MAKE_DWORD(reg[i], remainder) % divisor); + } + } + + if (IsNegative() && remainder) + remainder = divisor - remainder; + + return remainder; +} + +void Integer::Negate() +{ + if (!!(*this)) // don't flip sign if *this==0 + sign = Sign(1-sign); +} + +int Integer::PositiveCompare(const Integer& t) const +{ + unsigned size = WordCount(), tSize = t.WordCount(); + + if (size == tSize) + return CryptoPP::Compare(reg, t.reg, size); + else + return size > tSize ? 1 : -1; +} + +int Integer::Compare(const Integer& t) const +{ + if (NotNegative()) + { + if (t.NotNegative()) + return PositiveCompare(t); + else + return 1; + } + else + { + if (t.NotNegative()) + return -1; + else + return -PositiveCompare(t); + } +} + +Integer Integer::SquareRoot() const +{ + if (!IsPositive()) + return Zero(); + + // overestimate square root + Integer x, y = Power2((BitCount()+1)/2); + assert(y*y >= *this); + + do + { + x = y; + y = (x + *this/x) >> 1; + } while (y<x); + + return x; +} + +bool Integer::IsSquare() const +{ + Integer r = SquareRoot(); + return *this == r.Squared(); +} + +bool Integer::IsUnit() const +{ + return (WordCount() == 1) && (reg[0] == 1); +} + +Integer Integer::MultiplicativeInverse() const +{ + return IsUnit() ? *this : Zero(); +} + +Integer a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m) +{ + return x*y%m; +} + +Integer a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m) +{ + ModularArithmetic mr(m); + return mr.Exponentiate(x, e); +} + +Integer Integer::Gcd(const Integer &a, const Integer &b) +{ + return EuclideanDomainOf<Integer>().Gcd(a, b); +} + +Integer Integer::InverseMod(const Integer &m) const +{ + assert(m.NotNegative()); + + if (IsNegative() || *this>=m) + return (*this%m).InverseMod(m); + + if (m.IsEven()) + { + if (!m || IsEven()) + return Zero(); // no inverse + if (*this == One()) + return One(); + + Integer u = m.InverseMod(*this); + return !u ? Zero() : (m*(*this-u)+1)/(*this); + } + + SecBlock<word> T(m.reg.size() * 4); + Integer r((word)0, m.reg.size()); + unsigned k = AlmostInverse(r.reg, T, reg, reg.size(), m.reg, m.reg.size()); + DivideByPower2Mod(r.reg, r.reg, k, m.reg, m.reg.size()); + return r; +} + +word Integer::InverseMod(const word mod) const +{ + word g0 = mod, g1 = *this % mod; + word v0 = 0, v1 = 1; + word y; + + while (g1) + { + if (g1 == 1) + return v1; + y = g0 / g1; + g0 = g0 % g1; + v0 += y * v1; + + if (!g0) + break; + if (g0 == 1) + return mod-v0; + y = g1 / g0; + g1 = g1 % g0; + v1 += y * v0; + } + return 0; +} + +// ******************************************************** + +ModularArithmetic::ModularArithmetic(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + OID oid(seq); + if (oid != ASN1::prime_field()) + BERDecodeError(); + modulus.BERDecode(seq); + seq.MessageEnd(); + result.reg.resize(modulus.reg.size()); +} + +void ModularArithmetic::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::prime_field().DEREncode(seq); + modulus.DEREncode(seq); + seq.MessageEnd(); +} + +void ModularArithmetic::DEREncodeElement(BufferedTransformation &out, const Element &a) const +{ + a.DEREncodeAsOctetString(out, MaxElementByteLength()); +} + +void ModularArithmetic::BERDecodeElement(BufferedTransformation &in, Element &a) const +{ + a.BERDecodeAsOctetString(in, MaxElementByteLength()); +} + +const Integer& ModularArithmetic::Half(const Integer &a) const +{ + if (a.reg.size()==modulus.reg.size()) + { + CryptoPP::DivideByPower2Mod(result.reg.begin(), a.reg, 1, modulus.reg, a.reg.size()); + return result; + } + else + return result1 = (a.IsEven() ? (a >> 1) : ((a+modulus) >> 1)); +} + +const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const +{ + if (a.reg.size()==modulus.reg.size() && b.reg.size()==modulus.reg.size()) + { + if (CryptoPP::Add(result.reg.begin(), a.reg, b.reg, a.reg.size()) + || Compare(result.reg, modulus.reg, a.reg.size()) >= 0) + { + CryptoPP::Subtract(result.reg.begin(), result.reg, modulus.reg, a.reg.size()); + } + return result; + } + else + { + result1 = a+b; + if (result1 >= modulus) + result1 -= modulus; + return result1; + } +} + +Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const +{ + if (a.reg.size()==modulus.reg.size() && b.reg.size()==modulus.reg.size()) + { + if (CryptoPP::Add(a.reg, a.reg, b.reg, a.reg.size()) + || Compare(a.reg, modulus.reg, a.reg.size()) >= 0) + { + CryptoPP::Subtract(a.reg, a.reg, modulus.reg, a.reg.size()); + } + } + else + { + a+=b; + if (a>=modulus) + a-=modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Subtract(const Integer &a, const Integer &b) const +{ + if (a.reg.size()==modulus.reg.size() && b.reg.size()==modulus.reg.size()) + { + if (CryptoPP::Subtract(result.reg.begin(), a.reg, b.reg, a.reg.size())) + CryptoPP::Add(result.reg.begin(), result.reg, modulus.reg, a.reg.size()); + return result; + } + else + { + result1 = a-b; + if (result1.IsNegative()) + result1 += modulus; + return result1; + } +} + +Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const +{ + if (a.reg.size()==modulus.reg.size() && b.reg.size()==modulus.reg.size()) + { + if (CryptoPP::Subtract(a.reg, a.reg, b.reg, a.reg.size())) + CryptoPP::Add(a.reg, a.reg, modulus.reg, a.reg.size()); + } + else + { + a-=b; + if (a.IsNegative()) + a+=modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Inverse(const Integer &a) const +{ + if (!a) + return a; + + CopyWords(result.reg.begin(), modulus.reg, modulus.reg.size()); + if (CryptoPP::Subtract(result.reg.begin(), result.reg, a.reg, a.reg.size())) + Decrement(result.reg.begin()+a.reg.size(), 1, modulus.reg.size()-a.reg.size()); + + return result; +} + +Integer ModularArithmetic::CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const +{ + if (modulus.IsOdd()) + { + MontgomeryRepresentation dr(modulus); + return dr.ConvertOut(dr.CascadeExponentiate(dr.ConvertIn(x), e1, dr.ConvertIn(y), e2)); + } + else + return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2); +} + +void ModularArithmetic::SimultaneousExponentiate(Integer *results, const Integer &base, const Integer *exponents, unsigned int exponentsCount) const +{ + if (modulus.IsOdd()) + { + MontgomeryRepresentation dr(modulus); + dr.SimultaneousExponentiate(results, dr.ConvertIn(base), exponents, exponentsCount); + for (unsigned int i=0; i<exponentsCount; i++) + results[i] = dr.ConvertOut(results[i]); + } + else + AbstractRing<Integer>::SimultaneousExponentiate(results, base, exponents, exponentsCount); +} + +MontgomeryRepresentation::MontgomeryRepresentation(const Integer &m) // modulus must be odd + : ModularArithmetic(m), + u((word)0, modulus.reg.size()), + workspace(5*modulus.reg.size()) +{ + if (!modulus.IsOdd()) + throw InvalidArgument("MontgomeryRepresentation: Montgomery representation requires an odd modulus"); + + RecursiveInverseModPower2(u.reg, workspace, modulus.reg, modulus.reg.size()); +} + +const Integer& MontgomeryRepresentation::Multiply(const Integer &a, const Integer &b) const +{ + word *const T = workspace.begin(); + word *const R = result.reg.begin(); + const unsigned int N = modulus.reg.size(); + assert(a.reg.size()<=N && b.reg.size()<=N); + + AsymmetricMultiply(T, T+2*N, a.reg, a.reg.size(), b.reg, b.reg.size()); + SetWords(T+a.reg.size()+b.reg.size(), 0, 2*N-a.reg.size()-b.reg.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg, u.reg, N); + return result; +} + +const Integer& MontgomeryRepresentation::Square(const Integer &a) const +{ + word *const T = workspace.begin(); + word *const R = result.reg.begin(); + const unsigned int N = modulus.reg.size(); + assert(a.reg.size()<=N); + + CryptoPP::Square(T, T+2*N, a.reg, a.reg.size()); + SetWords(T+2*a.reg.size(), 0, 2*N-2*a.reg.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg, u.reg, N); + return result; +} + +Integer MontgomeryRepresentation::ConvertOut(const Integer &a) const +{ + word *const T = workspace.begin(); + word *const R = result.reg.begin(); + const unsigned int N = modulus.reg.size(); + assert(a.reg.size()<=N); + + CopyWords(T, a.reg, a.reg.size()); + SetWords(T+a.reg.size(), 0, 2*N-a.reg.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg, u.reg, N); + return result; +} + +const Integer& MontgomeryRepresentation::MultiplicativeInverse(const Integer &a) const +{ +// return (EuclideanMultiplicativeInverse(a, modulus)<<(2*WORD_BITS*modulus.reg.size()))%modulus; + word *const T = workspace.begin(); + word *const R = result.reg.begin(); + const unsigned int N = modulus.reg.size(); + assert(a.reg.size()<=N); + + CopyWords(T, a.reg, a.reg.size()); + SetWords(T+a.reg.size(), 0, 2*N-a.reg.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg, u.reg, N); + unsigned k = AlmostInverse(R, T, R, N, modulus.reg, N); + +// cout << "k=" << k << " N*32=" << 32*N << endl; + + if (k>N*WORD_BITS) + DivideByPower2Mod(R, R, k-N*WORD_BITS, modulus.reg, N); + else + MultiplyByPower2Mod(R, R, N*WORD_BITS-k, modulus.reg, N); + + return result; +} + +template class AbstractRing<Integer>; + +NAMESPACE_END diff --git a/integer.h b/integer.h new file mode 100644 index 0000000..b79c07c --- /dev/null +++ b/integer.h @@ -0,0 +1,435 @@ +#ifndef CRYPTOPP_INTEGER_H +#define CRYPTOPP_INTEGER_H + +/** \file */ + +#include "cryptlib.h" +#include "secblock.h" + +#include <iosfwd> +#include <algorithm> + +#ifdef _M_IX86 +# if (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 500)) || (defined(__ICL) && (__ICL >= 500)) +# define SSE2_INTRINSICS_AVAILABLE +# elif defined(_MSC_VER) + // _mm_free seems to be the only way to tell if the Processor Pack is installed or not +# include <malloc.h> +# if defined(_mm_free) +# define SSE2_INTRINSICS_AVAILABLE +# endif +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef SSE2_INTRINSICS_AVAILABLE + template <class T> + class AlignedAllocator : public AllocatorBase<T> + { + public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + pointer allocate(size_type n, const void *); + void deallocate(void *p, size_type n); + pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve) + { + return StandardReallocate(*this, p, oldSize, newSize, preserve); + } + }; + typedef SecBlock<word, AlignedAllocator<word> > SecAlignedWordBlock; +#else + typedef SecWordBlock SecAlignedWordBlock; +#endif + +//! multiple precision integer and basic arithmetics +/*! This class can represent positive and negative integers + with absolute value less than (256**sizeof(word)) ** (256**sizeof(int)). + \nosubgrouping +*/ +class Integer : public ASN1Object +{ +public: + //! \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + //! division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {} + }; + + //! + class RandomNumberNotFound : public Exception + { + public: + RandomNumberNotFound() : Exception(OTHER_ERROR, "Integer: no integer satisfies the given parameters") {} + }; + + //! + enum Signedness { + //! + UNSIGNED, + //! + SIGNED}; + + //! + enum RandomNumberType { + //! + ANY, + //! + PRIME}; + //@} + + //! \name CREATORS + //@{ + //! creates the zero integer + Integer(); + + //! copy constructor + Integer(const Integer& t); + + //! convert from signed long + Integer(signed long value); + + //! convert from string + /*! str can be in base 2, 8, 10, or 16. Base is determined by a + case insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10. + */ + explicit Integer(const char *str); + explicit Integer(const wchar_t *str); + + //! convert from big-endian byte array + Integer(const byte *encodedInteger, unsigned int byteCount, Signedness s=UNSIGNED); + + //! convert from big-endian form stored in a BufferedTransformation + Integer(BufferedTransformation &bt, unsigned int byteCount, Signedness s=UNSIGNED); + + //! convert from BER encoded byte array stored in a BufferedTransformation object + explicit Integer(BufferedTransformation &bt); + + //! create a random integer + /*! The random integer created is uniformly distributed over [0, 2**bitcount). */ + Integer(RandomNumberGenerator &rng, unsigned int bitcount); + + //! avoid calling constructors for these frequently used integers + static const Integer &Zero(); + //! avoid calling constructors for these frequently used integers + static const Integer &One(); + //! avoid calling constructors for these frequently used integers + static const Integer &Two(); + + //! create a random integer of special type + /*! Ideally, the random integer created should be uniformly distributed + over {x | min <= x <= max and x is of rnType and x % mod == equiv}. + However the actual distribution may not be uniform because sequential + search is used to find an appropriate number from a random starting + point. + May return (with very small probability) a pseudoprime when a prime + is requested and max > lastSmallPrime*lastSmallPrime (lastSmallPrime + is declared in nbtheory.h). + \throw RandomNumberNotFound if the set is empty. + */ + Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType=ANY, const Integer &equiv=Zero(), const Integer &mod=One()); + + //! return the integer 2**e + static Integer Power2(unsigned int e); + //@} + + //! \name ENCODE/DECODE + //@{ + //! minimum number of bytes to encode this integer + /*! MinEncodedSize of 0 is 1 */ + unsigned int MinEncodedSize(Signedness=UNSIGNED) const; + //! encode in big-endian format + /*! unsigned means encode absolute value, signed means encode two's complement if negative. + if outputLen < MinEncodedSize, the most significant bytes will be dropped + if outputLen > MinEncodedSize, the most significant bytes will be padded + */ + unsigned int Encode(byte *output, unsigned int outputLen, Signedness=UNSIGNED) const; + //! + unsigned int Encode(BufferedTransformation &bt, unsigned int outputLen, Signedness=UNSIGNED) const; + + //! encode using Distinguished Encoding Rules, put result into a BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + //! encode absolute value as big-endian octet string + void DEREncodeAsOctetString(BufferedTransformation &bt, unsigned int length) const; + + //! encode absolute value in OpenPGP format, return length of output + unsigned int OpenPGPEncode(byte *output, unsigned int bufferSize) const; + //! encode absolute value in OpenPGP format, put result into a BufferedTransformation object + unsigned int OpenPGPEncode(BufferedTransformation &bt) const; + + //! + void Decode(const byte *input, unsigned int inputLen, Signedness=UNSIGNED); + //! + //* Precondition: bt.MaxRetrievable() >= inputLen + void Decode(BufferedTransformation &bt, unsigned int inputLen, Signedness=UNSIGNED); + + //! + void BERDecode(const byte *input, unsigned int inputLen); + //! + void BERDecode(BufferedTransformation &bt); + + //! decode nonnegative value as big-endian octet string + void BERDecodeAsOctetString(BufferedTransformation &bt, unsigned int length); + + class OpenPGPDecodeErr : public Exception + { + public: + OpenPGPDecodeErr() : Exception(INVALID_DATA_FORMAT, "OpenPGP decode error") {} + }; + + //! + void OpenPGPDecode(const byte *input, unsigned int inputLen); + //! + void OpenPGPDecode(BufferedTransformation &bt); + //@} + + //! \name ACCESSORS + //@{ + //! return true if *this can be represented as a signed long + bool IsConvertableToLong() const; + //! return equivalent signed long if possible, otherwise undefined + signed long ConvertToLong() const; + + //! number of significant bits = floor(log2(abs(*this))) + 1 + unsigned int BitCount() const; + //! number of significant bytes = ceiling(BitCount()/8) + unsigned int ByteCount() const; + //! number of significant words = ceiling(ByteCount()/sizeof(word)) + unsigned int WordCount() const; + + //! return the i-th bit, i=0 being the least significant bit + bool GetBit(unsigned int i) const; + //! return the i-th byte + byte GetByte(unsigned int i) const; + //! return n lowest bits of *this >> i + unsigned long GetBits(unsigned int i, unsigned int n) const; + + //! + bool IsZero() const {return !*this;} + //! + bool NotZero() const {return !IsZero();} + //! + bool IsNegative() const {return sign == NEGATIVE;} + //! + bool NotNegative() const {return !IsNegative();} + //! + bool IsPositive() const {return NotNegative() && NotZero();} + //! + bool NotPositive() const {return !IsPositive();} + //! + bool IsEven() const {return GetBit(0) == 0;} + //! + bool IsOdd() const {return GetBit(0) == 1;} + //@} + + //! \name MANIPULATORS + //@{ + //! + Integer& operator=(const Integer& t); + + //! + Integer& operator+=(const Integer& t); + //! + Integer& operator-=(const Integer& t); + //! + Integer& operator*=(const Integer& t) {return *this = Times(t);} + //! + Integer& operator/=(const Integer& t) {return *this = DividedBy(t);} + //! + Integer& operator%=(const Integer& t) {return *this = Modulo(t);} + //! + Integer& operator/=(word t) {return *this = DividedBy(t);} + //! + Integer& operator%=(word t) {return *this = Modulo(t);} + + //! + Integer& operator<<=(unsigned int); + //! + Integer& operator>>=(unsigned int); + + //! + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); + //! + void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); + //! set this Integer to a random element of {x | min <= x <= max and x is of rnType and x % mod == equiv} + /*! returns false if the set is empty */ + bool Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv=Zero(), const Integer &mod=One()); + + bool GenerateRandomNoThrow(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs); + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) + { + if (!GenerateRandomNoThrow(rng, params)) + throw RandomNumberNotFound(); + } + + //! set the n-th bit to value + void SetBit(unsigned int n, bool value=1); + //! set the n-th byte to value + void SetByte(unsigned int n, byte value); + + //! + void Negate(); + //! + void SetPositive() {sign = POSITIVE;} + //! + void SetNegative() {if (!!(*this)) sign = NEGATIVE;} + + //! + void swap(Integer &a); + //@} + + //! \name UNARY OPERATORS + //@{ + //! + bool operator!() const; + //! + Integer operator+() const {return *this;} + //! + Integer operator-() const; + //! + Integer& operator++(); + //! + Integer& operator--(); + //! + Integer operator++(int) {Integer temp = *this; ++*this; return temp;} + //! + Integer operator--(int) {Integer temp = *this; --*this; return temp;} + //@} + + //! \name BINARY OPERATORS + //@{ + //! signed comparison + /*! \retval -1 if *this < a + \retval 0 if *this = a + \retval 1 if *this > a + */ + int Compare(const Integer& a) const; + + //! + Integer Plus(const Integer &b) const; + //! + Integer Minus(const Integer &b) const; + //! + Integer Times(const Integer &b) const; + //! + Integer DividedBy(const Integer &b) const; + //! + Integer Modulo(const Integer &b) const; + //! + Integer DividedBy(word b) const; + //! + word Modulo(word b) const; + + //! + Integer operator>>(unsigned int n) const {return Integer(*this)>>=n;} + //! + Integer operator<<(unsigned int n) const {return Integer(*this)<<=n;} + //@} + + //! \name OTHER ARITHMETIC FUNCTIONS + //@{ + //! + Integer AbsoluteValue() const; + //! + Integer Doubled() const {return Plus(*this);} + //! + Integer Squared() const {return Times(*this);} + //! extract square root, if negative return 0, else return floor of square root + Integer SquareRoot() const; + //! return whether this integer is a perfect square + bool IsSquare() const; + + //! is 1 or -1 + bool IsUnit() const; + //! return inverse if 1 or -1, otherwise return 0 + Integer MultiplicativeInverse() const; + + //! modular multiplication + friend Integer a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m); + //! modular exponentiation + friend Integer a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m); + + //! calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + static void Divide(Integer &r, Integer &q, const Integer &a, const Integer &d); + //! use a faster division algorithm when divisor is short + static void Divide(word &r, Integer &q, const Integer &a, word d); + + //! returns same result as Divide(r, q, a, Power2(n)), but faster + static void DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n); + + //! greatest common divisor + static Integer Gcd(const Integer &a, const Integer &n); + //! calculate multiplicative inverse of *this mod n + Integer InverseMod(const Integer &n) const; + //! + word InverseMod(word n) const; + //@} + + //! \name INPUT/OUTPUT + //@{ + //! + friend std::istream& operator>>(std::istream& in, Integer &a); + //! + friend std::ostream& operator<<(std::ostream& out, const Integer &a); + //@} + +private: + friend class ModularArithmetic; + friend class MontgomeryRepresentation; + friend class HalfMontgomeryRepresentation; + + Integer(word value, unsigned int length); + + int PositiveCompare(const Integer &t) const; + friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b); + friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b); + friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b); + friend void PositiveDivide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor); + + enum Sign {POSITIVE=0, NEGATIVE=1}; + + SecAlignedWordBlock reg; + Sign sign; +}; + +//! +inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;} +//! +inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;} +//! +inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;} +//! +inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;} +//! +inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;} +//! +inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;} +//! +inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);} +//! +inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);} +//! +inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);} +//! +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);} +//! +inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);} +//! +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);} +//! +inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/iterhash.cpp b/iterhash.cpp new file mode 100644 index 0000000..08f7626 --- /dev/null +++ b/iterhash.cpp @@ -0,0 +1,123 @@ +// iterhash.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "iterhash.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T, class BASE> +IteratedHashBase<T, BASE>::IteratedHashBase(unsigned int blockSize, unsigned int digestSize) + : m_data(blockSize/sizeof(T)), m_digest(digestSize/sizeof(T)) + , m_countHi(0), m_countLo(0) +{ +} + +template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, unsigned int len) +{ + HashWordType tmp = m_countLo; + if ((m_countLo = tmp + len) < tmp) + m_countHi++; // Carry from low to high + m_countHi += SafeRightShift<8*sizeof(HashWordType)>(len); + + unsigned int blockSize = BlockSize(); + unsigned int num = (unsigned int)(tmp & (blockSize-1)); + + if (num != 0) + { + if ((num+len) >= blockSize) + { + memcpy((byte *)m_data.begin()+num, input, blockSize-num); + HashBlock(m_data); + input += (blockSize-num); + len-=(blockSize - num); + num=0; + // drop through and do the rest + } + else + { + memcpy((byte *)m_data.begin()+num, input, len); + return; + } + } + + // we now can process the input data in blocks of blockSize + // chars and save the leftovers to this->data. + if (len >= blockSize) + { + if (input == (byte *)m_data.begin()) + { + assert(len == blockSize); + HashBlock(m_data); + return; + } + else if (IsAligned<T>(input)) + { + unsigned int leftOver = HashMultipleBlocks((T *)input, len); + input += (len - leftOver); + len = leftOver; + } + else + do + { // copy input first if it's not aligned correctly + memcpy(m_data, input, blockSize); + HashBlock(m_data); + input+=blockSize; + len-=blockSize; + } while (len >= blockSize); + } + + memcpy(m_data, input, len); +} + +template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(unsigned int &size) +{ + unsigned int blockSize = BlockSize(); + unsigned int num = ModPowerOf2(m_countLo, blockSize); + size = blockSize - num; + return (byte *)m_data.begin() + num; +} + +template <class T, class BASE> unsigned int IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, unsigned int length) +{ + unsigned int blockSize = BlockSize(); + do + { + HashBlock(input); + input += blockSize/sizeof(T); + length -= blockSize; + } + while (length >= blockSize); + return length; +} + +template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst) +{ + unsigned int blockSize = BlockSize(); + unsigned int num = ModPowerOf2(m_countLo, blockSize); + ((byte *)m_data.begin())[num++]=padFirst; + if (num <= lastBlockSize) + memset((byte *)m_data.begin()+num, 0, lastBlockSize-num); + else + { + memset((byte *)m_data.begin()+num, 0, blockSize-num); + HashBlock(m_data); + memset(m_data, 0, lastBlockSize); + } +} + +template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart() +{ + m_countLo = m_countHi = 0; + Init(); +} + +#ifdef WORD64_AVAILABLE +template class IteratedHashBase<word64, HashTransformation>; +template class IteratedHashBase<word64, MessageAuthenticationCode>; +#endif + +template class IteratedHashBase<word32, HashTransformation>; +template class IteratedHashBase<word32, MessageAuthenticationCode>; + +NAMESPACE_END diff --git a/iterhash.h b/iterhash.h new file mode 100644 index 0000000..1ae9b15 --- /dev/null +++ b/iterhash.h @@ -0,0 +1,120 @@ +#ifndef CRYPTOPP_ITERHASH_H +#define CRYPTOPP_ITERHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T, class BASE> +class IteratedHashBase : public BASE +{ +public: + typedef T HashWordType; + + IteratedHashBase(unsigned int blockSize, unsigned int digestSize); + unsigned int DigestSize() const {return m_digest.size() * sizeof(T);}; + unsigned int OptimalBlockSize() const {return BlockSize();} + void Update(const byte *input, unsigned int length); + byte * CreateUpdateSpace(unsigned int &size); + void Restart(); + +protected: + T GetBitCountHi() const {return (m_countLo >> (8*sizeof(T)-3)) + (m_countHi << 3);} + T GetBitCountLo() const {return m_countLo << 3;} + + virtual unsigned int HashMultipleBlocks(const T *input, unsigned int length); + void PadLastBlock(unsigned int lastBlockSize, byte padFirst=0x80); + virtual void Init() =0; + virtual void HashBlock(const T *input) =0; + virtual unsigned int BlockSize() const =0; + + SecBlock<T> m_data; // Data buffer + SecBlock<T> m_digest; // Message digest + +private: + T m_countLo, m_countHi; +}; + +//! . +template <class T, class B, class BASE> +class IteratedHashBase2 : public IteratedHashBase<T, BASE> +{ +public: + IteratedHashBase2(unsigned int blockSize, unsigned int digestSize) + : IteratedHashBase<T, BASE>(blockSize, digestSize) {} + + typedef B ByteOrderClass; + typedef typename IteratedHashBase<T, BASE>::HashWordType HashWordType; + + inline static void CorrectEndianess(HashWordType *out, const HashWordType *in, unsigned int byteCount) + { + ConditionalByteReverse(B::ToEnum(), out, in, byteCount); + } + + void TruncatedFinal(byte *hash, unsigned int size); + +protected: + void HashBlock(const HashWordType *input); + + virtual void vTransform(const HashWordType *data) =0; +}; + +//! . +template <class T, class B, unsigned int S, class BASE = HashTransformation> +class IteratedHash : public IteratedHashBase2<T, B, BASE> +{ +public: + enum {BLOCKSIZE = S}; + +private: + CRYPTOPP_COMPILE_ASSERT((BLOCKSIZE & (BLOCKSIZE - 1)) == 0); // blockSize is a power of 2 + +protected: + IteratedHash(unsigned int digestSize) : IteratedHashBase2<T, B, BASE>(BLOCKSIZE, digestSize) {} + unsigned int BlockSize() const {return BLOCKSIZE;} +}; + +template <class T, class B, unsigned int S, class M> +class IteratedHashWithStaticTransform : public IteratedHash<T, B, S> +{ +protected: + IteratedHashWithStaticTransform(unsigned int digestSize) : IteratedHash<T, B, S>(digestSize) {} + void vTransform(const T *data) {M::Transform(m_digest, data);} + std::string AlgorithmName() const {return M::StaticAlgorithmName();} +}; + +// ************************************************************* + +template <class T, class B, class BASE> void IteratedHashBase2<T, B, BASE>::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(BlockSize() - 2*sizeof(HashWordType)); + CorrectEndianess(m_data, m_data, BlockSize() - 2*sizeof(HashWordType)); + + m_data[m_data.size()-2] = B::ToEnum() ? GetBitCountHi() : GetBitCountLo(); + m_data[m_data.size()-1] = B::ToEnum() ? GetBitCountLo() : GetBitCountHi(); + + vTransform(m_data); + CorrectEndianess(m_digest, m_digest, DigestSize()); + memcpy(hash, m_digest, size); + + Restart(); // reinit for next use +} + +template <class T, class B, class BASE> void IteratedHashBase2<T, B, BASE>::HashBlock(const HashWordType *input) +{ + if (NativeByteOrderIs(B::ToEnum())) + vTransform(input); + else + { + ByteReverse(m_data.begin(), input, BlockSize()); + vTransform(m_data); + } +} + +NAMESPACE_END + +#endif diff --git a/lubyrack.h b/lubyrack.h new file mode 100644 index 0000000..6228b29 --- /dev/null +++ b/lubyrack.h @@ -0,0 +1,138 @@ +// lubyrack.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_LUBYRACK_H +#define CRYPTOPP_LUBYRACK_H + +/** \file */ + +#include "simple.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> struct DigestSizeDoubleWorkaround {enum {RESULT = 2*T::DIGESTSIZE};}; // VC60 workaround + +//! . +template <class T> +struct LR_Info : public VariableKeyLength<16, 0, 2*(UINT_MAX/2), 2>, public FixedBlockSize<DigestSizeDoubleWorkaround<T>::RESULT> +{ + static std::string StaticAlgorithmName() {return std::string("LR/")+T::StaticAlgorithmName();} +}; + +//! Luby-Rackoff +template <class T> +class LR : public LR_Info<T>, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<LR_Info<T> > + { + public: + // VC60 workaround: have to define these functions within class definition + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) + { + AssertValidKeyLength(length); + + L = length/2; + buffer.New(2*S); + digest.New(S); + key.Assign(userKey, 2*L); + } + + protected: + enum {S=T::DIGESTSIZE}; + unsigned int L; // key length / 2 + SecByteBlock key; + + mutable T hm; + mutable SecByteBlock buffer, digest; + }; + + class Enc : public Base + { + public: + +#define KL key +#define KR key+L +#define BL buffer +#define BR buffer+S +#define IL inBlock +#define IR inBlock+S +#define OL outBlock +#define OR outBlock+S + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + hm.Update(KL, L); + hm.Update(IL, S); + hm.Final(BR); + xorbuf(BR, IR, S); + + hm.Update(KR, L); + hm.Update(BR, S); + hm.Final(BL); + xorbuf(BL, IL, S); + + hm.Update(KL, L); + hm.Update(BL, S); + hm.Final(digest); + xorbuf(BR, digest, S); + + hm.Update(KR, L); + hm.Update(OR, S); + hm.Final(digest); + xorbuf(BL, digest, S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, buffer, 2*S); + else + memcpy(outBlock, buffer, 2*S); + } + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + hm.Update(KR, L); + hm.Update(IR, S); + hm.Final(BL); + xorbuf(BL, IL, S); + + hm.Update(KL, L); + hm.Update(BL, S); + hm.Final(BR); + xorbuf(BR, IR, S); + + hm.Update(KR, L); + hm.Update(BR, S); + hm.Final(digest); + xorbuf(BL, digest, S); + + hm.Update(KL, L); + hm.Update(OL, S); + hm.Final(digest); + xorbuf(BR, digest, S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, buffer, 2*S); + else + memcpy(outBlock, buffer, 2*S); + } +#undef KL +#undef KR +#undef BL +#undef BR +#undef IL +#undef IR +#undef OL +#undef OR + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,212 @@ +// luc.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "luc.h" +#include "asn.h" +#include "nbtheory.h" +#include "sha.h" +#include "algparam.h" + +#include "oaep.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void LUC_TestInstantiations() +{ + LUC_HMP<SHA>::Signer t1; + LUCFunction t2; + InvertibleLUCFunction t3; +} + +bool DL_Algorithm_LUC_HMP::Sign(const DL_GroupParameters<Integer> ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const +{ + const Integer &q = params.GetSubgroupOrder(); + r = params.ExponentiateBase(k); + s = (k + x*(r+e)) % q; + return true; +} + +bool DL_Algorithm_LUC_HMP::Verify(const DL_GroupParameters<Integer> ¶ms, const DL_PublicKey<Integer> &publicKey, const Integer &e, const Integer &r, const Integer &s) const +{ + Integer p = params.GetGroupOrder()-1; + const Integer &q = params.GetSubgroupOrder(); + + Integer Vsg = params.ExponentiateBase(s); + Integer Vry = publicKey.ExponentiatePublicElement((r+e)%q); + return (Vsg*Vsg + Vry*Vry + r*r) % p == (Vsg * Vry * r + 4) % p; +} + +Integer DL_BasePrecomputation_LUC::Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const +{ + return Lucas(exponent, m_g, static_cast<const DL_GroupPrecomputation_LUC &>(group).GetModulus()); +} + +void DL_GroupParameters_LUC::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + for (unsigned int i=0; i<exponentsCount; i++) + results[i] = Lucas(exponents[i], base, GetModulus()); +} + +void LUCFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_e.BERDecode(seq); + seq.MessageEnd(); +} + +void LUCFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + seq.MessageEnd(); +} + +Integer LUCFunction::ApplyFunction(const Integer &x) const +{ + DoQuickSanityCheck(); + return Lucas(m_e, x, m_n); +} + +bool LUCFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + pass = pass && m_e > Integer::One() && m_e.IsOdd() && m_e < m_n; + return pass; +} + +bool LUCFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void LUCFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** +// private key operations: + +class LUCPrimeSelector : public PrimeSelector +{ +public: + LUCPrimeSelector(const Integer &e) : m_e(e) {} + bool IsAcceptable(const Integer &candidate) const + { + return RelativelyPrime(m_e, candidate+1) && RelativelyPrime(m_e, candidate-1); + } + Integer m_e; +}; + +void InvertibleLUCFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleLUCFunction: specified modulus size is too small"); + + m_e = alg.GetValueWithDefault("PublicExponent", Integer(17)); + + if (m_e < 5 || m_e.IsEven()) + throw InvalidArgument("InvertibleLUCFunction: invalid public exponent"); + + LUCPrimeSelector selector(m_e); + const NameValuePairs &primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + ("PointerToPrimeSelector", selector.GetSelectorPointer()); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); +} + +void InvertibleLUCFunction::Initialize(RandomNumberGenerator &rng, unsigned int keybits, const Integer &e) +{ + GenerateRandom(rng, MakeParameters("ModulusSize", (int)keybits)("PublicExponent", e)); +} + +void InvertibleLUCFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + + Integer version(seq); + if (!!version) // make sure version is 0 + BERDecodeError(); + + m_n.BERDecode(seq); + m_e.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); +} + +void InvertibleLUCFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + + const byte version[] = {INTEGER, 1, 0}; + seq.Put(version, sizeof(version)); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +Integer InvertibleLUCFunction::CalculateInverse(const Integer &x) const +{ + DoQuickSanityCheck(); + return InverseLucas(m_e, x, m_q, m_p, m_u); +} + +bool InvertibleLUCFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = LUCFunction::Validate(rng, level); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + pass = pass && m_u.IsPositive() && m_u < m_p; + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + pass = pass && RelativelyPrime(m_e, m_p+1); + pass = pass && RelativelyPrime(m_e, m_p-1); + pass = pass && RelativelyPrime(m_e, m_q+1); + pass = pass && RelativelyPrime(m_e, m_q-1); + pass = pass && m_u * m_q % m_p == 1; + } + if (level >= 2) + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + return pass; +} + +bool InvertibleLUCFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<LUCFunction>(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleLUCFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper<LUCFunction>(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +NAMESPACE_END @@ -0,0 +1,234 @@ +#ifndef CRYPTOPP_LUC_H +#define CRYPTOPP_LUC_H + +/** \file +*/ + +#include "pkcspad.h" +#include "oaep.h" +#include "integer.h" +#include "dh.h" + +#include <limits.h> + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class LUCFunction : public TrapdoorFunction, public PublicKey +{ + typedef LUCFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +//! . +class InvertibleLUCFunction : public LUCFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleLUCFunction ThisClass; + +public: + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &eStart=17); + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_e = e; m_p = p; m_q = q; m_u = u;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize, PublicExponent (default 17)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +struct LUC +{ + static std::string StaticAlgorithmName() {return "LUC";} + typedef LUCFunction PublicKey; + typedef InvertibleLUCFunction PrivateKey; +}; + +//! LUC cryptosystem +template <class STANDARD> +struct LUCES : public TF_ES<STANDARD, LUC> +{ +}; + +//! LUC signature scheme with appendix +template <class H, class STANDARD = PKCS1v15> +struct LUCSSA : public TF_SSA<STANDARD, H, LUC> +{ +}; + +// analagous to the RSA schemes defined in PKCS #1 v2.0 +typedef LUCES<OAEP<SHA> >::Decryptor LUCES_OAEP_SHA_Decryptor; +typedef LUCES<OAEP<SHA> >::Encryptor LUCES_OAEP_SHA_Encryptor; + +typedef LUCSSA<SHA>::Signer LUCSSA_PKCS1v15_SHA_Signer; +typedef LUCSSA<SHA>::Verifier LUCSSA_PKCS1v15_SHA_Verifier; + +// ******************************************************** + +// no actual precomputation +class DL_GroupPrecomputation_LUC : public DL_GroupPrecomputation<Integer> +{ +public: + const AbstractGroup<Element> & GetGroup() const {assert(false); throw 0;} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_p = v;} + const Integer & GetModulus() const {return m_p;} + +private: + Integer m_p; +}; + +//! . +class DL_BasePrecomputation_LUC : public DL_FixedBasePrecomputation<Integer> +{ +public: + // DL_FixedBasePrecomputation + bool IsInitialized() const {return m_g.NotZero();} + void SetBase(const DL_GroupPrecomputation<Element> &group, const Integer &base) {m_g = base;} + const Integer & GetBase(const DL_GroupPrecomputation<Element> &group) const {return m_g;} + void Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage) {} + void Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) {} + void Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) const {} + Integer Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const; + Integer CascadeExponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent, const DL_FixedBasePrecomputation<Integer> &pc2, const Integer &exponent2) const + {throw NotImplemented("DL_BasePrecomputation_LUC: CascadeExponentiate not implemented");} // shouldn't be called + +private: + Integer m_g; +}; + +//! . +class DL_GroupParameters_LUC : public DL_GroupParameters_IntegerBasedImpl<DL_GroupPrecomputation_LUC, DL_BasePrecomputation_LUC> +{ +public: + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::Two();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + Element MultiplyElements(const Element &a, const Element &b) const + {throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented");} + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const + {throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented");} + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper<DL_GroupParameters_IntegerBased>(this, name, valueType, pValue).Assignable(); + } + +private: + int GetFieldType() const {return 2;} +}; + +//! . +class DL_GroupParameters_LUC_DefaultSafePrime : public DL_GroupParameters_LUC +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +//! . +class DL_Algorithm_LUC_HMP : public DL_ElgamalLikeSignatureAlgorithm<Integer> +{ +public: + static const char * StaticAlgorithmName() {return "LUC-HMP";} + + Integer EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen) const + {return DSA_EncodeDigest(modulusBits, digest, digestLen);} + + bool Sign(const DL_GroupParameters<Integer> ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const; + bool Verify(const DL_GroupParameters<Integer> ¶ms, const DL_PublicKey<Integer> &publicKey, const Integer &e, const Integer &r, const Integer &s) const; + + unsigned int RLen(const DL_GroupParameters<Integer> ¶ms) const + {return params.GetGroupOrder().ByteCount();} +}; + +//! . +struct DL_SignatureKeys_LUC +{ + typedef DL_GroupParameters_LUC GroupParameters; + typedef DL_PublicKey_GFP<GroupParameters> PublicKey; + typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey; +}; + +//! LUC-HMP, based on "Digital signature schemes based on Lucas functions" by Patrick Horster, Markus Michels, Holger Petersen +template <class H> +struct LUC_HMP : public DL_SSA<DL_SignatureKeys_LUC, DL_Algorithm_LUC_HMP, H> +{ +}; + +//! . +struct DL_CryptoKeys_LUC +{ + typedef DL_GroupParameters_LUC_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP<GroupParameters> PublicKey; + typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey; +}; + +//! LUC-IES +template <class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = true> +struct LUC_IES + : public DL_ES< + DL_CryptoKeys_LUC, + DL_KeyAgreementAlgorithm_DH<Integer, COFACTOR_OPTION>, + DL_KeyDerivationAlgorithm_P1363<Integer, DHAES_MODE, P1363_KDF2<SHA1> >, + DL_EncryptionAlgorithm_Xor<HMAC<SHA1>, DHAES_MODE>, + LUC_IES<> > +{ + static std::string StaticAlgorithmName() {return "LUC-IES";} // non-standard name +}; + +// ******************************************************** + +//! LUC-DH +typedef DH_Domain<DL_GroupParameters_LUC_DefaultSafePrime> LUC_DH; + +NAMESPACE_END + +#endif diff --git a/luc1024.dat b/luc1024.dat new file mode 100644 index 0000000..f81dea0 --- /dev/null +++ b/luc1024.dat @@ -0,0 +1 @@ +3082015202010002818100B7FE59813AF3A5DA48144EF03E5D229E3CFB55B0E3CEB63F9F973AC8655651409C3B36BBBE83698516F42A2E0FDC87DD83541697249D67FB5A91FA73470089C4997667811283CF22C74856F1E71129DB70FB23620A60E532B7931B7F93C0B9AA6B9D60E87529002BF2204B743773F501F6C370D067C7B22F6AD9DC07E8097347020111024100CFEA6177386C04D1668C984C39A7F889B36BB2B3BED2C7B83241D267F8D2038529AEB56D82CDE43264168873375C8D1F0897666CCC3F617C2F6B52E5143303C7024100E28BAB645993166EE1A984967AE8839EA41685F1E6392DBEB83EE6CA85A54396505DBD4E5C9024BAFCF27AD24D571DC6A3795CE7F0432669BCE742AF8FAF1481024078C6F402C266595B4F85098370528C2C0309BE93F6C45FC049F6AD987471A979FE215CC41455AA85F5A5B664F59E2F8E33C97C211698D14AD05FC65044F99510
\ No newline at end of file diff --git a/luc2048.dat b/luc2048.dat new file mode 100644 index 0000000..a4b3cef --- /dev/null +++ b/luc2048.dat @@ -0,0 +1 @@ +308202960201000282010100EF8E1C8C8FB330A26C2449F1A50F7BD457D131C66D3194ECA20CE06138CC95CBE32E1DF910E13FF2D74823363286E3461E4BA3037EA32D4728F262C2364692E5948B8577F651292D72EF42445C2AAF11A526D2235DCE172A6E762EB86178BB5B4A06B8736567DB1525C8BDEB7242C81CC9090F5EF7CFC193FABEA3E5B5407E7DFDDF2D557487C65302148969F28DEC68AC3166FD52D44F1DE2EA74451A4BA0508F09E2F4AB85D89E7D68EEE4E8F9BD5A4858BAE8BF36E3A31FF06DDECDD40AE70932ECD09B65617B3208FF203EFBB0D822CDC1887EF343EBECBB762FA9C5D9F9339C80C96D6F3D8E4F7298FF6C94581C3CBC21C8CA94015F2E48400C0556B70502011102818100FDAD5D856662FC0284BEEF8470DC328B3B853F5819F037EBC786EB0225FD5C45B5BF99073F6E6CE31E4D1BC31105A4BAABA3BEC3C28F40E5912E7D3D6E6BE6178164E52F615C65FED1AE61D9D8F858282AF3C59C25A650A9CA72DD2105D95219CFEFEDDEB067647FDBABB659FBF2FF82F33C1A3A8BA73FB5F3D0C5509DFD38FF02818100F1BFA4A7A9506E020F9A57019F4326AE3D974DE9CCEF9BCA284B313DE287378411BDF1C9A1859D9165604EFF2EB1C9A685C0B317A08CF50E5F45AF570EE2C79B35BEA60B38109B4A450E87811CB10D6873F50726248055FE645C5C74FD0482F22CB541D77ED93F8B44CA72C9F550331C516BD061816325F9EF543C4995832BFB0281805184D4DC8796329003CF0EDC79048A12C4C78A1F44D8DE37A5939776A4E19CAA1ADBC4B78BE72EF23F1A5EFFF7377439138ED19D166285D1325CE6C2A7CFA182BDD7B82B2AB63A041C80B17A4D78161C240EDB2D6A494BEB27D28168E02DAE83C50C01EE8384E31111B756DA9B5423A6817F9078E8A750D0DE2CE62CF223601D
\ No newline at end of file diff --git a/lucc1024.dat b/lucc1024.dat new file mode 100644 index 0000000..4366892 --- /dev/null +++ b/lucc1024.dat @@ -0,0 +1 @@ +3082013F0201003082011706072A8648CE3804013082010A02818100E16B572E39DB4D90689753D09CEA97B9CAE9C0AF04203AE5BC7FC985B85D5BB50B1EDEA30CAAD003B455640FEEA79E342F3E8CFF6761051B38D6931A2B0FD0DF8E2210E7DA74CAC5DC1A79D80CD8C0F9FC09D81BAEC94E2F3663F25B0140DF6B3D5AD04CBA27BCF24A92963319FB992E39544370FD28642FE07EB17EDA4D47B902818070B5AB971CEDA6C8344BA9E84E754BDCE574E05782101D72DE3FE4C2DC2EADDA858F6F5186556801DA2AB207F753CF1A179F467FB3B0828D9C6B498D1587E86FC7110873ED3A6562EE0D3CEC066C607CFE04EC0DD764A7179B31F92D80A06FB59EAD68265D13DE7925494B198CFDCC971CAA21B87E943217F03F58BF6D26A3DD020107041F021D03BDAFBB087B5A628730212217B01F15B303A0133D6AF4FC3CAF7286A8
\ No newline at end of file diff --git a/lucc512.dat b/lucc512.dat new file mode 100644 index 0000000..9c2cf1a --- /dev/null +++ b/lucc512.dat @@ -0,0 +1 @@ +3081B302010030819406072A8648CE380401308188024100B89A4AD4826B8FDDBFE3A6C0F5C8F805B7093AFF9BB2BD697C7D113C236BAC99ABF69000E169575CA2A2DDCDD1C7D9D06C63DCCC880121D933DCF598DD85C52102405C4D256A4135C7EEDFF1D3607AE47C02DB849D7FCDD95EB4BE3E889E11B5D64CD5FB480070B4ABAE51516EE6E8E3ECE83631EE66440090EC99EE7ACC6EC2E291020107041702150268EA4C567B18D0E35B1DA9D517CE5D359CD06779
\ No newline at end of file diff --git a/lucd1024.dat b/lucd1024.dat new file mode 100644 index 0000000..7c2c79f --- /dev/null +++ b/lucd1024.dat @@ -0,0 +1,4 @@ +30818702818100EE9C91E2C1D8B0AB999B3F32B3115A36AA95A36B23CC8507D2340FA21EAAF6F6EB +1B900839CD9F8AFBFC155467F91FD8917DD46EAC55A266B246DFFFEDDDA79D674F77884D34709DB3 +452C2C1E2578CCC0CCA91C504039C52762F23F2A391A58B2CAD2DB05666DDF5B9E3C1AC33DB487B7 +70C82B7E7DCDEE4381562FCEE427FD02010A diff --git a/lucd512.dat b/lucd512.dat new file mode 100644 index 0000000..9c97005 --- /dev/null +++ b/lucd512.dat @@ -0,0 +1,2 @@ +3046024100C339D027E5812ED5D9DE044F3697D0273625E5EA9EC4EF3FB89ADBFA9CD1FBF4D8C0EC +1118C44609F499EF644EEAECE2F38B3F67FAC81A075F31A60B5757A87D020109 diff --git a/lucs1024.dat b/lucs1024.dat new file mode 100644 index 0000000..1393199 --- /dev/null +++ b/lucs1024.dat @@ -0,0 +1 @@ +3082015B0201003082013306072A8648CE3804013082012602818100D57B7B758DC8041CE6CFC57DFE0AAA33FC8FEC48BEEA37562AD13359236FFFF6EED3CEB3A7BBC4269A384ED9A296160F12BC666066548E28201CE293B1791F951C8D2C5965696D82B336EFADCF1E0D619EDA43DBB86415BF3EE6F721C0AB17E770EA7B2360A054D3E4E878647245FCF87B2335098303004CDDC2B9DCDA57DB51021D034E48F160EC5855CCCD9F995988AD1B554AD1B591E64283E91A07D151028180017324ADC1F93CF002FA2B0619C60F897CDED488E457685625E1565377483C0FA4A7FD1CAE848C727E76654434CE3CCAF81EC6E6AAA156EEBBEA095F642FD0DA2D043996ACC14A1B1A6110B19C094638E29890B89AF5812E97C5F96F33B1FD7415079947994442295CA34447807662FB70621F069A98AE274D01B2777BF4E97E041F021D00F9F02A2BC1930F1AC93198F3D532BC937941D7C9A1E16F0EB932476E
\ No newline at end of file diff --git a/lucs512.dat b/lucs512.dat new file mode 100644 index 0000000..f8fd288 --- /dev/null +++ b/lucs512.dat @@ -0,0 +1 @@ +3081C70201003081A806072A8648CE38040130819C024100E64283E91A07D10F557B7B758DC8041CE6CFC57DFE0AAA33FC8FEC48BEEA37562AD13359236FFFF6EED3FB921690D2FD1339F8E1DD406EED70D7EE3085E3AADD02150F4E48F160EC5855CCCD9F995988AD1B554AD1B5F3024062503DFB092F0FD0D8BBD90B50A834A6BD5B0995BCFC1CC8C8C83103AA6837F3FBFF3E042E1B25E36963DB2FCFD7AD24A6626E65A1F6EECBB399F5CE73659F29041702150450A037413E9A711E601318AF21D32A498C0C501E
\ No newline at end of file diff --git a/mars.cpp b/mars.cpp new file mode 100644 index 0000000..804c9b1 --- /dev/null +++ b/mars.cpp @@ -0,0 +1,210 @@ +// mars.cpp - modified by Sean Woods from Brian Gladman's mars6.c for Crypto++ +// key setup updated by Wei Dai to reflect IBM's "tweak" proposed in August 1999 + +/* This is an independent implementation of the MARS encryption */ +/* algorithm designed by a team at IBM as a candidate for the US */ +/* NIST Advanced Encryption Standard (AES) effort. The algorithm */ +/* is subject to Patent action by IBM, who intend to offer royalty */ +/* free use if a Patent is granted. */ +/* */ +/* Copyright in this implementation is held by Dr B R Gladman but */ +/* I hereby give permission for its free direct or derivative use */ +/* subject to acknowledgment of its origin and compliance with any */ +/* constraints that IBM place on the use of the MARS algorithm. */ +/* */ +/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 4th October 1998 */ + +#include "pch.h" +#include "mars.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +ANONYMOUS_NAMESPACE_BEGIN +static word32 gen_mask(word32 x) +{ + word32 m; + + m = (~x ^ (x >> 1)) & 0x7fffffff; + m &= (m >> 1) & (m >> 2); m &= (m >> 3) & (m >> 6); + + if(!m) + return 0; + + m <<= 1; m |= (m << 1); m |= (m << 2); m |= (m << 4); + m |= (m << 1) & ~x & 0x80000000; + + return m & 0xfffffffc; +}; +NAMESPACE_END + +void MARS::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) +{ + AssertValidKeyLength(length); + + // Initialize T[] with the key data + FixedSizeSecBlock<word32, 15> T; + GetUserKey(LITTLE_ENDIAN_ORDER, T.begin(), 15, userKey, length); + T[length/4] = length/4; + + for (unsigned int j=0; j<4; j++) // compute 10 words of K[] in each iteration + { + unsigned int i; + // Do linear transformation + for (i=0; i<15; i++) + T[i] = T[i] ^ rotlFixed(T[(i+8)%15] ^ T[(i+13)%15], 3) ^ (4*i+j); + + // Do four rounds of stirring + for (unsigned int k=0; k<4; k++) + for (i=0; i<15; i++) + T[i] = rotlFixed(T[i] + Sbox[T[(i+14)%15]%512], 9); + + // Store next 10 key words into K[] + for (i=0; i<10; i++) + EK[10*j+i] = T[4*i%15]; + } + + // Modify multiplication key-words + for(unsigned int i = 5; i < 37; i += 2) + { + word32 w = EK[i] | 3; + word32 m = gen_mask(w); + if(m) + w ^= (rotlMod(Sbox[265 + (EK[i] & 3)], EK[i-1]) & m); + EK[i] = w; + } +} + +#define f_mix(a,b,c,d) \ + r = rotrFixed(a, 8); \ + b ^= Sbox[a & 255]; \ + b += Sbox[(r & 255) + 256]; \ + r = rotrFixed(a, 16); \ + a = rotrFixed(a, 24); \ + c += Sbox[r & 255]; \ + d ^= Sbox[(a & 255) + 256] + +#define b_mix(a,b,c,d) \ + r = rotlFixed(a, 8); \ + b ^= Sbox[(a & 255) + 256]; \ + c -= Sbox[r & 255]; \ + r = rotlFixed(a, 16); \ + a = rotlFixed(a, 24); \ + d -= Sbox[(r & 255) + 256]; \ + d ^= Sbox[a & 255] + +#define f_ktr(a,b,c,d,i) \ + m = a + EK[i]; \ + a = rotlFixed(a, 13); \ + r = a * EK[i + 1]; \ + l = Sbox[m & 511]; \ + r = rotlFixed(r, 5); \ + l ^= r; \ + c += rotlMod(m, r); \ + r = rotlFixed(r, 5); \ + l ^= r; \ + d ^= r; \ + b += rotlMod(l, r) + +#define r_ktr(a,b,c,d,i) \ + r = a * EK[i + 1]; \ + a = rotrFixed(a, 13); \ + m = a + EK[i]; \ + l = Sbox[m & 511]; \ + r = rotlFixed(r, 5); \ + l ^= r; \ + c -= rotlMod(m, r); \ + r = rotlFixed(r, 5); \ + l ^= r; \ + d ^= r; \ + b -= rotlMod(l, r) + +typedef BlockGetAndPut<word32, LittleEndian> Block; + +void MARS::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, l, m, r; + + Block::Get(inBlock)(a)(b)(c)(d); + + a += EK[0]; + b += EK[1]; + c += EK[2]; + d += EK[3]; + + int i; + for (i = 0; i < 2; i++) { + f_mix(a,b,c,d); + a += d; + f_mix(b,c,d,a); + b += c; + f_mix(c,d,a,b); + f_mix(d,a,b,c); + } + + f_ktr(a,b,c,d, 4); f_ktr(b,c,d,a, 6); f_ktr(c,d,a,b, 8); f_ktr(d,a,b,c,10); + f_ktr(a,b,c,d,12); f_ktr(b,c,d,a,14); f_ktr(c,d,a,b,16); f_ktr(d,a,b,c,18); + f_ktr(a,d,c,b,20); f_ktr(b,a,d,c,22); f_ktr(c,b,a,d,24); f_ktr(d,c,b,a,26); + f_ktr(a,d,c,b,28); f_ktr(b,a,d,c,30); f_ktr(c,b,a,d,32); f_ktr(d,c,b,a,34); + + for (i = 0; i < 2; i++) { + b_mix(a,b,c,d); + b_mix(b,c,d,a); + c -= b; + b_mix(c,d,a,b); + d -= a; + b_mix(d,a,b,c); + } + + a -= EK[36]; + b -= EK[37]; + c -= EK[38]; + d -= EK[39]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +void MARS::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, l, m, r; + + Block::Get(inBlock)(d)(c)(b)(a); + + d += EK[36]; + c += EK[37]; + b += EK[38]; + a += EK[39]; + + int i; + for (i = 0; i < 2; i++) { + f_mix(a,b,c,d); + a += d; + f_mix(b,c,d,a); + b += c; + f_mix(c,d,a,b); + f_mix(d,a,b,c); + } + + r_ktr(a,b,c,d,34); r_ktr(b,c,d,a,32); r_ktr(c,d,a,b,30); r_ktr(d,a,b,c,28); + r_ktr(a,b,c,d,26); r_ktr(b,c,d,a,24); r_ktr(c,d,a,b,22); r_ktr(d,a,b,c,20); + r_ktr(a,d,c,b,18); r_ktr(b,a,d,c,16); r_ktr(c,b,a,d,14); r_ktr(d,c,b,a,12); + r_ktr(a,d,c,b,10); r_ktr(b,a,d,c, 8); r_ktr(c,b,a,d, 6); r_ktr(d,c,b,a, 4); + + for (i = 0; i < 2; i++) { + b_mix(a,b,c,d); + b_mix(b,c,d,a); + c -= b; + b_mix(c,d,a,b); + d -= a; + b_mix(d,a,b,c); + } + + d -= EK[0]; + c -= EK[1]; + b -= EK[2]; + a -= EK[3]; + + Block::Put(xorBlock, outBlock)(d)(c)(b)(a); +} + +NAMESPACE_END @@ -0,0 +1,53 @@ +#ifndef CRYPTOPP_MARS_H +#define CRYPTOPP_MARS_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct MARS_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 56, 4> +{ + static const char *StaticAlgorithmName() {return "MARS";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#MARS">MARS</a> +class MARS : public MARS_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<MARS_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static const word32 Sbox[512]; + + FixedSizeSecBlock<word32, 40> EK; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef MARS::Encryption MARSEncryption; +typedef MARS::Decryption MARSDecryption; + +NAMESPACE_END + +#endif diff --git a/marss.cpp b/marss.cpp new file mode 100644 index 0000000..7c38f14 --- /dev/null +++ b/marss.cpp @@ -0,0 +1,139 @@ +// MARS S-Box + +#include "pch.h" +#include "mars.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 MARS::Base::Sbox[512] = { + 0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, + 0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93, + 0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d, + 0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4, + 0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, + 0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac, + 0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4, + 0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26, + 0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, + 0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086, + 0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c, + 0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253, + 0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, + 0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e, + 0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b, + 0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a, + 0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, + 0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb, + 0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958, + 0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215, + 0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, + 0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c, + 0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462, + 0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44, + 0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, + 0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df, + 0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8, + 0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae, + 0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, + 0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365, + 0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3, + 0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55, + 0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, + 0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7, + 0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8, + 0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063, + 0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, + 0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371, + 0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6, + 0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b, + 0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, + 0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1, + 0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd, + 0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294, + 0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, + 0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98, + 0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f, + 0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d, + 0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, + 0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48, + 0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149, + 0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9, + 0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, + 0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e, + 0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3, + 0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52, + 0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, + 0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f, + 0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59, + 0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8, + 0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, + 0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca, + 0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3, + 0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030, + 0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, + 0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734, + 0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b, + 0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03, + 0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, + 0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3, + 0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf, + 0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568, + 0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, + 0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10, + 0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce, + 0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047, + 0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, + 0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158, + 0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969, + 0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f, + 0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, + 0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05, + 0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3, + 0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33, + 0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, + 0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd, + 0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e, + 0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246, + 0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, + 0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e, + 0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2, + 0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b, + 0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, + 0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba, + 0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c, + 0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5, + 0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, + 0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47, + 0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54, + 0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72, + 0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, + 0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6, + 0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9, + 0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68, + 0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, + 0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f, + 0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4, + 0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7, + 0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, + 0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038, + 0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c, + 0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53, + 0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, + 0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336, + 0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235, + 0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185, + 0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, + 0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558, + 0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830, + 0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85, + 0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, + 0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6, + 0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319, + 0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469, + 0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, + 0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b, + 0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0, + 0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee +}; + +NAMESPACE_END diff --git a/marsval.dat b/marsval.dat new file mode 100644 index 0000000..661872f --- /dev/null +++ b/marsval.dat @@ -0,0 +1,9 @@ +00000000000000000000000000000000 00000000000000000000000000000000 DCC07B8DFB0738D6E30A22DFCF27E886 +00000000000000000000000000000000 DCC07B8DFB0738D6E30A22DFCF27E886 33CAFFBDDC7F1DDA0F9C15FA2F30E2FF +CB14A1776ABBC1CDAFE7243DEF2CEA02 F94512A9B42D034EC4792204D708A69B 225DA2CB64B73F79069F21A5E3CB8522 +86EDF4DA31824CABEF6A4637C40B0BAB 4DF955AD5B398D66408D620A2B27E1A9 A4B737340AE6D2CAFD930BA97D86129F +000000000000000000000000000000000000000000000000 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 97778747D60E425C2B4202599DB856FB +D158860838874D9500000000000000000000000000000000 93A953A82C10411DD158860838874D95 4FA0E5F64893131712F01408D233E9F7 +791739A58B04581A93A953A82C10411DD158860838874D95 6761C42D3E6142D2A84FBFADB383158F F706BC0FD97E28B6F1AF4E17D8755FFF +0000000000000000000000000000000000000000000000000000000000000000 62E45B4CF3477F1DD65063729D9ABA8F 0F4B897EA014D21FBC20F1054A42F719 +FBA167983E7AEF22317CE28C02AAE1A3E8E5CC3CEDBEA82A99DBC39AD65E7227 1344ABA4D3C44708A8A72116D4F49384 458335D95EA42A9F4DCCD41AECC2390D @@ -0,0 +1,108 @@ +// md2.cpp - modified by Wei Dai from Andrew M. Kuchling's md2.c +// The original code and all modifications are in the public domain. + +// This is the original introductory comment: + +/* + * md2.c : MD2 hash algorithm. + * + * Part of the Python Cryptography Toolkit, version 1.1 + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +#include "pch.h" +#include "md2.h" + +NAMESPACE_BEGIN(CryptoPP) + +MD2::MD2() + : m_X(48), m_C(16), m_buf(16) +{ + Init(); +} + +void MD2::Init() +{ + memset(m_X, 0, 48); + memset(m_C, 0, 16); + memset(m_buf, 0, 16); + m_count = 0; +} + +void MD2::Update(const byte *buf, unsigned int len) +{ + static const byte S[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + }; + + while (len) + { + word32 L = (16-m_count) < len ? (16-m_count) : len; + memcpy(m_buf+m_count, buf, L); + m_count+=L; + buf+=L; + len-=L; + if (m_count==16) + { + byte t; + int i,j; + + m_count=0; + memcpy(m_X+16, m_buf, 16); + t=m_C[15]; + for(i=0; i<16; i++) + { + m_X[32+i]=m_X[16+i]^m_X[i]; + t=m_C[i]^=S[m_buf[i]^t]; + } + + t=0; + for(i=0; i<18; i++) + { + for(j=0; j<48; j++) + t=m_X[j]^=S[t]; + t=(t+i) & 0xFF; + } + } + } +} + +void MD2::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte padding[16]; + word32 padlen; + unsigned int i; + + padlen= 16-m_count; + for(i=0; i<padlen; i++) padding[i]=(byte)padlen; + Update(padding, padlen); + Update(m_C, 16); + memcpy(hash, m_X, size); + + Init(); +} + +NAMESPACE_END @@ -0,0 +1,31 @@ +#ifndef CRYPTOPP_MD2_H +#define CRYPTOPP_MD2_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/md.html#MD2">MD2</a> +/** 128 Bit Hash */ +class MD2 : public HashTransformation +{ +public: + MD2(); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *hash, unsigned int size); + unsigned int DigestSize() const {return DIGESTSIZE;} + static const char * StaticAlgorithmName() {return "MD2";} + + enum {DIGESTSIZE = 16, BLOCKSIZE = 16}; + +private: + void Transform(); + void Init(); + SecByteBlock m_X, m_C, m_buf; + unsigned int m_count; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,107 @@ +// md4.cpp - modified by Wei Dai from Andrew M. Kuchling's md4.c +// The original code and all modifications are in the public domain. + +// This is the original introductory comment: + +/* + * md4.c : MD4 hash algorithm. + * + * Part of the Python Cryptography Toolkit, version 1.1 + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +#include "pch.h" +#include "md4.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void MD4::Init() +{ + m_digest[0] = 0x67452301L; + m_digest[1] = 0xefcdab89L; + m_digest[2] = 0x98badcfeL; + m_digest[3] = 0x10325476L; +} + +void MD4::Transform (word32 *digest, const word32 *in) +{ +// #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + + word32 A, B, C, D; + + A=digest[0]; + B=digest[1]; + C=digest[2]; + D=digest[3]; + +#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+in[k],s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 1, 7); + function(C,D,A,B, 2,11); + function(B,C,D,A, 3,19); + function(A,B,C,D, 4, 3); + function(D,A,B,C, 5, 7); + function(C,D,A,B, 6,11); + function(B,C,D,A, 7,19); + function(A,B,C,D, 8, 3); + function(D,A,B,C, 9, 7); + function(C,D,A,B,10,11); + function(B,C,D,A,11,19); + function(A,B,C,D,12, 3); + function(D,A,B,C,13, 7); + function(C,D,A,B,14,11); + function(B,C,D,A,15,19); + +#undef function +#define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+in[k]+0x5a827999,s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 4, 5); + function(C,D,A,B, 8, 9); + function(B,C,D,A,12,13); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 5, 5); + function(C,D,A,B, 9, 9); + function(B,C,D,A,13,13); + function(A,B,C,D, 2, 3); + function(D,A,B,C, 6, 5); + function(C,D,A,B,10, 9); + function(B,C,D,A,14,13); + function(A,B,C,D, 3, 3); + function(D,A,B,C, 7, 5); + function(C,D,A,B,11, 9); + function(B,C,D,A,15,13); + +#undef function +#define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+in[k]+0x6ed9eba1,s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 8, 9); + function(C,D,A,B, 4,11); + function(B,C,D,A,12,15); + function(A,B,C,D, 2, 3); + function(D,A,B,C,10, 9); + function(C,D,A,B, 6,11); + function(B,C,D,A,14,15); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 9, 9); + function(C,D,A,B, 5,11); + function(B,C,D,A,13,15); + function(A,B,C,D, 3, 3); + function(D,A,B,C,11, 9); + function(C,D,A,B, 7,11); + function(B,C,D,A,15,15); + + digest[0]+=A; + digest[1]+=B; + digest[2]+=C; + digest[3]+=D; +} + +NAMESPACE_END @@ -0,0 +1,25 @@ +#ifndef CRYPTOPP_MD4_H +#define CRYPTOPP_MD4_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! <a href="http://www.weidai.com/scan-mirror/md.html#MD4">MD4</a> +/*! \warning MD4 is considered insecure, and should not be used + unless you absolutely need compatibility with a broken product. */ +class MD4 : public IteratedHashWithStaticTransform<word32, LittleEndian, 64, MD4> +{ +public: + enum {DIGESTSIZE = 16}; + MD4() : IteratedHashWithStaticTransform<word32, LittleEndian, 64, MD4>(DIGESTSIZE) {Init();} + static void Transform(word32 *digest, const word32 *data); + static const char *StaticAlgorithmName() {return "MD4";} + +protected: + void Init(); +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,115 @@ +// md5.cpp - modified by Wei Dai from Colin Plumb's public domain md5.c +// any modifications are placed in the public domain + +#include "pch.h" +#include "md5.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void MD5_TestInstantiations() +{ + MD5 x; +} + +void MD5::Init() +{ + m_digest[0] = 0x67452301L; + m_digest[1] = 0xefcdab89L; + m_digest[2] = 0x98badcfeL; + m_digest[3] = 0x10325476L; +} + +void MD5::Transform (word32 *digest, const word32 *in) +{ +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + w = rotlFixed(w + f(x, y, z) + data, s) + x + + word32 a, b, c, d; + + a=digest[0]; + b=digest[1]; + c=digest[2]; + d=digest[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + digest[0]+=a; + digest[1]+=b; + digest[2]+=c; + digest[3]+=d; +} + +NAMESPACE_END @@ -0,0 +1,24 @@ +#ifndef CRYPTOPP_MD5_H +#define CRYPTOPP_MD5_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! <a href="http://www.weidai.com/scan-mirror/md.html#MD5">MD5</a> +/*! 128 Bit Hash */ +class MD5 : public IteratedHashWithStaticTransform<word32, LittleEndian, 64, MD5> +{ +public: + enum {DIGESTSIZE = 16}; + MD5() : IteratedHashWithStaticTransform<word32, LittleEndian, 64, MD5>(DIGESTSIZE) {Init();} + static void Transform(word32 *digest, const word32 *data); + static const char * StaticAlgorithmName() {return "MD5";} + +protected: + void Init(); +}; + +NAMESPACE_END + +#endif diff --git a/md5mac.cpp b/md5mac.cpp new file mode 100644 index 0000000..78b8ede --- /dev/null +++ b/md5mac.cpp @@ -0,0 +1,166 @@ +// md5mac.cpp - modified by Wei Dai from Colin Plumb's public domain md5.c +// any modifications are placed in the public domain + +#include "pch.h" +#include "md5mac.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 MD5MAC_Base::T[12] = + { 0xac45ef97,0xcd430f29,0x551b7e45,0x3411801c, + 0x96ce77b1,0x7c8e722e,0x0aab5a5f,0x18be4336, + 0x21b4219d,0x4db987bc,0xbd279da2,0xc3d75bc7 }; + +void MD5MAC_Base::UncheckedSetKey(const byte *userKey, unsigned int keylength) +{ + const word32 zeros[4] = {0,0,0,0}; + + for (unsigned i=0, j; i<3; i++) + { + m_key[4*i+0] = 0x67452301L; + m_key[4*i+1] = 0xefcdab89L; + m_key[4*i+2] = 0x98badcfeL; + m_key[4*i+3] = 0x10325476L; + + memcpy(m_data, userKey, KEYLENGTH); + CorrectEndianess(m_data, m_data, KEYLENGTH); + for (j=0; j<3; j++) + memcpy(m_data+4+4*j, T+((i+j)%3)*4, 16); + Transform(m_key+4*i, m_data, zeros); + + for (j=0; j<3; j++) + memcpy(m_data+4*j, T+((i+j)%3)*4, 16); + memcpy(m_data+12, userKey, KEYLENGTH); + CorrectEndianess(m_data+12, m_data+12, KEYLENGTH); + Transform(m_key+4*i, m_data, zeros); + } + + Init(); +} + +void MD5MAC_Base::Init() +{ + m_digest[0] = m_key[0]; + m_digest[1] = m_key[1]; + m_digest[2] = m_key[2]; + m_digest[3] = m_key[3]; +} + +void MD5MAC_Base::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(56); + CorrectEndianess(m_data, m_data, 56); + + m_data[14] = GetBitCountLo(); + m_data[15] = GetBitCountHi(); + + Transform(m_digest, m_data, m_key+4); + + unsigned i; + for (i=0; i<4; i++) + m_data[i] = m_key[8+i]; + for (i=0; i<12; i++) + m_data[i+4] = T[i] ^ m_key[8+i%4]; + Transform(m_digest, m_data, m_key+4); + + CorrectEndianess(m_digest, m_digest, DIGESTSIZE); + memcpy(hash, m_digest, size); + + Restart(); // reinit for next use +} + +void MD5MAC_Base::Transform(word32 *digest, const word32 *in, const word32 *key) +{ +#define F1(x, y, z) ((z ^ (x & (y ^ z))) + key[0]) +#define F2(x, y, z) ((y ^ (z & (x ^ y))) + key[1]) +#define F3(x, y, z) ((x ^ y ^ z) + key[2]) +#define F4(x, y, z) ((y ^ (x | ~z)) + key[3]) + +#define MD5STEP(f, w, x, y, z, data, s) \ + w = rotlFixed(w + f(x, y, z) + data, s) + x + + word32 a, b, c, d; + + a=digest[0]; + b=digest[1]; + c=digest[2]; + d=digest[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + digest[0]+=a; + digest[1]+=b; + digest[2]+=c; + digest[3]+=d; +} + +NAMESPACE_END diff --git a/md5mac.h b/md5mac.h new file mode 100644 index 0000000..e335145 --- /dev/null +++ b/md5mac.h @@ -0,0 +1,38 @@ +#ifndef CRYPTOPP_MD5MAC_H +#define CRYPTOPP_MD5MAC_H + +/** \file +*/ + +#include "seckey.h" +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class MD5MAC_Base : public FixedKeyLength<16>, public IteratedHash<word32, LittleEndian, 64, MessageAuthenticationCode> +{ +public: + static std::string StaticAlgorithmName() {return "MD5-MAC";} + enum {DIGESTSIZE = 16}; + + MD5MAC_Base() : IteratedHash<word32, LittleEndian, 64, MessageAuthenticationCode>(DIGESTSIZE) {} + + void UncheckedSetKey(const byte *userKey, unsigned int keylength); + void TruncatedFinal(byte *mac, unsigned int size); + +protected: + static void Transform (word32 *buf, const word32 *in, const word32 *key); + void vTransform(const word32 *data) {Transform(m_digest, data, m_key+4);} + void Init(); + + static const word32 T[12]; + FixedSizeSecBlock<word32, 12> m_key; +}; + +//! <a href="http://www.weidai.com/scan-mirror/mac.html#MD5-MAC">MD5-MAC</a> +typedef MessageAuthenticationCodeTemplate<MD5MAC_Base> MD5MAC; + +NAMESPACE_END + +#endif @@ -0,0 +1,72 @@ + // mdc.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_MDC_H +#define CRYPTOPP_MDC_H + +/** \file +*/ + +#include "seckey.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +struct MDC_Info : public FixedBlockSize<T::DIGESTSIZE>, public FixedKeyLength<T::BLOCKSIZE> +{ + static std::string StaticAlgorithmName() {return std::string("MDC/")+T::StaticAlgorithmName();} +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#MDC">MDC</a> +/*! a construction by Peter Gutmann to turn an iterated hash function into a PRF */ +template <class T> +class MDC : public MDC_Info<T> +{ + class Enc : public BlockCipherBaseTemplate<MDC_Info<T> > + { + typedef typename T::HashWordType HashWordType; + + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) + { + assert(direction == ENCRYPTION); + AssertValidKeyLength(length); + memcpy(Key(), userKey, KEYLENGTH); + T::CorrectEndianess(Key(), Key(), KEYLENGTH); + } + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + T::CorrectEndianess(Buffer(), (HashWordType *)inBlock, BLOCKSIZE); + T::Transform(Buffer(), Key()); + if (xorBlock) + { + T::CorrectEndianess(Buffer(), Buffer(), BLOCKSIZE); + xorbuf(outBlock, xorBlock, m_buffer, BLOCKSIZE); + } + else + T::CorrectEndianess((HashWordType *)outBlock, Buffer(), BLOCKSIZE); + } + + bool IsPermutation() const {return false;} + + unsigned int GetAlignment() const {return sizeof(HashWordType);} + + private: + HashWordType *Key() {return (HashWordType *)m_key.data();} + const HashWordType *Key() const {return (const HashWordType *)m_key.data();} + HashWordType *Buffer() const {return (HashWordType *)m_buffer.data();} + + // VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup + FixedSizeSecBlock<byte, MDC_Info<T>::KEYLENGTH, AllocatorWithCleanup<byte> > m_key; + mutable FixedSizeSecBlock<byte, MDC_Info<T>::BLOCKSIZE, AllocatorWithCleanup<byte> > m_buffer; + }; + +public: + //! use BlockCipher interface + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; +}; + +NAMESPACE_END + +#endif diff --git a/misc.cpp b/misc.cpp new file mode 100644 index 0000000..c193b3f --- /dev/null +++ b/misc.cpp @@ -0,0 +1,83 @@ +// misc.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "misc.h" +#include "words.h" + +NAMESPACE_BEGIN(CryptoPP) + +byte OAEP_P_DEFAULT[1]; + +template<> void ByteReverse(word16 *, const word16 *, unsigned int); +template<> void ByteReverse(word32 *, const word32 *, unsigned int); +#ifdef WORD64_AVAILABLE +template<> void ByteReverse(word64 *, const word64 *, unsigned int); +#endif + +void xorbuf(byte *buf, const byte *mask, unsigned int count) +{ + if (((unsigned int)buf | (unsigned int)mask | count) % WORD_SIZE == 0) + XorWords((word *)buf, (const word *)mask, count/WORD_SIZE); + else + { + for (unsigned int i=0; i<count; i++) + buf[i] ^= mask[i]; + } +} + +void xorbuf(byte *output, const byte *input, const byte *mask, unsigned int count) +{ + if (((unsigned int)output | (unsigned int)input | (unsigned int)mask | count) % WORD_SIZE == 0) + XorWords((word *)output, (const word *)input, (const word *)mask, count/WORD_SIZE); + else + { + for (unsigned int i=0; i<count; i++) + output[i] = input[i] ^ mask[i]; + } +} + +unsigned int Parity(unsigned long value) +{ + for (unsigned int i=8*sizeof(value)/2; i>0; i/=2) + value ^= value >> i; + return (unsigned int)value&1; +} + +unsigned int BytePrecision(unsigned long value) +{ + unsigned int i; + for (i=sizeof(value); i; --i) + if (value >> (i-1)*8) + break; + + return i; +} + +unsigned int BitPrecision(unsigned long value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + + while (h-l > 1) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h; +} + +unsigned long Crop(unsigned long value, unsigned int size) +{ + if (size < 8*sizeof(value)) + return (value & ((1L << size) - 1)); + else + return value; +} + +NAMESPACE_END @@ -0,0 +1,688 @@ +#ifndef CRYPTOPP_MISC_H +#define CRYPTOPP_MISC_H + +#include "config.h" +#include "cryptlib.h" +#include <assert.h> +#include <string.h> // CodeWarrior doesn't have memory.h +#include <algorithm> +#include <string> + +#ifdef INTEL_INTRINSICS +#include <stdlib.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** compile-time assertion *************** + +template <bool b> +struct CompileAssert +{ + static char dummy[2*b-1]; +}; + +#define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) +#define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) static CompileAssert<(assertion)> CRYPTOPP_ASSERT_JOIN(cryptopp_assert_, instance) +#define CRYPTOPP_ASSERT_JOIN(X, Y) CRYPTOPP_DO_ASSERT_JOIN(X, Y) +#define CRYPTOPP_DO_ASSERT_JOIN(X, Y) X##Y + +// ************** misc classes *************** + +class Empty +{ +}; + +template <class BASE1, class BASE2> +class TwoBases : public BASE1, public BASE2 +{ +}; + +template <class BASE1, class BASE2, class BASE3> +class ThreeBases : public BASE1, public BASE2, public BASE3 +{ +}; + +template <class T> +class ObjectHolder +{ +protected: + T m_object; +}; + +class NotCopyable +{ +public: + NotCopyable() {} +private: + NotCopyable(const NotCopyable &); + void operator=(const NotCopyable &); +}; + +// ************** misc functions *************** + +// can't use std::min or std::max in MSVC60 or Cygwin 1.1.0 +template <class _Tp> inline const _Tp& STDMIN(const _Tp& __a, const _Tp& __b) +{ + return __b < __a ? __b : __a; +} + +template <class _Tp> inline const _Tp& STDMAX(const _Tp& __a, const _Tp& __b) +{ + return __a < __b ? __b : __a; +} + +#define RETURN_IF_NONZERO(x) unsigned int returnedValue = x; if (returnedValue) return returnedValue + +// this version of the macro is fastest on Pentium 3 and Pentium 4 with MSVC 6 SP5 w/ Processor Pack +#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) +// these may be faster on other CPUs/compilers +// #define GETBYTE(x, y) (unsigned int)(((x)>>(8*(y)))&255) +// #define GETBYTE(x, y) (((byte *)&(x))[y]) + +unsigned int Parity(unsigned long); +unsigned int BytePrecision(unsigned long); +unsigned int BitPrecision(unsigned long); +unsigned long Crop(unsigned long, unsigned int size); + +inline unsigned int BitsToBytes(unsigned int bitCount) +{ + return ((bitCount+7)/(8)); +} + +inline unsigned int BytesToWords(unsigned int byteCount) +{ + return ((byteCount+WORD_SIZE-1)/WORD_SIZE); +} + +inline unsigned int BitsToWords(unsigned int bitCount) +{ + return ((bitCount+WORD_BITS-1)/(WORD_BITS)); +} + +void xorbuf(byte *buf, const byte *mask, unsigned int count); +void xorbuf(byte *output, const byte *input, const byte *mask, unsigned int count); + +template <class T> +inline bool IsPowerOf2(T n) +{ + return n > 0 && (n & (n-1)) == 0; +} + +template <class T1, class T2> +inline T2 ModPowerOf2(T1 a, T2 b) +{ + assert(IsPowerOf2(b)); + return T2(a) & (b-1); +} + +template <class T> +inline T RoundDownToMultipleOf(T n, T m) +{ + return n - (IsPowerOf2(m) ? ModPowerOf2(n, m) : (n%m)); +} + +template <class T> +inline T RoundUpToMultipleOf(T n, T m) +{ + return RoundDownToMultipleOf(n+m-1, m); +} + +template <class T> +inline unsigned int GetAlignment(T *dummy=NULL) // VC60 workaround +{ +#if (_MSC_VER >= 1300) + return __alignof(T); +#elif defined(__GNUC__) + return __alignof__(T); +#else + return sizeof(T); +#endif +} + +inline bool IsAlignedOn(const void *p, unsigned int alignment) +{ + return IsPowerOf2(alignment) ? ModPowerOf2((unsigned int)p, alignment) == 0 : (unsigned int)p % alignment == 0; +} + +template <class T> +inline bool IsAligned(const void *p, T *dummy=NULL) // VC60 workaround +{ + return IsAlignedOn(p, GetAlignment<T>()); +} + +#ifdef IS_LITTLE_ENDIAN + typedef LittleEndian NativeByteOrder; +#else + typedef BigEndian NativeByteOrder; +#endif + +inline ByteOrder GetNativeByteOrder() +{ + return NativeByteOrder::ToEnum(); +} + +inline bool NativeByteOrderIs(ByteOrder order) +{ + return order == GetNativeByteOrder(); +} + +template <class T> // can't use <sstream> because GCC 2.95.2 doesn't have it +std::string IntToString(T a, unsigned int base = 10) +{ + if (a == 0) + return "0"; + bool negate = false; + if (a < 0) + { + negate = true; + a = 0-a; // VC .NET does not like -a + } + std::string result; + while (a > 0) + { + T digit = a % base; + result = char((digit < 10 ? '0' : ('a' - 10)) + digit) + result; + a /= base; + } + if (negate) + result = "-" + result; + return result; +} + +template <class T1, class T2> +inline T1 SaturatingSubtract(T1 a, T2 b) +{ + CRYPTOPP_COMPILE_ASSERT_INSTANCE(T1(-1)>0, 0); // T1 is unsigned type + CRYPTOPP_COMPILE_ASSERT_INSTANCE(T2(-1)>0, 1); // T2 is unsigned type + return T1((a > b) ? (a - b) : 0); +} + +template <class T> +inline CipherDir GetCipherDir(const T &obj) +{ + return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; +} + +// ************** rotate functions *************** + +template <class T> inline T rotlFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x<<y) | (x>>(sizeof(T)*8-y)); +} + +template <class T> inline T rotrFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +template <class T> inline T rotlVariable(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x<<y) | (x>>(sizeof(T)*8-y)); +} + +template <class T> inline T rotrVariable(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +template <class T> inline T rotlMod(T x, unsigned int y) +{ + y %= sizeof(T)*8; + return (x<<y) | (x>>(sizeof(T)*8-y)); +} + +template <class T> inline T rotrMod(T x, unsigned int y) +{ + y %= sizeof(T)*8; + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +#ifdef INTEL_INTRINSICS + +#pragma intrinsic(_lrotl, _lrotr) + +template<> inline word32 rotlFixed<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? _lrotl(x, y) : x; +} + +template<> inline word32 rotrFixed<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? _lrotr(x, y) : x; +} + +template<> inline word32 rotlVariable<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return _lrotl(x, y); +} + +template<> inline word32 rotrVariable<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return _lrotr(x, y); +} + +template<> inline word32 rotlMod<word32>(word32 x, unsigned int y) +{ + return _lrotl(x, y); +} + +template<> inline word32 rotrMod<word32>(word32 x, unsigned int y) +{ + return _lrotr(x, y); +} + +#endif // #ifdef INTEL_INTRINSICS + +#ifdef PPC_INTRINSICS + +template<> inline word32 rotlFixed<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? __rlwinm(x,y,0,31) : x; +} + +template<> inline word32 rotrFixed<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? __rlwinm(x,32-y,0,31) : x; +} + +template<> inline word32 rotlVariable<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrVariable<word32>(word32 x, unsigned int y) +{ + assert(y < 32); + return (__rlwnm(x,32-y,0,31)); +} + +template<> inline word32 rotlMod<word32>(word32 x, unsigned int y) +{ + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrMod<word32>(word32 x, unsigned int y) +{ + return (__rlwnm(x,32-y,0,31)); +} + +#endif // #ifdef PPC_INTRINSICS + +// ************** endian reversal *************** + +template <class T> +inline unsigned int GetByte(ByteOrder order, T value, unsigned int index) +{ + if (order == LITTLE_ENDIAN_ORDER) + return GETBYTE(value, index); + else + return GETBYTE(value, sizeof(T)-index-1); +} + +inline byte ByteReverse(byte value) +{ + return value; +} + +inline word16 ByteReverse(word16 value) +{ + return rotlFixed(value, 8U); +} + +inline word32 ByteReverse(word32 value) +{ +#ifdef PPC_INTRINSICS + // PPC: load reverse indexed instruction + return (word32)__lwbrx(&value,0); +#elif defined(FAST_ROTATE) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + +#ifdef WORD64_AVAILABLE +inline word64 ByteReverse(word64 value) +{ +#ifdef SLOW_WORD64 + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed(value, 32U); +#endif +} +#endif + +inline byte BitReverse(byte value) +{ + value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); + value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); + return rotlFixed(value, 4); +} + +inline word16 BitReverse(word16 value) +{ + value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1); + value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2); + value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4); + return ByteReverse(value); +} + +inline word32 BitReverse(word32 value) +{ + value = ((value & 0xAAAAAAAA) >> 1) | ((value & 0x55555555) << 1); + value = ((value & 0xCCCCCCCC) >> 2) | ((value & 0x33333333) << 2); + value = ((value & 0xF0F0F0F0) >> 4) | ((value & 0x0F0F0F0F) << 4); + return ByteReverse(value); +} + +#ifdef WORD64_AVAILABLE +inline word64 BitReverse(word64 value) +{ +#ifdef SLOW_WORD64 + return (word64(BitReverse(word32(value))) << 32) | BitReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xAAAAAAAAAAAAAAAA)) >> 1) | ((value & W64LIT(0x5555555555555555)) << 1); + value = ((value & W64LIT(0xCCCCCCCCCCCCCCCC)) >> 2) | ((value & W64LIT(0x3333333333333333)) << 2); + value = ((value & W64LIT(0xF0F0F0F0F0F0F0F0)) >> 4) | ((value & W64LIT(0x0F0F0F0F0F0F0F0F)) << 4); + return ByteReverse(value); +#endif +} +#endif + +template <class T> +inline T BitReverse(T value) +{ + if (sizeof(T) == 1) + return (T)BitReverse((byte)value); + else if (sizeof(T) == 2) + return (T)BitReverse((word16)value); + else if (sizeof(T) == 4) + return (T)BitReverse((word32)value); + else + { +#ifdef WORD64_AVAILABLE + assert(sizeof(T) == 8); + return (T)BitReverse((word64)value); +#else + assert(false); + return 0; +#endif + } +} + +template <class T> +inline T ConditionalByteReverse(ByteOrder order, T value) +{ + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +template <class T> +void ByteReverse(T *out, const T *in, unsigned int byteCount) +{ + assert(byteCount % sizeof(T) == 0); + unsigned int count = byteCount/sizeof(T); + for (unsigned int i=0; i<count; i++) + out[i] = ByteReverse(in[i]); +} + +template <class T> +inline void ConditionalByteReverse(ByteOrder order, T *out, const T *in, unsigned int byteCount) +{ + if (!NativeByteOrderIs(order)) + ByteReverse(out, in, byteCount); + else if (in != out) + memcpy(out, in, byteCount); +} + +template <class T> +inline void GetUserKey(ByteOrder order, T *out, unsigned int outlen, const byte *in, unsigned int inlen) +{ + const unsigned int U = sizeof(T); + assert(inlen <= outlen*U); + memcpy(out, in, inlen); + memset((byte *)out+inlen, 0, outlen*U-inlen); + ConditionalByteReverse(order, out, out, RoundUpToMultipleOf(inlen, U)); +} + +inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, byte*) +{ + return block[0]; +} + +inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, word16*) +{ + return (order == BIG_ENDIAN_ORDER) + ? block[1] | (block[0] << 8) + : block[0] | (block[1] << 8); +} + +inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, word32*) +{ + return (order == BIG_ENDIAN_ORDER) + ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) | (word32(block[0]) << 24) + : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) | (word32(block[3]) << 24); +} + +template <class T> +inline T UnalignedGetWord(ByteOrder order, const byte *block, T*dummy=NULL) +{ + return UnalignedGetWordNonTemplate(order, block, dummy); +} + +inline void UnalignedPutWord(ByteOrder order, byte *block, byte value, const byte *xorBlock = NULL) +{ + block[0] = xorBlock ? (value ^ xorBlock[0]) : value; +} + +inline void UnalignedPutWord(ByteOrder order, byte *block, word16 value, const byte *xorBlock = NULL) +{ + if (order == BIG_ENDIAN_ORDER) + { + block[0] = GETBYTE(value, 1); + block[1] = GETBYTE(value, 0); + } + else + { + block[0] = GETBYTE(value, 0); + block[1] = GETBYTE(value, 1); + } + + if (xorBlock) + { + block[0] ^= xorBlock[0]; + block[1] ^= xorBlock[1]; + } +} + +inline void UnalignedPutWord(ByteOrder order, byte *block, word32 value, const byte *xorBlock = NULL) +{ + if (order == BIG_ENDIAN_ORDER) + { + block[0] = GETBYTE(value, 3); + block[1] = GETBYTE(value, 2); + block[2] = GETBYTE(value, 1); + block[3] = GETBYTE(value, 0); + } + else + { + block[0] = GETBYTE(value, 0); + block[1] = GETBYTE(value, 1); + block[2] = GETBYTE(value, 2); + block[3] = GETBYTE(value, 3); + } + + if (xorBlock) + { + block[0] ^= xorBlock[0]; + block[1] ^= xorBlock[1]; + block[2] ^= xorBlock[2]; + block[3] ^= xorBlock[3]; + } +} + +template <class T> +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + if (assumeAligned) + { + assert(IsAligned<T>(block)); + return ConditionalByteReverse(order, *reinterpret_cast<const T *>(block)); + } + else + return UnalignedGetWord<T>(order, block); +} + +template <class T> +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) +{ + result = GetWord<T>(assumeAligned, order, block); +} + +template <class T> +inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULL) +{ + if (assumeAligned) + { + assert(IsAligned<T>(block)); + if (xorBlock) + *reinterpret_cast<T *>(block) = ConditionalByteReverse(order, value) ^ *reinterpret_cast<const T *>(xorBlock); + else + *reinterpret_cast<T *>(block) = ConditionalByteReverse(order, value); + } + else + UnalignedPutWord(order, block, value, xorBlock); +} + +template <class T, class B, bool A=true> +class GetBlock +{ +public: + GetBlock(const void *block) + : m_block((const byte *)block) {} + + template <class U> + inline GetBlock<T, B, A> & operator()(U &x) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord<T>(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +template <class T, class B, bool A=true> +class PutBlock +{ +public: + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + template <class U> + inline PutBlock<T, B, A> & operator()(U x) + { + PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); + m_block += sizeof(T); + if (m_xorBlock) + m_xorBlock += sizeof(T); + return *this; + } + +private: + const byte *m_xorBlock; + byte *m_block; +}; + +template <class T, class B, bool A=true> +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between expression-statements and declarations + static inline GetBlock<T, B, A> Get(const void *block) {return GetBlock<T, B, A>(block);} + typedef PutBlock<T, B, A> Put; +}; + +template <class T> +std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) +{ + if (!NativeByteOrderIs(order)) + value = ByteReverse(value); + + return std::string((char *)&value, sizeof(value)); +} + +template <class T> +T StringToWord(const std::string &str, ByteOrder order = BIG_ENDIAN_ORDER) +{ + T value = 0; + memcpy(&value, str.data(), STDMIN(sizeof(value), str.size())); + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +// ************** help remove warning on g++ *************** + +template <bool overflow> struct SafeShifter; + +template<> struct SafeShifter<true> +{ + template <class T> + static inline T RightShift(T value, unsigned int bits) + { + return 0; + } + + template <class T> + static inline T LeftShift(T value, unsigned int bits) + { + return 0; + } +}; + +template<> struct SafeShifter<false> +{ + template <class T> + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + template <class T> + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +template <unsigned int bits, class T> +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +template <unsigned int bits, class T> +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + +NAMESPACE_END + +#endif // MISC_H diff --git a/modarith.h b/modarith.h new file mode 100644 index 0000000..b97b106 --- /dev/null +++ b/modarith.h @@ -0,0 +1,149 @@ +#ifndef CRYPTOPP_MODARITH_H +#define CRYPTOPP_MODARITH_H + +// implementations are in integer.cpp + +#include "cryptlib.h" +#include "misc.h" +#include "integer.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class ModularArithmetic : public AbstractRing<Integer> +{ +public: + + typedef int RandomizationParameter; + typedef Integer Element; + + ModularArithmetic(const Integer &modulus = Integer::One()) + : modulus(modulus), result((word)0, modulus.reg.size()) {} + + ModularArithmetic(const ModularArithmetic &ma) + : modulus(ma.modulus), result((word)0, modulus.reg.size()) {} + + ModularArithmetic(BufferedTransformation &bt); // construct from BER encoded parameters + + virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);} + + void DEREncode(BufferedTransformation &bt) const; + + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + const Integer& GetModulus() const {return modulus;} + void SetModulus(const Integer &newModulus) {modulus = newModulus; result.reg.resize(modulus.reg.size());} + + virtual bool IsMontgomeryRepresentation() const {return false;} + + virtual Integer ConvertIn(const Integer &a) const + {return a%modulus;} + + virtual Integer ConvertOut(const Integer &a) const + {return a;} + + const Integer& Half(const Integer &a) const; + + bool Equal(const Integer &a, const Integer &b) const + {return a==b;} + + const Integer& Identity() const + {return Integer::Zero();} + + const Integer& Add(const Integer &a, const Integer &b) const; + + Integer& Accumulate(Integer &a, const Integer &b) const; + + const Integer& Inverse(const Integer &a) const; + + const Integer& Subtract(const Integer &a, const Integer &b) const; + + Integer& Reduce(Integer &a, const Integer &b) const; + + const Integer& Double(const Integer &a) const + {return Add(a, a);} + + const Integer& MultiplicativeIdentity() const + {return Integer::One();} + + const Integer& Multiply(const Integer &a, const Integer &b) const + {return result1 = a*b%modulus;} + + const Integer& Square(const Integer &a) const + {return result1 = a.Squared()%modulus;} + + bool IsUnit(const Integer &a) const + {return Integer::Gcd(a, modulus).IsUnit();} + + const Integer& MultiplicativeInverse(const Integer &a) const + {return result1 = a.InverseMod(modulus);} + + const Integer& Divide(const Integer &a, const Integer &b) const + {return Multiply(a, MultiplicativeInverse(b));} + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const; + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + unsigned int MaxElementBitLength() const + {return (modulus-1).BitCount();} + + unsigned int MaxElementByteLength() const + {return (modulus-1).ByteCount();} + + Element RandomElement( RandomNumberGenerator &rng , const RandomizationParameter &ignore_for_now = 0 ) const + // left RandomizationParameter arg as ref in case RandomizationParameter becomes a more complicated struct + { + return Element( rng , Integer( (long) 0) , modulus - Integer( (long) 1 ) ) ; + } + + static const RandomizationParameter DefaultRandomizationParameter ; + +protected: + Integer modulus; + mutable Integer result, result1; + +}; + +// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ; + +//! do modular arithmetics in Montgomery representation for increased speed +class MontgomeryRepresentation : public ModularArithmetic +{ +public: + MontgomeryRepresentation(const Integer &modulus); // modulus must be odd + + virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);} + + bool IsMontgomeryRepresentation() const {return true;} + + Integer ConvertIn(const Integer &a) const + {return (a<<(WORD_BITS*modulus.reg.size()))%modulus;} + + Integer ConvertOut(const Integer &a) const; + + const Integer& MultiplicativeIdentity() const + {return result1 = Integer::Power2(WORD_BITS*modulus.reg.size())%modulus;} + + const Integer& Multiply(const Integer &a, const Integer &b) const; + + const Integer& Square(const Integer &a) const; + + const Integer& MultiplicativeInverse(const Integer &a) const; + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const + {return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing<Integer>::SimultaneousExponentiate(results, base, exponents, exponentsCount);} + +private: + Integer u; + mutable SecAlignedWordBlock workspace; +}; + +NAMESPACE_END + +#endif diff --git a/modes.cpp b/modes.cpp new file mode 100644 index 0000000..0222260 --- /dev/null +++ b/modes.cpp @@ -0,0 +1,227 @@ +// modes.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "modes.h" + +#include "des.h" + +#include "strciphr.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void Modes_TestInstantiations() +{ + CFB_Mode<DES>::Encryption m0; + CFB_Mode<DES>::Decryption m1; + OFB_Mode<DES>::Encryption m2; + CTR_Mode<DES>::Encryption m3; + ECB_Mode<DES>::Encryption m4; + CBC_Mode<DES>::Encryption m5; +} + +// explicit instantiations for Darwin gcc-932.1 +template class CFB_CipherTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> >; +template class CFB_EncryptionTemplate<>; +template class CFB_DecryptionTemplate<>; +template class AdditiveCipherTemplate<>; +template class CFB_CipherTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> >; +template class CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> >; +template class CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> >; +template class AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, OFB_ModePolicy> >; +template class AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, CTR_ModePolicy> >; + +void CipherModeBase::SetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + UncheckedSetKey(params, key, length); // the underlying cipher will check the key length +} + +void CipherModeBase::GetNextIV(byte *IV) +{ + if (!IsForwardTransformation()) + throw NotImplemented("CipherModeBase: GetNextIV() must be called on an encryption object"); + + m_cipher->ProcessBlock(m_register); + memcpy(IV, m_register, BlockSize()); +} + +void CipherModeBase::SetIV(const byte *iv) +{ + if (iv) + Resynchronize(iv); + else if (IsResynchronizable()) + { + if (!CanUseStructuredIVs()) + throw InvalidArgument("CipherModeBase: this cipher mode cannot use a null IV"); + + // use all zeros as default IV + SecByteBlock iv(BlockSize()); + memset(iv, 0, iv.size()); + Resynchronize(iv); + } +} + +void CTR_ModePolicy::SeekToIteration(dword iterationCount) +{ + int carry=0; + for (int i=BlockSize()-1; i>=0 && (iterationCount || carry); i--) + { + unsigned int sum = m_counterArray[i] + byte(iterationCount) + carry; + m_counterArray[i] = (byte) sum; + carry = sum >> 8; + iterationCount >>= 8; + } +} + +void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + unsigned int maxBlocks = m_cipher->OptimalNumberOfParallelBlocks(); + unsigned int sizeIncrement = maxBlocks * m_cipher->BlockSize(); + while (iterationCount >= maxBlocks) + { + ProcessMultipleBlocks(output, input, maxBlocks); + output += sizeIncrement; + input += sizeIncrement; + iterationCount -= maxBlocks; + } + if (iterationCount > 0) + ProcessMultipleBlocks(output, input, iterationCount); +} +void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv) +{ + unsigned int s = BlockSize(); + memcpy(m_register, iv, s); + m_counterArray.New(s * m_cipher->OptimalNumberOfParallelBlocks()); + memcpy(m_counterArray, iv, s); +} + +void BlockOrientedCipherModeBase::UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + const byte *iv = params.GetValueWithDefault(Name::IV(), (const byte *)NULL); + SetIV(iv); +} + +void BlockOrientedCipherModeBase::ProcessData(byte *outString, const byte *inString, unsigned int length) +{ + unsigned int s = BlockSize(); + assert(length % s == 0); + unsigned int alignment = m_cipher->BlockAlignment(); + bool requireAlignedInput = RequireAlignedInput(); + + if (IsAlignedOn(outString, alignment)) + { + if (!requireAlignedInput || IsAlignedOn(inString, alignment)) + ProcessBlocks(outString, inString, length / s); + else + { + memcpy(outString, inString, length); + ProcessBlocks(outString, outString, length / s); + } + } + else + { + while (length) + { + if (!requireAlignedInput || IsAlignedOn(inString, alignment)) + ProcessBlocks(m_buffer, inString, 1); + else + { + memcpy(m_buffer, inString, s); + ProcessBlocks(m_buffer, m_buffer, 1); + } + memcpy(outString, m_buffer, s); + length -= s; + } + } +} + +void CBC_Encryption::ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks) +{ + unsigned int blockSize = BlockSize(); + while (numberOfBlocks--) + { + xorbuf(m_register, inString, blockSize); + m_cipher->ProcessBlock(m_register); + memcpy(outString, m_register, blockSize); + inString += blockSize; + outString += blockSize; + } +} + +void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, unsigned int length) +{ + if (length <= BlockSize()) + { + if (!m_stolenIV) + throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing"); + + // steal from IV + memcpy(outString, m_register, length); + outString = m_stolenIV; + } + else + { + // steal from next to last block + xorbuf(m_register, inString, BlockSize()); + m_cipher->ProcessBlock(m_register); + inString += BlockSize(); + length -= BlockSize(); + memcpy(outString+BlockSize(), m_register, length); + } + + // output last full ciphertext block + xorbuf(m_register, inString, length); + m_cipher->ProcessBlock(m_register); + memcpy(outString, m_register, BlockSize()); +} + +void CBC_Decryption::ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks) +{ + unsigned int blockSize = BlockSize(); + while (numberOfBlocks--) + { + memcpy(m_temp, inString, blockSize); + m_cipher->ProcessBlock(m_temp, outString); + xorbuf(outString, m_register, blockSize); + m_register.swap(m_temp); + inString += blockSize; + outString += blockSize; + } +} + +void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, unsigned int length) +{ + const byte *pn, *pn1; + bool stealIV = length <= BlockSize(); + + if (stealIV) + { + pn = inString; + pn1 = m_register; + } + else + { + pn = inString + BlockSize(); + pn1 = inString; + length -= BlockSize(); + } + + // decrypt last partial plaintext block + memcpy(m_temp, pn1, BlockSize()); + m_cipher->ProcessBlock(m_temp); + xorbuf(m_temp, pn, length); + + if (stealIV) + memcpy(outString, m_temp, length); + else + { + memcpy(outString+BlockSize(), m_temp, length); + // decrypt next to last plaintext block + memcpy(m_temp, pn, length); + m_cipher->ProcessBlock(m_temp); + xorbuf(outString, m_temp, m_register, BlockSize()); + } +} + +NAMESPACE_END @@ -0,0 +1,380 @@ +#ifndef CRYPTOPP_MODES_H +#define CRYPTOPP_MODES_H + +/*! \file +*/ + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "strciphr.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Cipher mode documentation. See NIST SP 800-38A for definitions of these modes. + +/*! Each class derived from this one defines two types, Encryption and Decryption, + both of which implement the SymmetricCipher interface. + For each mode there are two classes, one of which is a template class, + and the other one has a name that ends in "_ExternalCipher". + The "external cipher" mode objects hold a reference to the underlying block cipher, + instead of holding an instance of it. The reference must be passed in to the constructor. + For the "cipher holder" classes, the CIPHER template parameter should be a class + derived from BlockCipherDocumentation, for example DES or AES. +*/ +struct CipherModeDocumentation : public SymmetricCipherDocumentation +{ +}; + +class CipherModeBase : public SymmetricCipher +{ +public: + unsigned int MinKeyLength() const {return m_cipher->MinKeyLength();} + unsigned int MaxKeyLength() const {return m_cipher->MaxKeyLength();} + unsigned int DefaultKeyLength() const {return m_cipher->DefaultKeyLength();} + unsigned int GetValidKeyLength(unsigned int n) const {return m_cipher->GetValidKeyLength(n);} + bool IsValidKeyLength(unsigned int n) const {return m_cipher->IsValidKeyLength(n);} + + void SetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms = g_nullNameValuePairs); + + unsigned int OptimalDataAlignment() const {return BlockSize();} + + unsigned int IVSize() const {return BlockSize();} + void GetNextIV(byte *IV); + virtual IV_Requirement IVRequirement() const =0; + +protected: + inline unsigned int BlockSize() const {assert(m_register.size() > 0); return m_register.size();} + void SetIV(const byte *iv); + virtual void SetFeedbackSize(unsigned int feedbackSize) + { + if (!(feedbackSize == 0 || feedbackSize == BlockSize())) + throw InvalidArgument("CipherModeBase: feedback size cannot be specified for this cipher mode"); + } + virtual void ResizeBuffers() + { + m_register.New(m_cipher->BlockSize()); + } + virtual void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) =0; + + BlockCipher *m_cipher; + SecByteBlock m_register; +}; + +template <class POLICY_INTERFACE> +class ModePolicyCommonTemplate : public CipherModeBase, public POLICY_INTERFACE +{ + unsigned int GetAlignment() const {return m_cipher->BlockAlignment();} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) + { + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + int feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0); + SetFeedbackSize(feedbackSize); + const byte *iv = params.GetValueWithDefault(Name::IV(), (const byte *)NULL); + SetIV(iv); + } +}; + +class CFB_ModePolicy : public ModePolicyCommonTemplate<CFB_CipherAbstractPolicy> +{ +public: + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return m_feedbackSize;} + byte * GetRegisterBegin() {return m_register + BlockSize() - m_feedbackSize;} + void TransformRegister() + { + m_cipher->ProcessBlock(m_register, m_temp); + memmove(m_register, m_register+m_feedbackSize, BlockSize()-m_feedbackSize); + memcpy(m_register+BlockSize()-m_feedbackSize, m_temp, m_feedbackSize); + } + void CipherResynchronize(const byte *iv) + { + memcpy(m_register, iv, BlockSize()); + TransformRegister(); + } + void SetFeedbackSize(unsigned int feedbackSize) + { + if (feedbackSize > BlockSize()) + throw InvalidArgument("CFB_Mode: invalid feedback size"); + m_feedbackSize = feedbackSize ? feedbackSize : BlockSize(); + } + void ResizeBuffers() + { + CipherModeBase::ResizeBuffers(); + m_temp.New(BlockSize()); + } + + SecByteBlock m_temp; + unsigned int m_feedbackSize; +}; + +class OFB_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy> +{ + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return 1;} + void WriteKeystream(byte *keystreamBuffer, unsigned int iterationCount) + { + assert(iterationCount == 1); + m_cipher->ProcessBlock(keystreamBuffer); + } + void CipherResynchronize(byte *keystreamBuffer, const byte *iv) + { + memcpy(keystreamBuffer, iv, BlockSize()); + } + bool IsRandomAccess() const {return false;} + IV_Requirement IVRequirement() const {return STRUCTURED_IV;} +}; + +class CTR_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy> +{ + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *buffer, unsigned int iterationCount) + {OperateKeystream(WRITE_KEYSTREAM, buffer, NULL, iterationCount);} + bool CanOperateKeystream() const {return true;} + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv); + bool IsRandomAccess() const {return true;} + void SeekToIteration(dword iterationCount); + IV_Requirement IVRequirement() const {return STRUCTURED_IV;} + + static inline void IncrementCounterByOne(byte *output, const byte *input, unsigned int s) + { + for (int i=s-1, carry=1; i>=0 && carry; i--) + carry = !(output[i] = input[i]+1); + } + inline void ProcessMultipleBlocks(byte *output, const byte *input, unsigned int n) + { + unsigned int s = BlockSize(), j = 0; + for (unsigned int i=1; i<n; i++, j+=s) + IncrementCounterByOne(m_counterArray + j + s, m_counterArray + j, s); + m_cipher->ProcessAndXorMultipleBlocks(m_counterArray, input, output, n); + IncrementCounterByOne(m_counterArray, m_counterArray + s*(n-1), s); + } + + SecByteBlock m_counterArray; +}; + +class BlockOrientedCipherModeBase : public CipherModeBase +{ +public: + void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + unsigned int MandatoryBlockSize() const {return BlockSize();} + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return false;} + bool IsForwardTransformation() const {return m_cipher->IsForwardTransformation();} + void Resynchronize(const byte *iv) {memcpy(m_register, iv, BlockSize());} + void ProcessData(byte *outString, const byte *inString, unsigned int length); + +protected: + bool RequireAlignedInput() const {return true;} + virtual void ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks) =0; + void ResizeBuffers() + { + CipherModeBase::ResizeBuffers(); + m_buffer.New(BlockSize()); + } + + SecByteBlock m_buffer; +}; + +class ECB_OneWay : public BlockOrientedCipherModeBase +{ +public: + IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;} + unsigned int OptimalBlockSize() const {return BlockSize() * m_cipher->OptimalNumberOfParallelBlocks();} + void ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks) + {m_cipher->ProcessAndXorMultipleBlocks(inString, NULL, outString, numberOfBlocks);} +}; + +class CBC_ModeBase : public BlockOrientedCipherModeBase +{ +public: + IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;} + bool RequireAlignedInput() const {return false;} + unsigned int MinLastBlockSize() const {return 0;} +}; + +class CBC_Encryption : public CBC_ModeBase +{ +public: + void ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks); +}; + +class CBC_CTS_Encryption : public CBC_Encryption +{ +public: + void SetStolenIV(byte *iv) {m_stolenIV = iv;} + +protected: + void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) + { + CBC_Encryption::UncheckedSetKey(params, key, length); + m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), (byte *)NULL); + } + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length); + + byte *m_stolenIV; +}; + +class CBC_Decryption : public CBC_ModeBase +{ +public: + void ProcessBlocks(byte *outString, const byte *inString, unsigned int numberOfBlocks); + +protected: + void ResizeBuffers() + { + BlockOrientedCipherModeBase::ResizeBuffers(); + m_temp.New(BlockSize()); + } + SecByteBlock m_temp; +}; + +class CBC_CTS_Decryption : public CBC_Decryption +{ + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length); +}; + +//! . +template <class CIPHER, class BASE> +class CipherModeFinalTemplate_CipherHolder : public ObjectHolder<CIPHER>, public BASE +{ +public: + CipherModeFinalTemplate_CipherHolder() + { + m_cipher = &m_object; + ResizeBuffers(); + } + CipherModeFinalTemplate_CipherHolder(const byte *key, unsigned int length) + { + m_cipher = &m_object; + SetKey(key, length); + } + CipherModeFinalTemplate_CipherHolder(const byte *key, unsigned int length, const byte *iv, int feedbackSize = 0) + { + m_cipher = &m_object; + SetKey(key, length, MakeParameters("IV", iv)("FeedbackSize", feedbackSize)); + } +}; + +//! . +template <class BASE> +class CipherModeFinalTemplate_ExternalCipher : public BASE +{ +public: + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher, const byte *iv = NULL, int feedbackSize = 0) + { + m_cipher = &cipher; + ResizeBuffers(); + SetFeedbackSize(feedbackSize); + SetIV(iv); + } +}; + +//! CFB mode +template <class CIPHER> +struct CFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Decryption; +}; + +//! CFB mode, external cipher +struct CFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Decryption; +}; + +//! OFB mode +template <class CIPHER> +struct OFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, OFB_ModePolicy> > > > Encryption; + typedef Encryption Decryption; +}; + +//! OFB mode, external cipher +struct OFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, OFB_ModePolicy> > > > Encryption; + typedef Encryption Decryption; +}; + +//! CTR mode +template <class CIPHER> +struct CTR_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, CTR_ModePolicy> > > > Encryption; + typedef Encryption Decryption; +}; + +//! CTR mode, external cipher +struct CTR_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, CTR_ModePolicy> > > > Encryption; + typedef Encryption Decryption; +}; + +//! ECB mode +template <class CIPHER> +struct ECB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ECB_OneWay> Encryption; + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, ECB_OneWay> Decryption; +}; + +//! ECB mode, external cipher +struct ECB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<ECB_OneWay> Encryption; + typedef Encryption Decryption; +}; + +//! CBC mode +template <class CIPHER> +struct CBC_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, CBC_Encryption> Encryption; + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, CBC_Decryption> Decryption; +}; + +//! CBC mode, external cipher +struct CBC_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<CBC_Encryption> Encryption; + typedef CipherModeFinalTemplate_ExternalCipher<CBC_Decryption> Decryption; +}; + +//! CBC mode with ciphertext stealing +template <class CIPHER> +struct CBC_CTS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, CBC_CTS_Encryption> Encryption; + typedef CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, CBC_CTS_Decryption> Decryption; +}; + +//! CBC mode with ciphertext stealing, external cipher +struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Encryption> Encryption; + typedef CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Decryption> Decryption; +}; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY +typedef CFB_Mode_ExternalCipher::Encryption CFBEncryption; +typedef CFB_Mode_ExternalCipher::Decryption CFBDecryption; +typedef OFB_Mode_ExternalCipher::Encryption OFB; +typedef OFB_Mode_ExternalCipher::Encryption CounterMode; +#endif + +NAMESPACE_END + +#endif diff --git a/modexppc.cpp b/modexppc.cpp new file mode 100644 index 0000000..454854d --- /dev/null +++ b/modexppc.cpp @@ -0,0 +1,80 @@ +// modexppc.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "modexppc.h" +#include "asn.h" + +#include "algebra.cpp" +#include "eprecomp.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +template class DL_FixedBasePrecomputationImpl<Integer>; + +/* +ModExpPrecomputation& ModExpPrecomputation::operator=(const ModExpPrecomputation &rhs) +{ + m_base = rhs.m_base; + m_mr = rhs.m_mr; + m_ep = rhs.m_ep; + if (m_mr.get() != NULL) + m_ep.m_group = &m_mr->MultiplicativeGroup(); + return *this; +} + +void ModExpPrecomputation::SetModulusAndBase(const Integer &modulus, const Integer &base) +{ + m_base = base; + if (m_mr.get() == NULL || modulus != m_mr->GetModulus()) + m_mr.reset(new MontgomeryRepresentation(modulus)); + m_ep.SetGroupAndBase(m_mr->MultiplicativeGroup(), m_mr->ConvertIn(base)); +} + +void ModExpPrecomputation::SetBase(const Integer &base) +{ + m_base = base; + m_ep.SetGroupAndBase(m_mr->MultiplicativeGroup(), m_mr->ConvertIn(base)); +} + +void ModExpPrecomputation::Precompute(unsigned int maxExpBits, unsigned int storage) +{ + m_ep.Precompute(maxExpBits, storage); +} + +void ModExpPrecomputation::Load(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1); + m_ep.m_exponentBase.BERDecode(seq); + m_ep.m_windowSize = m_ep.m_exponentBase.BitCount() - 1; + m_ep.m_bases.clear(); + while (!seq.EndReached()) + m_ep.m_bases.push_back(Integer(seq)); + if (!m_ep.m_bases.empty()) + m_base = m_mr->ConvertOut(m_ep.m_bases[0]); + seq.MessageEnd(); +} + +void ModExpPrecomputation::Save(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned<word32>(seq, 1); // version + m_ep.m_exponentBase.DEREncode(seq); + for (unsigned i=0; i<m_ep.m_bases.size(); i++) + m_ep.m_bases[i].DEREncode(seq); + seq.MessageEnd(); +} + +Integer ModExpPrecomputation::Exponentiate(const Integer &exponent) const +{ + return m_mr->ConvertOut(m_ep.Exponentiate(exponent)); +} + +Integer ModExpPrecomputation::CascadeExponentiate(const Integer &exponent, const DL_FixedBasePrecomputation<Integer> &pc2, const Integer &exponent2) const +{ + return m_mr->ConvertOut(m_ep.CascadeExponentiate(exponent, static_cast<const ModExpPrecomputation &>(pc2).m_ep, exponent2)); +} +*/ + +NAMESPACE_END diff --git a/modexppc.h b/modexppc.h new file mode 100644 index 0000000..05cdaa6 --- /dev/null +++ b/modexppc.h @@ -0,0 +1,32 @@ +#ifndef CRYPTOPP_MODEXPPC_H +#define CRYPTOPP_MODEXPPC_H + +#include "modarith.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +class ModExpPrecomputation : public DL_GroupPrecomputation<Integer> +{ +public: + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &v) const {return m_mr->ConvertIn(v);} + virtual Element ConvertOut(const Element &v) const {return m_mr->ConvertOut(v);} + const AbstractGroup<Element> & GetGroup() const {return m_mr->MultiplicativeGroup();} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_mr.reset(new MontgomeryRepresentation(v));} + const Integer & GetModulus() const {return m_mr->GetModulus();} + +private: + value_ptr<MontgomeryRepresentation> m_mr; +}; + +NAMESPACE_END + +#endif diff --git a/mqueue.cpp b/mqueue.cpp new file mode 100644 index 0000000..2bac976 --- /dev/null +++ b/mqueue.cpp @@ -0,0 +1,182 @@ +// mqueue.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "mqueue.h" + +NAMESPACE_BEGIN(CryptoPP) + +MessageQueue::MessageQueue(unsigned int nodeSize) + : m_queue(nodeSize), m_lengths(1, 0U), m_messageCounts(1, 0U) +{ +} + +unsigned int MessageQueue::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + if (begin >= MaxRetrievable()) + return 0; + + return m_queue.CopyRangeTo2(target, begin, STDMIN(MaxRetrievable(), end), channel, blocking); +} + +unsigned int MessageQueue::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + transferBytes = STDMIN(MaxRetrievable(), transferBytes); + unsigned int blockedBytes = m_queue.TransferTo2(target, transferBytes, channel, blocking); + m_lengths.front() -= transferBytes; + return blockedBytes; +} + +bool MessageQueue::GetNextMessage() +{ + if (NumberOfMessages() > 0 && !AnyRetrievable()) + { + m_lengths.pop_front(); + if (m_messageCounts[0] == 0 && m_messageCounts.size() > 1) + m_messageCounts.pop_front(); + return true; + } + else + return false; +} + +unsigned int MessageQueue::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + ByteQueue::Walker walker(m_queue); + std::deque<unsigned long>::const_iterator it = m_lengths.begin(); + unsigned int i; + for (i=0; i<count && it != --m_lengths.end(); ++i, ++it) + { + walker.TransferTo(target, *it, channel); + if (GetAutoSignalPropagation()) + target.ChannelMessageEnd(channel, GetAutoSignalPropagation()-1); + } + return i; +} + +void MessageQueue::swap(MessageQueue &rhs) +{ + m_queue.swap(rhs.m_queue); + m_lengths.swap(rhs.m_lengths); +} + +const byte * MessageQueue::Spy(unsigned int &contiguousSize) const +{ + const byte *result = m_queue.Spy(contiguousSize); + contiguousSize = (unsigned int)STDMIN((unsigned long)contiguousSize, MaxRetrievable()); + return result; +} + +// ************************************************************* + +unsigned int EqualityComparisonFilter::MapChannel(const std::string &channel) const +{ + if (channel == m_firstChannel) + return 0; + else if (channel == m_secondChannel) + return 1; + else + return 2; +} + +unsigned int EqualityComparisonFilter::ChannelPut2(const std::string &channel, const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("EqualityComparisonFilter"); + + unsigned int i = MapChannel(channel); + + if (i == 2) + return Output(3, inString, length, messageEnd, blocking, channel); + else if (m_mismatchDetected) + return 0; + else + { + MessageQueue &q1 = m_q[i], &q2 = m_q[1-i]; + + if (q2.AnyMessages() && q2.MaxRetrievable() < length) + goto mismatch; + + while (length > 0 && q2.AnyRetrievable()) + { + unsigned int len = length; + const byte *data = q2.Spy(len); + len = STDMIN(len, length); + if (memcmp(inString, data, len) != 0) + goto mismatch; + inString += len; + length -= len; + q2.Skip(len); + } + + q1.Put(inString, length); + + if (messageEnd) + { + if (q2.AnyRetrievable()) + goto mismatch; + else if (q2.AnyMessages()) + q2.GetNextMessage(); + else if (q2.NumberOfMessageSeries() > 0) + goto mismatch; + else + q1.MessageEnd(); + } + + return 0; + +mismatch: + return HandleMismatchDetected(blocking); + } +} + +void EqualityComparisonFilter::ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters, int propagation) +{ + unsigned int i = MapChannel(channel); + + if (i == 2) + PropagateInitialize(parameters, propagation, channel); + else + { + m_q[i].Initialize(); + m_mismatchDetected = false; + } +} + +bool EqualityComparisonFilter::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + unsigned int i = MapChannel(channel); + + if (i == 2) + { + OutputMessageSeriesEnd(4, propagation, blocking, channel); + return false; + } + else if (m_mismatchDetected) + return false; + else + { + MessageQueue &q1 = m_q[i], &q2 = m_q[1-i]; + + if (q2.AnyRetrievable() || q2.AnyMessages()) + goto mismatch; + else if (q2.NumberOfMessageSeries() > 0) + return Output(2, (const byte *)"\1", 1, 0, blocking) != 0; + else + q1.MessageSeriesEnd(); + + return false; + +mismatch: + return HandleMismatchDetected(blocking); + } +} + +bool EqualityComparisonFilter::HandleMismatchDetected(bool blocking) +{ + m_mismatchDetected = true; + if (m_throwIfNotEqual) + throw MismatchDetected(); + return Output(1, (const byte *)"\0", 1, 0, blocking) != 0; +} + +NAMESPACE_END diff --git a/mqueue.h b/mqueue.h new file mode 100644 index 0000000..edc701a --- /dev/null +++ b/mqueue.h @@ -0,0 +1,98 @@ +#ifndef CRYPTOPP_MQUEUE_H +#define CRYPTOPP_MQUEUE_H + +#include "queue.h" +#include "filters.h" +#include <deque> + +NAMESPACE_BEGIN(CryptoPP) + +//! Message Queue +class MessageQueue : public AutoSignaling<BufferedTransformation> +{ +public: + MessageQueue(unsigned int nodeSize=256); + + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_queue.IsolatedInitialize(parameters); m_lengths.assign(1, 0U); m_messageCounts.assign(1, 0U);} + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + { + m_queue.Put(begin, length); + m_lengths.back() += length; + if (messageEnd) + { + m_lengths.push_back(0); + m_messageCounts.back()++; + } + return 0; + } + bool IsolatedFlush(bool hardFlush, bool blocking) {return false;} + bool IsolatedMessageSeriesEnd(bool blocking) + {m_messageCounts.push_back(0); return false;} + + unsigned long MaxRetrievable() const + {return m_lengths.front();} + bool AnyRetrievable() const + {return m_lengths.front() > 0;} + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + + unsigned long TotalBytesRetrievable() const + {return m_queue.MaxRetrievable();} + unsigned int NumberOfMessages() const + {return m_lengths.size()-1;} + bool GetNextMessage(); + + unsigned int NumberOfMessagesInThisSeries() const + {return m_messageCounts[0];} + unsigned int NumberOfMessageSeries() const + {return m_messageCounts.size()-1;} + + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=NULL_CHANNEL) const; + + const byte * Spy(unsigned int &contiguousSize) const; + + void swap(MessageQueue &rhs); + +private: + ByteQueue m_queue; + std::deque<unsigned long> m_lengths, m_messageCounts; +}; + + +//! A filter that checks messages on two channels for equality +class EqualityComparisonFilter : public Unflushable<Multichannel<Filter> > +{ +public: + struct MismatchDetected : public Exception {MismatchDetected() : Exception(DATA_INTEGRITY_CHECK_FAILED, "EqualityComparisonFilter: did not receive the same data on two channels") {}}; + + /*! if throwIfNotEqual is false, this filter will output a '\0' byte when it detects a mismatch, '\1' otherwise */ + EqualityComparisonFilter(BufferedTransformation *attachment=NULL, bool throwIfNotEqual=true, const std::string &firstChannel="0", const std::string &secondChannel="1") + : Unflushable<Multichannel<Filter> >(attachment), m_throwIfNotEqual(throwIfNotEqual), m_mismatchDetected(false) + , m_firstChannel(firstChannel), m_secondChannel(secondChannel) {} + + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking); + + void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + +private: + unsigned int MapChannel(const std::string &channel) const; + bool HandleMismatchDetected(bool blocking); + + bool m_throwIfNotEqual, m_mismatchDetected; + std::string m_firstChannel, m_secondChannel; + MessageQueue m_q[2]; +}; + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::MessageQueue &a, CryptoPP::MessageQueue &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif @@ -0,0 +1,13 @@ +// mqv.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "mqv.h" + +NAMESPACE_BEGIN(CryptoPP) + +void TestInstantiations_MQV() +{ + MQV mqv; +} + +NAMESPACE_END @@ -0,0 +1,141 @@ +#ifndef CRYPTOPP_MQV_H +#define CRYPTOPP_MQV_H + +/** \file +*/ + +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption> +class MQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef MQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain; + + MQV_Domain() {} + + MQV_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + MQV_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + template <class T1, class T2> + MQV_Domain(T1 v1, T2 v2) + {m_groupParameters.Initialize(v1, v2);} + + template <class T1, class T2, class T3> + MQV_Domain(T1 v1, T2 v2, T2 v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + template <class T1, class T2, class T3, class T4> + MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();} + + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + try + { + const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters(); + Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV = params.DecodeElement(ephemeralOtherPublicKey, true); + + Integer s(staticPrivateKey, StaticPrivateKeyLength()); + Integer u(ephemeralPrivateKey, StaticPrivateKeyLength()); + Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false); + + const Integer &r = params.GetSubgroupOrder(); + Integer h2 = Integer::Power2((r.BitCount()+1)/2); + Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r; + Integer tt = h2 + params.ConvertElementToInteger(VV) % h2; + + if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION) + { + Element P = params.ExponentiateElement(WW, tt); + P = m_groupParameters.MultiplyElements(P, VV); + Element R[2]; + const Integer e2[2] = {r, e}; + params.SimultaneousExponentiate(R, P, e2, 2); + if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1])) + return false; + params.EncodeElement(false, R[1], agreedValue); + } + else + { + const Integer &k = params.GetCofactor(); + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + e = ModularArithmetic(r).Divide(e, k); + Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r)); + if (params.IsIdentity(P)) + return false; + params.EncodeElement(false, P, agreedValue); + } + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +private: + DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +//! Menezes-Qu-Vanstone in GF(p) with key validation, AKA <a href="http://www.weidai.com/scan-mirror/ka.html#MQV">MQV</a> +typedef MQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> MQV; + +NAMESPACE_END + +#endif diff --git a/mqv1024.dat b/mqv1024.dat new file mode 100644 index 0000000..415377a --- /dev/null +++ b/mqv1024.dat @@ -0,0 +1 @@ +3082011E028181009A21FC66469293103CEF66960B17880F905C738DB692B7481922FC2D454D14067C6BFC158B93FCC1B8D128D4D86D893082F8A3592238EE8B693B6245F26F55968D7D13752D6BFBA271E8E36E11482815D887BB9F6B600E820E7E2AF2EE6ECDBC1CB35B12A4EF48A8907C090482DE7D49B751BB3A50F78BE29506114BC85D3A6102150C896422EC558A74B883BA85E2F10D4A58F28D2B09028180350C4BB19C0A9B224E5E1BACCC1B1952A97628021B4673831C851C3280F06D3EFA73DAE27E5D4E4A0499E0B2B9A369649E883A1F260EF250B5CCF3E3C922332B210EEA07D3BF92210BA7A7374A30DDDE3D1B3D575B77CD36B001EAE4A2A3BFAFF12FCE74F3330B30ACF6DCFF580ECBFB5B00FD5DD2B8EA9DB09C7E1C7100BD67
\ No newline at end of file diff --git a/mqv2048.dat b/mqv2048.dat new file mode 100644 index 0000000..ef32456 --- /dev/null +++ b/mqv2048.dat @@ -0,0 +1 @@ +308202280282010100A5C07CE5BF0894C0BA8752F4D9A6D0BF6556D325B618A655CCFE3EEC85B56D47DBDF5A9A5C8588AE6F4C44BBCB339E869A21BE057A243DC797B912C547FBA359C4FC9965C72278370AB6C0DD246197A8D83A08C69425786482D1744C41FBB3C36BEA5963C05B0778AAEF9230C3E2E12072268038E5ADB6433542F94D8C25A6A1785E4D2D97AF119F2139E69AECA46F11B344785A0B1B280CF8D678AB9627780271A350A9B15B92E105F14733C5F15C1753F7C48A645FAAAC1BFA266B5AD6F7C46350465DA31150ABB10FF63FD6C01C849DFCD5645C5D1AF8B967372449DF90D02177E12439BD36A1EED1FAEDB8166927F755B71A5368CC27CD00AB5CF04601E7021D03134944D9AA15697107F48AC5621A1531649AD5EE8EEC1D1F282B5481028201003468652FBB1E3C7F2FBB99A89EA14FB9205F534943034CDE9D9CC57A790D9713EC7B21032EAA8ED2B24FFABD612EDADFC9265964C753AE276380294D4D16C63389A4C392A0058EF1549F6C0D13C4A09759C67650A51F7362B38C61AF2942A6004BB8C3CD4C489E66DE1567E2306821788A519727CD27945DBC5778AC6E8B1DFC05573D76DF9E9AA4F1CE657A2A07BEF833091614C0A6065507BD51099C54148327903626DE6D01FEC9A7F5F9A901C90E219D452C2E2A90AA2303A52776EF174CC85C1AA4F28924B1DFF3E3C5538D820A422374DCFB0D14D620AE282A72416C6506F02D3ED1E6208F66B9DB49294D8D605D7D146BB6A970211289B1BE7AB12531
\ No newline at end of file diff --git a/nbtheory.cpp b/nbtheory.cpp new file mode 100644 index 0000000..852beb5 --- /dev/null +++ b/nbtheory.cpp @@ -0,0 +1,1127 @@ +// nbtheory.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "nbtheory.h" +#include "modarith.h" +#include "algparam.h" + +#include <math.h> +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +const unsigned int maxPrimeTableSize = 3511; // last prime 32719 +const word lastSmallPrime = 32719; +unsigned int primeTableSize=552; + +word primeTable[maxPrimeTableSize] = + {2, 3, 5, 7, 11, 13, 17, 19, + 23, 29, 31, 37, 41, 43, 47, 53, + 59, 61, 67, 71, 73, 79, 83, 89, + 97, 101, 103, 107, 109, 113, 127, 131, + 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, + 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, + 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, + 571, 577, 587, 593, 599, 601, 607, 613, + 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, + 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, + 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, + 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, + 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, + 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, + 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, + 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, + 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, + 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, + 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, + 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, + 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, + 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, + 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, + 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, + 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, + 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, + 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, + 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, + 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, + 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, + 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, + 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, + 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, + 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, + 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, + 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, + 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, + 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, + 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, + 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, + 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, + 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, + 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, + 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, + 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, + 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, + 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, + 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, + 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003}; + +void BuildPrimeTable() +{ + unsigned int p=primeTable[primeTableSize-1]; + for (unsigned int i=primeTableSize; i<maxPrimeTableSize; i++) + { + int j; + do + { + p+=2; + for (j=1; j<54; j++) + if (p%primeTable[j] == 0) + break; + } while (j!=54); + primeTable[i] = p; + } + primeTableSize = maxPrimeTableSize; + assert(primeTable[primeTableSize-1] == lastSmallPrime); +} + +bool IsSmallPrime(const Integer &p) +{ + BuildPrimeTable(); + + if (p.IsPositive() && p <= primeTable[primeTableSize-1]) + return std::binary_search(primeTable, primeTable+primeTableSize, (word)p.ConvertToLong()); + else + return false; +} + +bool TrialDivision(const Integer &p, unsigned bound) +{ + assert(primeTable[primeTableSize-1] >= bound); + + unsigned int i; + for (i = 0; primeTable[i]<bound; i++) + if ((p % primeTable[i]) == 0) + return true; + + if (bound == primeTable[i]) + return (p % bound == 0); + else + return false; +} + +bool SmallDivisorsTest(const Integer &p) +{ + BuildPrimeTable(); + return !TrialDivision(p, primeTable[primeTableSize-1]); +} + +bool IsFermatProbablePrime(const Integer &n, const Integer &b) +{ + if (n <= 3) + return n==2 || n==3; + + assert(n>3 && b>1 && b<n-1); + return a_exp_b_mod_c(b, n-1, n)==1; +} + +bool IsStrongProbablePrime(const Integer &n, const Integer &b) +{ + if (n <= 3) + return n==2 || n==3; + + assert(n>3 && b>1 && b<n-1); + + if ((n.IsEven() && n!=2) || GCD(b, n) != 1) + return false; + + Integer nminus1 = (n-1); + unsigned int a; + + // calculate a = largest power of 2 that divides (n-1) + for (a=0; ; a++) + if (nminus1.GetBit(a)) + break; + Integer m = nminus1>>a; + + Integer z = a_exp_b_mod_c(b, m, n); + if (z==1 || z==nminus1) + return true; + for (unsigned j=1; j<a; j++) + { + z = z.Squared()%n; + if (z==nminus1) + return true; + if (z==1) + return false; + } + return false; +} + +bool RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds) +{ + if (n <= 3) + return n==2 || n==3; + + assert(n>3); + + Integer b; + for (unsigned int i=0; i<rounds; i++) + { + b.Randomize(rng, 2, n-2); + if (!IsStrongProbablePrime(n, b)) + return false; + } + return true; +} + +bool IsLucasProbablePrime(const Integer &n) +{ + if (n <= 1) + return false; + + if (n.IsEven()) + return n==2; + + assert(n>2); + + Integer b=3; + unsigned int i=0; + int j; + + while ((j=Jacobi(b.Squared()-4, n)) == 1) + { + if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square + return false; + ++b; ++b; + } + + if (j==0) + return false; + else + return Lucas(n+1, b, n)==2; +} + +bool IsStrongLucasProbablePrime(const Integer &n) +{ + if (n <= 1) + return false; + + if (n.IsEven()) + return n==2; + + assert(n>2); + + Integer b=3; + unsigned int i=0; + int j; + + while ((j=Jacobi(b.Squared()-4, n)) == 1) + { + if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square + return false; + ++b; ++b; + } + + if (j==0) + return false; + + Integer n1 = n+1; + unsigned int a; + + // calculate a = largest power of 2 that divides n1 + for (a=0; ; a++) + if (n1.GetBit(a)) + break; + Integer m = n1>>a; + + Integer z = Lucas(m, b, n); + if (z==2 || z==n-2) + return true; + for (i=1; i<a; i++) + { + z = (z.Squared()-2)%n; + if (z==n-2) + return true; + if (z==2) + return false; + } + return false; +} + +bool IsPrime(const Integer &p) +{ + static const Integer lastSmallPrimeSquared = Integer(lastSmallPrime).Squared(); + + if (p <= lastSmallPrime) + return IsSmallPrime(p); + else if (p <= lastSmallPrimeSquared) + return SmallDivisorsTest(p); + else + return SmallDivisorsTest(p) && IsStrongProbablePrime(p, 3) && IsStrongLucasProbablePrime(p); +} + +bool VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level) +{ + bool pass = IsPrime(p) && RabinMillerTest(rng, p, 1); + if (level >= 1) + pass = pass && RabinMillerTest(rng, p, 10); + return pass; +} + +unsigned int PrimeSearchInterval(const Integer &max) +{ + return max.BitCount(); +} + +static inline bool FastProbablePrimeTest(const Integer &n) +{ + return IsStrongProbablePrime(n,2); +} + +AlgorithmParameters<AlgorithmParameters<AlgorithmParameters<NullNameValuePairs, Integer::RandomNumberType>, Integer>, Integer> + MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength) +{ + if (productBitLength < 16) + throw InvalidArgument("invalid bit length"); + + Integer minP, maxP; + + if (productBitLength%2==0) + { + minP = Integer(182) << (productBitLength/2-8); + maxP = Integer::Power2(productBitLength/2)-1; + } + else + { + minP = Integer::Power2((productBitLength-1)/2); + maxP = Integer(181) << ((productBitLength+1)/2-8); + } + + return MakeParameters("RandomNumberType", Integer::PRIME)("Min", minP)("Max", maxP); +} + +class PrimeSieve +{ +public: + // delta == 1 or -1 means double sieve with p = 2*q + delta + PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta=0); + bool NextCandidate(Integer &c); + + void DoSieve(); + static void SieveSingle(std::vector<bool> &sieve, word p, const Integer &first, const Integer &step, word stepInv); + + Integer m_first, m_last, m_step; + signed int m_delta; + word m_next; + std::vector<bool> m_sieve; +}; + +PrimeSieve::PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta) + : m_first(first), m_last(last), m_step(step), m_delta(delta), m_next(0) +{ + DoSieve(); +} + +bool PrimeSieve::NextCandidate(Integer &c) +{ + m_next = std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(); + if (m_next == m_sieve.size()) + { + m_first += m_sieve.size()*m_step; + if (m_first > m_last) + return false; + else + { + m_next = 0; + DoSieve(); + return NextCandidate(c); + } + } + else + { + c = m_first + m_next*m_step; + ++m_next; + return true; + } +} + +void PrimeSieve::SieveSingle(std::vector<bool> &sieve, word p, const Integer &first, const Integer &step, word stepInv) +{ + if (stepInv) + { + unsigned int sieveSize = sieve.size(); + word j = word((dword(p-(first%p))*stepInv) % p); + // if the first multiple of p is p, skip it + if (first.WordCount() <= 1 && first + step*j == p) + j += p; + for (; j < sieveSize; j += p) + sieve[j] = true; + } +} + +void PrimeSieve::DoSieve() +{ + BuildPrimeTable(); + + const unsigned int maxSieveSize = 32768; + unsigned int sieveSize = STDMIN(Integer(maxSieveSize), (m_last-m_first)/m_step+1).ConvertToLong(); + + m_sieve.clear(); + m_sieve.resize(sieveSize, false); + + if (m_delta == 0) + { + for (unsigned int i = 0; i < primeTableSize; ++i) + SieveSingle(m_sieve, primeTable[i], m_first, m_step, m_step.InverseMod(primeTable[i])); + } + else + { + assert(m_step%2==0); + Integer qFirst = (m_first-m_delta) >> 1; + Integer halfStep = m_step >> 1; + for (unsigned int i = 0; i < primeTableSize; ++i) + { + word p = primeTable[i]; + word stepInv = m_step.InverseMod(p); + SieveSingle(m_sieve, p, m_first, m_step, stepInv); + + word halfStepInv = 2*stepInv < p ? 2*stepInv : 2*stepInv-p; + SieveSingle(m_sieve, p, qFirst, halfStep, halfStepInv); + } + } +} + +bool FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector) +{ + assert(!equiv.IsNegative() && equiv < mod); + + Integer gcd = GCD(equiv, mod); + if (gcd != Integer::One()) + { + // the only possible prime p such that p%mod==equiv where GCD(mod,equiv)!=1 is GCD(mod,equiv) + if (p <= gcd && gcd <= max && IsPrime(gcd)) + { + p = gcd; + return true; + } + else + return false; + } + + BuildPrimeTable(); + + if (p <= primeTable[primeTableSize-1]) + { + word *pItr; + + --p; + if (p.IsPositive()) + pItr = std::upper_bound(primeTable, primeTable+primeTableSize, (word)p.ConvertToLong()); + else + pItr = primeTable; + + while (pItr < primeTable+primeTableSize && *pItr%mod != equiv) + ++pItr; + + if (pItr < primeTable+primeTableSize) + { + p = *pItr; + return p <= max; + } + + p = primeTable[primeTableSize-1]+1; + } + + assert(p > primeTable[primeTableSize-1]); + + if (mod.IsOdd()) + return FirstPrime(p, max, CRT(equiv, mod, 1, 2, 1), mod<<1, pSelector); + + p += (equiv-p)%mod; + + if (p>max) + return false; + + PrimeSieve sieve(p, max, mod); + + while (sieve.NextCandidate(p)) + { + if ((!pSelector || pSelector->IsAcceptable(p)) && FastProbablePrimeTest(p) && IsPrime(p)) + return true; + } + + return false; +} + +// the following two functions are based on code and comments provided by Preda Mihailescu +static bool ProvePrime(const Integer &p, const Integer &q) +{ + assert(p < q*q*q); + assert(p % q == 1); + +// this is the Quisquater test. Numbers p having passed the Lucas - Lehmer test +// for q and verifying p < q^3 can only be built up of two factors, both = 1 mod q, +// or be prime. The next two lines build the discriminant of a quadratic equation +// which holds iff p is built up of two factors (excercise ... ) + + Integer r = (p-1)/q; + if (((r%q).Squared()-4*(r/q)).IsSquare()) + return false; + + assert(primeTableSize >= 50); + for (int i=0; i<50; i++) + { + Integer b = a_exp_b_mod_c(primeTable[i], r, p); + if (b != 1) + return a_exp_b_mod_c(b, q, p) == 1; + } + return false; +} + +Integer MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int pbits) +{ + Integer p; + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + + if (maxP <= Integer(lastSmallPrime).Squared()) + { + // Randomize() will generate a prime provable by trial division + p.Randomize(rng, minP, maxP, Integer::PRIME); + return p; + } + + unsigned int qbits = (pbits+2)/3 + 1 + rng.GenerateWord32(0, pbits/36); + Integer q = MihailescuProvablePrime(rng, qbits); + Integer q2 = q<<1; + + while (true) + { + // this initializes the sieve to search in the arithmetic + // progression p = p_0 + \lambda * q2 = p_0 + 2 * \lambda * q, + // with q the recursively generated prime above. We will be able + // to use Lucas tets for proving primality. A trick of Quisquater + // allows taking q > cubic_root(p) rather then square_root: this + // decreases the recursion. + + p.Randomize(rng, minP, maxP, Integer::ANY, 1, q2); + PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*q2, maxP), q2); + + while (sieve.NextCandidate(p)) + { + if (FastProbablePrimeTest(p) && ProvePrime(p, q)) + return p; + } + } + + // not reached + return p; +} + +Integer MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits) +{ + const unsigned smallPrimeBound = 29, c_opt=10; + Integer p; + + BuildPrimeTable(); + if (bits < smallPrimeBound) + { + do + p.Randomize(rng, Integer::Power2(bits-1), Integer::Power2(bits)-1, Integer::ANY, 1, 2); + while (TrialDivision(p, 1 << ((bits+1)/2))); + } + else + { + const unsigned margin = bits > 50 ? 20 : (bits-10)/2; + double relativeSize; + do + relativeSize = pow(2.0, double(rng.GenerateWord32())/0xffffffff - 1); + while (bits * relativeSize >= bits - margin); + + Integer a,b; + Integer q = MaurerProvablePrime(rng, unsigned(bits*relativeSize)); + Integer I = Integer::Power2(bits-2)/q; + Integer I2 = I << 1; + unsigned int trialDivisorBound = (unsigned int)STDMIN((unsigned long)primeTable[primeTableSize-1], (unsigned long)bits*bits/c_opt); + bool success = false; + while (!success) + { + p.Randomize(rng, I, I2, Integer::ANY); + p *= q; p <<= 1; ++p; + if (!TrialDivision(p, trialDivisorBound)) + { + a.Randomize(rng, 2, p-1, Integer::ANY); + b = a_exp_b_mod_c(a, (p-1)/q, p); + success = (GCD(b-1, p) == 1) && (a_exp_b_mod_c(b, q, p) == 1); + } + } + } + return p; +} + +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u) +{ + // isn't operator overloading great? + return p * (u * (xq-xp) % q) + xp; +} + +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q) +{ + return CRT(xp, p, xq, q, EuclideanMultiplicativeInverse(p, q)); +} + +Integer ModularSquareRoot(const Integer &a, const Integer &p) +{ + if (p%4 == 3) + return a_exp_b_mod_c(a, (p+1)/4, p); + + Integer q=p-1; + unsigned int r=0; + while (q.IsEven()) + { + r++; + q >>= 1; + } + + Integer n=2; + while (Jacobi(n, p) != -1) + ++n; + + Integer y = a_exp_b_mod_c(n, q, p); + Integer x = a_exp_b_mod_c(a, (q-1)/2, p); + Integer b = (x.Squared()%p)*a%p; + x = a*x%p; + Integer tempb, t; + + while (b != 1) + { + unsigned m=0; + tempb = b; + do + { + m++; + b = b.Squared()%p; + if (m==r) + return Integer::Zero(); + } + while (b != 1); + + t = y; + for (unsigned i=0; i<r-m-1; i++) + t = t.Squared()%p; + y = t.Squared()%p; + r = m; + x = x*t%p; + b = tempb*y%p; + } + + assert(x.Squared()%p == a); + return x; +} + +bool SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p) +{ + Integer D = (b.Squared() - 4*a*c) % p; + switch (Jacobi(D, p)) + { + default: + assert(false); // not reached + return false; + case -1: + return false; + case 0: + r1 = r2 = (-b*(a+a).InverseMod(p)) % p; + assert(((r1.Squared()*a + r1*b + c) % p).IsZero()); + return true; + case 1: + Integer s = ModularSquareRoot(D, p); + Integer t = (a+a).InverseMod(p); + r1 = (s-b)*t % p; + r2 = (-s-b)*t % p; + assert(((r1.Squared()*a + r1*b + c) % p).IsZero()); + assert(((r2.Squared()*a + r2*b + c) % p).IsZero()); + return true; + } +} + +Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, + const Integer &p, const Integer &q, const Integer &u) +{ + Integer p2 = ModularExponentiation((a % p), dp, p); + Integer q2 = ModularExponentiation((a % q), dq, q); + return CRT(p2, p, q2, q, u); +} + +Integer ModularRoot(const Integer &a, const Integer &e, + const Integer &p, const Integer &q) +{ + Integer dp = EuclideanMultiplicativeInverse(e, p-1); + Integer dq = EuclideanMultiplicativeInverse(e, q-1); + Integer u = EuclideanMultiplicativeInverse(p, q); + assert(!!dp && !!dq && !!u); + return ModularRoot(a, dp, dq, p, q, u); +} + +/* +Integer GCDI(const Integer &x, const Integer &y) +{ + Integer a=x, b=y; + unsigned k=0; + + assert(!!a && !!b); + + while (a[0]==0 && b[0]==0) + { + a >>= 1; + b >>= 1; + k++; + } + + while (a[0]==0) + a >>= 1; + + while (b[0]==0) + b >>= 1; + + while (1) + { + switch (a.Compare(b)) + { + case -1: + b -= a; + while (b[0]==0) + b >>= 1; + break; + + case 0: + return (a <<= k); + + case 1: + a -= b; + while (a[0]==0) + a >>= 1; + break; + + default: + assert(false); + } + } +} + +Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) +{ + assert(b.Positive()); + + if (a.Negative()) + return EuclideanMultiplicativeInverse(a%b, b); + + if (b[0]==0) + { + if (!b || a[0]==0) + return Integer::Zero(); // no inverse + if (a==1) + return 1; + Integer u = EuclideanMultiplicativeInverse(b, a); + if (!u) + return Integer::Zero(); // no inverse + else + return (b*(a-u)+1)/a; + } + + Integer u=1, d=a, v1=b, v3=b, t1, t3, b2=(b+1)>>1; + + if (a[0]) + { + t1 = Integer::Zero(); + t3 = -b; + } + else + { + t1 = b2; + t3 = a>>1; + } + + while (!!t3) + { + while (t3[0]==0) + { + t3 >>= 1; + if (t1[0]==0) + t1 >>= 1; + else + { + t1 >>= 1; + t1 += b2; + } + } + if (t3.Positive()) + { + u = t1; + d = t3; + } + else + { + v1 = b-t1; + v3 = -t3; + } + t1 = u-v1; + t3 = d-v3; + if (t1.Negative()) + t1 += b; + } + if (d==1) + return u; + else + return Integer::Zero(); // no inverse +} +*/ + +int Jacobi(const Integer &aIn, const Integer &bIn) +{ + assert(bIn.IsOdd()); + + Integer b = bIn, a = aIn%bIn; + int result = 1; + + while (!!a) + { + unsigned i=0; + while (a.GetBit(i)==0) + i++; + a>>=i; + + if (i%2==1 && (b%8==3 || b%8==5)) + result = -result; + + if (a%4==3 && b%4==3) + result = -result; + + std::swap(a, b); + a %= b; + } + + return (b==1) ? result : 0; +} + +Integer Lucas(const Integer &e, const Integer &pIn, const Integer &n) +{ + unsigned i = e.BitCount(); + if (i==0) + return Integer::Two(); + + MontgomeryRepresentation m(n); + Integer p=m.ConvertIn(pIn%n), two=m.ConvertIn(Integer::Two()); + Integer v=p, v1=m.Subtract(m.Square(p), two); + + i--; + while (i--) + { + if (e.GetBit(i)) + { + // v = (v*v1 - p) % m; + v = m.Subtract(m.Multiply(v,v1), p); + // v1 = (v1*v1 - 2) % m; + v1 = m.Subtract(m.Square(v1), two); + } + else + { + // v1 = (v*v1 - p) % m; + v1 = m.Subtract(m.Multiply(v,v1), p); + // v = (v*v - 2) % m; + v = m.Subtract(m.Square(v), two); + } + } + return m.ConvertOut(v); +} + +// This is Peter Montgomery's unpublished Lucas sequence evalutation algorithm. +// The total number of multiplies and squares used is less than the binary +// algorithm (see above). Unfortunately I can't get it to run as fast as +// the binary algorithm because of the extra overhead. +/* +Integer Lucas(const Integer &n, const Integer &P, const Integer &modulus) +{ + if (!n) + return 2; + +#define f(A, B, C) m.Subtract(m.Multiply(A, B), C) +#define X2(A) m.Subtract(m.Square(A), two) +#define X3(A) m.Multiply(A, m.Subtract(m.Square(A), three)) + + MontgomeryRepresentation m(modulus); + Integer two=m.ConvertIn(2), three=m.ConvertIn(3); + Integer A=m.ConvertIn(P), B, C, p, d=n, e, r, t, T, U; + + while (d!=1) + { + p = d; + unsigned int b = WORD_BITS * p.WordCount(); + Integer alpha = (Integer(5)<<(2*b-2)).SquareRoot() - Integer::Power2(b-1); + r = (p*alpha)>>b; + e = d-r; + B = A; + C = two; + d = r; + + while (d!=e) + { + if (d<e) + { + swap(d, e); + swap(A, B); + } + + unsigned int dm2 = d[0], em2 = e[0]; + unsigned int dm3 = d%3, em3 = e%3; + +// if ((dm6+em6)%3 == 0 && d <= e + (e>>2)) + if ((dm3+em3==0 || dm3+em3==3) && (t = e, t >>= 2, t += e, d <= t)) + { + // #1 +// t = (d+d-e)/3; +// t = d; t += d; t -= e; t /= 3; +// e = (e+e-d)/3; +// e += e; e -= d; e /= 3; +// d = t; + +// t = (d+e)/3 + t = d; t += e; t /= 3; + e -= t; + d -= t; + + T = f(A, B, C); + U = f(T, A, B); + B = f(T, B, A); + A = U; + continue; + } + +// if (dm6 == em6 && d <= e + (e>>2)) + if (dm3 == em3 && dm2 == em2 && (t = e, t >>= 2, t += e, d <= t)) + { + // #2 +// d = (d-e)>>1; + d -= e; d >>= 1; + B = f(A, B, C); + A = X2(A); + continue; + } + +// if (d <= (e<<2)) + if (d <= (t = e, t <<= 2)) + { + // #3 + d -= e; + C = f(A, B, C); + swap(B, C); + continue; + } + + if (dm2 == em2) + { + // #4 +// d = (d-e)>>1; + d -= e; d >>= 1; + B = f(A, B, C); + A = X2(A); + continue; + } + + if (dm2 == 0) + { + // #5 + d >>= 1; + C = f(A, C, B); + A = X2(A); + continue; + } + + if (dm3 == 0) + { + // #6 +// d = d/3 - e; + d /= 3; d -= e; + T = X2(A); + C = f(T, f(A, B, C), C); + swap(B, C); + A = f(T, A, A); + continue; + } + + if (dm3+em3==0 || dm3+em3==3) + { + // #7 +// d = (d-e-e)/3; + d -= e; d -= e; d /= 3; + T = f(A, B, C); + B = f(T, A, B); + A = X3(A); + continue; + } + + if (dm3 == em3) + { + // #8 +// d = (d-e)/3; + d -= e; d /= 3; + T = f(A, B, C); + C = f(A, C, B); + B = T; + A = X3(A); + continue; + } + + assert(em2 == 0); + // #9 + e >>= 1; + C = f(C, B, A); + B = X2(B); + } + + A = f(A, B, C); + } + +#undef f +#undef X2 +#undef X3 + + return m.ConvertOut(A); +} +*/ + +Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u) +{ + Integer d = (m*m-4); + Integer p2 = p-Jacobi(d,p); + Integer q2 = q-Jacobi(d,q); + return CRT(Lucas(EuclideanMultiplicativeInverse(e,p2), m, p), p, Lucas(EuclideanMultiplicativeInverse(e,q2), m, q), q, u); +} + +Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q) +{ + return InverseLucas(e, m, p, q, EuclideanMultiplicativeInverse(p, q)); +} + +unsigned int FactoringWorkFactor(unsigned int n) +{ + // extrapolated from the table in Odlyzko's "The Future of Integer Factorization" + // updated to reflect the factoring of RSA-130 + if (n<5) return 0; + else return (unsigned int)(2.4 * pow((double)n, 1.0/3.0) * pow(log(double(n)), 2.0/3.0) - 5); +} + +unsigned int DiscreteLogWorkFactor(unsigned int n) +{ + // assuming discrete log takes about the same time as factoring + if (n<5) return 0; + else return (unsigned int)(2.4 * pow((double)n, 1.0/3.0) * pow(log(double(n)), 2.0/3.0) - 5); +} + +// ******************************************************** + +void PrimeAndGenerator::Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits) +{ + // no prime exists for delta = -1, qbits = 4, and pbits = 5 + assert(qbits > 4); + assert(pbits > qbits); + + if (qbits+1 == pbits) + { + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + bool success = false; + + while (!success) + { + p.Randomize(rng, minP, maxP, Integer::ANY, 6+5*delta, 12); + PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*12, maxP), 12, delta); + + while (sieve.NextCandidate(p)) + { + assert(IsSmallPrime(p) || SmallDivisorsTest(p)); + q = (p-delta) >> 1; + assert(IsSmallPrime(q) || SmallDivisorsTest(q)); + if (FastProbablePrimeTest(q) && FastProbablePrimeTest(p) && IsPrime(q) && IsPrime(p)) + { + success = true; + break; + } + } + } + + if (delta == 1) + { + // find g such that g is a quadratic residue mod p, then g has order q + // g=4 always works, but this way we get the smallest quadratic residue (other than 1) + for (g=2; Jacobi(g, p) != 1; ++g) {} + // contributed by Walt Tuvell: g should be the following according to the Law of Quadratic Reciprocity + assert((p%8==1 || p%8==7) ? g==2 : (p%12==1 || p%12==11) ? g==3 : g==4); + } + else + { + assert(delta == -1); + // find g such that g*g-4 is a quadratic non-residue, + // and such that g has order q + for (g=3; ; ++g) + if (Jacobi(g*g-4, p)==-1 && Lucas(q, g, p)==2) + break; + } + } + else + { + Integer minQ = Integer::Power2(qbits-1); + Integer maxQ = Integer::Power2(qbits) - 1; + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + + do + { + q.Randomize(rng, minQ, maxQ, Integer::PRIME); + } while (!p.Randomize(rng, minP, maxP, Integer::PRIME, delta%q, q)); + + // find a random g of order q + if (delta==1) + { + do + { + Integer h(rng, 2, p-2, Integer::ANY); + g = a_exp_b_mod_c(h, (p-1)/q, p); + } while (g <= 1); + assert(a_exp_b_mod_c(g, q, p)==1); + } + else + { + assert(delta==-1); + do + { + Integer h(rng, 3, p-1, Integer::ANY); + if (Jacobi(h*h-4, p)==1) + continue; + g = Lucas((p+1)/q, h, p); + } while (g <= 2); + assert(Lucas(q, g, p) == 2); + } + } +} + +NAMESPACE_END diff --git a/nbtheory.h b/nbtheory.h new file mode 100644 index 0000000..685dc41 --- /dev/null +++ b/nbtheory.h @@ -0,0 +1,143 @@ +// nbtheory.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_NBTHEORY_H +#define CRYPTOPP_NBTHEORY_H + +#include "integer.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +// export a table of small primes +extern const unsigned int maxPrimeTableSize; +extern const word lastSmallPrime; +extern unsigned int primeTableSize; +extern word primeTable[]; + +// build up the table to maxPrimeTableSize +void BuildPrimeTable(); + +// ************ primality testing **************** + +// generate a provable prime +Integer MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits); +Integer MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +bool IsSmallPrime(const Integer &p); + +// returns true if p is divisible by some prime less than bound +// bound not be greater than the largest entry in the prime table +bool TrialDivision(const Integer &p, unsigned bound); + +// returns true if p is NOT divisible by small primes +bool SmallDivisorsTest(const Integer &p); + +// These is no reason to use these two, use the ones below instead +bool IsFermatProbablePrime(const Integer &n, const Integer &b); +bool IsLucasProbablePrime(const Integer &n); + +bool IsStrongProbablePrime(const Integer &n, const Integer &b); +bool IsStrongLucasProbablePrime(const Integer &n); + +// Rabin-Miller primality test, i.e. repeating the strong probable prime test +// for several rounds with random bases +bool RabinMillerTest(RandomNumberGenerator &rng, const Integer &w, unsigned int rounds); + +// primality test, used to generate primes +bool IsPrime(const Integer &p); + +// more reliable than IsPrime(), used to verify primes generated by others +bool VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1); + +class PrimeSelector +{ +public: + const PrimeSelector *GetSelectorPointer() const {return this;} + virtual bool IsAcceptable(const Integer &candidate) const =0; +}; + +// use a fast sieve to find the first probable prime in {x | p<=x<=max and x%mod==equiv} +// returns true iff successful, value of p is undefined if no such prime exists +bool FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector); + +unsigned int PrimeSearchInterval(const Integer &max); + +AlgorithmParameters<AlgorithmParameters<AlgorithmParameters<NullNameValuePairs, Integer::RandomNumberType>, Integer>, Integer> + MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength); + +// ********** other number theoretic functions ************ + +inline Integer GCD(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b);} +inline bool RelativelyPrime(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b) == Integer::One();} +inline Integer LCM(const Integer &a, const Integer &b) + {return a/Integer::Gcd(a,b)*b;} +inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) + {return a.InverseMod(b);} + +// use Chinese Remainder Theorem to calculate x given x mod p and x mod q +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q); +// use this one if u = inverse of p mod q has been precalculated +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u); + +// if b is prime, then Jacobi(a, b) returns 0 if a%b==0, 1 if a is quadratic residue mod b, -1 otherwise +// check a number theory book for what Jacobi symbol means when b is not prime +int Jacobi(const Integer &a, const Integer &b); + +// calculates the Lucas function V_e(p, 1) mod n +Integer Lucas(const Integer &e, const Integer &p, const Integer &n); +// calculates x such that m==Lucas(e, x, p*q), p q primes +Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q); +// use this one if u=inverse of p mod q has been precalculated +Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u); + +inline Integer ModularExponentiation(const Integer &a, const Integer &e, const Integer &m) + {return a_exp_b_mod_c(a, e, m);} +// returns x such that x*x%p == a, p prime +Integer ModularSquareRoot(const Integer &a, const Integer &p); +// returns x such that a==ModularExponentiation(x, e, p*q), p q primes, +// and e relatively prime to (p-1)*(q-1) +Integer ModularRoot(const Integer &a, const Integer &e, const Integer &p, const Integer &q); +// use this one if dp=d%(p-1), dq=d%(q-1), (d is inverse of e mod (p-1)*(q-1)) +// and u=inverse of p mod q have been precalculated +Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u); + +// find r1 and r2 such that ax^2 + bx + c == 0 (mod p) for x in {r1, r2}, p prime +// returns true if solutions exist +bool SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p); + +// returns log base 2 of estimated number of operations to calculate discrete log or factor a number +unsigned int DiscreteLogWorkFactor(unsigned int bitlength); +unsigned int FactoringWorkFactor(unsigned int bitlength); + +// ******************************************************** + +//! generator of prime numbers of special forms +class PrimeAndGenerator +{ +public: + PrimeAndGenerator() {} + // generate a random prime p of the form 2*q+delta, where delta is 1 or -1 and q is also prime + // Precondition: pbits > 5 + // warning: this is slow, because primes of this form are harder to find + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits) + {Generate(delta, rng, pbits, pbits-1);} + // generate a random prime p of the form 2*r*q+delta, where q is also prime + // Precondition: qbits > 4 && pbits > qbits + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits) + {Generate(delta, rng, pbits, qbits);} + + void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits); + + const Integer& Prime() const {return p;} + const Integer& SubPrime() const {return q;} + const Integer& Generator() const {return g;} + +private: + Integer p, q, g; +}; + +NAMESPACE_END + +#endif diff --git a/network.cpp b/network.cpp new file mode 100644 index 0000000..72001d4 --- /dev/null +++ b/network.cpp @@ -0,0 +1,211 @@ +// network.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "network.h" + +NAMESPACE_BEGIN(CryptoPP) + +unsigned int NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blocking) +{ + if (messageCount == 0) + return 0; + + unsigned long byteCount = ULONG_MAX; + messageCount = 0; + RETURN_IF_NONZERO(Pump2(byteCount, blocking)); + if (!m_messageEndSent && SourceExhausted()) + { + RETURN_IF_NONZERO(AttachedTransformation()->Put2(NULL, 0, GetAutoSignalPropagation(), true)); + m_messageEndSent = true; + messageCount = 1; + } + return 0; +} + +bool NonblockingSink::IsolatedFlush(bool hardFlush, bool blocking) +{ + TimedFlush(blocking ? INFINITE_TIME : 0); + return hardFlush && !!GetCurrentBufferSize(); +} + +// ************************************************************* + +#ifdef HIGHRES_TIMER_AVAILABLE + +NetworkSource::NetworkSource(BufferedTransformation *attachment) + : NonblockingSource(attachment), m_buf(1024*4), m_bufSize(0), m_state(NORMAL) +{ +} + +unsigned int NetworkSource::GeneralPump2(unsigned long &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter) +{ + NetworkReceiver &receiver = AccessReceiver(); + + unsigned long maxSize = byteCount; + byteCount = 0; + bool forever = maxTime == INFINITE_TIME; + Timer timer(Timer::MILLISECONDS, forever); + unsigned long timeout; + BufferedTransformation *t = AttachedTransformation(); + + if (m_state == OUTPUT_BLOCKED) + goto DoOutput; + + while (true) + { + if (m_state == WAITING_FOR_RESULT) + { + if (receiver.MustWaitForResult()) + { + timeout = SaturatingSubtract(maxTime, timer.ElapsedTime()); + if (!receiver.Wait(timeout)) + break; + } + + unsigned int recvResult = receiver.GetReceiveResult(); +// assert(recvResult > 0 || receiver.EofReceived()); + m_bufSize += recvResult; + m_state = NORMAL; + } + + if (m_bufSize == 0) + { + if (receiver.EofReceived()) + break; + } + else + { + m_putSize = STDMIN((unsigned long)m_bufSize, maxSize - byteCount); + if (checkDelimiter) + m_putSize = std::find(m_buf.begin(), m_buf+m_putSize, delimiter) - m_buf; + +DoOutput: + unsigned int result = t->PutModifiable2(m_buf, m_putSize, 0, forever || blockingOutput); + if (result) + { + timeout = SaturatingSubtract(maxTime, timer.ElapsedTime()); + if (t->Wait(timeout)) + goto DoOutput; + else + { + m_state = OUTPUT_BLOCKED; + return result; + } + } + m_state = NORMAL; + + byteCount += m_putSize; + m_bufSize -= m_putSize; + if (m_bufSize > 0) + { + memmove(m_buf, m_buf+m_putSize, m_bufSize); + if (checkDelimiter && m_buf[0] == delimiter) + break; + } + } + + if (byteCount == maxSize) + break; + + unsigned long elapsed = timer.ElapsedTime(); + if (elapsed > maxTime) + break; // once time limit is reached, return even if there is more data waiting + + if (receiver.MustWaitToReceive()) + { + if (!receiver.Wait(maxTime - elapsed)) + break; + } + + receiver.Receive(m_buf+m_bufSize, m_buf.size()-m_bufSize); + m_state = WAITING_FOR_RESULT; + } + + return 0; +} + +// ************************************************************* + +unsigned int NetworkSink::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (m_blockedBytes) + { + assert(length >= m_blockedBytes); + inString += length - m_blockedBytes; + length = m_blockedBytes; + } + m_buffer.LazyPut(inString, length); + + unsigned int targetSize = messageEnd ? 0 : m_maxBufferSize; + TimedFlush(blocking ? INFINITE_TIME : 0, m_autoFlush ? 0 : targetSize); + + if (m_buffer.CurrentSize() > targetSize) + { + assert(!blocking); + m_blockedBytes = STDMIN(m_buffer.CurrentSize() - targetSize, (unsigned long)length); + m_buffer.UndoLazyPut(m_blockedBytes); + m_buffer.FinalizeLazyPut(); + return STDMAX(m_blockedBytes, 1U); + } + m_blockedBytes = 0; + + if (messageEnd) + AccessSender().SendEof(); + return 0; +} + +unsigned int NetworkSink::TimedFlush(unsigned long maxTime, unsigned int targetSize) +{ + if (m_buffer.IsEmpty()) + return 0; + + NetworkSender &sender = AccessSender(); + + bool forever = maxTime == INFINITE_TIME; + Timer timer(Timer::MILLISECONDS, forever); + unsigned long timeout; + unsigned int totalFlushSize = 0; + + while (true) + { + if (m_needSendResult) + { + if (sender.MustWaitForResult()) + { + timeout = SaturatingSubtract(maxTime, timer.ElapsedTime()); + if (!sender.Wait(timeout)) + break; + } + + unsigned int sendResult = sender.GetSendResult(); + m_buffer.Skip(sendResult); + totalFlushSize += sendResult; + m_needSendResult = false; + + if (m_buffer.CurrentSize() <= targetSize) + break; + } + + unsigned long elapsed = timer.ElapsedTime(); + if (elapsed > maxTime) + break; // once time limit is reached, return even if there is more data waiting + + if (sender.MustWaitToSend()) + { + if (!sender.Wait(maxTime - elapsed)) + break; + } + + unsigned int contiguousSize = 0; + const byte *block = m_buffer.Spy(contiguousSize); + + sender.Send(block, contiguousSize); + m_needSendResult = true; + } + + return totalFlushSize; +} + +#endif // #ifdef HIGHRES_TIMER_AVAILABLE + +NAMESPACE_END diff --git a/network.h b/network.h new file mode 100644 index 0000000..8679a28 --- /dev/null +++ b/network.h @@ -0,0 +1,152 @@ +#ifndef CRYPTOPP_NETWORK_H +#define CRYPTOPP_NETWORK_H + +#include "filters.h" +#include "hrtimer.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! a Source class that can pump from a device for a specified amount of time. +class NonblockingSource : public AutoSignaling<Source> +{ +public: + NonblockingSource(BufferedTransformation *attachment) + : AutoSignaling<Source>(attachment), m_messageEndSent(false) {} + + //! \name NONBLOCKING SOURCE + //@{ + + //! pump up to maxSize bytes using at most maxTime milliseconds + /*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */ + virtual unsigned int GeneralPump2(unsigned long &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n') =0; + + unsigned long GeneralPump(unsigned long maxSize=ULONG_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n') + { + GeneralPump2(maxSize, true, maxTime, checkDelimiter, delimiter); + return maxSize; + } + unsigned long TimedPump(unsigned long maxTime) + {return GeneralPump(ULONG_MAX, maxTime);} + unsigned long PumpLine(byte delimiter='\n', unsigned long maxSize=1024) + {return GeneralPump(maxSize, INFINITE_TIME, true, delimiter);} + + unsigned int Pump2(unsigned long &byteCount, bool blocking=true) + {return GeneralPump2(byteCount, blocking, blocking ? INFINITE_TIME : 0);} + unsigned int PumpMessages2(unsigned int &messageCount, bool blocking=true); + //@} + +private: + bool m_messageEndSent; +}; + +//! Network Receiver +class NetworkReceiver : public Waitable +{ +public: + virtual bool MustWaitToReceive() {return false;} + virtual bool MustWaitForResult() {return false;} + virtual void Receive(byte* buf, unsigned int bufLen) =0; + virtual unsigned int GetReceiveResult() =0; + virtual bool EofReceived() const =0; +}; + +//! a Sink class that queues input and can flush to a device for a specified amount of time. +class NonblockingSink : public Sink +{ +public: + bool IsolatedFlush(bool hardFlush, bool blocking); + + //! flush to device for no more than maxTime milliseconds + /*! This function will repeatedly attempt to flush data to some device, until + the queue is empty, or a total of maxTime milliseconds have elapsed. + If maxTime == 0, at least one attempt will be made to flush some data, but + it is likely that not all queued data will be flushed, even if the device + is ready to receive more data without waiting. If you want to flush as much data + as possible without waiting for the device, call this function in a loop. + For example: while (sink.TimedFlush(0) > 0) {} + \return number of bytes flushed + */ + virtual unsigned int TimedFlush(unsigned long maxTime, unsigned int targetSize = 0) =0; + + virtual void SetMaxBufferSize(unsigned int maxBufferSize) =0; + virtual void SetAutoFlush(bool autoFlush = true) =0; + + virtual unsigned int GetMaxBufferSize() const =0; + virtual unsigned int GetCurrentBufferSize() const =0; +}; + +//! Network Sender +class NetworkSender : public Waitable +{ +public: + virtual bool MustWaitToSend() {return false;} + virtual bool MustWaitForResult() {return false;} + virtual void Send(const byte* buf, unsigned int bufLen) =0; + virtual unsigned int GetSendResult() =0; + virtual void SendEof() =0; +}; + +#ifdef HIGHRES_TIMER_AVAILABLE + +//! Network Source +class NetworkSource : public NonblockingSource +{ +public: + NetworkSource(BufferedTransformation *attachment); + + unsigned int GetMaxWaitObjectCount() const + {return GetReceiver().GetMaxWaitObjectCount() + AttachedTransformation()->GetMaxWaitObjectCount();} + void GetWaitObjects(WaitObjectContainer &container) + {AccessReceiver().GetWaitObjects(container); AttachedTransformation()->GetWaitObjects(container);} + + unsigned int GeneralPump2(unsigned long &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n'); + bool SourceExhausted() const {return GetReceiver().EofReceived();} + +protected: + virtual NetworkReceiver & AccessReceiver() =0; + const NetworkReceiver & GetReceiver() const {return const_cast<NetworkSource *>(this)->AccessReceiver();} + +private: + enum {NORMAL, WAITING_FOR_RESULT, OUTPUT_BLOCKED}; + SecByteBlock m_buf; + unsigned int m_bufSize, m_putSize, m_state; +}; + +//! Network Sink +class NetworkSink : public NonblockingSink +{ +public: + NetworkSink(unsigned int maxBufferSize, bool autoFlush) + : m_maxBufferSize(maxBufferSize), m_autoFlush(autoFlush), m_needSendResult(false), m_blockedBytes(0) {} + + unsigned int GetMaxWaitObjectCount() const + {return GetSender().GetMaxWaitObjectCount();} + void GetWaitObjects(WaitObjectContainer &container) + {if (m_blockedBytes || !m_buffer.IsEmpty()) AccessSender().GetWaitObjects(container);} + + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); + + unsigned int TimedFlush(unsigned long maxTime, unsigned int targetSize = 0); + + void SetMaxBufferSize(unsigned int maxBufferSize) {m_maxBufferSize = maxBufferSize;} + void SetAutoFlush(bool autoFlush = true) {m_autoFlush = autoFlush;} + + unsigned int GetMaxBufferSize() const {return m_maxBufferSize;} + unsigned int GetCurrentBufferSize() const {return m_buffer.CurrentSize();} + +protected: + virtual NetworkSender & AccessSender() =0; + const NetworkSender & GetSender() const {return const_cast<NetworkSink *>(this)->AccessSender();} + +private: + unsigned int m_maxBufferSize; + bool m_autoFlush, m_needSendResult; + ByteQueue m_buffer; + unsigned int m_blockedBytes; +}; + +#endif // #ifdef HIGHRES_TIMER_AVAILABLE + +NAMESPACE_END + +#endif @@ -0,0 +1,6 @@ +#ifndef CRYPTOPP_NR_H +#define CRYPTOPP_NR_H + +#include "gfpcrypt.h" + +#endif diff --git a/nr1024.dat b/nr1024.dat new file mode 100644 index 0000000..6778ccf --- /dev/null +++ b/nr1024.dat @@ -0,0 +1 @@ +3082014C0201003082012C06072A8648CE3804013082011F02818100F89F4EBE58E222B517D218D615BDC00611501CD18417886BD3FCBD22578C4611B1E8C06EB0FE9D473A5589BC277AA58C1979DC2869B728D78EC38B4C044A790A60314E7BD3DFDC0BBD8B770A9271D7D048F3E13C73866D096C7304782125847C70EDD721B36F1C379CF7CCEE0A728DD66336ED5F93E8A1BD3EDB22C8761EB987021526A578AB11C3A0812A636D24D120BE544B7973E4D302818100BF927ACE4D175A44622494E37F9552E97B74303321FFEF9B76CDECB14F7D612608DDFEA77C04A8FCACCF7F16CB01AE05AD5EDB65C3B9A380D720F34C7D96C8817E2EFF7D0049EE149DF61C52D7C80271206155CDAEBC8A7F4A8DCE5196E3C18FD5EDF11A394C43A5D59BC65D976817438CA0A7F01713548F61355E976DE75E1E04170215247B2531CFF01D1B1665F0CFD2A836446798353330
\ No newline at end of file diff --git a/nr2048.dat b/nr2048.dat new file mode 100644 index 0000000..d9f11f1 --- /dev/null +++ b/nr2048.dat @@ -0,0 +1 @@ +3082025D0201003082023506072A8648CE38040130820228028201010083C69F32A1F3A67B201D7A92BA204281681DAAD29F50BD866D70A2E01438653B18602AFE606AA925389381682EC0E2CE5D5D366793917879860799ECEDDB4831ED4A4E76D9C34FFDD0BC786588F00E8A19705B997C4298F9CAF9AEE46E0A5677AA1240DC141BD78A8720A829F64C912FA3D961ADE698C5344F18FE4CE70CF7B94F45258C6A9553830FFB80B6BB7E1C510D4526C1904C1D6E2F1B8C1CA6499DBD291438717131804FA2F5F42E5C06293D6DA493C88A38EBC6A6DCF40B2BAB0BF7C7FA0F9C070F1C48FD12CA2B7337E9C58EB9AFDAC6FEEAB0BD62415B26D405D6BF47F11D70B1740BC398A76BE70723A829082EB548D35F4D78E4E015DAD12D5B021D083118E4DC11622CB53E7E4D7634BFBDE45A2D8F8B097A251803505315028201005BAC6CBFE089F75274A532564735786477478F19BE099AB38E0F843393D6D81964CBCFF4B68C5DA2614F06BB844672288F0A65216954990051BA691CA6796AFAAE91A79350F53D9DF3CC688387306EFFDCEF70A14A672E2103B8C861523703157D05DF6EB42DCD81506C88300ED8D8ED40D41AB6D669D309C976B84D82C8D18747578358CBA1EF4B00118B0DEEF11409DD8CB0D83399A33E10C18249574FA2242AE4241CD789C891FEC1C63771EE4517274493240EDAAC44AEDC42F318A5122B052244DFA9A282B8D94BC4BAB360D44E4D0204F8D28817B5B6F808047C92032AA94926D697CFA2FC211FAAE26A5F1FC2B1EB03DA68AD5E01EAC489FB64A66EA3041F021D042ADA16929DA18A7A3C8FDCDD8FC46A6D8AAB79FF33D60E2BF09DEF4F
\ No newline at end of file diff --git a/oaep.cpp b/oaep.cpp new file mode 100644 index 0000000..9391f5b --- /dev/null +++ b/oaep.cpp @@ -0,0 +1,103 @@ +// oaep.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "oaep.h" + +#include <functional> + +NAMESPACE_BEGIN(CryptoPP) + +// ******************************************************** + +ANONYMOUS_NAMESPACE_BEGIN + template <class H, byte *P, unsigned int PLen> + struct PHashComputation + { + PHashComputation() {H().CalculateDigest(pHash, P, PLen);} + byte pHash[H::DIGESTSIZE]; + }; + + template <class H, byte *P, unsigned int PLen> + const byte *PHash() + { + static PHashComputation<H,P,PLen> pHash; + return pHash.pHash; + } +NAMESPACE_END + +template <class H, class MGF, byte *P, unsigned int PLen> +unsigned int OAEP<H,MGF,P,PLen>::MaxUnpaddedLength(unsigned int paddedLength) const +{ + return paddedLength/8 > 1+2*H::DIGESTSIZE ? paddedLength/8-1-2*H::DIGESTSIZE : 0; +} + +template <class H, class MGF, byte *P, unsigned int PLen> +void OAEP<H,MGF,P,PLen>::Pad(RandomNumberGenerator &rng, const byte *input, unsigned int inputLength, byte *oaepBlock, unsigned int oaepBlockLen) const +{ + assert (inputLength <= MaxUnpaddedLength(oaepBlockLen)); + + // convert from bit length to byte length + if (oaepBlockLen % 8 != 0) + { + oaepBlock[0] = 0; + oaepBlock++; + } + oaepBlockLen /= 8; + + const unsigned int hLen = H::DIGESTSIZE; + const unsigned int seedLen = hLen, dbLen = oaepBlockLen-seedLen; + byte *const maskedSeed = oaepBlock; + byte *const maskedDB = oaepBlock+seedLen; + + // DB = pHash || 00 ... || 01 || M + memcpy(maskedDB, PHash<H,P,PLen>(), hLen); + memset(maskedDB+hLen, 0, dbLen-hLen-inputLength-1); + maskedDB[dbLen-inputLength-1] = 0x01; + memcpy(maskedDB+dbLen-inputLength, input, inputLength); + + rng.GenerateBlock(maskedSeed, seedLen); + MGF::GenerateAndMask(maskedDB, dbLen, maskedSeed, seedLen); + MGF::GenerateAndMask(maskedSeed, seedLen, maskedDB, dbLen); +} + +template <class H, class MGF, byte *P, unsigned int PLen> +DecodingResult OAEP<H,MGF,P,PLen>::Unpad(const byte *oaepBlock, unsigned int oaepBlockLen, byte *output) const +{ + bool invalid = false; + + // convert from bit length to byte length + if (oaepBlockLen % 8 != 0) + { + invalid = (oaepBlock[0] != 0) || invalid; + oaepBlock++; + } + oaepBlockLen /= 8; + + const unsigned int hLen = H::DIGESTSIZE; + const unsigned int seedLen = hLen, dbLen = oaepBlockLen-seedLen; + + invalid = (oaepBlockLen < 2*hLen+1) || invalid; + + SecByteBlock t(oaepBlock, oaepBlockLen); + byte *const maskedSeed = t; + byte *const maskedDB = t+seedLen; + + MGF::GenerateAndMask(maskedSeed, seedLen, maskedDB, dbLen); + MGF::GenerateAndMask(maskedDB, dbLen, maskedSeed, seedLen); + + // DB = pHash' || 00 ... || 01 || M + + byte *M = std::find(maskedDB+hLen, maskedDB+dbLen, 0x01); + invalid = (M == maskedDB+dbLen) || invalid; + invalid = (std::find_if(maskedDB+hLen, M, std::bind2nd(std::not_equal_to<byte>(), 0)) != M) || invalid; + invalid = (memcmp(maskedDB, PHash<H,P,PLen>(), hLen) != 0) || invalid; + + if (invalid) + return DecodingResult(); + + M++; + memcpy(output, M, maskedDB+dbLen-M); + return DecodingResult(maskedDB+dbLen-M); +} + +NAMESPACE_END @@ -0,0 +1,25 @@ +#ifndef CRYPTOPP_OAEP_H +#define CRYPTOPP_OAEP_H + +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +extern byte OAEP_P_DEFAULT[]; // defined in misc.cpp + +/// <a href="http://www.weidai.com/scan-mirror/ca.html#cem_OAEP-MGF1">EME-OAEP</a>, for use with RSAES +template <class H, class MGF=P1363_MGF1<H>, byte *P=OAEP_P_DEFAULT, unsigned int PLen=0> +class OAEP : public PK_PaddingAlgorithm, public EncryptionStandard +{ +public: + static std::string StaticAlgorithmName() {return "OAEP-" + MGF::StaticAlgorithmName();} + typedef OAEP<H, MGF, P, PLen> EncryptionPaddingAlgorithm; + + unsigned int MaxUnpaddedLength(unsigned int paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedLength) const; + DecodingResult Unpad(const byte *padded, unsigned int paddedLength, byte *raw) const; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,112 @@ +#ifndef CRYPTOPP_OIDS_H +#define CRYPTOPP_OIDS_H + +// crypto-related ASN.1 object identifiers + +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +NAMESPACE_BEGIN(ASN1) + +#define DEFINE_OID(value, name) inline OID name() {return value;} + +DEFINE_OID(1, iso) + DEFINE_OID(iso()+2, member_body) + DEFINE_OID(member_body()+840, iso_us) + DEFINE_OID(iso_us()+10040, ansi_x9_57) + DEFINE_OID(ansi_x9_57()+4+1, id_dsa) + DEFINE_OID(iso_us()+10045, ansi_x9_62) + DEFINE_OID(ansi_x9_62()+1, id_fieldType) + DEFINE_OID(id_fieldType()+1, prime_field) + DEFINE_OID(id_fieldType()+2, characteristic_two_field) + DEFINE_OID(characteristic_two_field()+3, id_characteristic_two_basis) + DEFINE_OID(id_characteristic_two_basis()+1, gnBasis) + DEFINE_OID(id_characteristic_two_basis()+2, tpBasis) + DEFINE_OID(id_characteristic_two_basis()+3, ppBasis) + DEFINE_OID(ansi_x9_62()+2, id_publicKeyType) + DEFINE_OID(id_publicKeyType()+1, id_ecPublicKey) + DEFINE_OID(ansi_x9_62()+3, ansi_x9_62_curves) + DEFINE_OID(ansi_x9_62_curves()+1, ansi_x9_62_curves_prime) + DEFINE_OID(ansi_x9_62_curves_prime()+1, secp192r1) + DEFINE_OID(ansi_x9_62_curves_prime()+7, secp256r1) + DEFINE_OID(iso_us()+113549, rsadsi) + DEFINE_OID(rsadsi()+1, pkcs) + DEFINE_OID(pkcs()+1, pkcs_1) + DEFINE_OID(pkcs_1()+1, rsaEncryption); + DEFINE_OID(rsadsi()+2, rsadsi_digestAlgorithm) + DEFINE_OID(rsadsi_digestAlgorithm()+2, id_md2) + DEFINE_OID(rsadsi_digestAlgorithm()+5, id_md5) + DEFINE_OID(iso()+3, identified_organization); + DEFINE_OID(identified_organization()+14, oiw); + DEFINE_OID(oiw()+14, oiw_secsig); + DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms); + DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1); + DEFINE_OID(identified_organization()+36, teletrust); + DEFINE_OID(teletrust()+3+2+1, id_ripemd160) + DEFINE_OID(identified_organization()+132, certicom); + DEFINE_OID(certicom()+0, certicom_ellipticCurve); + // these are sorted by curve type and then by OID + // first curves based on GF(p) + DEFINE_OID(certicom_ellipticCurve()+6, secp112r1); + DEFINE_OID(certicom_ellipticCurve()+7, secp112r2); + DEFINE_OID(certicom_ellipticCurve()+8, secp160r1); + DEFINE_OID(certicom_ellipticCurve()+9, secp160k1); + DEFINE_OID(certicom_ellipticCurve()+10, secp256k1); + DEFINE_OID(certicom_ellipticCurve()+28, secp128r1); + DEFINE_OID(certicom_ellipticCurve()+29, secp128r2); + DEFINE_OID(certicom_ellipticCurve()+30, secp160r2); + DEFINE_OID(certicom_ellipticCurve()+31, secp192k1); + DEFINE_OID(certicom_ellipticCurve()+32, secp224k1); + DEFINE_OID(certicom_ellipticCurve()+33, secp224r1); + DEFINE_OID(certicom_ellipticCurve()+34, secp384r1); + DEFINE_OID(certicom_ellipticCurve()+35, secp521r1); + // then curves based on GF(2^n) + DEFINE_OID(certicom_ellipticCurve()+1, sect163k1); + DEFINE_OID(certicom_ellipticCurve()+2, sect163r1); + DEFINE_OID(certicom_ellipticCurve()+3, sect239k1); + DEFINE_OID(certicom_ellipticCurve()+4, sect113r1); + DEFINE_OID(certicom_ellipticCurve()+5, sect113r2); + DEFINE_OID(certicom_ellipticCurve()+15, sect163r2); + DEFINE_OID(certicom_ellipticCurve()+16, sect283k1); + DEFINE_OID(certicom_ellipticCurve()+17, sect283r1); + DEFINE_OID(certicom_ellipticCurve()+22, sect131r1); + DEFINE_OID(certicom_ellipticCurve()+23, sect131r2); + DEFINE_OID(certicom_ellipticCurve()+24, sect193r1); + DEFINE_OID(certicom_ellipticCurve()+25, sect193r2); + DEFINE_OID(certicom_ellipticCurve()+26, sect233k1); + DEFINE_OID(certicom_ellipticCurve()+27, sect233r1); + DEFINE_OID(certicom_ellipticCurve()+36, sect409k1); + DEFINE_OID(certicom_ellipticCurve()+37, sect409r1); + DEFINE_OID(certicom_ellipticCurve()+38, sect571k1); + DEFINE_OID(certicom_ellipticCurve()+39, sect571r1); +DEFINE_OID(2, joint_iso_ccitt) + DEFINE_OID(joint_iso_ccitt()+16, country) + DEFINE_OID(country()+840, joint_iso_ccitt_us) + DEFINE_OID(joint_iso_ccitt_us()+1, us_organization) + DEFINE_OID(us_organization()+101, us_gov) + DEFINE_OID(us_gov()+3, csor) + DEFINE_OID(csor()+4, nistalgorithms) + DEFINE_OID(nistalgorithms()+1, aes) + DEFINE_OID(aes()+1, id_aes128_ECB) + DEFINE_OID(aes()+2, id_aes128_cbc) + DEFINE_OID(aes()+3, id_aes128_ofb) + DEFINE_OID(aes()+4, id_aes128_cfb) + DEFINE_OID(aes()+21, id_aes192_ECB) + DEFINE_OID(aes()+22, id_aes192_cbc) + DEFINE_OID(aes()+23, id_aes192_ofb) + DEFINE_OID(aes()+24, id_aes192_cfb) + DEFINE_OID(aes()+41, id_aes256_ECB) + DEFINE_OID(aes()+42, id_aes256_cbc) + DEFINE_OID(aes()+43, id_aes256_ofb) + DEFINE_OID(aes()+44, id_aes256_cfb) + DEFINE_OID(nistalgorithms()+2, nist_hashalgs) + DEFINE_OID(nist_hashalgs()+1, id_sha256) + DEFINE_OID(nist_hashalgs()+2, id_sha384) + DEFINE_OID(nist_hashalgs()+3, id_sha512) + +NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/osrng.cpp b/osrng.cpp new file mode 100644 index 0000000..9f45b86 --- /dev/null +++ b/osrng.cpp @@ -0,0 +1,170 @@ +// osrng.cpp - written and placed in the public domain by Wei Dai + +// Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool. + +#include "pch.h" +#include "osrng.h" + +#ifdef OS_RNG_AVAILABLE + +#include "rng.h" + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#include <windows.h> +#include <wincrypt.h> +#else +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE) +OS_RNG_Err::OS_RNG_Err(const std::string &operation) + : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " + +#ifdef CRYPTOPP_WIN32_AVAILABLE + "0x" + IntToString(GetLastError(), 16) +#else + IntToString(errno) +#endif + ) +{ +} +#endif + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE + +MicrosoftCryptoProvider::MicrosoftCryptoProvider() +{ + if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + throw OS_RNG_Err("CryptAcquireContext"); +} + +MicrosoftCryptoProvider::~MicrosoftCryptoProvider() +{ + CryptReleaseContext(m_hProvider, 0); +} + +#endif + +NonblockingRng::NonblockingRng() +{ +#ifndef CRYPTOPP_WIN32_AVAILABLE + m_fd = open("/dev/urandom",O_RDONLY); + if (m_fd == -1) + throw OS_RNG_Err("open /dev/urandom"); +#endif +} + +NonblockingRng::~NonblockingRng() +{ +#ifndef CRYPTOPP_WIN32_AVAILABLE + close(m_fd); +#endif +} + +byte NonblockingRng::GenerateByte() +{ + byte b; + GenerateBlock(&b, 1); + return b; +} + +void NonblockingRng::GenerateBlock(byte *output, unsigned int size) +{ +#ifdef CRYPTOPP_WIN32_AVAILABLE +# ifdef WORKAROUND_MS_BUG_Q258000 + static MicrosoftCryptoProvider m_Provider; +# endif + if (!CryptGenRandom(m_Provider.GetProviderHandle(), size, output)) + throw OS_RNG_Err("CryptGenRandom"); +#else + if (read(m_fd, output, size) != size) + throw OS_RNG_Err("read /dev/urandom"); +#endif +} + +#endif + +// ************************************************************* + +#ifdef BLOCKING_RNG_AVAILABLE + +BlockingRng::BlockingRng() +{ + m_fd = open("/dev/random",O_RDONLY); + if (m_fd == -1) + throw OS_RNG_Err("open /dev/random"); +} + +BlockingRng::~BlockingRng() +{ + close(m_fd); +} + +byte BlockingRng::GenerateByte() +{ + byte b; + GenerateBlock(&b, 1); + return b; +} + +void BlockingRng::GenerateBlock(byte *output, unsigned int size) +{ + while (size) + { + // on some systems /dev/random will block until all bytes + // are available, on others it will returns immediately + int len = read(m_fd, output, STDMIN(size, (unsigned int)INT_MAX)); + if (len == -1) + throw OS_RNG_Err("read /dev/random"); + size -= len; + output += len; + if (size) + sleep(1); + } +} + +#endif + +// ************************************************************* + +void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size) +{ +#ifdef NONBLOCKING_RNG_AVAILABLE + if (blocking) +#endif + { +#ifdef BLOCKING_RNG_AVAILABLE + BlockingRng rng; + rng.GenerateBlock(output, size); +#endif + } + +#ifdef BLOCKING_RNG_AVAILABLE + if (!blocking) +#endif + { +#ifdef NONBLOCKING_RNG_AVAILABLE + NonblockingRng rng; + rng.GenerateBlock(output, size); +#endif + } +} + +void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize) +{ + SecByteBlock seed(seedSize); + OS_GenerateRandomBlock(blocking, seed, seedSize); + Put(seed, seedSize); +} + +NAMESPACE_END + +#endif @@ -0,0 +1,157 @@ +#ifndef CRYPTOPP_OSRNG_H +#define CRYPTOPP_OSRNG_H + +#include "config.h" + +#ifdef OS_RNG_AVAILABLE + +#include "randpool.h" +#include "rng.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Exception class for Operating-System Random Number Generator. +class OS_RNG_Err : public Exception +{ +public: + OS_RNG_Err(const std::string &operation); +}; + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE +class MicrosoftCryptoProvider +{ +public: + MicrosoftCryptoProvider(); + ~MicrosoftCryptoProvider(); +#if defined(_WIN64) + typedef unsigned __int64 ProviderHandle; // type HCRYPTPROV, avoid #include <windows.h> +#else + typedef unsigned long ProviderHandle; +#endif + ProviderHandle GetProviderHandle() const {return m_hProvider;} +private: + ProviderHandle m_hProvider; +}; +#endif + +//! encapsulate CryptoAPI's CryptGenRandom or /dev/urandom +class NonblockingRng : public RandomNumberGenerator +{ +public: + NonblockingRng(); + ~NonblockingRng(); + byte GenerateByte(); + void GenerateBlock(byte *output, unsigned int size); + +protected: +#ifdef CRYPTOPP_WIN32_AVAILABLE +# ifndef WORKAROUND_MS_BUG_Q258000 + MicrosoftCryptoProvider m_Provider; +# endif +#else + int m_fd; +#endif +}; + +#endif + +#ifdef BLOCKING_RNG_AVAILABLE + +//! encapsulate /dev/random +class BlockingRng : public RandomNumberGenerator +{ +public: + BlockingRng(); + ~BlockingRng(); + byte GenerateByte(); + void GenerateBlock(byte *output, unsigned int size); + +protected: + int m_fd; +}; + +#endif + +void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size); + +//! Automaticly Seeded Randomness Pool +/*! This class seeds itself using an operating system provided RNG. */ +class AutoSeededRandomPool : public RandomPool +{ +public: + //! blocking will be ignored if the prefered RNG isn't available + explicit AutoSeededRandomPool(bool blocking = false, unsigned int seedSize = 32) + {Reseed(blocking, seedSize);} + void Reseed(bool blocking = false, unsigned int seedSize = 32); +}; + +//! RNG from ANSI X9.17 Appendix C, seeded using an OS provided RNG +template <class BLOCK_CIPHER> +class AutoSeededX917RNG : public RandomNumberGenerator +{ +public: + //! blocking will be ignored if the prefered RNG isn't available + explicit AutoSeededX917RNG(bool blocking = false) + {Reseed(blocking);} + void Reseed(bool blocking = false); + + byte GenerateByte(); + +private: + member_ptr<RandomNumberGenerator> m_rng; + SecByteBlock m_lastBlock; + bool m_isDifferent; + unsigned int m_counter; +}; + +template <class BLOCK_CIPHER> +void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking) +{ + SecByteBlock seed(BLOCK_CIPHER::BLOCKSIZE + BLOCK_CIPHER::DEFAULT_KEYLENGTH); + const byte *key; + do + { + OS_GenerateRandomBlock(blocking, seed, seed.size()); + key = seed + BLOCK_CIPHER::BLOCKSIZE; + } // check that seed and key don't have same value + while (memcmp(key, seed, STDMIN((unsigned int)BLOCK_CIPHER::BLOCKSIZE, (unsigned int)BLOCK_CIPHER::DEFAULT_KEYLENGTH)) == 0); + m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH), seed)); + + if (FIPS_140_2_ComplianceEnabled()) + { + m_lastBlock.resize(16); + m_rng->GenerateBlock(m_lastBlock, m_lastBlock.size()); + m_counter = 0; + m_isDifferent = false; + } +} + +template <class BLOCK_CIPHER> +byte AutoSeededX917RNG<BLOCK_CIPHER>::GenerateByte() +{ + byte b = m_rng->GenerateByte(); + + if (FIPS_140_2_ComplianceEnabled()) + { + m_isDifferent = m_isDifferent || b != m_lastBlock[m_counter]; + m_lastBlock[m_counter] = b; + ++m_counter; + if (m_counter == m_lastBlock.size()) + { + if (!m_isDifferent) + throw SelfTestFailure("AutoSeededX917RNG: Continuous random number generator test failed."); + m_counter = 0; + m_isDifferent = false; + } + } + + return b; +} + +NAMESPACE_END + +#endif + +#endif diff --git a/panama.cpp b/panama.cpp new file mode 100644 index 0000000..e121a75 --- /dev/null +++ b/panama.cpp @@ -0,0 +1,146 @@ +// panama.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "panama.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class B> +void Panama<B>::Reset() +{ + m_bstart = 0; + memset(m_state, 0, m_state.size()*4); +} + +template <class B> +void Panama<B>::Iterate(unsigned int count, const word32 *p, word32 *z, const word32 *y) +{ + unsigned int bstart = m_bstart; + word32 *const a = m_state; +#define c (a+17) +#define b ((Stage *)(a+34)) + +// output +#define OA(i) z[i] = ConditionalByteReverse(B::ToEnum(), a[i+9]) +#define OX(i) z[i] = y[i] ^ ConditionalByteReverse(B::ToEnum(), a[i+9]) +// buffer update +#define US(i) {word32 t=b0[i]; b0[i]=ConditionalByteReverse(B::ToEnum(), p[i])^t; b25[(i+6)%8]^=t;} +#define UL(i) {word32 t=b0[i]; b0[i]=a[i+1]^t; b25[(i+6)%8]^=t;} +// gamma and pi +#define GP(i) c[5*i%17] = rotlFixed(a[i] ^ (a[(i+1)%17] | ~a[(i+2)%17]), ((5*i%17)*((5*i%17)+1)/2)%32) +// theta and sigma +#define T(i,x) a[i] = c[i] ^ c[(i+1)%17] ^ c[(i+4)%17] ^ x +#define TS1S(i) T(i+1, ConditionalByteReverse(B::ToEnum(), p[i])) +#define TS1L(i) T(i+1, b4[i]) +#define TS2(i) T(i+9, b16[i]) + + while (count--) + { + if (z) + { + if (y) + { + OX(0); OX(1); OX(2); OX(3); OX(4); OX(5); OX(6); OX(7); + y += 8; + } + else + { + OA(0); OA(1); OA(2); OA(3); OA(4); OA(5); OA(6); OA(7); + } + z += 8; + } + + word32 *const b16 = b[(bstart+16) % STAGES]; + word32 *const b4 = b[(bstart+4) % STAGES]; + bstart = (bstart + STAGES - 1) % STAGES; + word32 *const b0 = b[bstart]; + word32 *const b25 = b[(bstart+25) % STAGES]; + + + if (p) + { + US(0); US(1); US(2); US(3); US(4); US(5); US(6); US(7); + } + else + { + UL(0); UL(1); UL(2); UL(3); UL(4); UL(5); UL(6); UL(7); + } + + GP(0); GP(1); GP(2); GP(3); GP(4); GP(5); GP(6); GP(7); + GP(8); GP(9); GP(10); GP(11); GP(12); GP(13); GP(14); GP(15); GP(16); + + T(0,1); + + if (p) + { + TS1S(0); TS1S(1); TS1S(2); TS1S(3); TS1S(4); TS1S(5); TS1S(6); TS1S(7); + p += 8; + } + else + { + TS1L(0); TS1L(1); TS1L(2); TS1L(3); TS1L(4); TS1L(5); TS1L(6); TS1L(7); + } + + TS2(0); TS2(1); TS2(2); TS2(3); TS2(4); TS2(5); TS2(6); TS2(7); + } + m_bstart = bstart; +} + +template <class B> +unsigned int PanamaHash<B>::HashMultipleBlocks(const word32 *input, unsigned int length) +{ + Iterate(length / BLOCKSIZE, input); + return length % BLOCKSIZE; +} + +template <class B> +void PanamaHash<B>::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(BLOCKSIZE, 0x01); + + vTransform(m_data); + + Iterate(32); // pull + + ConditionalByteReverse(B::ToEnum(), m_state+9, m_state+9, DIGESTSIZE); + memcpy(hash, m_state+9, size); + + Restart(); // reinit for next use +} + +template <class B> +void PanamaCipherPolicy<B>::CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + FixedSizeSecBlock<word32, 8> buf; + + Reset(); + memcpy(buf, key, 32); + Iterate(1, buf); + if (length == 64) + memcpy(buf, key+32, 32); + else + memset(buf, 0, 32); + Iterate(1, buf); + + Iterate(32); +} + +template <class B> +void PanamaCipherPolicy<B>::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + Iterate(iterationCount, NULL, (word32 *)output, (const word32 *)input); +} + +template class Panama<BigEndian>; +template class Panama<LittleEndian>; + +template class PanamaHash<BigEndian>; +template class PanamaHash<LittleEndian>; + +template class PanamaCipherPolicy<BigEndian>; +template class PanamaCipherPolicy<LittleEndian>; + +NAMESPACE_END diff --git a/panama.h b/panama.h new file mode 100644 index 0000000..a24113d --- /dev/null +++ b/panama.h @@ -0,0 +1,105 @@ +#ifndef CRYPTOPP_PANAMA_H +#define CRYPTOPP_PANAMA_H + +#include "seckey.h" +#include "secblock.h" +#include "iterhash.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// base class, do not use directly +template <class B> +class Panama +{ +public: + void Reset(); + void Iterate(unsigned int count, const word32 *p=NULL, word32 *z=NULL, const word32 *y=NULL); + +protected: + typedef word32 Stage[8]; + enum {STAGES = 32}; + + FixedSizeSecBlock<word32, 17*2 + STAGES*sizeof(Stage)> m_state; + unsigned int m_bstart; +}; + +/// <a href="http://www.weidai.com/scan-mirror/md.html#Panama">Panama Hash</a> +template <class B = LittleEndian> +class PanamaHash : protected Panama<B>, public IteratedHash<word32, NativeByteOrder, 32> +{ +public: + enum {DIGESTSIZE = 32}; + PanamaHash() : IteratedHash<word32, NativeByteOrder, 32>(0) {Panama<B>::Reset();} + unsigned int DigestSize() const {return DIGESTSIZE;} + void TruncatedFinal(byte *hash, unsigned int size); + +protected: + void Init() {Panama<B>::Reset();} + void vTransform(const word32 *data) {Iterate(1, data);} // push + unsigned int HashMultipleBlocks(const word32 *input, unsigned int length); +}; + +//! . +template <class B = LittleEndian> +class PanamaMAC_Base : public PanamaHash<B>, public VariableKeyLength<32, 0, UINT_MAX>, public MessageAuthenticationCode +{ +public: + void UncheckedSetKey(const byte *userKey, unsigned int keylength) + { + m_key.Assign(userKey, keylength); + Restart(); + } + + static const char * StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN ? "Panama-BE" : "Panama-LE";} + +protected: + void Init() + { + PanamaHash<B>::Init(); + Update(m_key, m_key.size()); + } + + SecByteBlock m_key; +}; + +/// Panama MAC +template <class B = LittleEndian> +class PanamaMAC : public MessageAuthenticationCodeTemplate<PanamaMAC_Base<B> > +{ +public: + PanamaMAC() {} + PanamaMAC(const byte *key, unsigned int length=PanamaMAC_Base<B>::DEFAULT_KEYLENGTH) + {SetKey(key, length);} +}; + +//! . +template <class B> +struct PanamaCipherInfo : public VariableKeyLength<32, 32, 64, 32, SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + static const char * StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} +}; + +//! . +template <class B> +class PanamaCipherPolicy : public AdditiveCipherConcretePolicy<word32, 32>, + public PanamaCipherInfo<B>, + protected Panama<B> +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); + bool IsRandomAccess() const {return false;} +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#Panama">Panama Stream Cipher</a> +template <class B = LittleEndian> +struct PanamaCipher : public PanamaCipherInfo<B>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<PanamaCipherPolicy<B>, AdditiveCipherTemplate<> > > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1 @@ +#include "pch.h" @@ -0,0 +1,13 @@ +#ifndef CRYPTOPP_PCH_H +#define CRYPTOPP_PCH_H + +#include "config.h" + +#ifdef USE_PRECOMPILED_HEADERS +#include "simple.h" +#include "secblock.h" +#include "misc.h" +#include "smartptr.h" +#endif + +#endif diff --git a/pkcspad.cpp b/pkcspad.cpp new file mode 100644 index 0000000..e94a1fd --- /dev/null +++ b/pkcspad.cpp @@ -0,0 +1,151 @@ +// pkcspad.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pkcspad.h" +#include <assert.h> + +NAMESPACE_BEGIN(CryptoPP) + +template<> const byte PKCS_DigestDecoration<SHA>::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration<SHA>::length = sizeof(PKCS_DigestDecoration<SHA>::decoration); + +template<> const byte PKCS_DigestDecoration<MD2>::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10}; +template<> const unsigned int PKCS_DigestDecoration<MD2>::length = sizeof(PKCS_DigestDecoration<MD2>::decoration); + +template<> const byte PKCS_DigestDecoration<MD5>::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10}; +template<> const unsigned int PKCS_DigestDecoration<MD5>::length = sizeof(PKCS_DigestDecoration<MD5>::decoration); + +template<> const byte PKCS_DigestDecoration<RIPEMD160>::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration<RIPEMD160>::length = sizeof(PKCS_DigestDecoration<RIPEMD160>::decoration); + +template<> const byte PKCS_DigestDecoration<SHA256>::decoration[] = {0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20}; +template<> const unsigned int PKCS_DigestDecoration<SHA256>::length = sizeof(PKCS_DigestDecoration<SHA256>::decoration); + +template<> const byte PKCS_DigestDecoration<SHA384>::decoration[] = {0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30}; +template<> const unsigned int PKCS_DigestDecoration<SHA384>::length = sizeof(PKCS_DigestDecoration<SHA384>::decoration); + +template<> const byte PKCS_DigestDecoration<SHA512>::decoration[] = {0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40}; +template<> const unsigned int PKCS_DigestDecoration<SHA512>::length = sizeof(PKCS_DigestDecoration<SHA512>::decoration); + + + +unsigned int PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(unsigned int paddedLength) const +{ + return paddedLength/8 > 10 ? paddedLength/8-10 : 0; +} + +void PKCS_EncryptionPaddingScheme::Pad(RandomNumberGenerator &rng, const byte *input, unsigned int inputLen, byte *pkcsBlock, unsigned int pkcsBlockLen) const +{ + assert (inputLen <= MaxUnpaddedLength(pkcsBlockLen)); // this should be checked by caller + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + pkcsBlock[0] = 0; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + pkcsBlock[0] = 2; // block type 2 + + // pad with non-zero random bytes + for (unsigned i = 1; i < pkcsBlockLen-inputLen-1; i++) + pkcsBlock[i] = (byte)rng.GenerateWord32(1, 0xff); + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator + memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + +DecodingResult PKCS_EncryptionPaddingScheme::Unpad(const byte *pkcsBlock, unsigned int pkcsBlockLen, byte *output) const +{ + bool invalid = false; + unsigned int maxOutputLen = MaxUnpaddedLength(pkcsBlockLen); + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + invalid = (pkcsBlock[0] != 0) || invalid; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + // Require block type 2. + invalid = (pkcsBlock[0] != 2) || invalid; + + // skip past the padding until we find the seperator + unsigned i=1; + while (i<pkcsBlockLen && pkcsBlock[i++]) { // null body + } + assert(i==pkcsBlockLen || pkcsBlock[i-1]==0); + + unsigned int outputLen = pkcsBlockLen - i; + invalid = (outputLen > maxOutputLen) || invalid; + + if (invalid) + return DecodingResult(); + + memcpy (output, pkcsBlock+i, outputLen); + return DecodingResult(outputLen); +} + +// ******************************************************** + +unsigned int PKCS_SignaturePaddingScheme::MaxUnpaddedLength(unsigned int paddedLength) const +{ + return paddedLength/8 > 10 ? paddedLength/8-10 : 0; +} + +void PKCS_SignaturePaddingScheme::Pad(RandomNumberGenerator &, const byte *input, unsigned int inputLen, byte *pkcsBlock, unsigned int pkcsBlockLen) const +{ + assert (inputLen <= MaxUnpaddedLength(pkcsBlockLen)); // this should be checked by caller + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + pkcsBlock[0] = 0; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + pkcsBlock[0] = 1; // block type 1 + + // padd with 0xff + memset(pkcsBlock+1, 0xff, pkcsBlockLen-inputLen-2); + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator + memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + +DecodingResult PKCS_SignaturePaddingScheme::Unpad(const byte *pkcsBlock, unsigned int pkcsBlockLen, byte *output) const +{ + unsigned int maxOutputLen = MaxUnpaddedLength(pkcsBlockLen); + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + if (pkcsBlock[0] != 0) + return DecodingResult(); + pkcsBlock++; + } + pkcsBlockLen /= 8; + + // Require block type 1. + if (pkcsBlock[0] != 1) + return DecodingResult(); + + // skip past the padding until we find the seperator + unsigned i=1; + while (i<pkcsBlockLen && pkcsBlock[i++]) + if (pkcsBlock[i-1] != 0xff) // not valid padding + return DecodingResult(); + assert(i==pkcsBlockLen || pkcsBlock[i-1]==0); + + unsigned int outputLen = pkcsBlockLen - i; + if (outputLen > maxOutputLen) + return DecodingResult(); + + memcpy (output, pkcsBlock+i, outputLen); + return DecodingResult(outputLen); +} + +NAMESPACE_END diff --git a/pkcspad.h b/pkcspad.h new file mode 100644 index 0000000..347bd95 --- /dev/null +++ b/pkcspad.h @@ -0,0 +1,92 @@ +#ifndef CRYPTOPP_PKCSPAD_H +#define CRYPTOPP_PKCSPAD_H + +#include "cryptlib.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/ca.html#cem_PKCS1-1.5">EME-PKCS1-v1_5</a> +class PKCS_EncryptionPaddingScheme : public PK_PaddingAlgorithm +{ +public: + static const char * StaticAlgorithmName() {return "EME-PKCS1-v1_5";} + + unsigned int MaxUnpaddedLength(unsigned int paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedLength) const; + DecodingResult Unpad(const byte *padded, unsigned int paddedLength, byte *raw) const; +}; + +/// <a href="http://www.weidai.com/scan-mirror/sig.html#sem_PKCS1-1.5">EMSA-PKCS1-v1_5</a> +class PKCS_SignaturePaddingScheme : public PK_PaddingAlgorithm +{ +public: + static const char * StaticAlgorithmName() {return "EMSA-PKCS1-v1_5";} + + unsigned int MaxUnpaddedLength(unsigned int paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedLength) const; + DecodingResult Unpad(const byte *padded, unsigned int paddedLength, byte *raw) const; +}; + +/// <a href="http://www.weidai.com/scan-mirror/sig.html#sem_PKCS1-1.5">EMSA-PKCS1-v1_5</a> +template <class H> +class PKCS_DecoratedHashModule : public HashTransformationWithDefaultTruncation +{ +public: + static std::string StaticAlgorithmName() {return std::string("EMSA-PKCS1-v1_5(") + H::StaticAlgorithmName() + ")";} + + void Update(const byte *input, unsigned int length) + {h.Update(input, length);} + unsigned int DigestSize() const; + void Final(byte *digest); + void Restart() {h.Restart();} + +private: + H h; +}; + +//! PKCS #1 version 1.5, for use with RSAES and RSASSA +/*! The following hash functions are supported for signature: SHA, MD2, MD5, RIPEMD160, SHA256, SHA384, SHA512. */ +struct PKCS1v15 : public SignatureStandard, public EncryptionStandard +{ + typedef PKCS_EncryptionPaddingScheme EncryptionPaddingAlgorithm; + + template <class H> struct SignaturePaddingAlgorithm {typedef PKCS_SignaturePaddingScheme type;}; + template <class H> struct DecoratedHashingAlgorithm {typedef PKCS_DecoratedHashModule<H> type;}; +}; + +template<> struct CryptoStandardTraits<PKCS1v15> : public PKCS1v15 {}; + +template <class H> struct PKCS_DigestDecoration +{ + static const byte decoration[]; + static const unsigned int length; +}; + +// PKCS_DecoratedHashModule can be instantiated with the following +// classes as specified in PKCS#1 v2.0 and P1363a +class SHA; +class MD2; +class MD5; +class RIPEMD160; +class SHA256; +class SHA384; +class SHA512; + +template <class H> +void PKCS_DecoratedHashModule<H>::Final(byte *digest) +{ + const unsigned int decorationLen = PKCS_DigestDecoration<H>::length; + memcpy(digest, PKCS_DigestDecoration<H>::decoration, decorationLen); + h.Final(digest+decorationLen); +} + +template <class H> +unsigned int PKCS_DecoratedHashModule<H>::DigestSize() const +{ + return h.DigestSize() + PKCS_DigestDecoration<H>::length; // PKCS_DigestDecoration<H>::length; +} + +NAMESPACE_END + +#endif diff --git a/polynomi.cpp b/polynomi.cpp new file mode 100644 index 0000000..168fff8 --- /dev/null +++ b/polynomi.cpp @@ -0,0 +1,579 @@ +// polynomi.cpp - written and placed in the public domain by Wei Dai + +// Part of the code for polynomial evaluation and interpolation +// originally came from Hal Finney's public domain secsplit.c. + +#include "pch.h" +#include "polynomi.h" +#include "secblock.h" + +#include <strstream> +#include <iostream> + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> +void PolynomialOver<T>::Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) +{ + m_coefficients.resize(parameter.m_coefficientCount); + for (unsigned int i=0; i<m_coefficients.size(); ++i) + m_coefficients[i] = ring.RandomElement(rng, parameter.m_coefficientParameter); +} + +template <class T> +void PolynomialOver<T>::FromStr(const char *str, const Ring &ring) +{ + std::istrstream in((char *)str); + bool positive = true; + CoefficientType coef; + unsigned int power; + + while (in) + { + std::ws(in); + if (in.peek() == 'x') + coef = ring.MultiplicativeIdentity(); + else + in >> coef; + + std::ws(in); + if (in.peek() == 'x') + { + in.get(); + std::ws(in); + if (in.peek() == '^') + { + in.get(); + in >> power; + } + else + power = 1; + } + else + power = 0; + + if (!positive) + coef = ring.Inverse(coef); + + SetCoefficient(power, coef, ring); + + std::ws(in); + switch (in.get()) + { + case '+': + positive = true; + break; + case '-': + positive = false; + break; + default: + return; // something's wrong with the input string + } + } +} + +template <class T> +unsigned int PolynomialOver<T>::CoefficientCount(const Ring &ring) const +{ + unsigned count = m_coefficients.size(); + while (count && ring.Equal(m_coefficients[count-1], ring.Identity())) + count--; + const_cast<std::vector<CoefficientType> &>(m_coefficients).resize(count); + return count; +} + +template <class T> +typename PolynomialOver<T>::CoefficientType PolynomialOver<T>::GetCoefficient(unsigned int i, const Ring &ring) const +{ + return (i < m_coefficients.size()) ? m_coefficients[i] : ring.Identity(); +} + +template <class T> +PolynomialOver<T>& PolynomialOver<T>::operator=(const PolynomialOver<T>& t) +{ + if (this != &t) + { + m_coefficients.resize(t.m_coefficients.size()); + for (unsigned int i=0; i<m_coefficients.size(); i++) + m_coefficients[i] = t.m_coefficients[i]; + } + return *this; +} + +template <class T> +PolynomialOver<T>& PolynomialOver<T>::Accumulate(const PolynomialOver<T>& t, const Ring &ring) +{ + unsigned int count = t.CoefficientCount(ring); + + if (count > CoefficientCount(ring)) + m_coefficients.resize(count, ring.Identity()); + + for (unsigned int i=0; i<count; i++) + ring.Accumulate(m_coefficients[i], t.GetCoefficient(i, ring)); + + return *this; +} + +template <class T> +PolynomialOver<T>& PolynomialOver<T>::Reduce(const PolynomialOver<T>& t, const Ring &ring) +{ + unsigned int count = t.CoefficientCount(ring); + + if (count > CoefficientCount(ring)) + m_coefficients.resize(count, ring.Identity()); + + for (unsigned int i=0; i<count; i++) + ring.Reduce(m_coefficients[i], t.GetCoefficient(i, ring)); + + return *this; +} + +template <class T> +typename PolynomialOver<T>::CoefficientType PolynomialOver<T>::EvaluateAt(const CoefficientType &x, const Ring &ring) const +{ + int degree = Degree(ring); + + if (degree < 0) + return ring.Identity(); + + CoefficientType result = m_coefficients[degree]; + for (int j=degree-1; j>=0; j--) + { + result = ring.Multiply(result, x); + ring.Accumulate(result, m_coefficients[j]); + } + return result; +} + +template <class T> +PolynomialOver<T>& PolynomialOver<T>::ShiftLeft(unsigned int n, const Ring &ring) +{ + unsigned int i = CoefficientCount(ring) + n; + m_coefficients.resize(i, ring.Identity()); + while (i > n) + { + i--; + m_coefficients[i] = m_coefficients[i-n]; + } + while (i) + { + i--; + m_coefficients[i] = ring.Identity(); + } + return *this; +} + +template <class T> +PolynomialOver<T>& PolynomialOver<T>::ShiftRight(unsigned int n, const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + if (count > n) + { + for (unsigned int i=0; i<count-n; i++) + m_coefficients[i] = m_coefficients[i+n]; + m_coefficients.resize(count-n, ring.Identity()); + } + else + m_coefficients.resize(0, ring.Identity()); + return *this; +} + +template <class T> +void PolynomialOver<T>::SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring) +{ + if (i >= m_coefficients.size()) + m_coefficients.resize(i+1, ring.Identity()); + m_coefficients[i] = value; +} + +template <class T> +void PolynomialOver<T>::Negate(const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + for (unsigned int i=0; i<count; i++) + m_coefficients[i] = ring.Inverse(m_coefficients[i]); +} + +template <class T> +void PolynomialOver<T>::swap(PolynomialOver<T> &t) +{ + m_coefficients.swap(t.m_coefficients); +} + +template <class T> +bool PolynomialOver<T>::Equals(const PolynomialOver<T>& t, const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + + if (count != t.CoefficientCount(ring)) + return false; + + for (unsigned int i=0; i<count; i++) + if (!ring.Equal(m_coefficients[i], t.m_coefficients[i])) + return false; + + return true; +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::Plus(const PolynomialOver<T>& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver<T> result(ring, count); + + for (i=0; i<tCount; i++) + result.m_coefficients[i] = ring.Add(m_coefficients[i], t.m_coefficients[i]); + for (; i<count; i++) + result.m_coefficients[i] = m_coefficients[i]; + + return result; + } + else + { + PolynomialOver<T> result(ring, tCount); + + for (i=0; i<count; i++) + result.m_coefficients[i] = ring.Add(m_coefficients[i], t.m_coefficients[i]); + for (; i<tCount; i++) + result.m_coefficients[i] = t.m_coefficients[i]; + + return result; + } +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::Minus(const PolynomialOver<T>& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver<T> result(ring, count); + + for (i=0; i<tCount; i++) + result.m_coefficients[i] = ring.Subtract(m_coefficients[i], t.m_coefficients[i]); + for (; i<count; i++) + result.m_coefficients[i] = m_coefficients[i]; + + return result; + } + else + { + PolynomialOver<T> result(ring, tCount); + + for (i=0; i<count; i++) + result.m_coefficients[i] = ring.Subtract(m_coefficients[i], t.m_coefficients[i]); + for (; i<tCount; i++) + result.m_coefficients[i] = ring.Inverse(t.m_coefficients[i]); + + return result; + } +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::Inverse(const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + PolynomialOver<T> result(ring, count); + + for (unsigned int i=0; i<count; i++) + result.m_coefficients[i] = ring.Inverse(m_coefficients[i]); + + return result; +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::Times(const PolynomialOver<T>& t, const Ring &ring) const +{ + if (IsZero(ring) || t.IsZero(ring)) + return PolynomialOver<T>(); + + unsigned int count1 = CoefficientCount(ring), count2 = t.CoefficientCount(ring); + PolynomialOver<T> result(ring, count1 + count2 - 1); + + for (unsigned int i=0; i<count1; i++) + for (unsigned int j=0; j<count2; j++) + ring.Accumulate(result.m_coefficients[i+j], ring.Multiply(m_coefficients[i], t.m_coefficients[j])); + + return result; +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::DividedBy(const PolynomialOver<T>& t, const Ring &ring) const +{ + PolynomialOver<T> remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return quotient; +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::Modulo(const PolynomialOver<T>& t, const Ring &ring) const +{ + PolynomialOver<T> remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return remainder; +} + +template <class T> +PolynomialOver<T> PolynomialOver<T>::MultiplicativeInverse(const Ring &ring) const +{ + return Degree(ring)==0 ? ring.MultiplicativeInverse(m_coefficients[0]) : ring.Identity(); +} + +template <class T> +bool PolynomialOver<T>::IsUnit(const Ring &ring) const +{ + return Degree(ring)==0 && ring.IsUnit(m_coefficients[0]); +} + +template <class T> +std::istream& PolynomialOver<T>::Input(std::istream &in, const Ring &ring) +{ + char c; + unsigned int length = 0; + SecBlock<char> str(length + 16); + bool paren = false; + + std::ws(in); + + if (in.peek() == '(') + { + paren = true; + in.get(); + } + + do + { + in.read(&c, 1); + str[length++] = c; + if (length >= str.size()) + str.Grow(length + 16); + } + // if we started with a left paren, then read until we find a right paren, + // otherwise read until the end of the line + while (in && ((paren && c != ')') || (!paren && c != '\n'))); + + str[length-1] = '\0'; + *this = PolynomialOver<T>(str, ring); + + return in; +} + +template <class T> +std::ostream& PolynomialOver<T>::Output(std::ostream &out, const Ring &ring) const +{ + unsigned int i = CoefficientCount(ring); + if (i) + { + bool firstTerm = true; + + while (i--) + { + if (m_coefficients[i] != ring.Identity()) + { + if (firstTerm) + { + firstTerm = false; + if (!i || !ring.Equal(m_coefficients[i], ring.MultiplicativeIdentity())) + out << m_coefficients[i]; + } + else + { + CoefficientType inverse = ring.Inverse(m_coefficients[i]); + std::ostrstream pstr, nstr; + + pstr << m_coefficients[i]; + nstr << inverse; + + if (pstr.pcount() <= nstr.pcount()) + { + out << " + "; + if (!i || !ring.Equal(m_coefficients[i], ring.MultiplicativeIdentity())) + out << m_coefficients[i]; + } + else + { + out << " - "; + if (!i || !ring.Equal(inverse, ring.MultiplicativeIdentity())) + out << inverse; + } + } + + switch (i) + { + case 0: + break; + case 1: + out << "x"; + break; + default: + out << "x^" << i; + } + } + } + } + else + { + out << ring.Identity(); + } + return out; +} + +template <class T> +void PolynomialOver<T>::Divide(PolynomialOver<T> &r, PolynomialOver<T> &q, const PolynomialOver<T> &a, const PolynomialOver<T> &d, const Ring &ring) +{ + unsigned int i = a.CoefficientCount(ring); + const int dDegree = d.Degree(ring); + + if (dDegree < 0) + throw DivideByZero(); + + r = a; + q.m_coefficients.resize(STDMAX(0, int(i - dDegree))); + + while (i > (unsigned int)dDegree) + { + --i; + q.m_coefficients[i-dDegree] = ring.Divide(r.m_coefficients[i], d.m_coefficients[dDegree]); + for (int j=0; j<=dDegree; j++) + ring.Reduce(r.m_coefficients[i-dDegree+j], ring.Multiply(q.m_coefficients[i-dDegree], d.m_coefficients[j])); + } + + r.CoefficientCount(ring); // resize r.m_coefficients +} + +// ******************************************************** + +// helper function for Interpolate() and InterpolateAt() +template <class T> +void RingOfPolynomialsOver<T>::CalculateAlpha(std::vector<CoefficientType> &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + for (unsigned int j=0; j<n; ++j) + alpha[j] = y[j]; + + for (unsigned int k=1; k<n; ++k) + { + for (unsigned int j=n-1; j>=k; --j) + { + m_ring.Reduce(alpha[j], alpha[j-1]); + + CoefficientType d = m_ring.Subtract(x[j], x[j-k]); + if (!m_ring.IsUnit(d)) + throw InterpolationFailed(); + alpha[j] = m_ring.Divide(alpha[j], d); + } + } +} + +template <class T> +RingOfPolynomialsOver<T>::Element RingOfPolynomialsOver<T>::Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + assert(n > 0); + + std::vector<CoefficientType> alpha(n); + CalculateAlpha(alpha, x, y, n); + + std::vector<CoefficientType> coefficients((size_t)n, m_ring.Identity()); + coefficients[0] = alpha[n-1]; + + for (int j=n-2; j>=0; --j) + { + for (unsigned int i=n-j-1; i>0; i--) + coefficients[i] = m_ring.Subtract(coefficients[i-1], m_ring.Multiply(coefficients[i], x[j])); + + coefficients[0] = m_ring.Subtract(alpha[j], m_ring.Multiply(coefficients[0], x[j])); + } + + return PolynomialOver<T>(coefficients.begin(), coefficients.end()); +} + +template <class T> +typename RingOfPolynomialsOver<T>::CoefficientType RingOfPolynomialsOver<T>::InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + assert(n > 0); + + std::vector<CoefficientType> alpha(n); + CalculateAlpha(alpha, x, y, n); + + CoefficientType result = alpha[n-1]; + for (int j=n-2; j>=0; --j) + { + result = m_ring.Multiply(result, m_ring.Subtract(position, x[j])); + m_ring.Accumulate(result, alpha[j]); + } + return result; +} + +template <class Ring, class Element> +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + { + Element t = ring.MultiplicativeIdentity(); + for (unsigned int j=0; j<n; j++) + if (i != j) + t = ring.Multiply(t, ring.Subtract(x[i], x[j])); + w[i] = ring.MultiplicativeInverse(t); + } +} + +template <class Ring, class Element> +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n) +{ + assert(n > 0); + + std::vector<Element> a(2*n-1); + unsigned int i; + + for (i=0; i<n; i++) + a[n-1+i] = ring.Subtract(position, x[i]); + + for (i=n-1; i>1; i--) + a[i-1] = ring.Multiply(a[2*i], a[2*i-1]); + + a[0] = ring.MultiplicativeIdentity(); + + for (i=0; i<n-1; i++) + { + std::swap(a[2*i+1], a[2*i+2]); + a[2*i+1] = ring.Multiply(a[i], a[2*i+1]); + a[2*i+2] = ring.Multiply(a[i], a[2*i+2]); + } + + for (i=0; i<n; i++) + v[i] = ring.Multiply(a[n-1+i], w[i]); +} + +template <class Ring, class Element> +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n) +{ + Element result = ring.Identity(); + for (unsigned int i=0; i<n; i++) + ring.Accumulate(result, ring.Multiply(y[i], v[i])); + return result; +} + +// ******************************************************** + +template <class T, int instance> +const PolynomialOverFixedRing<T, instance> &PolynomialOverFixedRing<T, instance>::Zero() +{ + static const PolynomialOverFixedRing<T, instance> zero; + return zero; +} + +template <class T, int instance> +const PolynomialOverFixedRing<T, instance> &PolynomialOverFixedRing<T, instance>::One() +{ + static const PolynomialOverFixedRing<T, instance> one = fixedRing.MultiplicativeIdentity(); + return one; +} + +NAMESPACE_END diff --git a/polynomi.h b/polynomi.h new file mode 100644 index 0000000..3a327e5 --- /dev/null +++ b/polynomi.h @@ -0,0 +1,451 @@ +#ifndef CRYPTOPP_POLYNOMI_H +#define CRYPTOPP_POLYNOMI_H + +/*! \file */ + +#include "cryptlib.h" +#include "misc.h" +#include "algebra.h" + +#include <iosfwd> +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +//! represents single-variable polynomials over arbitrary rings +/*! \nosubgrouping */ +template <class T> class PolynomialOver +{ +public: + //! \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + //! division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialOver<T>: division by zero") {} + }; + + //! specify the distribution for randomization functions + class RandomizationParameter + { + public: + RandomizationParameter(unsigned int coefficientCount, const typename T::RandomizationParameter &coefficientParameter ) + : m_coefficientCount(coefficientCount), m_coefficientParameter(coefficientParameter) {} + + private: + unsigned int m_coefficientCount; + typename T::RandomizationParameter m_coefficientParameter; + friend class PolynomialOver<T>; + }; + + typedef T Ring; + typedef typename T::Element CoefficientType; + //@} + + //! \name CREATORS + //@{ + //! creates the zero polynomial + PolynomialOver() {} + + //! + PolynomialOver(const Ring &ring, unsigned int count) + : m_coefficients((size_t)count, ring.Identity()) {} + + //! copy constructor + PolynomialOver(const PolynomialOver<Ring> &t) + : m_coefficients(t.m_coefficients.size()) {*this = t;} + + //! construct constant polynomial + PolynomialOver(const CoefficientType &element) + : m_coefficients(1, element) {} + + //! construct polynomial with specified coefficients, starting from coefficient of x^0 + template <typename Iterator> PolynomialOver(Iterator begin, Iterator end) + : m_coefficients(begin, end) {} + + //! convert from string + PolynomialOver(const char *str, const Ring &ring) {FromStr(str, ring);} + + //! convert from big-endian byte array + PolynomialOver(const byte *encodedPolynomialOver, unsigned int byteCount); + + //! convert from Basic Encoding Rules encoded byte array + explicit PolynomialOver(const byte *BEREncodedPolynomialOver); + + //! convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOver(BufferedTransformation &bt); + + //! create a random PolynomialOver<T> + PolynomialOver(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) + {Randomize(rng, parameter, ring);} + //@} + + //! \name ACCESSORS + //@{ + //! the zero polynomial will return a degree of -1 + int Degree(const Ring &ring) const {return int(CoefficientCount(ring))-1;} + //! + unsigned int CoefficientCount(const Ring &ring) const; + //! return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i, const Ring &ring) const; + //@} + + //! \name MANIPULATORS + //@{ + //! + PolynomialOver<Ring>& operator=(const PolynomialOver<Ring>& t); + + //! + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring); + + //! set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring); + + //! + void Negate(const Ring &ring); + + //! + void swap(PolynomialOver<Ring> &t); + //@} + + + //! \name BASIC ARITHMETIC ON POLYNOMIALS + //@{ + bool Equals(const PolynomialOver<Ring> &t, const Ring &ring) const; + bool IsZero(const Ring &ring) const {return CoefficientCount(ring)==0;} + + PolynomialOver<Ring> Plus(const PolynomialOver<Ring>& t, const Ring &ring) const; + PolynomialOver<Ring> Minus(const PolynomialOver<Ring>& t, const Ring &ring) const; + PolynomialOver<Ring> Inverse(const Ring &ring) const; + + PolynomialOver<Ring> Times(const PolynomialOver<Ring>& t, const Ring &ring) const; + PolynomialOver<Ring> DividedBy(const PolynomialOver<Ring>& t, const Ring &ring) const; + PolynomialOver<Ring> Modulo(const PolynomialOver<Ring>& t, const Ring &ring) const; + PolynomialOver<Ring> MultiplicativeInverse(const Ring &ring) const; + bool IsUnit(const Ring &ring) const; + + PolynomialOver<Ring>& Accumulate(const PolynomialOver<Ring>& t, const Ring &ring); + PolynomialOver<Ring>& Reduce(const PolynomialOver<Ring>& t, const Ring &ring); + + //! + PolynomialOver<Ring> Doubled(const Ring &ring) const {return Plus(*this, ring);} + //! + PolynomialOver<Ring> Squared(const Ring &ring) const {return Times(*this, ring);} + + CoefficientType EvaluateAt(const CoefficientType &x, const Ring &ring) const; + + PolynomialOver<Ring>& ShiftLeft(unsigned int n, const Ring &ring); + PolynomialOver<Ring>& ShiftRight(unsigned int n, const Ring &ring); + + //! calculate r and q such that (a == d*q + r) && (0 <= degree of r < degree of d) + static void Divide(PolynomialOver<Ring> &r, PolynomialOver<Ring> &q, const PolynomialOver<Ring> &a, const PolynomialOver<Ring> &d, const Ring &ring); + //@} + + //! \name INPUT/OUTPUT + //@{ + std::istream& Input(std::istream &in, const Ring &ring); + std::ostream& Output(std::ostream &out, const Ring &ring) const; + //@} + +private: + void FromStr(const char *str, const Ring &ring); + + std::vector<CoefficientType> m_coefficients; +}; + +//! Polynomials over a fixed ring +/*! Having a fixed ring allows overloaded operators */ +template <class T, int instance> class PolynomialOverFixedRing : private PolynomialOver<T> +{ + typedef PolynomialOver<T> B; + typedef PolynomialOverFixedRing<T, instance> ThisType; + +public: + typedef T Ring; + typedef typename T::Element CoefficientType; + typedef B::DivideByZero DivideByZero; + typedef B::RandomizationParameter RandomizationParameter; + + //! \name CREATORS + //@{ + //! creates the zero polynomial + PolynomialOverFixedRing(unsigned int count = 0) : B(fixedRing, count) {} + + //! copy constructor + PolynomialOverFixedRing(const ThisType &t) : B(t) {} + + explicit PolynomialOverFixedRing(const B &t) : B(t) {} + + //! construct constant polynomial + PolynomialOverFixedRing(const CoefficientType &element) : B(element) {} + + //! construct polynomial with specified coefficients, starting from coefficient of x^0 + template <typename Iterator> PolynomialOverFixedRing(Iterator first, Iterator last) + : B(first, last) {} + + //! convert from string + explicit PolynomialOverFixedRing(const char *str) : B(str, fixedRing) {} + + //! convert from big-endian byte array + PolynomialOverFixedRing(const byte *encodedPoly, unsigned int byteCount) : B(encodedPoly, byteCount) {} + + //! convert from Basic Encoding Rules encoded byte array + explicit PolynomialOverFixedRing(const byte *BEREncodedPoly) : B(BEREncodedPoly) {} + + //! convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOverFixedRing(BufferedTransformation &bt) : B(bt) {} + + //! create a random PolynomialOverFixedRing + PolynomialOverFixedRing(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) : B(rng, parameter, fixedRing) {} + + static const ThisType &Zero(); + static const ThisType &One(); + //@} + + //! \name ACCESSORS + //@{ + //! the zero polynomial will return a degree of -1 + int Degree() const {return B::Degree(fixedRing);} + //! degree + 1 + unsigned int CoefficientCount() const {return B::CoefficientCount(fixedRing);} + //! return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i) const {return B::GetCoefficient(i, fixedRing);} + //! return coefficient for x^i + CoefficientType operator[](unsigned int i) const {return B::GetCoefficient(i, fixedRing);} + //@} + + //! \name MANIPULATORS + //@{ + //! + ThisType& operator=(const ThisType& t) {B::operator=(t); return *this;} + //! + ThisType& operator+=(const ThisType& t) {Accumulate(t, fixedRing); return *this;} + //! + ThisType& operator-=(const ThisType& t) {Reduce(t, fixedRing); return *this;} + //! + ThisType& operator*=(const ThisType& t) {return *this = *this*t;} + //! + ThisType& operator/=(const ThisType& t) {return *this = *this/t;} + //! + ThisType& operator%=(const ThisType& t) {return *this = *this%t;} + + //! + ThisType& operator<<=(unsigned int n) {ShiftLeft(n, fixedRing); return *this;} + //! + ThisType& operator>>=(unsigned int n) {ShiftRight(n, fixedRing); return *this;} + + //! set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value) {B::SetCoefficient(i, value, fixedRing);} + + //! + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) {B::Randomize(rng, parameter, fixedRing);} + + //! + void Negate() {B::Negate(fixedRing);} + + void swap(ThisType &t) {B::swap(t);} + //@} + + //! \name UNARY OPERATORS + //@{ + //! + bool operator!() const {return CoefficientCount()==0;} + //! + ThisType operator+() const {return *this;} + //! + ThisType operator-() const {return ThisType(Inverse(fixedRing));} + //@} + + //! \name BINARY OPERATORS + //@{ + //! + friend ThisType operator>>(ThisType a, unsigned int n) {return ThisType(a>>=n);} + //! + friend ThisType operator<<(ThisType a, unsigned int n) {return ThisType(a<<=n);} + //@} + + //! \name OTHER ARITHMETIC FUNCTIONS + //@{ + //! + ThisType MultiplicativeInverse() const {return ThisType(B::MultiplicativeInverse(fixedRing));} + //! + bool IsUnit() const {return B::IsUnit(fixedRing);} + + //! + ThisType Doubled() const {return ThisType(B::Doubled(fixedRing));} + //! + ThisType Squared() const {return ThisType(B::Squared(fixedRing));} + + CoefficientType EvaluateAt(const CoefficientType &x) const {return B::EvaluateAt(x, fixedRing);} + + //! calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + static void Divide(ThisType &r, ThisType &q, const ThisType &a, const ThisType &d) + {B::Divide(r, q, a, d, fixedRing);} + //@} + + //! \name INPUT/OUTPUT + //@{ + //! + friend std::istream& operator>>(std::istream& in, ThisType &a) + {return a.Input(in, fixedRing);} + //! + friend std::ostream& operator<<(std::ostream& out, const ThisType &a) + {return a.Output(out, fixedRing);} + //@} + +private: + static const Ring fixedRing; +}; + +//! Ring of polynomials over another ring +template <class T> class RingOfPolynomialsOver : public AbstractEuclideanDomain<PolynomialOver<T> > +{ +public: + typedef T CoefficientRing; + typedef PolynomialOver<T> Element; + typedef Element::CoefficientType CoefficientType; + typedef Element::RandomizationParameter RandomizationParameter; + + RingOfPolynomialsOver(const CoefficientRing &ring) : m_ring(ring) {} + + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) + {return Element(rng, parameter, m_ring);} + + bool Equal(const Element &a, const Element &b) const + {return a.Equals(b, m_ring);} + + const Element& Identity() const + {return result = m_ring.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a.Plus(b, m_ring);} + + Element& Accumulate(Element &a, const Element &b) const + {a.Accumulate(b, m_ring); return a;} + + const Element& Inverse(const Element &a) const + {return result = a.Inverse(m_ring);} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a.Minus(b, m_ring);} + + Element& Reduce(Element &a, const Element &b) const + {return a.Reduce(b, m_ring);} + + const Element& Double(const Element &a) const + {return result = a.Doubled(m_ring);} + + const Element& MultiplicativeIdentity() const + {return result = m_ring.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a.Times(b, m_ring);} + + const Element& Square(const Element &a) const + {return result = a.Squared(m_ring);} + + bool IsUnit(const Element &a) const + {return a.IsUnit(m_ring);} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse(m_ring);} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a.DividedBy(b, m_ring);} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a.Modulo(b, m_ring);} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d, m_ring);} + + class InterpolationFailed : public Exception + { + public: + InterpolationFailed() : Exception(OTHER_ERROR, "RingOfPolynomialsOver<T>: interpolation failed") {} + }; + + Element Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + // a faster version of Interpolate(x, y, n).EvaluateAt(position) + CoefficientType InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; +/* + void PrepareBulkInterpolation(CoefficientType *w, const CoefficientType x[], unsigned int n) const; + void PrepareBulkInterpolationAt(CoefficientType *v, const CoefficientType &position, const CoefficientType x[], const CoefficientType w[], unsigned int n) const; + CoefficientType BulkInterpolateAt(const CoefficientType y[], const CoefficientType v[], unsigned int n) const; +*/ +protected: + void CalculateAlpha(std::vector<CoefficientType> &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + CoefficientRing m_ring; +}; + +template <class Ring, class Element> +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n); +template <class Ring, class Element> +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n); +template <class Ring, class Element> +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n); + +//! +template <class T, int instance> +inline bool operator==(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return a.Equals(b, fixedRing);} +//! +template <class T, int instance> +inline bool operator!=(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return !(a==b);} + +//! +template <class T, int instance> +inline bool operator> (const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return a.Degree() > b.Degree();} +//! +template <class T, int instance> +inline bool operator>=(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return a.Degree() >= b.Degree();} +//! +template <class T, int instance> +inline bool operator< (const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return a.Degree() < b.Degree();} +//! +template <class T, int instance> +inline bool operator<=(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return a.Degree() <= b.Degree();} + +//! +template <class T, int instance> +inline CryptoPP::PolynomialOverFixedRing<T, instance> operator+(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return CryptoPP::PolynomialOverFixedRing<T, instance>(a.Plus(b, fixedRing));} +//! +template <class T, int instance> +inline CryptoPP::PolynomialOverFixedRing<T, instance> operator-(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return CryptoPP::PolynomialOverFixedRing<T, instance>(a.Minus(b, fixedRing));} +//! +template <class T, int instance> +inline CryptoPP::PolynomialOverFixedRing<T, instance> operator*(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return CryptoPP::PolynomialOverFixedRing<T, instance>(a.Times(b, fixedRing));} +//! +template <class T, int instance> +inline CryptoPP::PolynomialOverFixedRing<T, instance> operator/(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return CryptoPP::PolynomialOverFixedRing<T, instance>(a.DividedBy(b, fixedRing));} +//! +template <class T, int instance> +inline CryptoPP::PolynomialOverFixedRing<T, instance> operator%(const CryptoPP::PolynomialOverFixedRing<T, instance> &a, const CryptoPP::PolynomialOverFixedRing<T, instance> &b) + {return CryptoPP::PolynomialOverFixedRing<T, instance>(a.Modulo(b, fixedRing));} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template<class T> inline void swap(CryptoPP::PolynomialOver<T> &a, CryptoPP::PolynomialOver<T> &b) +{ + a.swap(b); +} +template<class T, int i> inline void swap(CryptoPP::PolynomialOverFixedRing<T,i> &a, CryptoPP::PolynomialOverFixedRing<T,i> &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif @@ -0,0 +1,169 @@ +#ifndef CRYPTOPP_PSSR_H +#define CRYPTOPP_PSSR_H + +#include "pubkey.h" +#include <functional> + +NAMESPACE_BEGIN(CryptoPP) + +// TODO: implement standard variant of PSSR +template <class H, class MGF=P1363_MGF1<H> > +class PSSR : public SignatureEncodingMethodWithRecovery +{ +public: + PSSR(unsigned int representativeBitLen); + PSSR(const byte *representative, unsigned int representativeBitLen); + ~PSSR() {} + void Update(const byte *input, unsigned int length); + unsigned int DigestSize() const {return BitsToBytes(representativeBitLen);} + void Restart() {h.Restart();} + void Encode(RandomNumberGenerator &rng, byte *representative); + bool Verify(const byte *representative); + DecodingResult Decode(byte *message); + unsigned int MaximumRecoverableLength() const {return MaximumRecoverableLength(representativeBitLen);} + static unsigned int MaximumRecoverableLength(unsigned int representativeBitLen); + static bool AllowLeftoverMessage() {return true;} + +protected: + static void EncodeRepresentative(byte *representative, unsigned int representativeBitLen, const byte *w, const byte *seed, const byte *m1, unsigned int m1Len); + static unsigned int DecodeRepresentative(const byte *representative, unsigned int representativeBitLen, byte *w, byte *seed, byte *m1); + + unsigned int representativeBitLen, m1Len; + H h; + SecByteBlock m1, w, seed; +}; + +template <class H, class MGF> +PSSR<H,MGF>::PSSR(unsigned int representativeBitLen) + : representativeBitLen(representativeBitLen), m1Len(0) + , m1(MaximumRecoverableLength()), w(H::DIGESTSIZE), seed(H::DIGESTSIZE) +{ +} + +template <class H, class MGF> +PSSR<H,MGF>::PSSR(const byte *representative, unsigned int representativeBitLen) + : representativeBitLen(representativeBitLen), m1Len(0) + , m1(MaximumRecoverableLength()), w(H::DIGESTSIZE), seed(H::DIGESTSIZE) +{ + m1Len = DecodeRepresentative(representative, representativeBitLen, w, seed, m1); + h.Update(m1, m1Len); +} + +template <class H, class MGF> +void PSSR<H,MGF>::Update(const byte *input, unsigned int length) +{ + unsigned int m1LenInc = STDMIN(length, MaximumRecoverableLength() - m1Len); + memcpy(m1+m1Len, input, m1LenInc); + m1Len += m1LenInc; + h.Update(input, length); +} + +template <class H, class MGF> +void PSSR<H,MGF>::Encode(RandomNumberGenerator &rng, byte *representative) +{ + rng.GenerateBlock(seed, seed.size()); + h.Update(seed, seed.size()); + h.Final(w); + EncodeRepresentative(representative, representativeBitLen, w, seed, m1, m1Len); +} + +template <class H, class MGF> +bool PSSR<H,MGF>::Verify(const byte *representative) +{ + SecByteBlock m1r(MaximumRecoverableLength()), wr(H::DIGESTSIZE); + unsigned int m1rLen = DecodeRepresentative(representative, representativeBitLen, wr, seed, m1r); + h.Update(seed, seed.size()); + h.Final(w); + return m1Len==m1rLen && memcmp(m1, m1r, m1Len)==0 && w==wr; +} + +template <class H, class MGF> +DecodingResult PSSR<H,MGF>::Decode(byte *message) +{ + SecByteBlock wh(H::DIGESTSIZE); + h.Update(seed, seed.size()); + h.Final(wh); + if (wh == w) + { + memcpy(message, m1, m1Len); + return DecodingResult(m1Len); + } + else + return DecodingResult(); +} + +template <class H, class MGF> +unsigned int PSSR<H,MGF>::MaximumRecoverableLength(unsigned int paddedLength) +{ + return paddedLength/8 > 1+2*H::DIGESTSIZE ? paddedLength/8-1-2*H::DIGESTSIZE : 0; +} + +template <class H, class MGF> +void PSSR<H,MGF>::EncodeRepresentative(byte *pssrBlock, unsigned int pssrBlockLen, const byte *w, const byte *seed, const byte *m1, unsigned int m1Len) +{ + assert (m1Len <= MaximumRecoverableLength(pssrBlockLen)); + + // convert from bit length to byte length + if (pssrBlockLen % 8 != 0) + { + pssrBlock[0] = 0; + pssrBlock++; + } + pssrBlockLen /= 8; + + const unsigned int hLen = H::DIGESTSIZE; + const unsigned int wLen = hLen, seedLen = hLen, dbLen = pssrBlockLen-wLen-seedLen; + byte *const maskedSeed = pssrBlock+wLen; + byte *const maskedDB = pssrBlock+wLen+seedLen; + + memcpy(pssrBlock, w, wLen); + memcpy(maskedSeed, seed, seedLen); + memset(maskedDB, 0, dbLen-m1Len-1); + maskedDB[dbLen-m1Len-1] = 0x01; + memcpy(maskedDB+dbLen-m1Len, m1, m1Len); + + MGF::GenerateAndMask(maskedSeed, seedLen+dbLen, w, wLen); +} + +template <class H, class MGF> +unsigned int PSSR<H,MGF>::DecodeRepresentative(const byte *pssrBlock, unsigned int pssrBlockLen, byte *w, byte *seed, byte *m1) +{ + // convert from bit length to byte length + if (pssrBlockLen % 8 != 0) + { + if (pssrBlock[0] != 0) + return 0; + pssrBlock++; + } + pssrBlockLen /= 8; + + const unsigned int hLen = H::DIGESTSIZE; + const unsigned int wLen = hLen, seedLen = hLen, dbLen = pssrBlockLen-wLen-seedLen; + + if (pssrBlockLen < 2*hLen+1) + return 0; + + memcpy(w, pssrBlock, wLen); + SecByteBlock t(pssrBlock+wLen, pssrBlockLen-wLen); + byte *const maskedSeed = t; + byte *const maskedDB = t+seedLen; + + MGF::GenerateAndMask(maskedSeed, seedLen+dbLen, w, wLen); + memcpy(seed, maskedSeed, seedLen); + + // DB = 00 ... || 01 || M + + byte *M = std::find_if(maskedDB, maskedDB+dbLen, std::bind2nd(std::not_equal_to<byte>(), 0)); + if (M!=maskedDB+dbLen && *M == 0x01) + { + M++; + memcpy(m1, M, maskedDB+dbLen-M); + return maskedDB+dbLen-M; + } + else + return 0; +} + +NAMESPACE_END + +#endif diff --git a/pubkey.cpp b/pubkey.cpp new file mode 100644 index 0000000..94dc271 --- /dev/null +++ b/pubkey.cpp @@ -0,0 +1,58 @@ +// pubkey.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +void TF_DigestSignerBase::SignDigest(RandomNumberGenerator &rng, const byte *digest, unsigned int digestLen, byte *signature) const +{ + assert(digestLen <= MaxDigestLength()); + + SecByteBlock paddedBlock(PaddedBlockByteLength()); + GetPaddingAlgorithm().Pad(rng, digest, digestLen, paddedBlock, PaddedBlockBitLength()); + GetTrapdoorFunctionInterface().CalculateRandomizedInverse(rng, Integer(paddedBlock, paddedBlock.size())).Encode(signature, DigestSignatureLength()); +} + +bool TF_DigestVerifierBase::VerifyDigest(const byte *digest, unsigned int digestLen, const byte *signature) const +{ + SecByteBlock paddedBlock(PaddedBlockByteLength()); + Integer x = GetTrapdoorFunctionInterface().ApplyFunction(Integer(signature, DigestSignatureLength())); + if (x.ByteCount() > paddedBlock.size()) + x = Integer::Zero(); // don't return false here to prevent timing attack + x.Encode(paddedBlock, paddedBlock.size()); + if (GetPaddingAlgorithm().IsReversible()) + { + SecByteBlock recoveredDigest(MaxDigestLength()); + DecodingResult result = GetPaddingAlgorithm().Unpad(paddedBlock, PaddedBlockBitLength(), recoveredDigest); + return result == DecodingResult(digestLen) && memcmp(digest, recoveredDigest, digestLen) == 0; + } + else + { + SecByteBlock paddedBlock2(PaddedBlockByteLength()); + GetPaddingAlgorithm().Pad(NullRNG(), digest, digestLen, paddedBlock2, PaddedBlockBitLength()); + return paddedBlock == paddedBlock2; + } +} + +DecodingResult TF_DecryptorBase::FixedLengthDecrypt(const byte *cipherText, byte *plainText) const +{ + SecByteBlock paddedBlock(PaddedBlockByteLength()); + Integer x = GetTrapdoorFunctionInterface().CalculateInverse(Integer(cipherText, FixedCiphertextLength())); + if (x.ByteCount() > paddedBlock.size()) + x = Integer::Zero(); // don't return false here to prevent timing attack + x.Encode(paddedBlock, paddedBlock.size()); + return GetPaddingAlgorithm().Unpad(paddedBlock, PaddedBlockBitLength(), plainText); +} + +void TF_EncryptorBase::Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const +{ + if (plainTextLength > FixedMaxPlaintextLength()) + throw InvalidArgument(AlgorithmName() + ": message too long for this public key"); + + SecByteBlock paddedBlock(PaddedBlockByteLength()); + GetPaddingAlgorithm().Pad(rng, plainText, plainTextLength, paddedBlock, PaddedBlockBitLength()); + GetTrapdoorFunctionInterface().ApplyRandomizedFunction(rng, Integer(paddedBlock, paddedBlock.size())).Encode(cipherText, FixedCiphertextLength()); +} + +NAMESPACE_END diff --git a/pubkey.h b/pubkey.h new file mode 100644 index 0000000..7331883 --- /dev/null +++ b/pubkey.h @@ -0,0 +1,1663 @@ +// pubkey.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_PUBKEY_H +#define CRYPTOPP_PUBKEY_H + +/** \file + + This file contains helper classes/functions for implementing public key algorithms. + + The class hierachies in this .h file tend to look like this: +<pre> + x1 + / \ + y1 z1 + | | + x2<y1> x2<z1> + | | + y2 z2 + | | + x3<y2> x3<z2> + | | + y3 z3 +</pre> + - x1, y1, z1 are abstract interface classes defined in cryptlib.h + - x2, y2, z2 are implementations of the interfaces using "abstract policies", which + are pure virtual functions that should return interfaces to interchangeable algorithms. + These classes have "Base" suffixes. + - x3, y3, z3 hold actual algorithms and implement those virtual functions. + These classes have "Impl" suffixes. + + The "TF_" prefix means an implementation using trapdoor functions on integers. + The "DL_" prefix means an implementation using group operations (in groups where discrete log is hard). +*/ + +#include "integer.h" +#include "filters.h" +#include "eprecomp.h" +#include "fips140.h" +#include "argnames.h" +#include <memory> + +// VC60 workaround: this macro is defined in shlobj.h and conflicts with a template parameter used in this file +#undef INTERFACE + +NAMESPACE_BEGIN(CryptoPP) + +Integer NR_EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen); +Integer DSA_EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLen); + +template <typename STANDARD> +struct CryptoStandardTraits +{ + typedef typename STANDARD::EncryptionPaddingAlgorithm EncryptionPaddingAlgorithm; + + template <class H> class SignaturePaddingAlgorithm {}; + template <class H> class DecoratedHashingAlgorithm {}; +}; + +// ******************************************************** + +//! . +class TrapdoorFunctionBounds +{ +public: + virtual ~TrapdoorFunctionBounds() {} + + virtual Integer PreimageBound() const =0; + virtual Integer ImageBound() const =0; + virtual Integer MaxPreimage() const {return --PreimageBound();} + virtual Integer MaxImage() const {return --ImageBound();} +}; + +//! . +class RandomizedTrapdoorFunction : public TrapdoorFunctionBounds +{ +public: + virtual Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +//! . +class TrapdoorFunction : public RandomizedTrapdoorFunction +{ +public: + Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const + {return ApplyFunction(x);} + + virtual Integer ApplyFunction(const Integer &x) const =0; +}; + +//! . +class RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~RandomizedTrapdoorFunctionInverse() {} + + virtual Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +//! . +class TrapdoorFunctionInverse : public RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~TrapdoorFunctionInverse() {} + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const + {return CalculateInverse(x);} + + virtual Integer CalculateInverse(const Integer &x) const =0; +}; + +// ******************************************************** + +//! . +class PK_PaddingAlgorithm +{ +public: + virtual ~PK_PaddingAlgorithm() {} + + virtual unsigned int MaxUnpaddedLength(unsigned int paddedLength) const =0; + + virtual void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedBitLength) const =0; + + virtual DecodingResult Unpad(const byte *padded, unsigned int paddedBitLength, byte *raw) const =0; + + virtual bool IsReversible() const {return true;} +}; + +//! . +class PK_NonreversiblePaddingAlgorithm : public PK_PaddingAlgorithm +{ + DecodingResult Unpad(const byte *padded, unsigned int paddedBitLength, byte *raw) const {assert(false); return DecodingResult();} + bool IsReversible() const {return false;} +}; + +// ******************************************************** + +//! . +template <class TFI> +class TF_Base +{ +protected: + unsigned int PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; + virtual const PK_PaddingAlgorithm & GetPaddingAlgorithm() const =0; + virtual unsigned int PaddedBlockBitLength() const =0; + + typedef TFI TrapdoorFunctionInterface; + virtual const TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const =0; +}; + +// ******************************************************** + +//! . +template <class INTERFACE, class BASE> +class TF_CryptoSystemBase : public INTERFACE, protected BASE +{ +public: + unsigned int FixedMaxPlaintextLength() const {return GetPaddingAlgorithm().MaxUnpaddedLength(PaddedBlockBitLength());} + unsigned int FixedCiphertextLength() const {return GetTrapdoorFunctionBounds().MaxImage().ByteCount();} + +protected: + unsigned int PaddedBlockBitLength() const {return GetTrapdoorFunctionBounds().PreimageBound().BitCount()-1;} +}; + +//! . +class TF_DecryptorBase : public TF_CryptoSystemBase<PK_FixedLengthDecryptor, TF_Base<TrapdoorFunctionInverse> > +{ +public: + DecodingResult FixedLengthDecrypt(const byte *cipherText, byte *plainText) const; +}; + +//! . +class TF_EncryptorBase : public TF_CryptoSystemBase<PK_FixedLengthEncryptor, TF_Base<RandomizedTrapdoorFunction> > +{ +public: + void Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const; +}; + +// ******************************************************** + +//! . +class DigestSignatureSystem +{ +public: + virtual unsigned int MaxDigestLength() const =0; + virtual unsigned int DigestSignatureLength() const =0; +}; + +//! . +class DigestSigner : virtual public DigestSignatureSystem, public PrivateKeyAlgorithm +{ +public: + virtual void SignDigest(RandomNumberGenerator &rng, const byte *digest, unsigned int digestLen, byte *signature) const =0; +}; + +//! . +class DigestVerifier : virtual public DigestSignatureSystem, public PublicKeyAlgorithm +{ +public: + virtual bool VerifyDigest(const byte *digest, unsigned int digestLen, const byte *sig) const =0; +}; + +// ******************************************************** + +//! . +template <class INTERFACE, class BASE> +class TF_DigestSignatureSystemBase : public INTERFACE, protected BASE +{ +public: + unsigned int MaxDigestLength() const {return GetPaddingAlgorithm().MaxUnpaddedLength(PaddedBlockBitLength());} + unsigned int DigestSignatureLength() const {return GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + +protected: + unsigned int PaddedBlockBitLength() const {return GetTrapdoorFunctionBounds().ImageBound().BitCount()-1;} +}; + +//! . +class TF_DigestSignerBase : public TF_DigestSignatureSystemBase<DigestSigner, TF_Base<RandomizedTrapdoorFunctionInverse> > +{ +public: + void SignDigest(RandomNumberGenerator &rng, const byte *message, unsigned int messageLength, byte *signature) const; +}; + +//! . +class TF_DigestVerifierBase : public TF_DigestSignatureSystemBase<DigestVerifier, TF_Base<TrapdoorFunction> > +{ +public: + bool VerifyDigest(const byte *digest, unsigned int digestLen, const byte *sig) const; +}; + +// ******************************************************** + +//! . +template <class T1, class T2, class T3> +struct TF_SchemeOptions +{ + typedef T1 AlgorithmInfo; + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; + typedef T3 PaddingAlgorithm; +}; + +//! . +template <class KEYS> +class PublicKeyCopier +{ +public: + virtual void CopyKeyInto(typename KEYS::PublicKey &key) const =0; +}; + +//! . +template <class KEYS> +class PrivateKeyCopier +{ +public: + virtual void CopyKeyInto(typename KEYS::PublicKey &key) const =0; + virtual void CopyKeyInto(typename KEYS::PrivateKey &key) const =0; +}; + +//! . +template <class BASE, class SCHEME_OPTIONS, class KEY> +class TF_ObjectImplBase : public AlgorithmImpl<BASE, typename SCHEME_OPTIONS::AlgorithmInfo> +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef KEY KeyClass; + + PublicKey & AccessPublicKey() {return AccessKey();} + const PublicKey & GetPublicKey() const {return GetKey();} + + PrivateKey & AccessPrivateKey() {return AccessKey();} + const PrivateKey & GetPrivateKey() const {return GetKey();} + + virtual const KeyClass & GetKey() const =0; + virtual KeyClass & AccessKey() =0; + + const KeyClass & GetTrapdoorFunction() const {return GetKey();} + +protected: + const PK_PaddingAlgorithm & GetPaddingAlgorithm() const {static typename SCHEME_OPTIONS::PaddingAlgorithm paddingScheme; return paddingScheme;} + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const {return GetKey();} + const typename BASE::TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const {return GetKey();} +}; + +//! . +template <class BASE, class SCHEME_OPTIONS, class KEY> +class TF_ObjectImplExtRef : public TF_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY> +{ +public: + TF_ObjectImplExtRef(const KEY *pKey = NULL) : m_pKey(pKey) {} + void SetKeyPtr(const KEY *pKey) {m_pKey = pKey;} + + const KEY & GetKey() const {return *m_pKey;} + KEY & AccessKey() {throw NotImplemented("TF_ObjectImplExtRef: cannot modify refererenced key");} + + void CopyKeyInto(typename SCHEME_OPTIONS::PrivateKey &key) const {assert(false);} + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const {assert(false);} + +private: + const KEY * m_pKey; +}; + +//! . +template <class BASE, class SCHEME_OPTIONS, class KEY> +class TF_ObjectImpl : public TF_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY> +{ +public: + const KEY & GetKey() const {return m_trapdoorFunction;} + KEY & AccessKey() {return m_trapdoorFunction;} + +private: + KEY m_trapdoorFunction; +}; + +//! . +template <class BASE, class SCHEME_OPTIONS> +class TF_PublicObjectImpl : public TF_ObjectImpl<BASE, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey>, public PublicKeyCopier<SCHEME_OPTIONS> +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const {key = GetKey();} +}; + +//! . +template <class BASE, class SCHEME_OPTIONS> +class TF_PrivateObjectImpl : public TF_ObjectImpl<BASE, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey>, public PrivateKeyCopier<SCHEME_OPTIONS> +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PrivateKey &key) const {key = GetKey();} + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const {key = GetKey();} +}; + +//! . +template <class SCHEME_OPTIONS> +class TF_DecryptorImpl : public TF_PrivateObjectImpl<TF_DecryptorBase, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class TF_EncryptorImpl : public TF_PublicObjectImpl<TF_EncryptorBase, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class TF_DigestSignerImpl : public TF_PrivateObjectImpl<TF_DigestSignerBase, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class TF_DigestVerifierImpl : public TF_PublicObjectImpl<TF_DigestVerifierBase, SCHEME_OPTIONS> +{ +}; + +// ******************************************************** + +//! . +template <class H> +class P1363_MGF1 +{ +public: + static std::string StaticAlgorithmName() {return std::string("MGF1(") + H::StaticAlgorithmName() + ")";} + static void GenerateAndMask(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength); +}; + +template <class H> +void P1363_MGF1<H>::GenerateAndMask(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength) +{ + H h; + ArrayXorSink *sink; + HashFilter filter(h, sink = new ArrayXorSink(output, outputLength)); + word32 counter = 0; + while (sink->AvailableSize() > 0) + { + filter.Put(input, inputLength); + filter.PutWord32(counter++); + filter.MessageEnd(); + } +} + +// ******************************************************** + +//! . +template <class H> +class P1363_KDF2 +{ +public: + static void DeriveKey(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength); +}; + +template <class H> +void P1363_KDF2<H>::DeriveKey(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength) +{ + H h; + ArraySink *sink; + HashFilter filter(h, sink = new ArraySink(output, outputLength)); + word32 counter = 1; + while (sink->AvailableSize() > 0) + { + filter.Put(input, inputLength); + filter.PutWord32(counter++); + filter.MessageEnd(); + } +} + +// ******************************************************** + +//! . +template <class H, class INTERFACE, class DS_INTERFACE> +class PK_SignatureSchemeBase : public INTERFACE +{ +public: + unsigned int SignatureLength() const {return GetDigestSignatureSchemeInterface().DigestSignatureLength();} + HashTransformation * NewMessageAccumulator() const {return new H;} + + virtual const DS_INTERFACE & GetDigestSignatureSchemeInterface() const =0; +}; + +//! . +template <class H> +class PK_SignerBase : public PK_SignatureSchemeBase<H, PK_Signer, DigestSigner> +{ +public: + void SignAndRestart(RandomNumberGenerator &rng, HashTransformation &messageAccumulator, byte *signature) const; +}; + +//! . +template <class H> +class PK_VerifierBase : public PK_SignatureSchemeBase<H, PK_Verifier, DigestVerifier> +{ +public: + bool VerifyAndRestart(HashTransformation &messageAccumulator, const byte *sig) const; +}; + +template <class H> +void PK_SignerBase<H>::SignAndRestart(RandomNumberGenerator &rng, HashTransformation &messageAccumulator, byte *signature) const +{ + if (messageAccumulator.DigestSize() > GetDigestSignatureSchemeInterface().MaxDigestLength()) + throw PK_Signer::KeyTooShort(); + SecByteBlock digest(messageAccumulator.DigestSize()); + messageAccumulator.Final(digest); + GetDigestSignatureSchemeInterface().SignDigest(rng, digest, digest.size(), signature); +} + +template <class H> +bool PK_VerifierBase<H>::VerifyAndRestart(HashTransformation &messageAccumulator, const byte *sig) const +{ + SecByteBlock digest(messageAccumulator.DigestSize()); + messageAccumulator.Final(digest); + return GetDigestSignatureSchemeInterface().VerifyDigest(digest, digest.size(), sig); +} + +//! . +template <class BASE, class DS> +class PK_SignatureSchemeImpl : public BASE +{ +public: + typedef typename DS::KeyClass KeyClass; + + // PublicKeyAlgorithm or PrivateKeyAlgorithm + std::string AlgorithmName() const {return m_ds.AlgorithmName();} + + PrivateKey & AccessPrivateKey() {return m_ds.AccessPrivateKey();} + const PrivateKey & GetPrivateKey() const {return m_ds.GetPrivateKey();} + + PublicKey & AccessPublicKey() {return m_ds.AccessPublicKey();} + const PublicKey & GetPublicKey() const {return m_ds.GetPublicKey();} + + KeyClass & AccessKey() {return m_ds.AccessKey();} + const KeyClass & GetKey() const {return m_ds.GetKey();} + + const KeyClass & GetTrapdoorFunction() const {return m_ds.GetTrapdoorFunction();} + + DS & AccessDigestSignatureScheme() {return m_ds;} + const DS & GetDigestSignatureScheme() const {return m_ds;} + +protected: + DS m_ds; +}; + +//! . +template <class DS, class H> +class PK_SignerImpl : public PK_SignatureSchemeImpl<PK_SignerBase<H>, DS>, public PrivateKeyCopier<typename DS::SchemeOptions> +{ + const DigestSigner & GetDigestSignatureSchemeInterface() const {return m_ds;} +public: + // PrivateKeyCopier + void CopyKeyInto(typename DS::SchemeOptions::PublicKey &key) const + {m_ds.CopyKeyInto(key);} + void CopyKeyInto(typename DS::SchemeOptions::PrivateKey &key) const + {m_ds.CopyKeyInto(key);} +}; + +//! . +template <class DS, class H> +class PK_VerifierImpl : public PK_SignatureSchemeImpl<PK_VerifierBase<H>, DS>, public PublicKeyCopier<typename DS::SchemeOptions> +{ + const DigestVerifier & GetDigestSignatureSchemeInterface() const {return m_ds;} +public: + // PublicKeyCopier + void CopyKeyInto(typename DS::SchemeOptions::PublicKey &key) const + {m_ds.CopyKeyInto(key);} +}; + +// ******************************************************** + +//! . +class SignatureEncodingMethodWithRecovery : public HashTransformationWithDefaultTruncation +{ +public: + void Final(byte *digest) {} + virtual void Encode(RandomNumberGenerator &rng, byte *representative) =0; + virtual bool Verify(const byte *representative) =0; + virtual DecodingResult Decode(byte *message) =0; + virtual unsigned int MaximumRecoverableLength() const =0; +}; + +//! . +template <class H> +class SignatureSystemWithRecoveryBaseTemplate : virtual public PK_SignatureSchemeWithRecovery +{ +public: + unsigned int SignatureLength() const {return GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + HashTransformation * NewMessageAccumulator() const {return new H(PaddedBlockBitLength());} + unsigned int MaximumRecoverableLength() const {return H::MaximumRecoverableLength(PaddedBlockBitLength());} + bool AllowLeftoverMessage() const {return H::AllowLeftoverMessage();} + +protected: + unsigned int PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + unsigned int PaddedBlockBitLength() const {return GetTrapdoorFunctionBounds().ImageBound().BitCount()-1;} + + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; +}; + +//! . +template <class TF, class H> +class SignerWithRecoveryTemplate : virtual public SignatureSystemWithRecoveryBaseTemplate<H>, virtual public PK_SignerWithRecovery, public TF +{ +public: + typedef TF KeyClass; + + const KeyClass & GetKey() const {return *this;} + KeyClass & AccessKey() {return *this;} + + PrivateKey & AccessPrivateKey() {return *this;} + + SignerWithRecoveryTemplate() {} + void SignAndRestart(RandomNumberGenerator &rng, HashTransformation &messageAccumulator, byte *signature) const; + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const {return *this;} +}; + +//! . +template <class TF, class H> +class VerifierWithRecoveryTemplate : virtual public SignatureSystemWithRecoveryBaseTemplate<H>, virtual public PK_VerifierWithRecovery, public TF +{ +public: + typedef TF KeyClass; + + const KeyClass & GetKey() const {return *this;} + KeyClass & AccessKey() {return *this;} + + PublicKey & AccessPublicKey() {return *this;} + + VerifierWithRecoveryTemplate() {} + bool VerifyAndRestart(HashTransformation &messageAccumulator, const byte *sig) const; + bool SignatureUpfrontForRecovery() const {return true;} + HashTransformation * NewRecoveryAccumulator(const byte *signature) const; + DecodingResult Recover(byte *recoveredMessage, HashTransformation *recoveryAccumulator, const byte *signature) const; + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const {return *this;} +}; + +template <class TF, class H> +void SignerWithRecoveryTemplate<TF, H>::SignAndRestart(RandomNumberGenerator &rng, HashTransformation &messageAccumulator, byte *signature) const +{ + H &ma = static_cast<H&>(messageAccumulator); + if (ma.MaximumRecoverableLength() == 0) + throw KeyTooShort(); + SecByteBlock representative(PaddedBlockByteLength()); + ma.Encode(rng, representative); + CalculateInverse(Integer(representative, representative.size())).Encode(signature, SignatureLength()); +} + +template <class TF, class H> +bool VerifierWithRecoveryTemplate<TF, H>::VerifyAndRestart(HashTransformation &messageAccumulator, const byte *signature) const +{ + SecByteBlock representative(PaddedBlockByteLength()); + ApplyFunction(Integer(signature, SignatureLength())).Encode(representative, representative.size()); + return messageAccumulator.Verify(representative); +} + +template <class TF, class H> +HashTransformation * VerifierWithRecoveryTemplate<TF, H>::NewRecoveryAccumulator(const byte *signature) const +{ + SecByteBlock representative(PaddedBlockByteLength()); + ApplyFunction(Integer(signature, SignatureLength())).Encode(representative, representative.size()); + return new H(representative, PaddedBlockBitLength()); +} + +template <class TF, class H> +DecodingResult VerifierWithRecoveryTemplate<TF, H>::Recover(byte *recoveredMessage, HashTransformation *recoveryAccumulator, const byte *signature) const +{ + std::auto_ptr<H> ma(static_cast<H*>(recoveryAccumulator)); + return ma->Decode(recoveredMessage); +} + +// ******************************************************** + +// to be thrown by DecodeElement and AgreeWithStaticPrivateKey +class DL_BadElement : public InvalidDataFormat +{ +public: + DL_BadElement() : InvalidDataFormat("CryptoPP: invalid group element") {} +}; + +//! . +template <class T> +class DL_GroupParameters : public CryptoParameters +{ + typedef DL_GroupParameters<T> ThisClass; + +public: + typedef T Element; + + DL_GroupParameters() : m_validationLevel(0) {} + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + if (!GetBasePrecomputation().IsInitialized()) + return false; + + if (m_validationLevel > level) + return true; + + bool pass = ValidateGroup(rng, level); + pass = pass && ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation()); + + m_validationLevel = pass ? level+1 : 0; + + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + { + AccessBasePrecomputation().Precompute(GetGroupPrecomputation(), GetSubgroupOrder().BitCount(), precomputationStorage); + } + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessBasePrecomputation().Load(GetGroupPrecomputation(), storedPrecomputation); + m_validationLevel = 0; + } + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetBasePrecomputation().Save(GetGroupPrecomputation(), storedPrecomputation); + } + + // non-inherited + virtual const Element & GetSubgroupGenerator() const {return GetBasePrecomputation().GetBase(GetGroupPrecomputation());} + virtual void SetSubgroupGenerator(const Element &base) {AccessBasePrecomputation().SetBase(GetGroupPrecomputation(), base);} + virtual Element ExponentiateBase(const Integer &exponent) const + { + return GetBasePrecomputation().Exponentiate(GetGroupPrecomputation(), exponent); + } + virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const + { + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; + } + + virtual const DL_GroupPrecomputation<Element> & GetGroupPrecomputation() const =0; + virtual const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const =0; + virtual DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() =0; + virtual const Integer & GetSubgroupOrder() const =0; // order of subgroup generated by base element + virtual Integer GetMaxExponent() const =0; + virtual Integer GetGroupOrder() const {return GetSubgroupOrder()*GetCofactor();} // one of these two needs to be overriden + virtual Integer GetCofactor() const {return GetGroupOrder()/GetSubgroupOrder();} + virtual unsigned int GetEncodedElementSize(bool reversible) const =0; + virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0; + virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0; + virtual Integer ConvertElementToInteger(const Element &element) const =0; + virtual bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const =0; + virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation<Element> *precomp) const =0; + virtual bool FastSubgroupCheckAvailable() const =0; + virtual bool IsIdentity(const Element &element) const =0; + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const =0; + +protected: + void ParametersChanged() {m_validationLevel = 0;} + +private: + mutable unsigned int m_validationLevel; +}; + +//! . +template <class GROUP_PRECOMP, class BASE_PRECOMP = DL_FixedBasePrecomputationImpl<typename GROUP_PRECOMP::Element>, class BASE = DL_GroupParameters<typename GROUP_PRECOMP::Element> > +class DL_GroupParametersImpl : public BASE +{ +public: + typedef GROUP_PRECOMP GroupPrecomputation; + typedef typename GROUP_PRECOMP::Element Element; + typedef BASE_PRECOMP BasePrecomputation; + + const DL_GroupPrecomputation<Element> & GetGroupPrecomputation() const {return m_groupPrecomputation;} + const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const {return m_gpc;} + DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() {return m_gpc;} + +protected: + GROUP_PRECOMP m_groupPrecomputation; + BASE_PRECOMP m_gpc; +}; + +//! . +template <class T> +class DL_Key +{ +public: + virtual const DL_GroupParameters<T> & GetAbstractGroupParameters() const =0; + virtual DL_GroupParameters<T> & AccessAbstractGroupParameters() =0; +}; + +//! . +template <class T> +class DL_PublicKey : public DL_Key<T> +{ + typedef DL_PublicKey<T> ThisClass; + +public: + typedef T Element; + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetAbstractGroupParameters().GetVoidValue(name, valueType, pValue) + || GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicElement); + } + + void AssignFrom(const NameValuePairs &source); + + // non-inherited + virtual const Element & GetPublicElement() const {return GetPublicPrecomputation().GetBase(GetAbstractGroupParameters().GetGroupPrecomputation());} + virtual void SetPublicElement(const Element &y) {AccessPublicPrecomputation().SetBase(GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + virtual Element ExponentiatePublicElement(const Integer &exponent) const + { + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + return GetPublicPrecomputation().Exponentiate(params.GetGroupPrecomputation(), exponent); + } + virtual Element CascadeExponentiateBaseAndPublicElement(const Integer &baseExp, const Integer &publicExp) const + { + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + return params.GetBasePrecomputation().CascadeExponentiate(params.GetGroupPrecomputation(), baseExp, GetPublicPrecomputation(), publicExp); + } + + virtual const DL_FixedBasePrecomputation<T> & GetPublicPrecomputation() const =0; + virtual DL_FixedBasePrecomputation<T> & AccessPublicPrecomputation() =0; +}; + +//! . +template <class T> +class DL_PrivateKey : public DL_Key<T> +{ + typedef DL_PrivateKey<T> ThisClass; + +public: + typedef T Element; + + void MakePublicKey(DL_PublicKey<T> &pub) const + { + pub.AccessAbstractGroupParameters().AssignFrom(GetAbstractGroupParameters()); + pub.SetPublicElement(GetAbstractGroupParameters().ExponentiateBase(GetPrivateExponent())); + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetAbstractGroupParameters().GetVoidValue(name, valueType, pValue) + || GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent); + } + + void AssignFrom(const NameValuePairs &source) + { + AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent); + } + + virtual const Integer & GetPrivateExponent() const =0; + virtual void SetPrivateExponent(const Integer &x) =0; +}; + +template <class T> +void DL_PublicKey<T>::AssignFrom(const NameValuePairs &source) +{ + DL_PrivateKey<T> *pPrivateKey = NULL; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } +} + +class OID; + +//! . +template <class PK, class GP> +class DL_KeyImpl : public PK +{ +public: + typedef GP GroupParameters; + + OID GetAlgorithmID() const {return GetGroupParameters().GetAlgorithmID();} +// void BERDecode(BufferedTransformation &bt) +// {PK::BERDecode(bt);} +// void DEREncode(BufferedTransformation &bt) const +// {PK::DEREncode(bt);} + bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {AccessGroupParameters().BERDecode(bt); return true;} + bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {GetGroupParameters().DEREncode(bt); return true;} + + const GP & GetGroupParameters() const {return m_groupParameters;} + GP & AccessGroupParameters() {return m_groupParameters;} + +private: + GP m_groupParameters; +}; + +class X509PublicKey; +class PKCS8PrivateKey; + +//! . +template <class GP> +class DL_PrivateKeyImpl : public DL_PrivateKey<CPP_TYPENAME GP::Element>, public DL_KeyImpl<PKCS8PrivateKey, GP> +{ +public: + typedef typename GP::Element Element; + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + bool pass = GetAbstractGroupParameters().Validate(rng, level); + + const Integer &q = GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = GetPrivateExponent(); + + pass = pass && x.IsPositive() && x < q; + if (level >= 1) + pass = pass && Integer::Gcd(x, q) == Integer::One(); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper<DL_PrivateKey<Element> >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper<DL_PrivateKey<Element> >(this, source); + } + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + if (!params.GetThisObject(AccessGroupParameters())) + AccessGroupParameters().GenerateRandom(rng, params); +// std::pair<const byte *, int> seed; + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); +// Integer::ANY, Integer::Zero(), Integer::One(), +// params.GetValue("DeterministicKeyGenerationSeed", seed) ? &seed : NULL); + SetPrivateExponent(x); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + {AccessAbstractGroupParameters().Precompute(precomputationStorage);} + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation);} + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation);} + + // DL_Key + const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return GetGroupParameters();} + DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return AccessGroupParameters();} + + // DL_PrivateKey + const Integer & GetPrivateExponent() const {return m_x;} + void SetPrivateExponent(const Integer &x) {m_x = x;} + + // PKCS8PrivateKey + void BERDecodeKey(BufferedTransformation &bt) + {m_x.BERDecode(bt);} + void DEREncodeKey(BufferedTransformation &bt) const + {m_x.DEREncode(bt);} + +private: + Integer m_x; +}; + +//! . +template <class BASE, class SIGNATURE_SCHEME> +class DL_PrivateKey_WithSignaturePairwiseConsistencyTest : public BASE +{ +public: + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + BASE::GenerateRandom(rng, params); + + if (FIPS_140_2_ComplianceEnabled()) + { + typename SIGNATURE_SCHEME::Signer signer(*this); + typename SIGNATURE_SCHEME::Verifier verifier(signer); + SignaturePairwiseConsistencyTest(signer, verifier); + } + } +}; + +//! . +template <class GP> +class DL_PublicKeyImpl : public DL_PublicKey<typename GP::Element>, public DL_KeyImpl<X509PublicKey, GP> +{ +public: + typedef typename GP::Element Element; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + bool pass = GetAbstractGroupParameters().Validate(rng, level); + pass = pass && GetAbstractGroupParameters().ValidateElement(level, GetPublicElement(), &GetPublicPrecomputation()); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper<DL_PublicKey<Element> >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper<DL_PublicKey<Element> >(this, source); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + { + AccessAbstractGroupParameters().Precompute(precomputationStorage); + AccessPublicPrecomputation().Precompute(GetAbstractGroupParameters().GetGroupPrecomputation(), GetAbstractGroupParameters().GetSubgroupOrder().BitCount(), precomputationStorage); + } + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation); + AccessPublicPrecomputation().Load(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation); + GetPublicPrecomputation().Save(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + // DL_Key + const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return GetGroupParameters();} + DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return AccessGroupParameters();} + + // DL_PublicKey + const DL_FixedBasePrecomputation<Element> & GetPublicPrecomputation() const {return m_ypc;} + DL_FixedBasePrecomputation<Element> & AccessPublicPrecomputation() {return m_ypc;} + + // non-inherited + bool operator==(const DL_PublicKeyImpl<GP> &rhs) const + {return GetGroupParameters() == rhs.GetGroupParameters() && GetPublicElement() == rhs.GetPublicElement();} + +private: + typename GP::BasePrecomputation m_ypc; +}; + +//! . +template <class T> +class DL_ElgamalLikeSignatureAlgorithm +{ +public: + virtual Integer EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLength) const =0; + virtual bool Sign(const DL_GroupParameters<T> ¶ms, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; + virtual bool Verify(const DL_GroupParameters<T> ¶ms, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0; + virtual unsigned int RLen(const DL_GroupParameters<T> ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + virtual unsigned int SLen(const DL_GroupParameters<T> ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} +}; + +//! . +template <class T> +class DL_KeyAgreementAlgorithm +{ +public: + typedef T Element; + + virtual Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters<Element> ¶ms, const DL_FixedBasePrecomputation<Element> &publicPrecomputation, const Integer &privateExponent) const =0; + virtual Element AgreeWithStaticPrivateKey(const DL_GroupParameters<Element> ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const =0; +}; + +//! . +template <class T> +class DL_KeyDerivationAlgorithm +{ +public: + virtual void Derive(const DL_GroupParameters<T> ¶ms, byte *derivedKey, unsigned int derivedLength, const T &agreedElement, const T &ephemeralPublicKey) const =0; +}; + +//! . +class DL_SymmetricEncryptionAlgorithm +{ +public: + virtual unsigned int GetSymmetricKeyLength(unsigned int plainTextLength) const =0; + virtual unsigned int GetSymmetricCiphertextLength(unsigned int plainTextLength) const =0; + virtual unsigned int GetMaxSymmetricPlaintextLength(unsigned int cipherTextLength) const =0; + virtual void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const =0; + virtual DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const =0; +}; + +//! . +template <class KI> +class DL_Base +{ +protected: + typedef KI KeyInterface; + typedef typename KI::Element Element; + + const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return GetKeyInterface().GetAbstractGroupParameters();} + DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return AccessKeyInterface().AccessAbstractGroupParameters();} + + virtual KeyInterface & AccessKeyInterface() =0; + virtual const KeyInterface & GetKeyInterface() const =0; +}; + +//! . +template <class INTERFACE, class KEY_INTERFACE> +class DL_DigestSignatureSystemBase : public INTERFACE, public DL_Base<KEY_INTERFACE> +{ +public: + unsigned int MaxDigestLength() const {return UINT_MAX;} + unsigned int DigestSignatureLength() const + { + return GetSignatureAlgorithm().RLen(GetAbstractGroupParameters()) + + GetSignatureAlgorithm().SLen(GetAbstractGroupParameters()); + } + +protected: + virtual const DL_ElgamalLikeSignatureAlgorithm<CPP_TYPENAME KEY_INTERFACE::Element> & GetSignatureAlgorithm() const =0; +}; + +//! . +template <class T> +class DL_DigestSignerBase : public DL_DigestSignatureSystemBase<DigestSigner, DL_PrivateKey<T> > +{ +public: + // for validation testing + void RawSign(const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const DL_ElgamalLikeSignatureAlgorithm<T> &alg = GetSignatureAlgorithm(); + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey<T> &key = GetKeyInterface(); + + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + } + + void SignDigest(RandomNumberGenerator &rng, const byte *digest, unsigned int digestLength, byte *signature) const + { + const DL_ElgamalLikeSignatureAlgorithm<T> &alg = GetSignatureAlgorithm(); + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey<T> &key = GetKeyInterface(); + + GetMaterial().DoQuickSanityCheck(); + const Integer &q = params.GetSubgroupOrder(); + Integer e = alg.EncodeDigest(q.BitCount(), digest, digestLength); + Integer k, r, s; + + do {k.Randomize(rng, 1, params.GetSubgroupOrder()-1);} + while (!alg.Sign(params, key.GetPrivateExponent(), k, e, r, s)); + + unsigned int rLen = alg.RLen(params); + r.Encode(signature, rLen); + s.Encode(signature+rLen, alg.SLen(params)); + } +}; + +//! . +template <class T> +class DL_DigestVerifierBase : public DL_DigestSignatureSystemBase<DigestVerifier, DL_PublicKey<T> > +{ +public: + bool VerifyDigest(const byte *digest, unsigned int digestLength, const byte *signature) const + { + const DL_ElgamalLikeSignatureAlgorithm<T> &alg = GetSignatureAlgorithm(); + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + const DL_PublicKey<T> &key = GetKeyInterface(); + + GetMaterial().DoQuickSanityCheck(); + const Integer &q = params.GetSubgroupOrder(); + Integer e = alg.EncodeDigest(q.BitCount(), digest, digestLength); + unsigned int rLen = alg.RLen(params); + Integer r(signature, rLen); + Integer s(signature+rLen, alg.SLen(params)); + return alg.Verify(params, key, e, r, s); + } +}; + +//! . +template <class PK, class KI> +class DL_CryptoSystemBase : public PK, public DL_Base<KI> +{ +public: + typedef typename DL_Base<KI>::Element Element; + + unsigned int MaxPlaintextLength(unsigned int cipherTextLength) const + { + unsigned int minLen = GetAbstractGroupParameters().GetEncodedElementSize(true); + return cipherTextLength < minLen ? 0 : GetSymmetricEncryptionAlgorithm().GetMaxSymmetricPlaintextLength(cipherTextLength - minLen); + } + + unsigned int CiphertextLength(unsigned int plainTextLength) const + { + unsigned int len = GetSymmetricEncryptionAlgorithm().GetSymmetricCiphertextLength(plainTextLength); + return len == 0 ? 0 : GetAbstractGroupParameters().GetEncodedElementSize(true) + len; + } + +protected: + virtual const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const =0; + virtual const DL_KeyDerivationAlgorithm<Element> & GetKeyDerivationAlgorithm() const =0; + virtual const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const =0; +}; + +//! . +template <class T, class PK = PK_Decryptor> +class DL_DecryptorBase : public DL_CryptoSystemBase<PK, DL_PrivateKey<T> > +{ +public: + typedef T Element; + + DecodingResult Decrypt(const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const + { + try + { + const DL_KeyAgreementAlgorithm<T> &agreeAlg = GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm<T> &derivAlg = GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey<T> &key = GetKeyInterface(); + + Element q = params.DecodeElement(cipherText, true); + unsigned int elementSize = params.GetEncodedElementSize(true); + cipherText += elementSize; + cipherTextLength -= elementSize; + + Element z = agreeAlg.AgreeWithStaticPrivateKey(params, q, true, key.GetPrivateExponent()); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(encAlg.GetMaxSymmetricPlaintextLength(cipherTextLength))); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q); + + return encAlg.SymmetricDecrypt(derivedKey, cipherText, cipherTextLength, plainText); + } + catch (DL_BadElement &) + { + return DecodingResult(); + } + } +}; + +//! . +template <class T, class PK = PK_Encryptor> +class DL_EncryptorBase : public DL_CryptoSystemBase<PK, DL_PublicKey<T> > +{ +public: + typedef T Element; + + void Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const + { + const DL_KeyAgreementAlgorithm<T> &agreeAlg = GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm<T> &derivAlg = GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + const DL_PublicKey<T> &key = GetKeyInterface(); + + Integer x(rng, Integer::One(), params.GetMaxExponent()); + Element q = params.ExponentiateBase(x); + params.EncodeElement(true, q, cipherText); + unsigned int elementSize = params.GetEncodedElementSize(true); + cipherText += elementSize; + + Element z = agreeAlg.AgreeWithEphemeralPrivateKey(params, key.GetPublicPrecomputation(), x); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(plainTextLength)); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q); + + encAlg.SymmetricEncrypt(rng, derivedKey, plainText, plainTextLength, cipherText); + } +}; + +//! . +template <class T1, class T2> +struct DL_SchemeOptionsBase +{ + typedef T1 AlgorithmInfo; + typedef T2 GroupParameters; + typedef typename GroupParameters::Element Element; +}; + +//! . +template <class T1, class T2> +struct DL_KeyedSchemeOptions : public DL_SchemeOptionsBase<T1, typename T2::PublicKey::GroupParameters> +{ + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; +}; + +//! . +template <class T1, class T2, class T3> +struct DL_SignatureSchemeOptions : public DL_KeyedSchemeOptions<T1, T2> +{ + typedef T3 SignatureAlgorithm; +}; + +//! . +template <class T1, class T2, class T3, class T4, class T5> +struct DL_CryptoSchemeOptions : public DL_KeyedSchemeOptions<T1, T2> +{ + typedef T3 KeyAgreementAlgorithm; + typedef T4 KeyDerivationAlgorithm; + typedef T5 SymmetricEncryptionAlgorithm; +}; + +//! . +template <class BASE, class SCHEME_OPTIONS, class KEY> +class DL_ObjectImplBase : public AlgorithmImpl<BASE, typename SCHEME_OPTIONS::AlgorithmInfo> +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef KEY KeyClass; + typedef typename KeyClass::Element Element; + + PrivateKey & AccessPrivateKey() {return m_key;} + PublicKey & AccessPublicKey() {return m_key;} + + // KeyAccessor + const KeyClass & GetKey() const {return m_key;} + KeyClass & AccessKey() {return m_key;} + +protected: + typename BASE::KeyInterface & AccessKeyInterface() {return m_key;} + const typename BASE::KeyInterface & GetKeyInterface() const {return m_key;} + +private: + KeyClass m_key; +}; + +//! . +template <class BASE, class SCHEME_OPTIONS, class KEY> +class DL_ObjectImpl : public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY> +{ +public: + typedef typename KEY::Element Element; + +protected: + const DL_ElgamalLikeSignatureAlgorithm<Element> & GetSignatureAlgorithm() const + {static typename SCHEME_OPTIONS::SignatureAlgorithm a; return a;} + const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const + {static typename SCHEME_OPTIONS::KeyAgreementAlgorithm a; return a;} + const DL_KeyDerivationAlgorithm<Element> & GetKeyDerivationAlgorithm() const + {static typename SCHEME_OPTIONS::KeyDerivationAlgorithm a; return a;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const + {static typename SCHEME_OPTIONS::SymmetricEncryptionAlgorithm a; return a;} +}; + +//! . +template <class BASE, class SCHEME_OPTIONS> +class DL_PublicObjectImpl : public DL_ObjectImpl<BASE, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey>, public PublicKeyCopier<SCHEME_OPTIONS> +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const + {key = GetKey();} +}; + +//! . +template <class BASE, class SCHEME_OPTIONS> +class DL_PrivateObjectImpl : public DL_ObjectImpl<BASE, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey>, public PrivateKeyCopier<SCHEME_OPTIONS> +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const + {GetKey().MakePublicKey(key);} + void CopyKeyInto(typename SCHEME_OPTIONS::PrivateKey &key) const + {key = GetKey();} +}; + +//! . +template <class SCHEME_OPTIONS> +class DL_DigestSignerImpl : public DL_PrivateObjectImpl<DL_DigestSignerBase<typename SCHEME_OPTIONS::Element>, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class DL_DigestVerifierImpl : public DL_PublicObjectImpl<DL_DigestVerifierBase<typename SCHEME_OPTIONS::Element>, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class DL_EncryptorImpl : public DL_PublicObjectImpl<DL_EncryptorBase<typename SCHEME_OPTIONS::Element>, SCHEME_OPTIONS> +{ +}; + +//! . +template <class SCHEME_OPTIONS> +class DL_DecryptorImpl : public DL_PrivateObjectImpl<DL_DecryptorBase<typename SCHEME_OPTIONS::Element>, SCHEME_OPTIONS> +{ +}; + +// ******************************************************** + +//! . +template <class T> +class DL_SimpleKeyAgreementDomainBase : public SimpleKeyAgreementDomain +{ +public: + typedef T Element; + + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + unsigned int PrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + unsigned int PublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, PrivateKeyLength()); + } + + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const + { + try + { + const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element w = params.DecodeElement(otherPublicKey, validateOtherPublicKey); + + Element z = GetKeyAgreementAlgorithm().AgreeWithStaticPrivateKey( + GetAbstractGroupParameters(), w, validateOtherPublicKey, x); + params.EncodeElement(false, z, agreedValue); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + + const Element &GetGenerator() const {return GetAbstractGroupParameters().GetSubgroupGenerator();} + +protected: + virtual const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const =0; + virtual DL_GroupParameters<Element> & AccessAbstractGroupParameters() =0; + const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return const_cast<DL_SimpleKeyAgreementDomainBase<Element> *>(this)->AccessAbstractGroupParameters();} +}; + +enum CofactorMultiplicationOption {NO_COFACTOR_MULTIPLICTION, COMPATIBLE_COFACTOR_MULTIPLICTION, INCOMPATIBLE_COFACTOR_MULTIPLICTION}; +typedef EnumToType<CofactorMultiplicationOption, NO_COFACTOR_MULTIPLICTION> NoCofactorMultiplication; +typedef EnumToType<CofactorMultiplicationOption, COMPATIBLE_COFACTOR_MULTIPLICTION> CompatibleCofactorMultiplication; +typedef EnumToType<CofactorMultiplicationOption, INCOMPATIBLE_COFACTOR_MULTIPLICTION> IncompatibleCofactorMultiplication; + +//! DH key agreement algorithm +template <class ELEMENT, class COFACTOR_OPTION> +class DL_KeyAgreementAlgorithm_DH : public DL_KeyAgreementAlgorithm<ELEMENT> +{ +public: + typedef ELEMENT Element; + + static const char *StaticAlgorithmName() + {return COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION ? "DH" : "DHC";} + + Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters<Element> ¶ms, const DL_FixedBasePrecomputation<Element> &publicPrecomputation, const Integer &privateExponent) const + { + return publicPrecomputation.Exponentiate(params.GetGroupPrecomputation(), + COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? privateExponent*params.GetCofactor() : privateExponent); + } + + Element AgreeWithStaticPrivateKey(const DL_GroupParameters<Element> ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const + { + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + { + const Integer &k = params.GetCofactor(); + return params.ExponentiateElement(publicElement, + ModularArithmetic(params.GetSubgroupOrder()).Divide(privateExponent, k)*k); + } + else if (COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION) + return params.ExponentiateElement(publicElement, privateExponent*params.GetCofactor()); + else + { + assert(COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION); + + if (!validateOtherPublicKey) + return params.ExponentiateElement(publicElement, privateExponent); + + if (params.FastSubgroupCheckAvailable()) + { + if (!params.ValidateElement(2, publicElement, NULL)) + throw DL_BadElement(); + return params.ExponentiateElement(publicElement, privateExponent); + } + else + { + const Integer e[2] = {params.GetSubgroupOrder(), privateExponent}; + Element r[2]; + params.SimultaneousExponentiate(r, publicElement, e, 2); + if (!params.IsIdentity(r[0])) + throw DL_BadElement(); + return r[1]; + } + } + } +}; + +// ******************************************************** + +//! A template implementing constructors for public key algorithm classes +template <class BASE> +class PK_FinalTemplate : public BASE +{ +public: + PK_FinalTemplate() {} + + PK_FinalTemplate(const Integer &v1) + {AccessKey().Initialize(v1);} + + PK_FinalTemplate(const typename BASE::KeyClass &key) {AccessKey().operator=(key);} + + template <class T> + PK_FinalTemplate(const PublicKeyCopier<T> &key) + {key.CopyKeyInto(AccessKey());} + + template <class T> + PK_FinalTemplate(const PrivateKeyCopier<T> &key) + {key.CopyKeyInto(AccessKey());} + + PK_FinalTemplate(BufferedTransformation &bt) {AccessKey().BERDecode(bt);} + +#if (defined(_MSC_VER) && _MSC_VER < 1300) + + template <class T1, class T2> + PK_FinalTemplate(T1 &v1, T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template <class T1, class T2, class T3> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template <class T1, class T2, class T3, class T4> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template <class T1, class T2, class T3, class T4, class T5> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5) + {AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template <class T1, class T2, class T3, class T4, class T5, class T6> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5, T6 &v6) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5, T6 &v6, T7 &v7) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5, T6 &v6, T7 &v7, T8 &v8) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + +#else + + template <class T1, class T2> + PK_FinalTemplate(const T1 &v1, const T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template <class T1, class T2, class T3> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template <class T1, class T2, class T3, class T4> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template <class T1, class T2, class T3, class T4, class T5> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template <class T1, class T2, class T3, class T4, class T5, class T6> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + + template <class T1, class T2> + PK_FinalTemplate(T1 &v1, const T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template <class T1, class T2, class T3> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template <class T1, class T2, class T3, class T4> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template <class T1, class T2, class T3, class T4, class T5> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template <class T1, class T2, class T3, class T4, class T5, class T6> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + +#endif +}; + +//! Base class for public key encryption standard classes. These classes are used to select from variants of algorithms. Note that not all standards apply to all algorithms. +struct EncryptionStandard {}; + +//! Base class for public key signature standard classes. These classes are used to select from variants of algorithms. Note that not all standards apply to all algorithms. +struct SignatureStandard {}; + +template <class STANDARD, class KEYS, class ALG_INFO> +class TF_ES; + +//! Trapdoor Function Based Encryption Scheme +template <class STANDARD, class KEYS, class ALG_INFO = TF_ES<STANDARD, KEYS, int> > +class TF_ES : public KEYS +{ + typedef typename STANDARD::EncryptionPaddingAlgorithm PaddingAlgorithm; + +public: + //! see EncryptionStandard for a list of standards + typedef STANDARD Standard; + typedef TF_SchemeOptions<ALG_INFO, KEYS, PaddingAlgorithm> SchemeOptions; + + static std::string StaticAlgorithmName() {return KEYS::StaticAlgorithmName() + "/" + PaddingAlgorithm::StaticAlgorithmName();} + + //! implements PK_Decryptor interface + typedef PK_FinalTemplate<TF_DecryptorImpl<SchemeOptions> > Decryptor; + //! implements PK_Encryptor interface + typedef PK_FinalTemplate<TF_EncryptorImpl<SchemeOptions> > Encryptor; +}; + +template <class STANDARD, class H, class KEYS, class ALG_INFO> // VC60 workaround: doesn't work if KEYS is first parameter +class TF_SSA; + +//! Trapdoor Function Based Signature Scheme With Appendix +template <class STANDARD, class H, class KEYS, class ALG_INFO = TF_SSA<STANDARD, H, KEYS, int> > // VC60 workaround: doesn't work if KEYS is first parameter +class TF_SSA : public KEYS +{ +#ifdef __GNUC__ + // GCC3 workaround: can't do this typedef in one line + typedef typename STANDARD::SignaturePaddingAlgorithm<H> Type1; + typedef typename Type1::type PaddingAlgorithm; + typedef typename STANDARD::DecoratedHashingAlgorithm<H> Type2; +public: + typedef typename Type2::type DecoratedHashAlgorithm; +#else + // VC60 workaround: using STANDARD directly causes internal compiler error + typedef CryptoStandardTraits<STANDARD> Traits; + typedef typename Traits::SignaturePaddingAlgorithm<H>::type PaddingAlgorithm; +public: + typedef typename Traits::DecoratedHashingAlgorithm<H>::type DecoratedHashAlgorithm; +#endif + + //! see SignatureStandard for a list of standards + typedef STANDARD Standard; + typedef TF_SchemeOptions<ALG_INFO, KEYS, PaddingAlgorithm> SchemeOptions; + + static std::string StaticAlgorithmName() {return KEYS::StaticAlgorithmName() + "/" + PaddingAlgorithm::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + + //! implements PK_Signer interface + typedef PK_FinalTemplate<PK_SignerImpl<TF_DigestSignerImpl<SchemeOptions>, DecoratedHashAlgorithm> > Signer; + //! implements PK_Verifier interface + typedef PK_FinalTemplate<PK_VerifierImpl<TF_DigestVerifierImpl<SchemeOptions>, DecoratedHashAlgorithm> > Verifier; +}; + +template <class KEYS, class SA, class H, class ALG_INFO> +class DL_SSA; + +//! Discrete Log Based Signature Scheme With Appendix +template <class KEYS, class SA, class H, class ALG_INFO = DL_SSA<KEYS, SA, H, int> > +class DL_SSA : public KEYS +{ + typedef DL_SignatureSchemeOptions<ALG_INFO, KEYS, SA> SchemeOptions; + +public: + static std::string StaticAlgorithmName() {return SA::StaticAlgorithmName() + std::string("/EMSA1(") + H::StaticAlgorithmName() + ")";} + + //! implements PK_Signer interface + typedef PK_FinalTemplate<PK_SignerImpl<DL_DigestSignerImpl<SchemeOptions>, H> > Signer; + //! implements PK_Verifier interface + typedef PK_FinalTemplate<PK_VerifierImpl<DL_DigestVerifierImpl<SchemeOptions>, H> > Verifier; +}; + +//! Discrete Log Based Encryption Scheme +template <class KEYS, class AA, class DA, class EA, class ALG_INFO> +class DL_ES : public KEYS +{ + typedef DL_CryptoSchemeOptions<ALG_INFO, KEYS, AA, DA, EA> SchemeOptions; + +public: + //! implements PK_Decryptor interface + typedef PK_FinalTemplate<DL_DecryptorImpl<SchemeOptions> > Decryptor; + //! implements PK_Encryptor interface + typedef PK_FinalTemplate<DL_EncryptorImpl<SchemeOptions> > Encryptor; +}; + +NAMESPACE_END + +#endif diff --git a/pwdbased.h b/pwdbased.h new file mode 100644 index 0000000..2880704 --- /dev/null +++ b/pwdbased.h @@ -0,0 +1,162 @@ +// pwdbased.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_PWDBASED_H +#define CRYPTOPP_PWDBASED_H + +#include "cryptlib.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +class PasswordBasedKeyDerivationFunction +{ +public: + virtual unsigned int MaxDerivedKeyLength() const =0; + virtual void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte purpose, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const =0; +}; + +//! PBKDF1 from PKCS #5, T should be a HashTransformation class +template <class T> +class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction +{ +public: + unsigned int MaxDerivedKeyLength() const {return T::DIGESTSIZE;} + // PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation allows salts of any length. + void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte ignored, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const + {DeriveKey(derived, derivedLen, password, passwordLen, salt, saltLen, iterations);} + void DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen=8, unsigned int iterations=1000) const; +}; + +//! PBKDF2 from PKCS #5, T should be a HashTransformation class +template <class T> +class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction +{ +public: + unsigned int MaxDerivedKeyLength() const {return 0xffffffffU;} // should multiply by T::DIGESTSIZE, but gets overflow that way + void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte ignored, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const + {DeriveKey(derived, derivedLen, password, passwordLen, salt, saltLen, iterations);} + void DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations=1000) const; +}; + +/* +class PBKDF2Params +{ +public: + SecByteBlock m_salt; + unsigned int m_interationCount; + ASNOptional<ASNUnsignedWrapper<word32> > m_keyLength; +}; +*/ + +template <class T> +void PKCS5_PBKDF1<T>::DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const +{ + assert(derivedLen <= MaxDerivedLength()); + assert(iterations > 0); + + T hash; + hash.Update(password, passwordLen); + hash.Update(salt, saltLen); + + SecByteBlock buffer(hash.DigestSize()); + hash.Final(buffer); + + for (unsigned int i=1; i<iterations; i++) + hash.CalculateDigest(buffer, buffer, buffer.size()); + + memcpy(derived, buffer, derivedLen); +} + +template <class T> +void PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const +{ + assert(derivedLen <= MaxDerivedKeyLength()); + assert(iterations > 0); + + HMAC<T> hmac(password, passwordLen); + SecByteBlock buffer(hmac.DigestSize()); + + unsigned int i=1; + while (derivedLen > 0) + { + hmac.Update(salt, saltLen); + unsigned int j; + for (j=0; j<4; j++) + { + byte b = i >> ((3-j)*8); + hmac.Update(&b, 1); + } + hmac.Final(buffer); + + unsigned int segmentLen = STDMIN(derivedLen, (unsigned int)buffer.size()); + memcpy(derived, buffer, segmentLen); + + for (j=1; j<iterations; j++) + { + hmac.CalculateDigest(buffer, buffer, buffer.size()); + xorbuf(derived, buffer, segmentLen); + } + + derived += segmentLen; + derivedLen -= segmentLen; + i++; + } +} + +//! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class +template <class T> +class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction +{ +public: + unsigned int MaxDerivedKeyLength() const {return UINT_MAX;} + void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte purpose, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const + {DeriveKey(derived, derivedLen, purpose, password, passwordLen, salt, saltLen, iterations);} + void DeriveKey(byte *derived, unsigned int derivedLen, byte ID, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations=1000) const; +}; + +template <class T> +void PKCS12_PBKDF<T>::DeriveKey(byte *derived, unsigned int derivedLen, byte ID, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const +{ + assert(derivedLen <= MaxDerivedKeyLength()); + assert(iterations > 0); + + const unsigned int v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12 + const unsigned int DLen = v, SLen = RoundUpToMultipleOf(saltLen, v); + const unsigned int PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen; + SecByteBlock buffer(DLen + SLen + PLen); + byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S; + + memset(D, ID, DLen); + unsigned int i; + for (i=0; i<SLen; i++) + S[i] = salt[i % saltLen]; + for (i=0; i<PLen; i++) + P[i] = password[i % passwordLen]; + + + T hash; + SecByteBlock Ai(T::DIGESTSIZE), B(v); + + while (derivedLen > 0) + { + hash.CalculateDigest(Ai, buffer, buffer.size()); + for (i=1; i<iterations; i++) + hash.CalculateDigest(Ai, Ai, Ai.size()); + for (i=0; i<B.size(); i++) + B[i] = Ai[i % Ai.size()]; + + Integer B1(B, B.size()); + ++B1; + for (i=0; i<ILen; i+=v) + (Integer(I+i, v) + B1).Encode(I+i, v); + + unsigned int segmentLen = STDMIN(derivedLen, (unsigned int)Ai.size()); + memcpy(derived, Ai, segmentLen); + derived += segmentLen; + derivedLen -= segmentLen; + } +} + +NAMESPACE_END + +#endif diff --git a/queue.cpp b/queue.cpp new file mode 100644 index 0000000..a01e213 --- /dev/null +++ b/queue.cpp @@ -0,0 +1,518 @@ +// queue.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "queue.h" +#include "filters.h" + +NAMESPACE_BEGIN(CryptoPP) + +// this class for use by ByteQueue only +class ByteQueueNode +{ +public: + ByteQueueNode(unsigned int maxSize) + : buf(maxSize) + { + m_head = m_tail = 0; + next = 0; + } + + inline unsigned int MaxSize() const {return buf.size();} + + inline unsigned int CurrentSize() const + { + return m_tail-m_head; + } + + inline bool UsedUp() const + { + return (m_head==MaxSize()); + } + + inline void Clear() + { + m_head = m_tail = 0; + } + +/* inline unsigned int Put(byte inByte) + { + if (MaxSize()==m_tail) + return 0; + + buf[m_tail++]=inByte; + return 1; + } +*/ + inline unsigned int Put(const byte *begin, unsigned int length) + { + unsigned int l = STDMIN(length, MaxSize()-m_tail); + memcpy(buf+m_tail, begin, l); + m_tail += l; + return l; + } + + inline unsigned int Peek(byte &outByte) const + { + if (m_tail==m_head) + return 0; + + outByte=buf[m_head]; + return 1; + } + + inline unsigned int Peek(byte *target, unsigned int copyMax) const + { + unsigned int len = STDMIN(copyMax, m_tail-m_head); + memcpy(target, buf+m_head, len); + return len; + } + + inline unsigned int CopyTo(BufferedTransformation &target, const std::string &channel=BufferedTransformation::NULL_CHANNEL) const + { + unsigned int len = m_tail-m_head; + target.ChannelPut(channel, buf+m_head, len); + return len; + } + + inline unsigned int CopyTo(BufferedTransformation &target, unsigned int copyMax, const std::string &channel=BufferedTransformation::NULL_CHANNEL) const + { + unsigned int len = STDMIN(copyMax, m_tail-m_head); + target.ChannelPut(channel, buf+m_head, len); + return len; + } + + inline unsigned int Get(byte &outByte) + { + unsigned int len = Peek(outByte); + m_head += len; + return len; + } + + inline unsigned int Get(byte *outString, unsigned int getMax) + { + unsigned int len = Peek(outString, getMax); + m_head += len; + return len; + } + + inline unsigned int TransferTo(BufferedTransformation &target, const std::string &channel=BufferedTransformation::NULL_CHANNEL) + { + unsigned int len = m_tail-m_head; + target.ChannelPutModifiable(channel, buf+m_head, len); + m_head = m_tail; + return len; + } + + inline unsigned int TransferTo(BufferedTransformation &target, unsigned int transferMax, const std::string &channel=BufferedTransformation::NULL_CHANNEL) + { + unsigned int len = STDMIN(transferMax, m_tail-m_head); + target.ChannelPutModifiable(channel, buf+m_head, len); + m_head += len; + return len; + } + + inline unsigned int Skip(unsigned int skipMax) + { + unsigned int len = STDMIN(skipMax, m_tail-m_head); + m_head += len; + return len; + } + + inline byte operator[](unsigned int i) const + { + return buf[m_head+i]; + } + + ByteQueueNode *next; + + SecByteBlock buf; + unsigned int m_head, m_tail; +}; + +// ******************************************************** + +ByteQueue::ByteQueue(unsigned int m_nodeSize) + : m_nodeSize(m_nodeSize), m_lazyLength(0) +{ + m_head = m_tail = new ByteQueueNode(m_nodeSize); +} + +ByteQueue::ByteQueue(const ByteQueue ©) +{ + CopyFrom(copy); +} + +void ByteQueue::CopyFrom(const ByteQueue ©) +{ + m_lazyLength = 0; + m_nodeSize = copy.m_nodeSize; + m_head = m_tail = new ByteQueueNode(*copy.m_head); + + for (ByteQueueNode *current=copy.m_head->next; current; current=current->next) + { + m_tail->next = new ByteQueueNode(*current); + m_tail = m_tail->next; + } + + m_tail->next = NULL; + + Put(copy.m_lazyString, copy.m_lazyLength); +} + +ByteQueue::~ByteQueue() +{ + Destroy(); +} + +void ByteQueue::Destroy() +{ + ByteQueueNode *next; + + for (ByteQueueNode *current=m_head; current; current=next) + { + next=current->next; + delete current; + } +} + +void ByteQueue::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256); + Clear(); +} + +unsigned long ByteQueue::CurrentSize() const +{ + unsigned long size=0; + + for (ByteQueueNode *current=m_head; current; current=current->next) + size += current->CurrentSize(); + + return size + m_lazyLength; +} + +bool ByteQueue::IsEmpty() const +{ + return m_head==m_tail && m_head->CurrentSize()==0 && m_lazyLength==0; +} + +void ByteQueue::Clear() +{ + Destroy(); + m_head = m_tail = new ByteQueueNode(m_nodeSize); + m_lazyLength = 0; +} + +unsigned int ByteQueue::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (m_lazyLength > 0) + FinalizeLazyPut(); + + unsigned int len; + while ((len=m_tail->Put(inString, length)) < length) + { + m_tail->next = new ByteQueueNode(m_nodeSize); + m_tail = m_tail->next; + inString += len; + length -= len; + } + + return 0; +} + +void ByteQueue::CleanupUsedNodes() +{ + while (m_head != m_tail && m_head->UsedUp()) + { + ByteQueueNode *temp=m_head; + m_head=m_head->next; + delete temp; + } + + if (m_head->CurrentSize() == 0) + m_head->Clear(); +} + +void ByteQueue::LazyPut(const byte *inString, unsigned int size) +{ + if (m_lazyLength > 0) + FinalizeLazyPut(); + m_lazyString = inString; + m_lazyLength = size; +} + +void ByteQueue::UndoLazyPut(unsigned int size) +{ + if (m_lazyLength < size) + throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large"); + + m_lazyLength -= size; +} + +void ByteQueue::FinalizeLazyPut() +{ + unsigned int len = m_lazyLength; + m_lazyLength = 0; + if (len) + Put(m_lazyString, len); +} + +unsigned int ByteQueue::Get(byte &outByte) +{ + if (m_head->Get(outByte)) + { + if (m_head->UsedUp()) + CleanupUsedNodes(); + return 1; + } + else if (m_lazyLength > 0) + { + outByte = *m_lazyString++; + m_lazyLength--; + return 1; + } + else + return 0; +} + +unsigned int ByteQueue::Get(byte *outString, unsigned int getMax) +{ + ArraySink sink(outString, getMax); + return TransferTo(sink, getMax); +} + +unsigned int ByteQueue::Peek(byte &outByte) const +{ + if (m_head->Peek(outByte)) + return 1; + else if (m_lazyLength > 0) + { + outByte = *m_lazyString; + return 1; + } + else + return 0; +} + +unsigned int ByteQueue::Peek(byte *outString, unsigned int peekMax) const +{ + ArraySink sink(outString, peekMax); + return CopyTo(sink, peekMax); +} + +unsigned int ByteQueue::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + if (blocking) + { + unsigned long bytesLeft = transferBytes; + for (ByteQueueNode *current=m_head; bytesLeft && current; current=current->next) + bytesLeft -= current->TransferTo(target, bytesLeft, channel); + CleanupUsedNodes(); + + unsigned int len = (unsigned int)STDMIN(bytesLeft, (unsigned long)m_lazyLength); + if (len) + { + target.ChannelPut(channel, m_lazyString, len); + m_lazyString += len; + m_lazyLength -= len; + bytesLeft -= len; + } + transferBytes -= bytesLeft; + return 0; + } + else + { + Walker walker(*this); + unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + Skip(transferBytes); + return blockedBytes; + } +} + +unsigned int ByteQueue::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + Walker walker(*this); + walker.Skip(begin); + unsigned long transferBytes = end-begin; + unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + begin += transferBytes; + return blockedBytes; +} + +void ByteQueue::Unget(byte inByte) +{ + Unget(&inByte, 1); +} + +void ByteQueue::Unget(const byte *inString, unsigned int length) +{ + // TODO: make this more efficient + ByteQueueNode *newHead = new ByteQueueNode(length); + newHead->next = m_head; + m_head = newHead; + m_head->Put(inString, length); +} + +const byte * ByteQueue::Spy(unsigned int &contiguousSize) const +{ + contiguousSize = m_head->m_tail - m_head->m_head; + if (contiguousSize == 0 && m_lazyLength > 0) + { + contiguousSize = m_lazyLength; + return m_lazyString; + } + else + return m_head->buf + m_head->m_head; +} + +byte * ByteQueue::CreatePutSpace(unsigned int &size) +{ + if (m_lazyLength > 0) + FinalizeLazyPut(); + + if (m_tail->m_tail == m_tail->MaxSize()) + { + m_tail->next = new ByteQueueNode(size < m_nodeSize ? m_nodeSize : STDMAX(m_nodeSize, 1024U)); + m_tail = m_tail->next; + } + + size = m_tail->MaxSize() - m_tail->m_tail; + return m_tail->buf + m_tail->m_tail; +} + +ByteQueue & ByteQueue::operator=(const ByteQueue &rhs) +{ + Destroy(); + CopyFrom(rhs); + return *this; +} + +bool ByteQueue::operator==(const ByteQueue &rhs) const +{ + const unsigned long currentSize = CurrentSize(); + + if (currentSize != rhs.CurrentSize()) + return false; + + Walker walker1(*this), walker2(rhs); + byte b1, b2; + + while (walker1.Get(b1) && walker2.Get(b2)) + if (b1 != b2) + return false; + + return true; +} + +byte ByteQueue::operator[](unsigned long i) const +{ + for (ByteQueueNode *current=m_head; current; current=current->next) + { + if (i < current->CurrentSize()) + return (*current)[i]; + + i -= current->CurrentSize(); + } + + assert(i < m_lazyLength); + return m_lazyString[i]; +} + +void ByteQueue::swap(ByteQueue &rhs) +{ + std::swap(m_nodeSize, rhs.m_nodeSize); + std::swap(m_head, rhs.m_head); + std::swap(m_tail, rhs.m_tail); + std::swap(m_lazyString, rhs.m_lazyString); + std::swap(m_lazyLength, rhs.m_lazyLength); +} + +// ******************************************************** + +void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_node = m_queue.m_head; + m_position = 0; + m_offset = 0; + m_lazyString = m_queue.m_lazyString; + m_lazyLength = m_queue.m_lazyLength; +} + +unsigned int ByteQueue::Walker::Get(byte &outByte) +{ + ArraySink sink(&outByte, 1); + return TransferTo(sink, 1); +} + +unsigned int ByteQueue::Walker::Get(byte *outString, unsigned int getMax) +{ + ArraySink sink(outString, getMax); + return TransferTo(sink, getMax); +} + +unsigned int ByteQueue::Walker::Peek(byte &outByte) const +{ + ArraySink sink(&outByte, 1); + return CopyTo(sink, 1); +} + +unsigned int ByteQueue::Walker::Peek(byte *outString, unsigned int peekMax) const +{ + ArraySink sink(outString, peekMax); + return CopyTo(sink, peekMax); +} + +unsigned int ByteQueue::Walker::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + unsigned long bytesLeft = transferBytes; + unsigned int blockedBytes = 0; + + while (m_node) + { + unsigned int len = STDMIN(bytesLeft, (unsigned long)m_node->CurrentSize()-m_offset); + blockedBytes = target.ChannelPut2(channel, m_node->buf+m_node->m_head+m_offset, len, 0, blocking); + + if (blockedBytes) + goto done; + + m_position += len; + bytesLeft -= len; + + if (!bytesLeft) + { + m_offset += len; + goto done; + } + + m_node = m_node->next; + m_offset = 0; + } + + if (bytesLeft && m_lazyLength) + { + unsigned int len = (unsigned int)STDMIN(bytesLeft, (unsigned long)m_lazyLength); + unsigned int blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking); + if (blockedBytes) + goto done; + + m_lazyString += len; + m_lazyLength -= len; + bytesLeft -= len; + } + +done: + transferBytes -= bytesLeft; + return blockedBytes; +} + +unsigned int ByteQueue::Walker::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const +{ + Walker walker(*this); + walker.Skip(begin); + unsigned long transferBytes = end-begin; + unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + begin += transferBytes; + return blockedBytes; +} + +NAMESPACE_END @@ -0,0 +1,128 @@ +// specification file for an unlimited queue for storing bytes + +#ifndef CRYPTOPP_QUEUE_H +#define CRYPTOPP_QUEUE_H + +#include "simple.h" +//#include <algorithm> + +NAMESPACE_BEGIN(CryptoPP) + +/** The queue is implemented as a linked list of byte arrays, but you don't need to + know about that. So just ignore this next line. :) */ +class ByteQueueNode; + +//! Byte Queue +class ByteQueue : public Bufferless<BufferedTransformation> +{ +public: + ByteQueue(unsigned int m_nodeSize=256); + ByteQueue(const ByteQueue ©); + ~ByteQueue(); + + unsigned long MaxRetrievable() const + {return CurrentSize();} + bool AnyRetrievable() const + {return !IsEmpty();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(unsigned int &size); + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); + + unsigned int Get(byte &outByte); + unsigned int Get(byte *outString, unsigned int getMax); + + unsigned int Peek(byte &outByte) const; + unsigned int Peek(byte *outString, unsigned int peekMax) const; + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + + // these member functions are not inherited + void SetNodeSize(unsigned int nodeSize) {m_nodeSize = nodeSize;} + + unsigned long CurrentSize() const; + bool IsEmpty() const; + + void Clear(); + + void Unget(byte inByte); + void Unget(const byte *inString, unsigned int length); + + const byte * Spy(unsigned int &contiguousSize) const; + + void LazyPut(const byte *inString, unsigned int size); + void UndoLazyPut(unsigned int size); + void FinalizeLazyPut(); + + ByteQueue & operator=(const ByteQueue &rhs); + bool operator==(const ByteQueue &rhs) const; + byte operator[](unsigned long i) const; + void swap(ByteQueue &rhs); + + class Walker : public InputRejecting<BufferedTransformation> + { + public: + Walker(const ByteQueue &queue) + : m_queue(queue) {Initialize();} + + unsigned long GetCurrentPosition() {return m_position;} + + unsigned long MaxRetrievable() const + {return m_queue.CurrentSize() - m_position;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + + unsigned int Get(byte &outByte); + unsigned int Get(byte *outString, unsigned int getMax); + + unsigned int Peek(byte &outByte) const; + unsigned int Peek(byte *outString, unsigned int peekMax) const; + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const; + + private: + const ByteQueue &m_queue; + const ByteQueueNode *m_node; + unsigned long m_position; + unsigned int m_offset; + const byte *m_lazyString; + unsigned int m_lazyLength; + }; + + friend class Walker; + +private: + void CleanupUsedNodes(); + void CopyFrom(const ByteQueue ©); + void Destroy(); + + unsigned int m_nodeSize; + ByteQueueNode *m_head, *m_tail; + const byte *m_lazyString; + unsigned int m_lazyLength; +}; + +//! use this to make sure LazyPut is finalized in event of exception +class LazyPutter +{ +public: + LazyPutter(ByteQueue &bq, const byte *inString, unsigned int size) + : m_bq(bq) {bq.LazyPut(inString, size);} + ~LazyPutter() + {try {m_bq.FinalizeLazyPut();} catch(...) {}} +private: + ByteQueue &m_bq; +}; + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/rabi1024.dat b/rabi1024.dat new file mode 100644 index 0000000..ef84137 --- /dev/null +++ b/rabi1024.dat @@ -0,0 +1 @@ +3082015202818100D132EDB1360E31D7B8DD84BB03111FDE0243FFE4031ED12B440E7FF36A634E57772EC81FFDC065607494717C6E16A5AB642283553442CC22569535C7A20E3D1C3E2B3747B26E9856D4A13D0325DC116DAAF8554B000321A753E5CFA730CA60F3E3FE2CA9750C6734A2A113AD4A76B6DAC5E199AB55F34CE6984BF56F6DFAC51D020105020102024100F90CBF726FA70ACB5074BD8E79932B74E9949057B627ABB29F41E5057AE699A03BC240EBB9637E956ABC0B6A20F633F78168A908086E2011FC5D030B9B94B51B024100D7097ACACD8BF8ED641A7D8A17A23F8FB385B92B760EEEB9A1233E1D25892F742315DE23DA0751F24EAE4C0C5B696D0AA0D16EAE94194193DC89D479A9626A2702403B5475CD2A7F519EF08433407826D89983C104AF1E74B44B79B31770149D224089300F828E0DF4CBC864BDB394C0F32CCF055F7B2B8872BF0B5F148020637B9C
\ No newline at end of file diff --git a/rabi2048.dat b/rabi2048.dat new file mode 100644 index 0000000..cb638ef --- /dev/null +++ b/rabi2048.dat @@ -0,0 +1 @@ +308202970282010100B8F2A74040753A7706CB98B80DD9EE33FB7969FCA65A2025E96853267AEF80ABB184FE463B9475F5166307FAFA988F6CA4BBC7122E9555755191AA408BAF4464221394342104ED2762EEA4FED8B5CDB4234442AB979A487446AB37C4A4FD67C259EB942E28B50DD54F3AA14447931821291D4C21BB8BD58C41302F3E1D2E6FF84F84AACEC02196282C492E0354985A66EBA50B1903EDF70D98BD9837E694876505760C58C186F0B5F6500711500297956C9825EBDCCF90633239484F9A3572271D3CD585BFC195BED0D5FFCABE785B25BFF6ACFF2B7C125D54B26CFEF60B1B077B2F953960DAEB57F102B6A1E30AA88B643090BC4D8971077C1B54EA61E4E45102011302010D02818100D02603BBFDB55F1063DFCEBB4CA32F551330E0F2901D87DF2A395EF6AF340F6352CE3514FCE85705652DC6BD401CD0D5D13855B124DA172D5183A7474B85B683AA03382775F3D8DC600F33E696246F9F2134E2DA061923F47B85A923EBB375B07DE3B43EE4FD71D3E24B4B416DAE6E4C2B6D32A9B45BF04296AECAD60C33DA0702818100E3773B5D8B828BEA922392100C54CDF41D0CD26B4C34A64F483B7975AB35920DA0E3F6AE238E72E26F8A498D9AD0C4A75C52F25421E1E2E3865ADD1A0FCEA4DE932DBE6EBEFA689494855B11714B960F57C5102C0E8876D253ABA8C2D6A511DBC0F30589A0FBE66AD6BCEFDFC4F67F8347726A52736274B7F744ECACFF6198E702818100BF84B25DB607930F80ED57C7AF89E7604B7E8E0D341C9C4A0C94FFE6D4B38810553B1E92F7BF9651D3D0149A9188E1FFD1FB86753A327ABC6169AF92271E7204A2C76488FBC781984BA99C3C48C8A799054DA34A201743C3064B4609831B35FBA2B8B1BC67FFD0C685DBA92FE688AD51D1F161C06EC0B9E0D0E187863BFBBEC0
\ No newline at end of file diff --git a/rabin.cpp b/rabin.cpp new file mode 100644 index 0000000..80e96a6 --- /dev/null +++ b/rabin.cpp @@ -0,0 +1,214 @@ +// rabin.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rabin.h" +#include "nbtheory.h" +#include "asn.h" +#include "sha.h" + +#include "oaep.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void RabinFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_r.BERDecode(seq); + m_s.BERDecode(seq); + seq.MessageEnd(); +} + +void RabinFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_r.DEREncode(seq); + m_s.DEREncode(seq); + seq.MessageEnd(); +} + +Integer RabinFunction::ApplyFunction(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer out = in.Squared()%m_n; + if (in.IsOdd()) + out = out*m_r%m_n; + if (Jacobi(in, m_n)==-1) + out = out*m_s%m_n; + return out; +} + +bool RabinFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n%4 == 1; + pass = pass && m_r > Integer::One() && m_r < m_n; + pass = pass && m_s > Integer::One() && m_s < m_n; + if (level >= 1) + pass = pass && Jacobi(m_r, m_n) == -1 && Jacobi(m_s, m_n) == -1; + return pass; +} + +bool RabinFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(QuadraticResidueModPrime1) + CRYPTOPP_GET_FUNCTION_ENTRY(QuadraticResidueModPrime2) + ; +} + +void RabinFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(QuadraticResidueModPrime1) + CRYPTOPP_SET_FUNCTION_ENTRY(QuadraticResidueModPrime2) + ; +} + +// ***************************************************************************** +// private key operations: + +// generate a random private key +void InvertibleRabinFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleRabinFunction: specified modulus size is too small"); + + // VC70 workaround: putting these after primeParam causes overlapped stack allocation + bool rFound=false, sFound=false; + Integer t=2; + + const NameValuePairs &primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + ("EquivalentTo", 3)("Mod", 4); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + while (!(rFound && sFound)) + { + int jp = Jacobi(t, m_p); + int jq = Jacobi(t, m_q); + + if (!rFound && jp==1 && jq==-1) + { + m_r = t; + rFound = true; + } + + if (!sFound && jp==-1 && jq==1) + { + m_s = t; + sFound = true; + } + + ++t; + } + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); +} + +void InvertibleRabinFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_r.BERDecode(seq); + m_s.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); +} + +void InvertibleRabinFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_r.DEREncode(seq); + m_s.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +Integer InvertibleRabinFunction::CalculateInverse(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer cp=in%m_p, cq=in%m_q; + + int jp = Jacobi(cp, m_p); + int jq = Jacobi(cq, m_q); + + if (jq==-1) + { + cp = cp*EuclideanMultiplicativeInverse(m_r, m_p)%m_p; + cq = cq*EuclideanMultiplicativeInverse(m_r, m_q)%m_q; + } + + if (jp==-1) + { + cp = cp*EuclideanMultiplicativeInverse(m_s, m_p)%m_p; + cq = cq*EuclideanMultiplicativeInverse(m_s, m_q)%m_q; + } + + cp = ModularSquareRoot(cp, m_p); + cq = ModularSquareRoot(cq, m_q); + + if (jp==-1) + cp = m_p-cp; + + Integer out = CRT(cq, m_q, cp, m_p, m_u); + + if ((jq==-1 && out.IsEven()) || (jq==1 && out.IsOdd())) + out = m_n-out; + + return out; +} + +bool InvertibleRabinFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RabinFunction::Validate(rng, level); + pass = pass && m_p > Integer::One() && m_p%4 == 3 && m_p < m_n; + pass = pass && m_q > Integer::One() && m_q%4 == 3 && m_q < m_n; + pass = pass && m_u.IsPositive() && m_u < m_p; + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + pass = pass && m_u * m_q % m_p == 1; + pass = pass && Jacobi(m_r, m_p) == 1; + pass = pass && Jacobi(m_r, m_q) == -1; + pass = pass && Jacobi(m_s, m_p) == -1; + pass = pass && Jacobi(m_s, m_q) == 1; + } + if (level >= 2) + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + return pass; +} + +bool InvertibleRabinFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<RabinFunction>(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleRabinFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper<RabinFunction>(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +NAMESPACE_END @@ -0,0 +1,123 @@ +#ifndef CRYPTOPP_RABIN_H +#define CRYPTOPP_RABIN_H + +/** \file +*/ + +#include "oaep.h" +#include "pssr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Rabin +class RabinFunction : public TrapdoorFunction, public PublicKey +{ + typedef RabinFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &r, const Integer &s) + {m_n = n; m_r = r; m_s = s;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + const Integer& GetQuadraticResidueModPrime1() const {return m_r;} + const Integer& GetQuadraticResidueModPrime2() const {return m_s;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetQuadraticResidueModPrime1(const Integer &r) {m_r = r;} + void SetQuadraticResidueModPrime2(const Integer &s) {m_s = s;} + +protected: + Integer m_n, m_r, m_s; +}; + +//! Invertible Rabin +class InvertibleRabinFunction : public RabinFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRabinFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &r, const Integer &s, + const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_r = r; m_s = s; m_p = p; m_q = q; m_u = u;} + void Initialize(RandomNumberGenerator &rng, unsigned int keybits) + {GenerateRandomWithKeySize(rng, keybits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +//! . +struct Rabin +{ + static std::string StaticAlgorithmName() {return "Rabin-Crypto++Variant";} + typedef RabinFunction PublicKey; + typedef InvertibleRabinFunction PrivateKey; +}; + +//! . +template <class STANDARD> +struct RabinES : public TF_ES<STANDARD, Rabin> +{ +}; + +//! . +template <class EM> +struct RabinSSR +{ + typedef PK_FinalTemplate<SignerWithRecoveryTemplate<InvertibleRabinFunction, EM> > Signer; + typedef PK_FinalTemplate<VerifierWithRecoveryTemplate<RabinFunction, EM> > Verifier; +}; + +//! . +template <class H> +struct RabinPSSR : public RabinSSR<PSSR<H> > +{ +}; + +class SHA; + +// More typedefs for backwards compatibility + +typedef RabinES<OAEP<SHA> >::Decryptor RabinDecryptor; +typedef RabinES<OAEP<SHA> >::Encryptor RabinEncryptor; + +#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY +// simulate template typedef +#define RabinSignerWith(H) RabinPSSR<H>::Signer +#define RabinVerifierWith(H) RabinPSSR<H>::Verifier +#endif + +NAMESPACE_END + +#endif diff --git a/randpool.cpp b/randpool.cpp new file mode 100644 index 0000000..9fa0b4b --- /dev/null +++ b/randpool.cpp @@ -0,0 +1,100 @@ +// randpool.cpp - written and placed in the public domain by Wei Dai +// The algorithm in this module comes from PGP's randpool.c + +#include "pch.h" +#include "randpool.h" +#include "mdc.h" +#include "sha.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +typedef MDC<SHA> RandomPoolCipher; + +RandomPool::RandomPool(unsigned int poolSize) + : pool(poolSize), key(RandomPoolCipher::DEFAULT_KEYLENGTH) +{ + assert(poolSize > key.size()); + + addPos=0; + getPos=poolSize; + memset(pool, 0, poolSize); + memset(key, 0, key.size()); +} + +void RandomPool::Stir() +{ + CFB_Mode<RandomPoolCipher>::Encryption cipher; + + for (int i=0; i<2; i++) + { + cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize()); + cipher.ProcessString(pool, pool.size()); + memcpy(key, pool, key.size()); + } + + addPos = 0; + getPos = key.size(); +} + +unsigned int RandomPool::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + unsigned t; + + while (length > (t = pool.size() - addPos)) + { + xorbuf(pool+addPos, inString, t); + inString += t; + length -= t; + Stir(); + } + + if (length) + { + xorbuf(pool+addPos, inString, length); + addPos += length; + getPos = pool.size(); // Force stir on get + } + + return 0; +} + +unsigned int RandomPool::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking) +{ + if (!blocking) + throw NotImplemented("RandomPool: nonblocking transfer is not implemented by this object"); + + unsigned int t; + unsigned long size = transferBytes; + + while (size > (t = pool.size() - getPos)) + { + target.ChannelPut(channel, pool+getPos, t); + size -= t; + Stir(); + } + + if (size) + { + target.ChannelPut(channel, pool+getPos, size); + getPos += size; + } + + return 0; +} + +byte RandomPool::GenerateByte() +{ + if (getPos == pool.size()) + Stir(); + + return pool[getPos++]; +} + +void RandomPool::GenerateBlock(byte *outString, unsigned int size) +{ + ArraySink sink(outString, size); + TransferTo(sink, size); +} + +NAMESPACE_END diff --git a/randpool.h b/randpool.h new file mode 100644 index 0000000..6bbe32f --- /dev/null +++ b/randpool.h @@ -0,0 +1,46 @@ +#ifndef CRYPTOPP_RANDPOOL_H +#define CRYPTOPP_RANDPOOL_H + +#include "cryptlib.h" +#include "filters.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! Randomness Pool +/*! This class can be used to generate + pseudorandom bytes after seeding the pool with + the Put() methods */ +class RandomPool : public RandomNumberGenerator, + public Bufferless<BufferedTransformation> +{ +public: + //! poolSize must be greater than 16 + RandomPool(unsigned int poolSize=384); + + unsigned int Put2(const byte *begin, unsigned int, int messageEnd, bool blocking); + + bool AnyRetrievable() const {return true;} + unsigned long MaxRetrievable() const {return ULONG_MAX;} + + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true); + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const + { + throw NotImplemented("RandomPool: CopyRangeTo2() is not supported by this store"); + } + + byte GenerateByte(); + void GenerateBlock(byte *output, unsigned int size); + + void IsolatedInitialize(const NameValuePairs ¶meters) {} + +protected: + void Stir(); + +private: + SecByteBlock pool, key; + unsigned int addPos, getPos; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,120 @@ +// rc2.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rc2.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC2::Base::UncheckedSetKey(CipherDir direction, const byte *key, unsigned int keyLen, unsigned int effectiveLen) +{ + AssertValidKeyLength(keyLen); + + static const unsigned char PITABLE[256] = { + 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157, + 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162, + 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50, + 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130, + 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220, + 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38, + 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3, + 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215, + 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42, + 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236, + 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57, + 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49, + 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201, + 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169, + 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46, + 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173}; + + SecByteBlock L(128); + memcpy(L, key, keyLen); + + int i; + for (i=keyLen; i<128; i++) + L[i] = PITABLE[(L[i-1] + L[i-keyLen]) & 255]; + + unsigned int T8 = (effectiveLen+7) / 8; + byte TM = 255 >> ((8-(effectiveLen%8))%8); + L[128-T8] = PITABLE[L[128-T8] & TM]; + + for (i=127-T8; i>=0; i--) + L[i] = PITABLE[L[i+1] ^ L[i+T8]]; + + for (i=0; i<64; i++) + K[i] = L[2*i] + (L[2*i+1] << 8); +} + +void RC2::Base::SetKeyWithEffectiveKeyLength(const byte *key, unsigned int length, unsigned int effectiveKeyLength) +{ + if (effectiveKeyLength > MAX_EFFECTIVE_KEYLENGTH) + throw InvalidArgument("RC2: effective key length parameter exceeds maximum"); + UncheckedSetKey(ENCRYPTION, key, length, effectiveKeyLength); +} + +typedef BlockGetAndPut<word16, LittleEndian> Block; + +void RC2::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 R0, R1, R2, R3; + Block::Get(inBlock)(R0)(R1)(R2)(R3); + + for (int i = 0; i < 16; i++) + { + R0 += (R1 & ~R3) + (R2 & R3) + K[4*i+0]; + R0 = rotlFixed(R0, 1); + + R1 += (R2 & ~R0) + (R3 & R0) + K[4*i+1]; + R1 = rotlFixed(R1, 2); + + R2 += (R3 & ~R1) + (R0 & R1) + K[4*i+2]; + R2 = rotlFixed(R2, 3); + + R3 += (R0 & ~R2) + (R1 & R2) + K[4*i+3]; + R3 = rotlFixed(R3, 5); + + if (i == 4 || i == 10) + { + R0 += K[R3 & 63]; + R1 += K[R0 & 63]; + R2 += K[R1 & 63]; + R3 += K[R2 & 63]; + } + } + + Block::Put(xorBlock, outBlock)(R0)(R1)(R2)(R3); +} + +void RC2::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 R0, R1, R2, R3; + Block::Get(inBlock)(R0)(R1)(R2)(R3); + + for (int i = 15; i >= 0; i--) + { + if (i == 4 || i == 10) + { + R3 -= K[R2 & 63]; + R2 -= K[R1 & 63]; + R1 -= K[R0 & 63]; + R0 -= K[R3 & 63]; + } + + R3 = rotrFixed(R3, 5); + R3 -= (R0 & ~R2) + (R1 & R2) + K[4*i+3]; + + R2 = rotrFixed(R2, 3); + R2 -= (R3 & ~R1) + (R0 & R1) + K[4*i+2]; + + R1 = rotrFixed(R1, 2); + R1 -= (R2 & ~R0) + (R3 & R0) + K[4*i+1]; + + R0 = rotrFixed(R0, 1); + R0 -= (R1 & ~R3) + (R2 & R3) + K[4*i+0]; + } + + Block::Put(xorBlock, outBlock)(R0)(R1)(R2)(R3); +} + +NAMESPACE_END @@ -0,0 +1,74 @@ +#ifndef CRYPTOPP_RC2_H +#define CRYPTOPP_RC2_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct RC2_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 128> +{ + enum {DEFAULT_EFFECTIVE_KEYLENGTH = 1024, MAX_EFFECTIVE_KEYLENGTH = 1024}; + static const char *StaticAlgorithmName() {return "RC2";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#RC2">RC2</a> +class RC2 : public RC2_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<RC2_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *key, unsigned int length, unsigned int effectiveKeyLength); + void SetKeyWithEffectiveKeyLength(const byte *key, unsigned int length, unsigned int effectiveKeyLength); + + protected: + template <class T> + static inline void CheckedSetKey(T *obj, CipherDir dir, const byte *key, unsigned int length, const NameValuePairs ¶m) + { + obj->ThrowIfInvalidKeyLength(length); + int effectiveKeyLength = param.GetIntValueWithDefault("EffectiveKeyLength", DEFAULT_EFFECTIVE_KEYLENGTH); + obj->SetKeyWithEffectiveKeyLength(key, length, effectiveKeyLength); + } + + FixedSizeSecBlock<word16, 64> K; // expanded key table + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + class Encryption : public BlockCipherTemplate<ENCRYPTION, Enc> + { + public: + Encryption() {} + Encryption(const byte *key, unsigned int keyLen=DEFAULT_KEYLENGTH, unsigned int effectiveLen=1024) + {SetKeyWithEffectiveKeyLength(key, keyLen, effectiveLen);} + }; + + class Decryption : public BlockCipherTemplate<DECRYPTION, Dec> + { + public: + Decryption() {} + Decryption(const byte *key, unsigned int keyLen=DEFAULT_KEYLENGTH, unsigned int effectiveLen=1024) + {SetKeyWithEffectiveKeyLength(key, keyLen, effectiveLen);} + }; +}; + +typedef RC2::Encryption RC2Encryption; +typedef RC2::Decryption RC2Decryption; + +NAMESPACE_END + +#endif diff --git a/rc2val.dat b/rc2val.dat new file mode 100644 index 0000000..b4f82a3 --- /dev/null +++ b/rc2val.dat @@ -0,0 +1,48 @@ +08 +3F +00000000 00000000 +00000000 00000000 +ebb773f9 93278eff + +08 +40 +ffffffff ffffffff +ffffffff ffffffff +278b27e4 2e2f0d49 + +08 +40 +30000000 00000000 +10000000 00000001 +30649edf 9be7d2c2 + +01 +40 +88 +00000000 00000000 +61a8a244 adacccf0 + +07 +40 +88bca90e 90875a +00000000 00000000 +6ccf4308 974c267f + +10 +40 +88bca90e 90875a7f 0f79c384 627bafb2 +00000000 00000000 +1a807d27 2bbe5db1 + +10 +80 +88bca90e 90875a7f 0f79c384 627bafb2 +00000000 00000000 +2269552a b0f85ca6 + +21 +81 +88bca90e 90875a7f 0f79c384 627bafb2 16f80a6f 85920584 + c42fceb0 be255daf 1e +00000000 00000000 +5b78d3a4 3dfff1f1 @@ -0,0 +1,80 @@ +// rc5.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rc5.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC5::Base::UncheckedSetKey(CipherDir direction, const byte *k, unsigned int keylen, unsigned int rounds) +{ + AssertValidKeyLength(keylen); + AssertValidRounds(rounds); + + r = rounds; + sTable.New(2*(r+1)); + + static const RC5_WORD MAGIC_P = 0xb7e15163L; // magic constant P for wordsize + static const RC5_WORD MAGIC_Q = 0x9e3779b9L; // magic constant Q for wordsize + static const int U=sizeof(RC5_WORD); + + const unsigned int c = STDMAX((keylen+U-1)/U, 1U); // RC6 paper says c=1 if keylen==0 + SecBlock<RC5_WORD> l(c); + + GetUserKey(LITTLE_ENDIAN_ORDER, l.begin(), c, k, keylen); + + sTable[0] = MAGIC_P; + for (unsigned j=1; j<sTable.size();j++) + sTable[j] = sTable[j-1] + MAGIC_Q; + + RC5_WORD a=0, b=0; + const unsigned n = 3*STDMAX((unsigned int)sTable.size(), c); + + for (unsigned h=0; h < n; h++) + { + a = sTable[h % sTable.size()] = rotlFixed((sTable[h % sTable.size()] + a + b), 3); + b = l[h % c] = rotlMod((l[h % c] + a + b), (a+b)); + } +} + +typedef BlockGetAndPut<RC5::RC5_WORD, LittleEndian> Block; + +void RC5::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC5_WORD *sptr = sTable; + RC5_WORD a, b; + + Block::Get(inBlock)(a)(b); + a += sptr[0]; + b += sptr[1]; + sptr += 2; + + for(unsigned i=0; i<r; i++) + { + a = rotlMod(a^b,b) + sptr[2*i+0]; + b = rotlMod(a^b,a) + sptr[2*i+1]; + } + + Block::Put(xorBlock, outBlock)(a)(b); +} + +void RC5::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC5_WORD *sptr = sTable.end(); + RC5_WORD a, b; + + Block::Get(inBlock)(a)(b); + + for (unsigned i=0; i<r; i++) + { + sptr-=2; + b = rotrMod(b-sptr[1], a) ^ a; + a = rotrMod(a-sptr[0], b) ^ b; + } + b -= sTable[1]; + a -= sTable[0]; + + Block::Put(xorBlock, outBlock)(a)(b); +} + +NAMESPACE_END @@ -0,0 +1,53 @@ +#ifndef CRYPTOPP_RC5_H +#define CRYPTOPP_RC5_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct RC5_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 0, 255>, public VariableRounds<16> +{ + static const char *StaticAlgorithmName() {return "RC5";} + typedef word32 RC5_WORD; +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#RC5">RC5</a> +class RC5 : public RC5_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<RC5_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds); + + protected: + unsigned int r; // number of rounds + SecBlock<RC5_WORD> sTable; // expanded key table + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef RC5::Encryption RC5Encryption; +typedef RC5::Decryption RC5Decryption; + +NAMESPACE_END + +#endif diff --git a/rc5val.dat b/rc5val.dat new file mode 100644 index 0000000..ea2b617 --- /dev/null +++ b/rc5val.dat @@ -0,0 +1,5 @@ +00000000000000000000000000000000 0000000000000000 21A5DBEE154B8F6D +915F4619BE41B2516355A50110A9CE91 21A5DBEE154B8F6D F7C013AC5B2B8952 +783348E75AEB0F2FD7B169BB8DC16787 F7C013AC5B2B8952 2F42B3B70369FC92 +DC49DB1375A5584F6485B413B5F12BAF 2F42B3B70369FC92 65C178B284D197CC +5269F149D41BA0152497574D7F153125 65C178B284D197CC EB44E415DA319824 @@ -0,0 +1,97 @@ +// rc6.cpp - written and placed in the public domain by Sean Woods +// based on Wei Dai's RC5 code. + +#include "pch.h" +#include "rc6.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC6::Base::UncheckedSetKey(CipherDir direction, const byte *k, unsigned int keylen, unsigned int rounds) +{ + AssertValidKeyLength(keylen); + AssertValidRounds(rounds); + + r = rounds; + sTable.New(2*(r+2)); + + static const RC6_WORD MAGIC_P = 0xb7e15163L; // magic constant P for wordsize + static const RC6_WORD MAGIC_Q = 0x9e3779b9L; // magic constant Q for wordsize + static const int U=sizeof(RC6_WORD); + + const unsigned int c = STDMAX((keylen+U-1)/U, 1U); // RC6 paper says c=1 if keylen==0 + SecBlock<RC6_WORD> l(c); + + GetUserKey(LITTLE_ENDIAN_ORDER, l.begin(), c, k, keylen); + + sTable[0] = MAGIC_P; + for (unsigned j=1; j<sTable.size();j++) + sTable[j] = sTable[j-1] + MAGIC_Q; + + RC6_WORD a=0, b=0; + const unsigned n = 3*STDMAX((unsigned int)sTable.size(), c); + + for (unsigned h=0; h < n; h++) + { + a = sTable[h % sTable.size()] = rotlFixed((sTable[h % sTable.size()] + a + b), 3); + b = l[h % c] = rotlMod((l[h % c] + a + b), (a+b)); + } +} + +typedef BlockGetAndPut<RC6::RC6_WORD, LittleEndian> Block; + +void RC6::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC6_WORD *sptr = sTable; + RC6_WORD a, b, c, d, t, u; + + Block::Get(inBlock)(a)(b)(c)(d); + b += sptr[0]; + d += sptr[1]; + sptr += 2; + + for(unsigned i=0; i<r; i++) + { + t = rotlFixed(b*(2*b+1), 5); + u = rotlFixed(d*(2*d+1), 5); + a = rotlMod(a^t,u) + sptr[0]; + c = rotlMod(c^u,t) + sptr[1]; + t = a; a = b; b = c; c = d; d = t; + sptr += 2; + } + + a += sptr[0]; + c += sptr[1]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +void RC6::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC6_WORD *sptr = sTable.end(); + RC6_WORD a, b, c, d, t, u; + + Block::Get(inBlock)(a)(b)(c)(d); + + sptr -= 2; + c -= sptr[1]; + a -= sptr[0]; + + for (unsigned i=0; i < r; i++) + { + sptr -= 2; + t = a; a = d; d = c; c = b; b = t; + u = rotlFixed(d*(2*d+1), 5); + t = rotlFixed(b*(2*b+1), 5); + c = rotrMod(c-sptr[1], t) ^ u; + a = rotrMod(a-sptr[0], u) ^ t; + } + + sptr -= 2; + d -= sTable[1]; + b -= sTable[0]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +NAMESPACE_END @@ -0,0 +1,53 @@ +#ifndef CRYPTOPP_RC6_H +#define CRYPTOPP_RC6_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct RC6_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 0, 255>, public VariableRounds<20> +{ + static const char *StaticAlgorithmName() {return "RC6";} + typedef word32 RC6_WORD; +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#RC6">RC6</a> +class RC6 : public RC6_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<RC6_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length, unsigned int rounds); + + protected: + unsigned int r; // number of rounds + SecBlock<RC6_WORD> sTable; // expanded key table + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef RC6::Encryption RC6Encryption; +typedef RC6::Decryption RC6Decryption; + +NAMESPACE_END + +#endif diff --git a/rc6val.dat b/rc6val.dat new file mode 100644 index 0000000..3efa3c9 --- /dev/null +++ b/rc6val.dat @@ -0,0 +1,17 @@ +00000000000000000000000000000000 + 00000000000000000000000000000000 8FC3A53656B1F778C129DF4E9848A41E + +0123456789ABCDEF0112233445566778 + 02132435465768798A9BACBDCEDFE0F1 524E192F4715C6231F51F6367EA43F18 + +000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000 6cd61bcb190b30384e8a3f168690ae82 + +0123456789abcdef0112233445566778899aabbccddeeff0 + 02132435465768798a9bacbdcedfe0f1 688329d019e505041e52e92af95291d4 + +0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000 8f5fbd0510d15fa893fa3fda6e857ec2 + +0123456789abcdef0112233445566778899aabbccddeeff01032547698badcfe + 02132435465768798a9bacbdcedfe0f1 c8241816f0d7e48920ad16a1674e5d48
\ No newline at end of file diff --git a/rdtables.cpp b/rdtables.cpp new file mode 100644 index 0000000..87ae597 --- /dev/null +++ b/rdtables.cpp @@ -0,0 +1,704 @@ +// Rijndael tables + +#include "pch.h" +#include "rijndael.h" + +// VC60 workaround: gives a C4786 warning without this function +// when runtime lib is set to multithread debug DLL +// even though warning 4786 is disabled! +void Rijndael_VC60Workaround() +{ +} + +NAMESPACE_BEGIN(CryptoPP) + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +const word32 Rijndael::Base::Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +const word32 Rijndael::Base::Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +const word32 Rijndael::Base::Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; + +const word32 Rijndael::Base::Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +const word32 Rijndael::Base::Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; + +const word32 Rijndael::Base::Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; + +const word32 Rijndael::Base::Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; + +const word32 Rijndael::Base::Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; + +const word32 Rijndael::Base::Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; + +const word32 Rijndael::Base::Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; + +const word32 Rijndael::Base::rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +NAMESPACE_END diff --git a/rijndael.cpp b/rijndael.cpp new file mode 100644 index 0000000..857e6bf --- /dev/null +++ b/rijndael.cpp @@ -0,0 +1,375 @@ +// rijndael.cpp - modified by Chris Morgan <cmorgan@wpi.edu> +// and Wei Dai from Paulo Baretto's Rijndael implementation +// The original code and all modifications are in the public domain. + +// This is the original introductory comment: + +/** + * version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> + * author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> + * author Paulo Barreto <paulo.barreto@terra.com.br> + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pch.h" +#include "rijndael.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Rijndael::Base::UncheckedSetKey(CipherDir dir, const byte *userKey, unsigned int keylen) +{ + AssertValidKeyLength(keylen); + + m_rounds = keylen/4 + 6; + m_key.New(4*(m_rounds+1)); + + word32 temp, *rk = m_key; + unsigned int i=0; + + GetUserKey(BIG_ENDIAN_ORDER, rk, keylen/4, userKey, keylen); + + switch(keylen) + { + case 16: + while (true) + { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) + break; + rk += 4; + } + break; + + case 24: + while (true) // for (;;) here triggers a bug in VC60 SP4 w/ Processor Pack + { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) + break; + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + break; + + case 32: + while (true) + { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) + break; + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 0)] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + break; + } + + if (dir == DECRYPTION) + { + unsigned int i, j; + rk = m_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*m_rounds; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < m_rounds; i++) { + rk += 4; + rk[0] = + Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + rk[1] = + Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + rk[2] = + Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + rk[3] = + Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + } + } +} + +typedef BlockGetAndPut<word32, BigEndian> Block; + +void Rijndael::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 s0, s1, s2, s3, t0, t1, t2, t3; + const word32 *rk = m_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + Block::Get(inBlock)(s0)(s1)(s2)(s3); + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + /* + * Nr - 1 full rounds: + */ + unsigned int r = m_rounds >> 1; + for (;;) { + t0 = + Te0[GETBYTE(s0, 3)] ^ + Te1[GETBYTE(s1, 2)] ^ + Te2[GETBYTE(s2, 1)] ^ + Te3[GETBYTE(s3, 0)] ^ + rk[4]; + t1 = + Te0[GETBYTE(s1, 3)] ^ + Te1[GETBYTE(s2, 2)] ^ + Te2[GETBYTE(s3, 1)] ^ + Te3[GETBYTE(s0, 0)] ^ + rk[5]; + t2 = + Te0[GETBYTE(s2, 3)] ^ + Te1[GETBYTE(s3, 2)] ^ + Te2[GETBYTE(s0, 1)] ^ + Te3[GETBYTE(s1, 0)] ^ + rk[6]; + t3 = + Te0[GETBYTE(s3, 3)] ^ + Te1[GETBYTE(s0, 2)] ^ + Te2[GETBYTE(s1, 1)] ^ + Te3[GETBYTE(s2, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[GETBYTE(t0, 3)] ^ + Te1[GETBYTE(t1, 2)] ^ + Te2[GETBYTE(t2, 1)] ^ + Te3[GETBYTE(t3, 0)] ^ + rk[0]; + s1 = + Te0[GETBYTE(t1, 3)] ^ + Te1[GETBYTE(t2, 2)] ^ + Te2[GETBYTE(t3, 1)] ^ + Te3[GETBYTE(t0, 0)] ^ + rk[1]; + s2 = + Te0[GETBYTE(t2, 3)] ^ + Te1[GETBYTE(t3, 2)] ^ + Te2[GETBYTE(t0, 1)] ^ + Te3[GETBYTE(t1, 0)] ^ + rk[2]; + s3 = + Te0[GETBYTE(t3, 3)] ^ + Te1[GETBYTE(t0, 2)] ^ + Te2[GETBYTE(t1, 1)] ^ + Te3[GETBYTE(t2, 0)] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + + s0 = + (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[3]; + + Block::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); +} + +void Rijndael::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 s0, s1, s2, s3, t0, t1, t2, t3; + const word32 *rk = m_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + Block::Get(inBlock)(s0)(s1)(s2)(s3); + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + /* + * Nr - 1 full rounds: + */ + unsigned int r = m_rounds >> 1; + for (;;) { + t0 = + Td0[GETBYTE(s0, 3)] ^ + Td1[GETBYTE(s3, 2)] ^ + Td2[GETBYTE(s2, 1)] ^ + Td3[GETBYTE(s1, 0)] ^ + rk[4]; + t1 = + Td0[GETBYTE(s1, 3)] ^ + Td1[GETBYTE(s0, 2)] ^ + Td2[GETBYTE(s3, 1)] ^ + Td3[GETBYTE(s2, 0)] ^ + rk[5]; + t2 = + Td0[GETBYTE(s2, 3)] ^ + Td1[GETBYTE(s1, 2)] ^ + Td2[GETBYTE(s0, 1)] ^ + Td3[GETBYTE(s3, 0)] ^ + rk[6]; + t3 = + Td0[GETBYTE(s3, 3)] ^ + Td1[GETBYTE(s2, 2)] ^ + Td2[GETBYTE(s1, 1)] ^ + Td3[GETBYTE(s0, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[GETBYTE(t0, 3)] ^ + Td1[GETBYTE(t3, 2)] ^ + Td2[GETBYTE(t2, 1)] ^ + Td3[GETBYTE(t1, 0)] ^ + rk[0]; + s1 = + Td0[GETBYTE(t1, 3)] ^ + Td1[GETBYTE(t0, 2)] ^ + Td2[GETBYTE(t3, 1)] ^ + Td3[GETBYTE(t2, 0)] ^ + rk[1]; + s2 = + Td0[GETBYTE(t2, 3)] ^ + Td1[GETBYTE(t1, 2)] ^ + Td2[GETBYTE(t0, 1)] ^ + Td3[GETBYTE(t3, 0)] ^ + rk[2]; + s3 = + Td0[GETBYTE(t3, 3)] ^ + Td1[GETBYTE(t2, 2)] ^ + Td2[GETBYTE(t1, 1)] ^ + Td3[GETBYTE(t0, 0)] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[3]; + + Block::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); +} + +NAMESPACE_END diff --git a/rijndael.dat b/rijndael.dat new file mode 100644 index 0000000..c3e43f0 --- /dev/null +++ b/rijndael.dat @@ -0,0 +1,9 @@ +000102030405060708090A0B0C0D0E0F 000102030405060708090A0B0C0D0E0F 0A940BB5416EF045F1C39458C653EA5A +00010203050607080A0B0C0D0F101112 506812A45F08C889B97F5980038B8359 D8F532538289EF7D06B506A4FD5BE9C9 +14151617191A1B1C1E1F202123242526 5C6D71CA30DE8B8B00549984D2EC7D4B 59AB30F4D4EE6E4FF9907EF65B1FB68C +28292A2B2D2E2F30323334353738393A 53F3F4C64F8616E4E7C56199F48F21F6 BF1ED2FCB2AF3FD41443B56D85025CB1 +00010203050607080A0B0C0D0F10111214151617191A1B1C 2D33EEF2C0430A8A9EBF45E809C40BB6 DFF4945E0336DF4C1C56BC700EFF837F +1E1F20212324252628292A2B2D2E2F30323334353738393A 6AA375D1FA155A61FB72353E0A5A8756 B6FDDEF4752765E347D5D2DC196D1252 +3C3D3E3F41424344464748494B4C4D4E5051525355565758 BC3736518B9490DCB8ED60EB26758ED4 D23684E3D963B3AFCF1A114ACA90CBD6 +00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526 834EADFCCAC7E1B30664B1ABA44815AB 1946DABF6A03A2A2C3D0B05080AED6FC +28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E D9DC4DBA3021B05D67C0518F72B62BF1 5ED301D747D3CC715445EBDEC62F2FB4 diff --git a/rijndael.h b/rijndael.h new file mode 100644 index 0000000..1c046db --- /dev/null +++ b/rijndael.h @@ -0,0 +1,66 @@ +#ifndef CRYPTOPP_RIJNDAEL_H +#define CRYPTOPP_RIJNDAEL_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Rijndael_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + static const char *StaticAlgorithmName() {return "Rijndael";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Rijndael">Rijndael</a> +class Rijndael : public Rijndael_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Rijndael_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static const word32 Te0[256]; + static const word32 Te1[256]; + static const word32 Te2[256]; + static const word32 Te3[256]; + static const word32 Te4[256]; + + static const word32 Td0[256]; + static const word32 Td1[256]; + static const word32 Td2[256]; + static const word32 Td3[256]; + static const word32 Td4[256]; + + static const word32 rcon[]; + + unsigned int m_rounds; + SecBlock<word32> m_key; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Rijndael::Encryption RijndaelEncryption; +typedef Rijndael::Decryption RijndaelDecryption; + +NAMESPACE_END + +#endif diff --git a/ripemd.cpp b/ripemd.cpp new file mode 100644 index 0000000..ac0a840 --- /dev/null +++ b/ripemd.cpp @@ -0,0 +1,227 @@ +// ripemd.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "ripemd.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RIPEMD160::Init() +{ + m_digest[0] = 0x67452301L; + m_digest[1] = 0xefcdab89L; + m_digest[2] = 0x98badcfeL; + m_digest[3] = 0x10325476L; + m_digest[4] = 0xc3d2e1f0L; +} + +void RIPEMD160::Transform (word32 *digest, const word32 *X) +{ +#define Subround(f, a, b, c, d, e, x, s, k) \ + a += f(b, c, d) + x + k;\ + a = rotlFixed((word32)a, s) + e;\ + c = rotlFixed((word32)c, 10U) + +#define F(x, y, z) (x ^ y ^ z) +#define G(x, y, z) (z ^ (x & (y^z))) +#define H(x, y, z) (z ^ (x | ~y)) +#define I(x, y, z) (y ^ (z & (x^y))) +#define J(x, y, z) (x ^ (y | ~z)) + +#define k0 0 +#define k1 0x5a827999UL +#define k2 0x6ed9eba1UL +#define k3 0x8f1bbcdcUL +#define k4 0xa953fd4eUL +#define k5 0x50a28be6UL +#define k6 0x5c4dd124UL +#define k7 0x6d703ef3UL +#define k8 0x7a6d76e9UL +#define k9 0 + + unsigned long a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + a1 = a2 = digest[0]; + b1 = b2 = digest[1]; + c1 = c2 = digest[2]; + d1 = d2 = digest[3]; + e1 = e2 = digest[4]; + + Subround(F, a1, b1, c1, d1, e1, X[ 0], 11, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 1], 14, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 2], 15, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 3], 12, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, X[ 5], 8, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 6], 7, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 7], 9, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 8], 11, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 9], 13, k0); + Subround(F, a1, b1, c1, d1, e1, X[10], 14, k0); + Subround(F, e1, a1, b1, c1, d1, X[11], 15, k0); + Subround(F, d1, e1, a1, b1, c1, X[12], 6, k0); + Subround(F, c1, d1, e1, a1, b1, X[13], 7, k0); + Subround(F, b1, c1, d1, e1, a1, X[14], 9, k0); + Subround(F, a1, b1, c1, d1, e1, X[15], 8, k0); + + Subround(G, e1, a1, b1, c1, d1, X[ 7], 7, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, X[13], 8, k1); + Subround(G, b1, c1, d1, e1, a1, X[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, e1, X[10], 11, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 6], 9, k1); + Subround(G, d1, e1, a1, b1, c1, X[15], 7, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 3], 15, k1); + Subround(G, b1, c1, d1, e1, a1, X[12], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[ 0], 12, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 9], 15, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 5], 9, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 2], 11, k1); + Subround(G, b1, c1, d1, e1, a1, X[14], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[11], 13, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 8], 12, k1); + + Subround(H, d1, e1, a1, b1, c1, X[ 3], 11, k2); + Subround(H, c1, d1, e1, a1, b1, X[10], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[14], 6, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 9], 14, k2); + Subround(H, d1, e1, a1, b1, c1, X[15], 9, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 8], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 2], 14, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 7], 8, k2); + Subround(H, d1, e1, a1, b1, c1, X[ 0], 13, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 6], 6, k2); + Subround(H, b1, c1, d1, e1, a1, X[13], 5, k2); + Subround(H, a1, b1, c1, d1, e1, X[11], 12, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 5], 7, k2); + Subround(H, d1, e1, a1, b1, c1, X[12], 5, k2); + + Subround(I, c1, d1, e1, a1, b1, X[ 1], 11, k3); + Subround(I, b1, c1, d1, e1, a1, X[ 9], 12, k3); + Subround(I, a1, b1, c1, d1, e1, X[11], 14, k3); + Subround(I, e1, a1, b1, c1, d1, X[10], 15, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 0], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 8], 15, k3); + Subround(I, b1, c1, d1, e1, a1, X[12], 9, k3); + Subround(I, a1, b1, c1, d1, e1, X[ 4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[13], 9, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 3], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 7], 5, k3); + Subround(I, b1, c1, d1, e1, a1, X[15], 6, k3); + Subround(I, a1, b1, c1, d1, e1, X[14], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[ 5], 6, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 6], 5, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 2], 12, k3); + + Subround(J, b1, c1, d1, e1, a1, X[ 4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 0], 15, k4); + Subround(J, e1, a1, b1, c1, d1, X[ 5], 5, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 9], 11, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 7], 6, k4); + Subround(J, b1, c1, d1, e1, a1, X[12], 8, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 2], 13, k4); + Subround(J, e1, a1, b1, c1, d1, X[10], 12, k4); + Subround(J, d1, e1, a1, b1, c1, X[14], 5, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 1], 12, k4); + Subround(J, b1, c1, d1, e1, a1, X[ 3], 13, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 8], 14, k4); + Subround(J, e1, a1, b1, c1, d1, X[11], 11, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 6], 8, k4); + Subround(J, c1, d1, e1, a1, b1, X[15], 5, k4); + Subround(J, b1, c1, d1, e1, a1, X[13], 6, k4); + + Subround(J, a2, b2, c2, d2, e2, X[ 5], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[14], 9, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 7], 9, k5); + Subround(J, c2, d2, e2, a2, b2, X[ 0], 11, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 9], 13, k5); + Subround(J, a2, b2, c2, d2, e2, X[ 2], 15, k5); + Subround(J, e2, a2, b2, c2, d2, X[11], 15, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, X[13], 7, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 6], 7, k5); + Subround(J, a2, b2, c2, d2, e2, X[15], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[ 8], 11, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 1], 14, k5); + Subround(J, c2, d2, e2, a2, b2, X[10], 14, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 3], 12, k5); + Subround(J, a2, b2, c2, d2, e2, X[12], 6, k5); + + Subround(I, e2, a2, b2, c2, d2, X[ 6], 9, k6); + Subround(I, d2, e2, a2, b2, c2, X[11], 13, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 3], 15, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 7], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 0], 12, k6); + Subround(I, e2, a2, b2, c2, d2, X[13], 8, k6); + Subround(I, d2, e2, a2, b2, c2, X[ 5], 9, k6); + Subround(I, c2, d2, e2, a2, b2, X[10], 11, k6); + Subround(I, b2, c2, d2, e2, a2, X[14], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[15], 7, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 8], 12, k6); + Subround(I, d2, e2, a2, b2, c2, X[12], 7, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 9], 15, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 1], 13, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 2], 11, k6); + + Subround(H, d2, e2, a2, b2, c2, X[15], 9, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 5], 7, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 1], 15, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 3], 11, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 7], 8, k7); + Subround(H, d2, e2, a2, b2, c2, X[14], 6, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 6], 6, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 9], 14, k7); + Subround(H, a2, b2, c2, d2, e2, X[11], 12, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 8], 13, k7); + Subround(H, d2, e2, a2, b2, c2, X[12], 5, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 2], 14, k7); + Subround(H, b2, c2, d2, e2, a2, X[10], 13, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 0], 13, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, X[13], 5, k7); + + Subround(G, c2, d2, e2, a2, b2, X[ 8], 15, k8); + Subround(G, b2, c2, d2, e2, a2, X[ 6], 5, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 1], 11, k8); + Subround(G, d2, e2, a2, b2, c2, X[ 3], 14, k8); + Subround(G, c2, d2, e2, a2, b2, X[11], 14, k8); + Subround(G, b2, c2, d2, e2, a2, X[15], 6, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 0], 14, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 5], 6, k8); + Subround(G, d2, e2, a2, b2, c2, X[12], 9, k8); + Subround(G, c2, d2, e2, a2, b2, X[ 2], 12, k8); + Subround(G, b2, c2, d2, e2, a2, X[13], 9, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 9], 12, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 7], 5, k8); + Subround(G, d2, e2, a2, b2, c2, X[10], 15, k8); + Subround(G, c2, d2, e2, a2, b2, X[14], 8, k8); + + Subround(F, b2, c2, d2, e2, a2, X[12], 8, k9); + Subround(F, a2, b2, c2, d2, e2, X[15], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[10], 12, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 1], 12, k9); + Subround(F, b2, c2, d2, e2, a2, X[ 5], 5, k9); + Subround(F, a2, b2, c2, d2, e2, X[ 8], 14, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 7], 6, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 6], 8, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 2], 13, k9); + Subround(F, b2, c2, d2, e2, a2, X[13], 6, k9); + Subround(F, a2, b2, c2, d2, e2, X[14], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 0], 15, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 3], 13, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 9], 11, k9); + Subround(F, b2, c2, d2, e2, a2, X[11], 11, k9); + + c1 = digest[1] + c1 + d2; + digest[1] = digest[2] + d1 + e2; + digest[2] = digest[3] + e1 + a2; + digest[3] = digest[4] + a1 + b2; + digest[4] = digest[0] + b1 + c2; + digest[0] = c1; +} + +NAMESPACE_END diff --git a/ripemd.h b/ripemd.h new file mode 100644 index 0000000..6ac8e71 --- /dev/null +++ b/ripemd.h @@ -0,0 +1,24 @@ +#ifndef CRYPTOPP_RIPEMD_H +#define CRYPTOPP_RIPEMD_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! <a href="http://www.weidai.com/scan-mirror/md.html#RIPEMD-160">RIPEMD-160</a> +/*! Digest Length = 160 bits */ +class RIPEMD160 : public IteratedHashWithStaticTransform<word32, LittleEndian, 64, RIPEMD160> +{ +public: + enum {DIGESTSIZE = 20}; + RIPEMD160() : IteratedHashWithStaticTransform<word32, LittleEndian, 64, RIPEMD160>(DIGESTSIZE) {Init();} + static void Transform(word32 *digest, const word32 *data); + static const char * StaticAlgorithmName() {return "RIPEMD-160";} + +protected: + void Init(); +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,124 @@ +// rng.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rng.h" + +#include <time.h> +#include <math.h> + +NAMESPACE_BEGIN(CryptoPP) + +// linear congruential generator +// originally by William S. England + +// do not use for cryptographic purposes + +/* +** Original_numbers are the original published m and q in the +** ACM article above. John Burton has furnished numbers for +** a reportedly better generator. The new numbers are now +** used in this program by default. +*/ + +#ifndef LCRNG_ORIGINAL_NUMBERS +const word32 LC_RNG::m=2147483647L; +const word32 LC_RNG::q=44488L; + +const word16 LC_RNG::a=(unsigned int)48271L; +const word16 LC_RNG::r=3399; +#else +const word32 LC_RNG::m=2147483647L; +const word32 LC_RNG::q=127773L; + +const word16 LC_RNG::a=16807; +const word16 LC_RNG::r=2836; +#endif + +byte LC_RNG::GenerateByte() +{ + word32 hi = seed/q; + word32 lo = seed%q; + + long test = a*lo - r*hi; + + if (test > 0) + seed = test; + else + seed = test+ m; + + return (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)); +} + +// ******************************************************** + +X917RNG::X917RNG(BlockTransformation *c, const byte *seed) + : cipher(c), + S(cipher->BlockSize()), + dtbuf(S), + randseed(seed, S), + randbuf(S), + randbuf_counter(0) +{ + time_t tstamp1 = time(0); + xorbuf(dtbuf, (byte *)&tstamp1, STDMIN((int)sizeof(tstamp1), S)); + cipher->ProcessBlock(dtbuf); + clock_t tstamp2 = clock(); + xorbuf(dtbuf, (byte *)&tstamp2, STDMIN((int)sizeof(tstamp2), S)); + cipher->ProcessBlock(dtbuf); +} + +byte X917RNG::GenerateByte() +{ + if (randbuf_counter==0) + { + // calculate new enciphered timestamp + clock_t tstamp = clock(); + xorbuf(dtbuf, (byte *)&tstamp, STDMIN((int)sizeof(tstamp), S)); + cipher->ProcessBlock(dtbuf); + + // combine enciphered timestamp with seed + xorbuf(randseed, dtbuf, S); + + // generate a new block of random bytes + cipher->ProcessBlock(randseed, randbuf); + + // compute new seed vector + for (int i=0; i<S; i++) + randseed[i] = randbuf[i] ^ dtbuf[i]; + cipher->ProcessBlock(randseed); + + randbuf_counter=S; + } + return(randbuf[--randbuf_counter]); +} + +MaurerRandomnessTest::MaurerRandomnessTest() + : sum(0.0), n(0) +{ + for (unsigned i=0; i<V; i++) + tab[i] = 0; +} + +inline void MaurerRandomnessTest::Put(byte inByte) +{ + if (n >= Q) + sum += log(double(n - tab[inByte])); + tab[inByte] = n; + n++; +} + +void MaurerRandomnessTest::Put(const byte *inString, unsigned int length) +{ + while (length--) + Put(*inString++); +} + +double MaurerRandomnessTest::GetTestValue() const +{ + double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer + + double value = fTu * 0.1392; // arbitrarily normalize it to + return value > 1.0 ? 1.0 : value; // a number between 0 and 1 +} + +NAMESPACE_END @@ -0,0 +1,77 @@ +#ifndef CRYPTOPP_RNG_H +#define CRYPTOPP_RNG_H + +#include "cryptlib.h" +#include "filters.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! linear congruential generator +/*! originally by William S. England, do not use for cryptographic purposes */ +class LC_RNG : public RandomNumberGenerator +{ +public: + LC_RNG(word32 init_seed) + : seed(init_seed) {} + + byte GenerateByte(); + + word32 GetSeed() {return seed;} + +private: + word32 seed; + + static const word32 m; + static const word32 q; + static const word16 a; + static const word16 r; +}; + +//! RNG derived from ANSI X9.17 Appendix C + +class X917RNG : public RandomNumberGenerator +{ +public: + // cipher will be deleted by destructor + X917RNG(BlockTransformation *cipher, const byte *seed); + + byte GenerateByte(); + +private: + member_ptr<BlockTransformation> cipher; + const int S; // blocksize of cipher + SecByteBlock dtbuf; // buffer for enciphered timestamp + SecByteBlock randseed, randbuf; + int randbuf_counter; // # of unused bytes left in randbuf +}; + +/** This class implements Maurer's Universal Statistical Test for Random Bit Generators + it is intended for measuring the randomness of *PHYSICAL* RNGs. + For more details see his paper in Journal of Cryptology, 1992. */ + +class MaurerRandomnessTest : public Sink +{ +public: + MaurerRandomnessTest(); + + void Put(byte inByte); + void Put(const byte *inString, unsigned int length); + + // BytesNeeded() returns how many more bytes of input is needed by the test + // GetTestValue() should not be called before BytesNeeded()==0 + unsigned int BytesNeeded() const {return n >= (Q+K) ? 0 : Q+K-n;} + + // returns a number between 0.0 and 1.0, describing the quality of the + // random numbers entered + double GetTestValue() const; + +private: + enum {L=8, V=256, Q=2000, K=2000}; + double sum; + unsigned int n; + unsigned int tab[V]; +}; + +NAMESPACE_END + +#endif @@ -0,0 +1,236 @@ +// rsa.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rsa.h" +#include "asn.h" +#include "oids.h" +#include "nbtheory.h" +#include "sha.h" +#include "algparam.h" +#include "fips140.h" + +#include "oaep.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void RSA_TestInstantiations() +{ + RSASSA<PKCS1v15, SHA>::Verifier x1(1, 1); + RSASSA<PKCS1v15, SHA>::Signer x2(NullRNG(), 1); + RSASSA<PKCS1v15, SHA>::Verifier x3(x2); + RSASSA<PKCS1v15, SHA>::Verifier x4(x2.GetKey()); + RSASSA<PKCS1v15, SHA>::Verifier x5(x3); + RSASSA<PKCS1v15, SHA>::Signer x6 = x2; + RSAES<PKCS1v15>::Encryptor x7(x2); + RSAES<PKCS1v15>::Encryptor x8(x3); + RSAES<OAEP<SHA> >::Encryptor x9(x2); + + x6 = x2; +#ifndef __MWERKS__ + x3 = x2; +#endif + x4 = x2.GetKey(); +} + +template class OAEP<SHA>; + +OID RSAFunction::GetAlgorithmID() const +{ + return ASN1::rsaEncryption(); +} + +void RSAFunction::BERDecodeKey(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_e.BERDecode(seq); + seq.MessageEnd(); +} + +void RSAFunction::DEREncodeKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + seq.MessageEnd(); +} + +Integer RSAFunction::ApplyFunction(const Integer &x) const +{ + DoQuickSanityCheck(); + return a_exp_b_mod_c(x, m_e, m_n); +} + +bool RSAFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + pass = pass && m_e > Integer::One() && m_e.IsOdd() && m_e < m_n; + return pass; +} + +bool RSAFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void RSAFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** + +class RSAPrimeSelector : public PrimeSelector +{ +public: + RSAPrimeSelector(const Integer &e) : m_e(e) {} + bool IsAcceptable(const Integer &candidate) const {return RelativelyPrime(m_e, candidate-Integer::One());} + Integer m_e; +}; + +void InvertibleRSAFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleRSAFunction: specified modulus size is too small"); + + m_e = alg.GetValueWithDefault("PublicExponent", Integer(17)); + + if (m_e < 3 || m_e.IsEven()) + throw InvalidArgument("InvertibleRSAFunction: invalid public exponent"); + + RSAPrimeSelector selector(m_e); + const NameValuePairs &primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + ("PointerToPrimeSelector", selector.GetSelectorPointer()); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + m_d = EuclideanMultiplicativeInverse(m_e, LCM(m_p-1, m_q-1)); + assert(m_d.IsPositive()); + + m_dp = m_d % (m_p-1); + m_dq = m_d % (m_q-1); + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); + + if (FIPS_140_2_ComplianceEnabled()) + { + RSASSA<PKCS1v15, SHA>::Signer signer(*this); + RSASSA<PKCS1v15, SHA>::Verifier verifier(signer); + SignaturePairwiseConsistencyTest(signer, verifier); + + RSAES<OAEP<SHA> >::Decryptor decryptor(*this); + RSAES<OAEP<SHA> >::Encryptor encryptor(decryptor); + EncryptionPairwiseConsistencyTest(encryptor, decryptor); + } +} + +void InvertibleRSAFunction::Initialize(RandomNumberGenerator &rng, unsigned int keybits, const Integer &e) +{ + GenerateRandom(rng, MakeParameters("ModulusSize", (int)keybits)("PublicExponent", e+e.IsEven())); +} + +void InvertibleRSAFunction::BERDecodeKey(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKey(bt); + word32 version; + BERDecodeUnsigned<word32>(privateKey, version, INTEGER, 0, 0); // check version + m_n.BERDecode(privateKey); + m_e.BERDecode(privateKey); + m_d.BERDecode(privateKey); + m_p.BERDecode(privateKey); + m_q.BERDecode(privateKey); + m_dp.BERDecode(privateKey); + m_dq.BERDecode(privateKey); + m_u.BERDecode(privateKey); + privateKey.MessageEnd(); +} + +void InvertibleRSAFunction::DEREncodeKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + DEREncodeUnsigned<word32>(privateKey, 0); // version + m_n.DEREncode(privateKey); + m_e.DEREncode(privateKey); + m_d.DEREncode(privateKey); + m_p.DEREncode(privateKey); + m_q.DEREncode(privateKey); + m_dp.DEREncode(privateKey); + m_dq.DEREncode(privateKey); + m_u.DEREncode(privateKey); + privateKey.MessageEnd(); +} + +Integer InvertibleRSAFunction::CalculateInverse(const Integer &x) const +{ + DoQuickSanityCheck(); + // here we follow the notation of PKCS #1 and let u=q inverse mod p + // but in ModRoot, u=p inverse mod q, so we reverse the order of p and q + return ModularRoot(x, m_dq, m_dp, m_q, m_p, m_u); +} + +bool InvertibleRSAFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RSAFunction::Validate(rng, level); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + pass = pass && m_d > Integer::One() && m_d.IsOdd() && m_d < m_n; + pass = pass && m_dp > Integer::One() && m_dp.IsOdd() && m_dp < m_p; + pass = pass && m_dq > Integer::One() && m_dq.IsOdd() && m_dq < m_q; + pass = pass && m_u.IsPositive() && m_u < m_p; + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + pass = pass && m_e*m_d % LCM(m_p-1, m_q-1) == 1; + pass = pass && m_dp == m_d%(m_p-1) && m_dq == m_d%(m_q-1); + pass = pass && m_u * m_q % m_p == 1; + } + if (level >= 2) + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + return pass; +} + +bool InvertibleRSAFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<RSAFunction>(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime1PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime2PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleRSAFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper<RSAFunction>(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime1PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime2PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +/* +bool RSAFunctionInverse_NonCRT::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + pass = pass && m_d > Integer::One() && m_d.IsOdd() && m_d < m_n; + return pass; +} +*/ + +NAMESPACE_END @@ -0,0 +1,167 @@ +#ifndef CRYPTOPP_RSA_H +#define CRYPTOPP_RSA_H + +/** \file + This file contains classes that implement the RSA + ciphers and signature schemes as defined in PKCS #1 v2.0. +*/ + +#include "pkcspad.h" +#include "oaep.h" +#include "integer.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class RSAFunction : public TrapdoorFunction, public X509PublicKey +{ + typedef RSAFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // X509PublicKey + OID GetAlgorithmID() const; + void BERDecodeKey(BufferedTransformation &bt); + void DEREncodeKey(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +//! . +class InvertibleRSAFunction : public RSAFunction, public TrapdoorFunctionInverse, public PKCS8PrivateKey +{ + typedef InvertibleRSAFunction ThisClass; + +public: + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &e = 17); + void Initialize(const Integer &n, const Integer &e, const Integer &d, const Integer &p, const Integer &q, const Integer &dp, const Integer &dq, const Integer &u) + {m_n = n; m_e = e; m_d = d; m_p = p; m_q = q; m_dp = dp; m_dq = dq; m_u = u;} + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void DEREncode(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + void BERDecodeKey(BufferedTransformation &bt); + void DEREncodeKey(BufferedTransformation &bt) const; + + // TrapdoorFunctionInverse + Integer CalculateInverse(const Integer &x) const; + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + /*! parameters: (ModulusSize, PublicExponent (default 17)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetPrivateExponent() const {return m_d;} + const Integer& GetModPrime1PrivateExponent() const {return m_dp;} + const Integer& GetModPrime2PrivateExponent() const {return m_dq;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetPrivateExponent(const Integer &d) {m_d = d;} + void SetModPrime1PrivateExponent(const Integer &dp) {m_dp = dp;} + void SetModPrime2PrivateExponent(const Integer &dq) {m_dq = dq;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const {} + virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt) {} + + Integer m_d, m_p, m_q, m_dp, m_dq, m_u; +}; + +/* +//! . +class RSAFunctionInverse_NonCRT : public TrapdoorFunctionBounds, public TrapdoorFunctionInverse, public PrivateKey +{ +public: + Integer CalculateInverse(const Integer &x) const + {return a_exp_b_mod_c(x, m_d, m_n);} + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + + const Integer& GetModulus() const {return m_n;} + const Integer& GetDecryptionExponent() const {return m_d;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetDecryptionExponent(const Integer &d) {m_d = d;} + + void SetPrivateValues(const Integer &n, const Integer &d) + {m_n = n; m_d = d;} + +private: + Integer m_n, m_d; +}; +*/ + +//! . +struct RSA +{ + static std::string StaticAlgorithmName() {return "RSA";} + typedef RSAFunction PublicKey; + typedef InvertibleRSAFunction PrivateKey; +}; + +//! <a href="http://www.weidai.com/scan-mirror/ca.html#RSA">RSA cryptosystem</a> +template <class STANDARD> +struct RSAES : public TF_ES<STANDARD, RSA> +{ +}; + +//! <a href="http://www.weidai.com/scan-mirror/sig.html#RSA">RSA signature scheme with appendix</a> +/*! See documentation of PKCS1v15 for a list of hash functions that can be used with it. */ +template <class STANDARD, class H> +struct RSASSA : public TF_SSA<STANDARD, H, RSA> +{ +}; + +// The two RSA encryption schemes defined in PKCS #1 v2.0 +typedef RSAES<PKCS1v15>::Decryptor RSAES_PKCS1v15_Decryptor; +typedef RSAES<PKCS1v15>::Encryptor RSAES_PKCS1v15_Encryptor; + +typedef RSAES<OAEP<SHA> >::Decryptor RSAES_OAEP_SHA_Decryptor; +typedef RSAES<OAEP<SHA> >::Encryptor RSAES_OAEP_SHA_Encryptor; + +// The three RSA signature schemes defined in PKCS #1 v2.0 +typedef RSASSA<PKCS1v15, SHA>::Signer RSASSA_PKCS1v15_SHA_Signer; +typedef RSASSA<PKCS1v15, SHA>::Verifier RSASSA_PKCS1v15_SHA_Verifier; + +typedef RSASSA<PKCS1v15, MD2>::Signer RSASSA_PKCS1v15_MD2_Signer; +typedef RSASSA<PKCS1v15, MD2>::Verifier RSASSA_PKCS1v15_MD2_Verifier; + +typedef RSASSA<PKCS1v15, MD5>::Signer RSASSA_PKCS1v15_MD5_Signer; +typedef RSASSA<PKCS1v15, MD5>::Verifier RSASSA_PKCS1v15_MD5_Verifier; + +NAMESPACE_END + +#endif diff --git a/rsa1024.dat b/rsa1024.dat new file mode 100644 index 0000000..70fb172 --- /dev/null +++ b/rsa1024.dat @@ -0,0 +1,32 @@ +30820274020100300D06092A864886F70D010101 +05000482025E3082025A02010002818100A39D4F +72D1BCFF65A47545C2897C0464CE9181E8703421 +2EC04407C4C24D569AA20C58B8138C85E17510BC +6B861CADA9034C3ECE3B050B546E97D2BDC07A07 +CF8A612F7D3646739633041893EF18C411264E45 +C9E033A1BD5EE5FA02D95E9A9ADA2D0C6DF480E3 +2FA3FCE02889798455CE53F084AAB4C5549266F7 +CE8C77DF1D0201110281800E6FC33ED64561D443 +378627C0D63C9F7BA36D584622B7A23E241ECD98 +AC78952C6A804C7A320BD020EAE372E62FB4F853 +1D50D5F6261796823A929845B06A19B35A5227CB +C819852A9CBE588CC2D1CEE07F426D13C2BF2FCA +1C99FDEEFDFE387859E2B3F654E85A71481A71E9 +D5256583B1200F29C1AA0F437CFDC2AEAF218102 +4100D5DDB104AD074F6C1B8192D9AC8AED4DE05C +F5C6509490DA8CCFC91FDF7B3A1323E03894DCAA +B2587716D652A56904F86244E10C1B8FA597C389 +2591C55DBD65024100C3D930B583B8AD9A349218 +795C988CF0004F09DA04FFEF6FDF7CB4FA654F74 +B262521FE185693CD6290A337589F62CDEECE24E +CCB5E79865275540F3B603FB59024064A48F89BA +D6437E2B0FCCA2AB8CABE86995285D5318BCA315 +167CC3B47639726B3C56DCA41417B128FBB026E4 +6DA7FC6A7AC441EEDA2FCEF29AE480D5594A1102 +40228FBD4D355CD35772B05EAC014818DF0F1D01 +BD0FF0EE04AEF7E3B3B7867E015CA514AF53C746 +F89DD49FAB5494DABDED9159332F28DEA8705A56 +C198974A79024100D1DCA40FBD19036F0E2A9438 +7D03C090DDF0A677CDE0B8634A81F247752A355E +C1CEA2482A4887767145C2BA703C9C10228FDA1E +BB2EBEA73D23AA9C34182179 diff --git a/rsa2048.dat b/rsa2048.dat new file mode 100644 index 0000000..83200c2 --- /dev/null +++ b/rsa2048.dat @@ -0,0 +1,61 @@ +308204BB020100300D06092A864886F70D010101 +0500048204A5308204A10201000282010100BB25 +80EB6B368287A0A3BDDF6AAA9EDA2EEF15D92C5F +E0B1C21473175C39B685A6FB0B0DB611092C19B4 +FA3CA5BB20F311E35B2E1097F48B077DF7684BEB +9A34EB78C7B5F02ADFAEA3F3A66F1EF91B0C47DE +68F0501F80A7E9603F794E928949F152C049A011 +D7E58C72F9303781E4FE7129DD7B87B5448D440A +62CE8E9C801F245039E2724A9C37CB17457950B7 +B3C4C9BE4D17A29EFC1EA1EF464FBD21DABE9F10 +ED0EB132405D68E4304008083BB675DA97CB6219 +147A1EB93D38A9C4023540F871272A85B45447B3 +6DE9A708E412CD31B1CB6470E4A37CBEA6000F36 +632DF86FD3C34466C63BD80F1350E4DD5081597F +F34F94F07AE6430DCC0563B1F7CF020111028201 +00034D763A5DC03580E33616ED5ABABA855B2E62 +4495DD8D002009656B5473772C85F55F10CE81CE +77BE31E04657410B1F6535B4CF1E6914E152F4AB +84DA2FD409F81BBB3DF0A96A58EACC9501F60162 +5C1356BF97D139C78A7E18496708EA7DE7B47266 +C81363B3FF888085E7403A028901FF3BA04C2EDE +930EC0EFAC4DCF8FD054C1119562A1C7CA455D79 +36CB95A16CE611ABC97918961DE6720CE171CC69 +A590E9A041EC1DAC6FDCF2E04946C100E03DEFCA +29FF480C926CD48589EB832D4476CF38AB320754 +D97BE77FDB9E5F2DCA1A2ABBC33D0790FE8C22CF +694BB8E0265733A5A17CC5D07DB54515DC80216A +A23A43EB12783888FF424EDB26FAF7DCB9028181 +00EB4C87F67AEA3F2047BF9DF61947DF2BA7E1C1 +64A03A8E3ED5F3BC6CDEE99FC6251C6A28F9502F +0A4B5A0CFA8038A12A2270AAE2C9342EDBA207CE +0F170B6D07550670CFEAE730B9411E66CD2D485F +3FC3E9C5348D32C768F68A53C756E66BE0FAC7E8 +FDC9FBE22644961782DA5DDC19D75B64D2E8B660 +052DDC95AD186633E902818100CB9C7830223B78 +FC28A6D2B77C50C3D389F32FC4DEF33341741205 +5102F8D852663DB44E1EA5E5E58A71D30D33C168 +E94855D79CC19CC7DFBAFBDFF7710490064A1375 +1CD75466219956B9D4C0AF0CC13E7D075F54E6AF +8CD67FBE3F4AB90425B039410686A168421E2E24 +FF0319D9D3F1C685BB650BC7B5BD12090CBDC392 +F702818060E3470B238DA185C330C89282E15BE4 +CCA84092D89094ECB2736BB45BC99C2469A249D4 +A2E4C8134C34237634CC06206888BED5DA60C800 +158ABE4272E6964E502FD41960B98C888439B1DC +039645567DD8BA9D2B14E8B2BFDE9AF7BA5EE120 +674341D1E9C211D385A736DB871796DD76CB47A2 +239663C5E5B52E9291937EC902818053D704500E +187D1C8935A20F514E6EC08418D76F2EA060663E +DA3E6CA6DEEFA97564B3A7B2444F9AC08938C933 +6DC1C9782358C8137CCAC5893A8965E33E1D2FC4 +262129FE4FEDD1997E10488B935F9ADD7EC6CCE6 +B957581C167B83791F01B52A71ED99467EB27593 +F4E20EA6EC86DECCF7643E1A8C614AD561C77DB7 +8CC40B02818100AF950A287679E6C55020400E8A +AD0642DB1C11D9AD5AE85F1B6FD2829D869453C9 +F67C0210D0847A4BD47C57FAECD9BE540BD66989 +E6C43F62D725B3D841B4F1DB7C28A722337358C8 +D1CD55F5CA6E31FAD6F827756BA074944D345C8D +2FCE759F4244B948D06F5AC863DEAAEF279B2F69 +955ADAD1F39DEA9DA028B94EF22F11 diff --git a/rsa400pb.dat b/rsa400pb.dat new file mode 100644 index 0000000..ccbc6ae --- /dev/null +++ b/rsa400pb.dat @@ -0,0 +1,10 @@ +30 4c 30 0d 06 09 2a 86 +48 86 f7 0d 01 01 01 05 +00 03 3b 00 30 38 02 33 +00 a3 07 9a 90 df 0d fd +72 ac 09 0c cc 2a 78 b8 +74 13 13 3e 40 75 9c 98 +fa f8 20 4f 35 8a 0b 26 +3c 67 70 e7 83 a9 3b 69 +71 b7 37 79 d2 71 7b e8 +34 77 cf 02 01 03 diff --git a/rsa400pv.dat b/rsa400pv.dat new file mode 100644 index 0000000..2a73123 --- /dev/null +++ b/rsa400pv.dat @@ -0,0 +1,41 @@ + 30 81 fb + 02 01 00 + 02 + 33 00 a3 07 9a 90 df 0d + fd 72 ac 09 0c cc 2a 78 + b8 74 13 13 3e 40 75 9c + 98 fa f8 20 4f 35 8a 0b + 26 3c 67 70 e7 83 a9 3b + 69 71 b7 37 79 d2 71 7b + e8 34 77 cf + 02 01 03 + 02 + 32 6c af bc 60 94 b3 fe + 4c 72 b0 b3 32 c6 fb 25 + a2 b7 62 29 80 4e 68 65 + fc a4 5a 74 df 0f 8f b8 + 41 3b 52 c0 d0 e5 3d 9b + 59 0f f1 9b e7 9f 49 dd + 21 e5 eb + 02 1a 00 cf 20 + 35 02 8b 9d 86 98 40 b4 + 16 66 b4 2e 92 ea 0d a3 + b4 32 04 b5 cf ce 91 + 02 + 1a 00 c9 7f b1 f0 27 f4 + 53 f6 34 12 33 ea aa d1 + d9 35 3f 6c 42 d0 88 66 + b1 d0 5f + 02 1a 00 8a 15 + 78 ac 5d 13 af 10 2b 22 + b9 99 cd 74 61 f1 5e 6d + 22 cc 03 23 df df 0b + 02 + 1a 00 86 55 21 4a c5 4d + 8d 4e cd 61 77 f1 c7 36 + 90 ce 2a 48 2c 8b 05 99 + cb e0 3f + 02 1a 00 83 ef + ef b8 a9 a4 0d 1d b6 ed + 98 ad 84 ed 13 35 dc c1 + 08 f3 22 d0 57 cf 8d
\ No newline at end of file diff --git a/rsa512a.dat b/rsa512a.dat new file mode 100644 index 0000000..e7edefa --- /dev/null +++ b/rsa512a.dat @@ -0,0 +1,35 @@ +30 82 01 50 + 02 01 00 + 30 0d + 06 09 + 2a 86 48 86 f7 0d 01 01 01 + 05 00 + 04 82 01 3a + 30 82 01 36 + 02 01 00 + 02 40 + 0a 66 79 1d c6 98 81 68 de 7a b7 74 19 bb 7f b0 + c0 01 c6 27 10 27 00 75 14 29 42 e1 9a 8d 8c 51 + d0 53 b3 e3 78 2a 1d e5 dc 5a f4 eb e9 94 68 17 + 01 14 a1 df e6 7c dc 9a 9a f5 5d 65 56 20 bb ab + 02 03 01 00 01 + 02 40 + 01 23 c5 b6 1b a3 6e db 1d 36 79 90 41 99 a8 9e + a8 0c 09 b9 12 2e 14 00 c0 9a dc f7 78 46 76 d0 + 1d 23 35 6a 7d 44 d6 bd 8b d5 0e 94 bf c7 23 fa + 87 d8 86 2b 75 17 76 91 c1 1d 75 76 92 df 88 81 + 02 20 + 33 d4 84 45 c8 59 e5 23 40 de 70 4b cd da 06 5f + bb 40 58 d7 40 bd 1d 67 d2 9e 9c 14 6c 11 cf 61 + 02 20 + 33 5e 84 08 86 6b 0f d3 8d c7 00 2d 3f 97 2c 67 + 38 9a 65 d5 d8 30 65 66 d5 c4 f2 a5 aa 52 62 8b + 02 20 + 04 5e c9 00 71 52 53 25 d3 d4 6d b7 96 95 e9 af + ac c4 52 39 64 36 0e 02 b1 19 ba a3 66 31 62 41 + 02 20 + 15 eb 32 73 60 c7 b6 0d 12 e5 e2 d1 6b dc d9 79 + 81 d1 7f ba 6b 70 db 13 b2 0b 43 6e 24 ea da 59 + 02 20 + 2c a6 36 6d 72 78 1d fa 24 d3 4a 9a 24 cb c2 ae + 92 7a 99 58 af 42 65 63 ff 63 fb 11 65 8a 46 1d @@ -0,0 +1,243 @@ +// rw.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rw.h" +#include "nbtheory.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +template<> const byte EMSA2DigestDecoration<SHA>::decoration = 0x33; +template<> const byte EMSA2DigestDecoration<RIPEMD160>::decoration = 0x31; + +void EMSA2Pad::Pad(RandomNumberGenerator &, const byte *input, unsigned int inputLen, byte *emsa2Block, unsigned int emsa2BlockLen) const +{ + assert (inputLen > 0 && inputLen <= MaxUnpaddedLength(emsa2BlockLen)); + + // convert from bit length to byte length + emsa2BlockLen++; + if (emsa2BlockLen % 8 > 1) + { + emsa2Block[0] = 0; + emsa2Block++; + } + emsa2BlockLen /= 8; + + emsa2Block[0] = input[0]; // indicate empty or non-empty message + memset(emsa2Block+1, 0xbb, emsa2BlockLen-inputLen-2); // padd with 0xbb + emsa2Block[emsa2BlockLen-inputLen-1] = 0xba; // separator + memcpy(emsa2Block+emsa2BlockLen-inputLen, input+1, inputLen-1); + emsa2Block[emsa2BlockLen-1] = 0xcc; // make it congruent to 12 mod 16 +} + +DecodingResult EMSA2Pad::Unpad(const byte *emsa2Block, unsigned int emsa2BlockLen, byte *output) const +{ + // convert from bit length to byte length + emsa2BlockLen++; + if (emsa2BlockLen % 8 > 1) + { + if (emsa2Block[0] != 0) + return DecodingResult(); + emsa2Block++; + } + emsa2BlockLen /= 8; + + // check last byte + if (emsa2Block[emsa2BlockLen-1] != 0xcc) + return DecodingResult(); + + // skip past the padding until we find the seperator + unsigned i=1; + while (i<emsa2BlockLen-1 && emsa2Block[i++] != 0xba) + if (emsa2Block[i-1] != 0xbb) // not valid padding + return DecodingResult(); + assert(i==emsa2BlockLen-1 || emsa2Block[i-1]==0xba); + + unsigned int outputLen = emsa2BlockLen - i; + output[0] = emsa2Block[0]; + memcpy (output+1, emsa2Block+i, outputLen-1); + return DecodingResult(outputLen); +} + +// ***************************************************************************** + +template <word r> +void RWFunction<r>::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + seq.MessageEnd(); +} + +template <word r> +void RWFunction<r>::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + seq.MessageEnd(); +} + +template <word r> +Integer RWFunction<r>::ApplyFunction(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer out = in.Squared()%m_n; + const word r2 = r/2; + const word r3a = (16 + 5 - r) % 16; // n%16 could be 5 or 13 + const word r3b = (16 + 13 - r) % 16; + const word r4 = (8 + 5 - r/2) % 8; // n%8 == 5 + switch (out % 16) + { + case r: + break; + case r2: + case r2+8: + out <<= 1; + break; + case r3a: + case r3b: + out.Negate(); + out += m_n; + break; + case r4: + case r4+8: + out.Negate(); + out += m_n; + out <<= 1; + break; + default: + out = Integer::Zero(); + } + return out; +} + +template <word r> +bool RWFunction<r>::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n%8 == 5; + return pass; +} + +template <word r> +bool RWFunction<r>::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + ; +} + +template <word r> +void RWFunction<r>::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + ; +} + +// ***************************************************************************** +// private key operations: + +// generate a random private key +template <word r> +void InvertibleRWFunction<r>::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleRWFunction: specified modulus length is too small"); + + const NameValuePairs &primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize); + m_p.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("EquivalentTo", 3)("Mod", 8))); + m_q.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("EquivalentTo", 7)("Mod", 8))); + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); +} + +template <word r> +void InvertibleRWFunction<r>::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); +} + +template <word r> +void InvertibleRWFunction<r>::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +template <word r> +Integer InvertibleRWFunction<r>::CalculateInverse(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer cp=in%m_p, cq=in%m_q; + + if (Jacobi(cp, m_p) * Jacobi(cq, m_q) != 1) + { + cp = cp%2 ? (cp+m_p) >> 1 : cp >> 1; + cq = cq%2 ? (cq+m_q) >> 1 : cq >> 1; + } + + cp = ModularSquareRoot(cp, m_p); + cq = ModularSquareRoot(cq, m_q); + + Integer out = CRT(cq, m_q, cp, m_p, m_u); + + return STDMIN(out, m_n-out); +} + +template <word r> +bool InvertibleRWFunction<r>::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RWFunction<r>::Validate(rng, level); + pass = pass && m_p > Integer::One() && m_p%8 == 3 && m_p < m_n; + pass = pass && m_q > Integer::One() && m_q%8 == 7 && m_q < m_n; + pass = pass && m_u.IsPositive() && m_u < m_p; + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + pass = pass && m_u * m_q % m_p == 1; + } + if (level >= 2) + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + return pass; +} + +template <word r> +bool InvertibleRWFunction<r>::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper<RWFunction<r> >(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +template <word r> +void InvertibleRWFunction<r>::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper<RWFunction<r> >(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +template class RWFunction<IFSSA_R>; +template class InvertibleRWFunction<IFSSA_R>; + +NAMESPACE_END @@ -0,0 +1,162 @@ +#ifndef CRYPTOPP_RW_H +#define CRYPTOPP_RW_H + +/** \file + This file contains classes that implement the + Rabin-Williams signature schemes as defined in IEEE P1363. +*/ + +#include "pubkey.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word IFSSR_R = 6; +const word IFSSA_R = 12; + +//! . +template <word r> +class RWFunction : virtual public TrapdoorFunction, public PublicKey +{ + typedef RWFunction ThisClass; + +public: + void Initialize(const Integer &n) + {m_n = n;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return ++(m_n>>1);} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + void SetModulus(const Integer &n) {m_n = n;} + +protected: + Integer m_n; +}; + +//! . +template <word r> +class InvertibleRWFunction : public RWFunction<r>, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRWFunction ThisClass; + +public: + void Initialize(const Integer &n, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_p = p; m_q = q; m_u = u;} + // generate a random private key + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +//! . +class EMSA2Pad : public PK_PaddingAlgorithm +{ +public: + static const char *StaticAlgorithmName() {return "EMSA2";} + + unsigned int MaxUnpaddedLength(unsigned int paddedLength) const {return (paddedLength+1)/8-2;} + + void Pad(RandomNumberGenerator &rng, const byte *raw, unsigned int inputLength, byte *padded, unsigned int paddedLength) const; + DecodingResult Unpad(const byte *padded, unsigned int paddedLength, byte *raw) const; +}; + +//! . +template <class H> +class EMSA2DecoratedHashModule : public HashTransformationWithDefaultTruncation +{ +public: + EMSA2DecoratedHashModule() : empty(true) {} + void Update(const byte *input, unsigned int length) + {h.Update(input, length); empty = empty && length==0;} + unsigned int DigestSize() const; + void Final(byte *digest); + void Restart() {h.Restart(); empty=true;} + +private: + H h; + bool empty; +}; + +template <class H> struct EMSA2DigestDecoration +{ + static const byte decoration; +}; + +//! EMSA2, for use with RW +/*! The following hash functions are supported: SHA, RIPEMD160. */ +struct P1363_EMSA2 : public SignatureStandard +{ + template <class H> struct SignaturePaddingAlgorithm {typedef EMSA2Pad type;}; + template <class H> struct DecoratedHashingAlgorithm {typedef EMSA2DecoratedHashModule<H> type;}; +}; + +template<> struct CryptoStandardTraits<P1363_EMSA2> : public P1363_EMSA2 {}; + +// EMSA2DecoratedHashModule can be instantiated with the following two classes. +class SHA; +class RIPEMD160; + +template <class H> +void EMSA2DecoratedHashModule<H>::Final(byte *digest) +{ + digest[0] = empty ? 0x4b : 0x6b; + h.Final(digest+1); + digest[DigestSize()-1] = EMSA2DigestDecoration<H>::decoration; + empty=true; +} + +template <class H> +unsigned int EMSA2DecoratedHashModule<H>::DigestSize() const +{ + return h.DigestSize() + 2; +} + +//! . +template <word r> +struct RW +{ + static std::string StaticAlgorithmName() {return "RW";} + typedef RWFunction<r> PublicKey; + typedef InvertibleRWFunction<r> PrivateKey; +}; + +//! RW +template <class H, class STANDARD = P1363_EMSA2> +struct RWSSA : public TF_SSA<STANDARD, H, RW<IFSSA_R> > +{ +}; + +NAMESPACE_END + +#endif diff --git a/rw1024.dat b/rw1024.dat new file mode 100644 index 0000000..dcd0209 --- /dev/null +++ b/rw1024.dat @@ -0,0 +1 @@ +3082014D02818100BECF1F40456801F6965E603BEBB61F530F0B17BBCB00E3A8866EB9BC84AE3892A4CB040280F568FC650B1734014CA78A200D5E4AB394CBB75C0034DCC47643E6F576A39F850C5F4528048165B084C82E9BA6BA4CFBCB3980F1EB47EC2C348EF52A6225A85AF743DFCEF5CD4583EB0B9C0DA77ABEBEB5BCC513D81BD768B579AD024100F06CA9C1FBE20EE2440F3AB2F9A9787D820943EAF59B6B8D103CFAB1C2F595DDC99D05DC73F9D1DB780B6F8B26CF87E58EB870DD983A2515600DF80C3EBB7B1B024100CB2B9BDEB0D508E21E646C86D836442FC16910D68C8D1D18BB1327899A506C16C1162E93EA7C2CB576B750AEAB152255D5AB22632025CFFAD927A070CBAEA2D7024100C90A853BEC7C25D773FDDB95C11CEF9BB3F487953773F07E42DB9D011325AE2725663478FB7F0EC1A5608280D9656BF3B9F463FF8B23F1CA1B543508D51826E2
\ No newline at end of file diff --git a/rw2048.dat b/rw2048.dat new file mode 100644 index 0000000..5547c88 --- /dev/null +++ b/rw2048.dat @@ -0,0 +1 @@ +3082029002820101008F2975B4DA54179A6C81764DB9E6B50AD925C91568DFE2C245DF9103AF39370BD5F25CD26BF6E41B6FEB0E24473BBFAE89343BC20743057B056BD2189C01258650567A3EC24040EED7EEAF94B77BDD39529807D1FCF5FF4A90E6B42BA58FF1FDCDACF981C641B8F077ABBB41BEFD53CCABF06745CD009A7F9DFAA61ED03F11466E4B5370DFA18C7DFEA1689B60F98012CDE9131FE86F74BFC6B93AC449DA73A2366EA2AE2233AFFBFF0CDE1899B1F852C179639B31CEE11991AA8D46DB5067B0C5FFB3D913612668F0C43CA134B11875F271C0BC8722AF4AD6CC93A43CE165EF31C1EB542ECC7CA1A38BFDF66F3A2175E4EA7159E168FFE3A549535B90C7BBDD02818100C5CEBA84E8B7C20BAA6F450000803F15C1160EB7E0875EBBC15F11DC7E3CAFE55973234FF4C74589406D2950B0C236ABE1B5A5B70D55C035F45D87AF089847C0E2A2DEF23EA4CC19FB5419DF43577523248BEF80B94C59F7342C717F12DE68FEEADAD97BA2DD436834D8559D0A7A31D6F9D9480F852C285EFC75BCA8AF32590302818100B947440D272629155C2B3E0E62B76124281155F7A189650D36C8F7D742F7DBC571ADDCC582ED2ED283C2E8A1CD8C996D3D8A50F33C56581285C5016A16DEDA533715DF519CAB7777F3DCB9F5335552F315B44FF8126DFDDF60B66850AA8FD108ED3A248D18E7473D7967F0F15C740C67476A75273DA254AE5C7B94FB059DD19F0281801EE99173837363981E0988DE22B2E36BFC9713EDC8454BF1CB764D767DFDA985B9DBAA346C0C39B1A9F83D849502AFDD80AE33F588C114BC4DE5FA949125FF56908F8C66CDFF6BF601F1CBF463B0C807DEABB1290C358FC0433ED74EBA074CB211C4D75538ED017F497C9722D8C3D3E082BB4A8A92D5768B5D5963BBDB1DB24D
\ No newline at end of file diff --git a/safer.cpp b/safer.cpp new file mode 100644 index 0000000..ef3f90a --- /dev/null +++ b/safer.cpp @@ -0,0 +1,148 @@ +// safer.cpp - modified by by Wei Dai from Richard De Moliner's safer.c + +#include "pch.h" +#include "safer.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +const byte SAFER::Base::exp_tab[256] = + {1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, + 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, + 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, + 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, + 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, + 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, + 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, + 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, + 0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, + 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, + 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, + 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, + 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, + 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, + 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, + 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40}; + +const byte SAFER::Base::log_tab[256] = + {128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248, + 192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130, + 112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37, + 201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15, + 32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198, + 175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84, + 121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188, + 189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217, + 208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158, + 210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42, + 95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219, + 164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29, + 41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14, + 122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104, + 109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66, + 184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48}; + +#define EXP(x) exp_tab[(x)] +#define LOG(x) log_tab[(x)] +#define PHT(x, y) { y += x; x += y; } +#define IPHT(x, y) { x -= y; y -= x; } + +static const unsigned int BLOCKSIZE = 8; +static const unsigned int MAX_ROUNDS = 13; + +void SAFER::Base::UncheckedSetKey(CipherDir dir, const byte *userkey_1, unsigned int length, unsigned nof_rounds) +{ + const byte *userkey_2 = length == 8 ? userkey_1 : userkey_1 + 8; + keySchedule.New(1 + BLOCKSIZE * (1 + 2 * nof_rounds)); + + unsigned int i, j; + byte *key = keySchedule; + SecByteBlock ka(BLOCKSIZE + 1), kb(BLOCKSIZE + 1); + + if (MAX_ROUNDS < nof_rounds) + nof_rounds = MAX_ROUNDS; + *key++ = (unsigned char)nof_rounds; + ka[BLOCKSIZE] = 0; + kb[BLOCKSIZE] = 0; + for (j = 0; j < BLOCKSIZE; j++) + { + ka[BLOCKSIZE] ^= ka[j] = rotlFixed(userkey_1[j], 5U); + kb[BLOCKSIZE] ^= kb[j] = *key++ = userkey_2[j]; + } + for (i = 1; i <= nof_rounds; i++) + { + for (j = 0; j < BLOCKSIZE + 1; j++) + { + ka[j] = rotlFixed(ka[j], 6U); + kb[j] = rotlFixed(kb[j], 6U); + } + for (j = 0; j < BLOCKSIZE; j++) + if (strengthened) + *key++ = (ka[(j + 2 * i - 1) % (BLOCKSIZE + 1)] + + exp_tab[exp_tab[18 * i + j + 1]]) & 0xFF; + else + *key++ = (ka[j] + exp_tab[exp_tab[18 * i + j + 1]]) & 0xFF; + for (j = 0; j < BLOCKSIZE; j++) + if (strengthened) + *key++ = (kb[(j + 2 * i) % (BLOCKSIZE + 1)] + + exp_tab[exp_tab[18 * i + j + 10]]) & 0xFF; + else + *key++ = (kb[j] + exp_tab[exp_tab[18 * i + j + 10]]) & 0xFF; + } +} + +typedef BlockGetAndPut<byte, BigEndian> Block; + +void SAFER::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + byte a, b, c, d, e, f, g, h, t; + const byte *key = keySchedule+1; + unsigned int round = keySchedule[0]; + + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + while(round--) + { + a ^= key[0]; b += key[1]; c += key[2]; d ^= key[3]; + e ^= key[4]; f += key[5]; g += key[6]; h ^= key[7]; + a = EXP(a) + key[ 8]; b = LOG(b) ^ key[ 9]; + c = LOG(c) ^ key[10]; d = EXP(d) + key[11]; + e = EXP(e) + key[12]; f = LOG(f) ^ key[13]; + g = LOG(g) ^ key[14]; h = EXP(h) + key[15]; + key += 16; + PHT(a, b); PHT(c, d); PHT(e, f); PHT(g, h); + PHT(a, c); PHT(e, g); PHT(b, d); PHT(f, h); + PHT(a, e); PHT(b, f); PHT(c, g); PHT(d, h); + t = b; b = e; e = c; c = t; t = d; d = f; f = g; g = t; + } + a ^= key[0]; b += key[1]; c += key[2]; d ^= key[3]; + e ^= key[4]; f += key[5]; g += key[6]; h ^= key[7]; + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +void SAFER::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + byte a, b, c, d, e, f, g, h, t; + unsigned int round = keySchedule[0]; + const byte *key = keySchedule + BLOCKSIZE * (1 + 2 * round) - 7; + + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + h ^= key[7]; g -= key[6]; f -= key[5]; e ^= key[4]; + d ^= key[3]; c -= key[2]; b -= key[1]; a ^= key[0]; + while (round--) + { + key -= 16; + t = e; e = b; b = c; c = t; t = f; f = d; d = g; g = t; + IPHT(a, e); IPHT(b, f); IPHT(c, g); IPHT(d, h); + IPHT(a, c); IPHT(e, g); IPHT(b, d); IPHT(f, h); + IPHT(a, b); IPHT(c, d); IPHT(e, f); IPHT(g, h); + h -= key[15]; g ^= key[14]; f ^= key[13]; e -= key[12]; + d -= key[11]; c ^= key[10]; b ^= key[9]; a -= key[8]; + h = LOG(h) ^ key[7]; g = EXP(g) - key[6]; + f = EXP(f) - key[5]; e = LOG(e) ^ key[4]; + d = LOG(d) ^ key[3]; c = EXP(c) - key[2]; + b = EXP(b) - key[1]; a = LOG(a) ^ key[0]; + } + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +NAMESPACE_END @@ -0,0 +1,101 @@ +#ifndef CRYPTOPP_SAFER_H +#define CRYPTOPP_SAFER_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// base class, do not use directly +class SAFER +{ +public: + class Base : public BlockCipher + { + public: + unsigned int GetAlignment() const {return 1;} + void UncheckedSetKey(CipherDir dir, const byte *userkey, unsigned int length, unsigned nof_rounds); + + bool strengthened; + SecByteBlock keySchedule; + static const byte exp_tab[256]; + static const byte log_tab[256]; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; +}; + +struct SAFER_K_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + static const char *StaticAlgorithmName() {return "SAFER-K";} + static unsigned int DefaultRounds(unsigned int keylength) {return keylength == 8 ? 6 : 10;} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#SAFER-K">SAFER-K</a> +class SAFER_K : public SAFER_K_Info, public SAFER, public BlockCipherDocumentation +{ + class Enc : public BlockCipherBaseTemplate<SAFER_K_Info, SAFER::Enc> + { + public: + Enc() {strengthened = false;} + }; + + class Dec : public BlockCipherBaseTemplate<SAFER_K_Info, SAFER::Dec> + { + public: + Dec() {strengthened = false;} + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +struct SAFER_SK_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + static const char *StaticAlgorithmName() {return "SAFER-SK";} + static unsigned int DefaultRounds(unsigned int keylength) {return keylength == 8 ? 8 : 10;} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#SAFER-SK">SAFER-SK</a> +class SAFER_SK : public SAFER_SK_Info, public SAFER, public BlockCipherDocumentation +{ + class Enc : public BlockCipherBaseTemplate<SAFER_SK_Info, SAFER::Enc> + { + public: + Enc() {strengthened = true;} + }; + + class Dec : public BlockCipherBaseTemplate<SAFER_SK_Info, SAFER::Dec> + { + public: + Dec() {strengthened = true;} + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef SAFER_K::Encryption SAFER_K_Encryption; +typedef SAFER_K::Decryption SAFER_K_Decryption; + +typedef SAFER_SK::Encryption SAFER_SK_Encryption; +typedef SAFER_SK::Decryption SAFER_SK_Decryption; + +NAMESPACE_END + +#endif diff --git a/saferval.dat b/saferval.dat new file mode 100644 index 0000000..cdcad06 --- /dev/null +++ b/saferval.dat @@ -0,0 +1,16 @@ +0000000000000000 0000000000000000 032808C90EE7AB7F +0000000000000000 0102030405060708 7D28038633B92EB4 +0102030405060708 1011121314151617 71E5CF7F083A59C5 +0102030405060708 18191A1B1C1D1E1F 356F702CC7FA8161 +08070605040302010807060504030201 5051525354555657 38E64DBF6E0F896E +08070605040302010807060504030201 58595A5B5C5D5E5F 7D8F014A902480FE +01020304050607080807060504030201 6061626364656667 113511C22E7936DF +01020304050607080807060504030201 68696A6B6C6D6E6F 9EEB2D17C0581437 +0000000000000001 7071727374757677 9ABE2C85BE2D7614 +0000000000000001 78797A7B7C7D7E7F EBC4A9C6C25CF215 +0102030405060708 8081828384858687 54E72BA2D744C566 +0102030405060708 88898A8B8C8D8E8F 57F55D0F7EB6F8FE +00000000000000010000000000000001 9091929394959697 9EAA4DF1E0EFF445 +00000000000000010000000000000001 98999A9B9C9D9E9F 4CC14838399E532D +01020304050607080000000000000000 A0A1A2A3A4A5A6A7 41246B65F1DC6AFA +00000000000000000102030405060708 A0A1A2A3A4A5A6A7 5CBD77B03626FE3B diff --git a/sapphire.cpp b/sapphire.cpp new file mode 100644 index 0000000..7e46ea7 --- /dev/null +++ b/sapphire.cpp @@ -0,0 +1,179 @@ +// sapphire.cpp -- modified by Wei Dai from: + +/* sapphire.cpp -- the Saphire II stream cipher class. + Dedicated to the Public Domain the author and inventor: + (Michael Paul Johnson). This code comes with no warranty. + Use it at your own risk. + Ported from the Pascal implementation of the Sapphire Stream + Cipher 9 December 1994. + Added hash pre- and post-processing 27 December 1994. + Modified initialization to make index variables key dependent, + made the output function more resistant to cryptanalysis, + and renamed to Sapphire II 2 January 1995 +*/ + +#include "pch.h" +#include "sapphire.h" + +NAMESPACE_BEGIN(CryptoPP) + +byte SapphireBase::keyrand(unsigned int limit, + const byte *user_key, + byte keysize, + byte *rsum, + unsigned *keypos) +{ + unsigned u, // Value from 0 to limit to return. + retry_limiter, // No infinite loops allowed. + mask; // Select just enough bits. + + retry_limiter = 0; + mask = 1; // Fill mask with enough bits to cover + while (mask < limit) // the desired range. + mask = (mask << 1) + 1; + do + { + *rsum = cards[*rsum] + user_key[(*keypos)++]; + if (*keypos >= keysize) + { + *keypos = 0; // Recycle the user key. + *rsum += keysize; // key "aaaa" != key "aaaaaaaa" + } + u = mask & *rsum; + if (++retry_limiter > 11) + u %= limit; // Prevent very rare long loops. + } + while (u > limit); + return u; +} + +SapphireBase::SapphireBase() + : cards(256) +{ +} + +SapphireBase::SapphireBase(const byte *key, unsigned int keysize) + : cards(256) +{ + assert(keysize < 256); + // Key size may be up to 256 bytes. + // Pass phrases may be used directly, with longer length + // compensating for the low entropy expected in such keys. + // Alternatively, shorter keys hashed from a pass phrase or + // generated randomly may be used. For random keys, lengths + // of from 4 to 16 bytes are recommended, depending on how + // secure you want this to be. + + int i; + byte rsum; + unsigned keypos; + + // Start with cards all in order, one of each. + + for (i=0;i<256;i++) + cards[i] = i; + + // Swap the card at each position with some other card. + + keypos = 0; // Start with first byte of user key. + rsum = 0; + for (i=255;i;i--) + std::swap(cards[i], cards[keyrand(i, key, keysize, &rsum, &keypos)]); + + // Initialize the indices and data dependencies. + // Indices are set to different values instead of all 0 + // to reduce what is known about the state of the cards + // when the first byte is emitted. + + rotor = cards[1]; + ratchet = cards[3]; + avalanche = cards[5]; + last_plain = cards[7]; + last_cipher = cards[rsum]; + + rsum = 0; + keypos = 0; +} + +SapphireBase::~SapphireBase() +{ + rotor = ratchet = avalanche = last_plain = last_cipher = 0; +} + +void SapphireEncryption::ProcessString(byte *outString, const byte *inString, unsigned int length) +{ + while(length--) + *outString++ = SapphireEncryption::ProcessByte(*inString++); +} + +void SapphireEncryption::ProcessString(byte *inoutString, unsigned int length) +{ + while(length--) + { + *inoutString = SapphireEncryption::ProcessByte(*inoutString); + inoutString++; + } +} + +void SapphireDecryption::ProcessString(byte *outString, const byte *inString, unsigned int length) +{ + while(length--) + *outString++ = SapphireDecryption::ProcessByte(*inString++); +} + +void SapphireDecryption::ProcessString(byte *inoutString, unsigned int length) +{ + while(length--) + { + *inoutString = SapphireDecryption::ProcessByte(*inoutString); + inoutString++; + } +} + +SapphireHash::SapphireHash(unsigned int hashLength) + : hashLength(hashLength) +{ + Init(); +} + +void SapphireHash::Init() +{ + // This function is used to initialize non-keyed hash + // computation. + + int i, j; + + // Initialize the indices and data dependencies. + + rotor = 1; + ratchet = 3; + avalanche = 5; + last_plain = 7; + last_cipher = 11; + + // Start with cards all in inverse order. + + for (i=0, j=255;i<256;i++,j--) + cards[i] = (byte) j; +} + +void SapphireHash::Update(const byte *input, unsigned int length) +{ + while(length--) + SapphireEncryption::ProcessByte(*input++); +} + +void SapphireHash::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + for (int i=255; i>=0; i--) + ProcessByte((byte) i); + + for (unsigned int j=0; j<size; j++) + hash[j] = ProcessByte(0); + + Init(); +} + +NAMESPACE_END diff --git a/sapphire.h b/sapphire.h new file mode 100644 index 0000000..481554d --- /dev/null +++ b/sapphire.h @@ -0,0 +1,115 @@ +#ifndef CRYPTOPP_SAPPHIRE_H +#define CRYPTOPP_SAPPHIRE_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// base class, do not use directly +class SapphireBase : public VariableKeyLength<16, 1, 255> +{ +protected: + SapphireBase(); + SapphireBase(const byte *userKey, unsigned int keyLength); + ~SapphireBase(); + + inline void ShuffleCards() + { + ratchet += cards[rotor++]; + byte swaptemp = cards[last_cipher]; + cards[last_cipher] = cards[ratchet]; + cards[ratchet] = cards[last_plain]; + cards[last_plain] = cards[rotor]; + cards[rotor] = swaptemp; + avalanche += cards[swaptemp]; + } + + // These variables comprise the state of the state machine. + + SecByteBlock cards; // A permutation of 0-255. + byte rotor, // Index that rotates smoothly + ratchet, // Index that moves erratically + avalanche, // Index heavily data dependent + last_plain, // Last plain text byte + last_cipher; // Last cipher text byte + +private: + byte keyrand(unsigned int limit, const byte *user_key, byte keysize, byte *rsum, unsigned *keypos); +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Sapphire-II">Sapphire-II Cipher</a> +class SapphireEncryption : public StreamTransformation, public SapphireBase +{ +public: + SapphireEncryption(const byte *userKey, unsigned int keyLength=DEFAULT_KEYLENGTH) + : SapphireBase(userKey, keyLength) {} + + inline byte ProcessByte(byte b) + { + ShuffleCards(); + last_cipher = b^cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^ + cards[cards[(cards[last_plain] + + cards[last_cipher] + + cards[avalanche])&0xFF]]; + last_plain = b; + return last_cipher; + } + + void ProcessString(byte *outString, const byte *inString, unsigned int length); + void ProcessString(byte *inoutString, unsigned int length); + +protected: + SapphireEncryption() {} // for SapphireHash +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Sapphire-II">Sapphire-II cipher</a> +class SapphireDecryption : public StreamTransformation, public SapphireBase +{ +public: + SapphireDecryption(const byte *userKey, unsigned int keyLength=DEFAULT_KEYLENGTH) + : SapphireBase(userKey, keyLength) {} + + inline byte ProcessByte(byte b) + { + ShuffleCards(); + last_plain = b^cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^ + cards[cards[(cards[last_plain] + + cards[last_cipher] + + cards[avalanche])&0xFF]]; + last_cipher = b; + return last_plain; + } + + void ProcessString(byte *outString, const byte *inString, unsigned int length); + void ProcessString(byte *inoutString, unsigned int length); +}; + +/// Sapphire Random Number Generator +class SapphireRNG : public RandomNumberGenerator, private SapphireEncryption +{ +public: + SapphireRNG(const byte *seed, unsigned int seedLength) + : SapphireEncryption(seed, seedLength) {} + + inline byte GetByte() {return SapphireEncryption::ProcessByte(0);} +}; + +//! Sapphire Hash +/*! Digest Length = 160 bits */ +class SapphireHash : public HashTransformation, private SapphireEncryption +{ +public: + SapphireHash(unsigned int hashLength=20); + void Update(const byte *input, unsigned int length); + void TruncatedFinal(byte *hash, unsigned int size); + unsigned int DigestSize() const {return hashLength;} + +private: + void Init(); + const unsigned int hashLength; +}; + +NAMESPACE_END + +#endif diff --git a/seal.cpp b/seal.cpp new file mode 100644 index 0000000..eaae7a7 --- /dev/null +++ b/seal.cpp @@ -0,0 +1,211 @@ +// seal.cpp - written and placed in the public domain by Wei Dai +// updated to SEAL 3.0 by Leonard Janke + +#include "pch.h" +#include "seal.h" +#include "sha.h" +#include "misc.h" + +#include "strciphr.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void SEAL_TestInstantiations() +{ + SEAL<>::Encryption x; +} + +struct SEAL_Gamma +{ + SEAL_Gamma(const byte *key) + : H(5), Z(5), D(16), lastIndex(0xffffffff) + { + GetUserKey(BIG_ENDIAN_ORDER, H.begin(), 5, key, 20); + memset(D, 0, 64); + } + + word32 Apply(word32 i); + + SecBlock<word32> H, Z, D; + word32 lastIndex; +}; + +word32 SEAL_Gamma::Apply(word32 i) +{ + word32 shaIndex = i/5; + if (shaIndex != lastIndex) + { + memcpy(Z, H, 20); + D[0] = shaIndex; + SHA::Transform(Z, D); + lastIndex = shaIndex; + } + return Z[i%5]; +} + +template <class B> +void SEAL_Policy<B>::CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + m_insideCounter = m_outsideCounter = m_startCount = 0; + + unsigned int L = params.GetIntValueWithDefault("NumberOfOutputBitsPerPositionIndex", 32*1024); + m_iterationsPerCount = L / 8192; + + SEAL_Gamma gamma(key); + unsigned int i; + + for (i=0; i<512; i++) + m_T[i] = gamma.Apply(i); + + for (i=0; i<256; i++) + m_S[i] = gamma.Apply(0x1000+i); + + m_R.New(4*(L/8192)); + + for (i=0; i<m_R.size(); i++) + m_R[i] = gamma.Apply(0x2000+i); +} + +template <class B> +void SEAL_Policy<B>::CipherResynchronize(byte *keystreamBuffer, const byte *IV) +{ + m_outsideCounter = UnalignedGetWord<word32>(BIG_ENDIAN_ORDER, IV); + m_startCount = m_outsideCounter; + m_insideCounter = 0; +} + +template <class B> +void SEAL_Policy<B>::SeekToIteration(dword iterationCount) +{ + m_outsideCounter = m_startCount + iterationCount / m_iterationsPerCount; + m_insideCounter = iterationCount % m_iterationsPerCount; +} + +template <class B> +void SEAL_Policy<B>::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + KeystreamOutput<B> keystreamOutput(operation, output, input); + word32 a, b, c, d, n1, n2, n3, n4; + unsigned int p, q; + + for (unsigned int iteration = 0; iteration < iterationCount; ++iteration) + { +#define Ttab(x) *(word32 *)((byte *)m_T.begin()+x) + + a = m_outsideCounter ^ m_R[4*m_insideCounter]; + b = rotrFixed(m_outsideCounter, 8U) ^ m_R[4*m_insideCounter+1]; + c = rotrFixed(m_outsideCounter, 16U) ^ m_R[4*m_insideCounter+2]; + d = rotrFixed(m_outsideCounter, 24U) ^ m_R[4*m_insideCounter+3]; + + for (unsigned int j=0; j<2; j++) + { + p = a & 0x7fc; + b += Ttab(p); + a = rotrFixed(a, 9U); + + p = b & 0x7fc; + c += Ttab(p); + b = rotrFixed(b, 9U); + + p = c & 0x7fc; + d += Ttab(p); + c = rotrFixed(c, 9U); + + p = d & 0x7fc; + a += Ttab(p); + d = rotrFixed(d, 9U); + } + + n1 = d, n2 = b, n3 = a, n4 = c; + + p = a & 0x7fc; + b += Ttab(p); + a = rotrFixed(a, 9U); + + p = b & 0x7fc; + c += Ttab(p); + b = rotrFixed(b, 9U); + + p = c & 0x7fc; + d += Ttab(p); + c = rotrFixed(c, 9U); + + p = d & 0x7fc; + a += Ttab(p); + d = rotrFixed(d, 9U); + + // generate 8192 bits + for (unsigned int i=0; i<64; i++) + { + p = a & 0x7fc; + a = rotrFixed(a, 9U); + b += Ttab(p); + b ^= a; + + q = b & 0x7fc; + b = rotrFixed(b, 9U); + c ^= Ttab(q); + c += b; + + p = (p+c) & 0x7fc; + c = rotrFixed(c, 9U); + d += Ttab(p); + d ^= c; + + q = (q+d) & 0x7fc; + d = rotrFixed(d, 9U); + a ^= Ttab(q); + a += d; + + p = (p+a) & 0x7fc; + b ^= Ttab(p); + a = rotrFixed(a, 9U); + + q = (q+b) & 0x7fc; + c += Ttab(q); + b = rotrFixed(b, 9U); + + p = (p+c) & 0x7fc; + d ^= Ttab(p); + c = rotrFixed(c, 9U); + + q = (q+d) & 0x7fc; + d = rotrFixed(d, 9U); + a += Ttab(q); + + keystreamOutput (b + m_S[4*i+0]) + (c ^ m_S[4*i+1]) + (d + m_S[4*i+2]) + (a ^ m_S[4*i+3]); + + if (i & 1) + { + a += n3; + b += n4; + c ^= n3; + d ^= n4; + } + else + { + a += n1; + b += n2; + c ^= n1; + d ^= n2; + } + } + + if (++m_insideCounter == m_iterationsPerCount) + { + ++m_outsideCounter; + m_insideCounter = 0; + } + } + + a = b = c = d = n1 = n2 = n3 = n4 = 0; + p = q = 0; +} + +template class SEAL_Policy<BigEndian>; +template class SEAL_Policy<LittleEndian>; + +NAMESPACE_END @@ -0,0 +1,47 @@ +#ifndef CRYPTOPP_SEAL_H +#define CRYPTOPP_SEAL_H + +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class B = BigEndian> +struct SEAL_Info : public FixedKeyLength<20, SimpleKeyingInterface::INTERNALLY_GENERATED_IV> +{ + static const char *StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "SEAL-3.0-LE" : "SEAL-3.0-BE";} +}; + +template <class B = BigEndian> +class SEAL_Policy : public AdditiveCipherConcretePolicy<word32, 1024>, public SEAL_Info<B> +{ +public: + unsigned int IVSize() const {return 4;} + void GetNextIV(byte *IV) const {UnalignedPutWord(BIG_ENDIAN_ORDER, IV, m_outsideCounter+1);} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV); + bool IsRandomAccess() const {return true;} + void SeekToIteration(dword iterationCount); + +private: + FixedSizeSecBlock<word32, 512> m_T; + FixedSizeSecBlock<word32, 256> m_S; + SecBlock<word32> m_R; + + word32 m_startCount, m_iterationsPerCount; + word32 m_outsideCounter, m_insideCounter; +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#SEAL-3.0-BE">SEAL</a> +template <class B = BigEndian> +struct SEAL : public SEAL_Info<B>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<SEAL_Policy<B>, AdditiveCipherTemplate<> >, SEAL_Info<B> > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/secblock.h b/secblock.h new file mode 100644 index 0000000..31997b6 --- /dev/null +++ b/secblock.h @@ -0,0 +1,376 @@ +// secblock.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_SECBLOCK_H +#define CRYPTOPP_SECBLOCK_H + +#include "config.h" +#include "misc.h" +#include <string.h> // CodeWarrior doesn't have memory.h +#include <assert.h> + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +template<class T> +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; +#if (defined(_MSC_VER) && _MSC_VER < 1300) + typedef ptrdiff_t difference_type; +#else + typedef std::ptrdiff_t difference_type; +#endif + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {p->~T();} + size_type max_size() const {return size_type(-1)/sizeof(T);} +}; + +#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \ +typedef typename AllocatorBase<T>::value_type value_type;\ +typedef typename AllocatorBase<T>::size_type size_type;\ +typedef typename AllocatorBase<T>::difference_type difference_type;\ +typedef typename AllocatorBase<T>::pointer pointer;\ +typedef typename AllocatorBase<T>::const_pointer const_pointer;\ +typedef typename AllocatorBase<T>::reference reference;\ +typedef typename AllocatorBase<T>::const_reference const_reference; + +template <class T, class A> +typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) +{ + if (oldSize == newSize) + return p; + + if (preserve) + { + typename A::pointer newPointer = a.allocate(newSize, NULL); + memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize)); + a.deallocate(p, oldSize); + return newPointer; + } + else + { + a.deallocate(p, oldSize); + return a.allocate(newSize, NULL); + } +} + +template <class T> +class AllocatorWithCleanup : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + pointer allocate(size_type n, const void * = NULL) + { + if (n > 0) + return new T[n]; + else + return NULL; + } + + void deallocate(void *p, size_type n) + { + memset(p, 0, n*sizeof(T)); + delete [] (T *)p; + } + + pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve) + { + return StandardReallocate(*this, p, oldSize, newSize, preserve); + } + + // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a + // template class member called rebind". + template <class U> struct rebind { typedef AllocatorWithCleanup<U> other; }; +}; + +template <class T> +class NullAllocator : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + pointer allocate(size_type n, const void * = NULL) + { + assert(false); + return NULL; + } + + void deallocate(void *p, size_type n) + { + assert(false); + } +}; + +// this allocator can't be used with standard collections +template <class T, unsigned int S, class A = NullAllocator<T> > +class FixedSizeAllocatorWithCleanup : public AllocatorBase<T> +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + pointer allocate(size_type n) + { + if (n <= S) + { + assert(!m_allocated); +#ifndef NDEBUG + m_allocated = true; +#endif + return m_array; + } + else + return m_fallbackAllocator.allocate(n); + } + + pointer allocate(size_type n, const void *hint) + { + if (n <= S) + { + assert(!m_allocated); +#ifndef NDEBUG + m_allocated = true; +#endif + return m_array; + } + else + return m_fallbackAllocator.allocate(n, hint); + } + + void deallocate(void *p, size_type n) + { + if (n <= S) + { + assert(m_allocated); + assert(p == m_array); +#ifndef NDEBUG + m_allocated = false; +#endif + memset(p, 0, n*sizeof(T)); + } + else + m_fallbackAllocator.deallocate(p, n); + } + + pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve) + { + if (oldSize <= S && newSize <= S) + return p; + + return StandardReallocate(*this, p, oldSize, newSize, preserve); + } + + size_type max_size() const {return m_fallbackAllocator.max_size();} + +private: + A m_fallbackAllocator; + T m_array[S]; + +#ifndef NDEBUG +public: + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + bool m_allocated; +#endif +}; + +//! a block of memory allocated using A +template <class T, class A = AllocatorWithCleanup<T> > +class SecBlock +{ +public: + explicit SecBlock(unsigned int size=0) + : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);} + SecBlock(const SecBlock<T, A> &t) + : m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy(m_ptr, t.m_ptr, m_size*sizeof(T));} + SecBlock(const T *t, unsigned int len) + : m_size(len) + { + m_ptr = m_alloc.allocate(len, NULL); + if (t == NULL) + memset(m_ptr, 0, len*sizeof(T)); + else + memcpy(m_ptr, t, len*sizeof(T)); + } + + ~SecBlock() + {m_alloc.deallocate(m_ptr, m_size);} + +#if defined(__GNUC__) || defined(__BCPLUSPLUS__) + operator const void *() const + {return m_ptr;} + operator void *() + {return m_ptr;} +#endif +#if defined(__GNUC__) // reduce warnings + operator const void *() + {return m_ptr;} +#endif + + operator const T *() const + {return m_ptr;} + operator T *() + {return m_ptr;} +#if defined(__GNUC__) // reduce warnings + operator const T *() + {return m_ptr;} +#endif + + template <typename I> + T *operator +(I offset) + {return m_ptr+offset;} + + template <typename I> + const T *operator +(I offset) const + {return m_ptr+offset;} + + template <typename I> + T& operator[](I index) + {assert(index >= 0 && (unsigned int)index < m_size); return m_ptr[index];} + + template <typename I> + const T& operator[](I index) const + {assert(index >= 0 && (unsigned int)index < m_size); return m_ptr[index];} + + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + typedef typename A::size_type size_type; + + iterator begin() + {return m_ptr;} + const_iterator begin() const + {return m_ptr;} + iterator end() + {return m_ptr+m_size;} + const_iterator end() const + {return m_ptr+m_size;} + + typename A::pointer data() {return m_ptr;} + typename A::const_pointer data() const {return m_ptr;} + + size_type size() const {return m_size;} + bool empty() const {return m_size == 0;} + + void Assign(const T *t, unsigned int len) + { + New(len); + memcpy(m_ptr, t, len*sizeof(T)); + } + + void Assign(const SecBlock<T, A> &t) + { + New(t.m_size); + memcpy(m_ptr, t.m_ptr, m_size*sizeof(T)); + } + + SecBlock& operator=(const SecBlock<T, A> &t) + { + Assign(t); + return *this; + } + + bool operator==(const SecBlock<T, A> &t) const + { + return m_size == t.m_size && memcmp(m_ptr, t.m_ptr, m_size*sizeof(T)) == 0; + } + + bool operator!=(const SecBlock<T, A> &t) const + { + return !operator==(t); + } + + void New(unsigned int newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); + m_size = newSize; + } + + void CleanNew(unsigned int newSize) + { + New(newSize); + memset(m_ptr, 0, m_size*sizeof(T)); + } + + void Grow(unsigned int newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + } + + void CleanGrow(unsigned int newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); + m_size = newSize; + } + } + + void resize(unsigned int newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + + void swap(SecBlock<T, A> &b); + +//private: + A m_alloc; + unsigned int m_size; + T *m_ptr; +}; + +template <class T, class A> void SecBlock<T, A>::swap(SecBlock<T, A> &b) +{ + std::swap(m_alloc, b.m_alloc); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); +} + +typedef SecBlock<byte> SecByteBlock; +typedef SecBlock<word> SecWordBlock; + +template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> > +class FixedSizeSecBlock : public SecBlock<T, A> +{ +public: + explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {} +}; + +template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > > +class SecBlockWithHint : public SecBlock<T, A> +{ +public: + explicit SecBlockWithHint(unsigned int size) : SecBlock<T, A>(size) {} +}; + +template<class T, class U> +inline bool operator==(const CryptoPP::AllocatorWithCleanup<T>&, const CryptoPP::AllocatorWithCleanup<U>&) {return (true);} +template<class T, class U> +inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T>&, const CryptoPP::AllocatorWithCleanup<U>&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template <class T, class A> +inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b) +{ + a.swap(b); +} + +NAMESPACE_END + +#endif diff --git a/seckey.h b/seckey.h new file mode 100644 index 0000000..aa85d14 --- /dev/null +++ b/seckey.h @@ -0,0 +1,237 @@ +// seckey.h - written and placed in the public domain by Wei Dai + +// This file contains helper classes/functions for implementing secret key algorithms. + +#ifndef CRYPTOPP_SECKEY_H +#define CRYPTOPP_SECKEY_H + +#include "cryptlib.h" +#include "misc.h" +#include "simple.h" + +NAMESPACE_BEGIN(CryptoPP) + +inline CipherDir ReverseCipherDir(CipherDir dir) +{ + return (dir == ENCRYPTION) ? DECRYPTION : ENCRYPTION; +} + +//! . +template <unsigned int N> +class FixedBlockSize +{ +public: + enum {BLOCKSIZE = N}; +}; + +// ************** rounds *************** + +//! . +template <unsigned int R> +class FixedRounds +{ +public: + enum {ROUNDS = R}; + +protected: + template <class T> + static inline void CheckedSetKey(T *obj, CipherDir dir, const byte *key, unsigned int length, const NameValuePairs ¶m) + { + obj->ThrowIfInvalidKeyLength(length); + int rounds = param.GetIntValueWithDefault("Rounds", ROUNDS); + if (rounds != ROUNDS) + throw InvalidRounds(obj->StaticAlgorithmName(), rounds); + obj->UncheckedSetKey(dir, key, length); + } +}; + +//! . +template <unsigned int D, unsigned int N=1, unsigned int M=INT_MAX> // use INT_MAX here because enums are treated as signed ints +class VariableRounds +{ +public: + enum {DEFAULT_ROUNDS = D, MIN_ROUNDS = N, MAX_ROUNDS = M}; + static unsigned int StaticGetDefaultRounds(unsigned int keylength) {return DEFAULT_ROUNDS;} + +protected: + static inline void AssertValidRounds(unsigned int rounds) + { + assert(rounds >= MIN_ROUNDS && rounds <= MAX_ROUNDS); + } + + template <class T> + static inline void CheckedSetKey(T *obj, CipherDir dir, const byte *key, unsigned int length, const NameValuePairs ¶m) + { + obj->ThrowIfInvalidKeyLength(length); + int rounds = param.GetIntValueWithDefault("Rounds", obj->StaticGetDefaultRounds(length)); + if (rounds < (unsigned int)MIN_ROUNDS || rounds > (unsigned int)MAX_ROUNDS) + throw InvalidRounds(obj->AlgorithmName(), rounds); + obj->UncheckedSetKey(dir, key, length, rounds); + } +}; + +// ************** key length *************** + +//! . +template <unsigned int N, unsigned int IV_REQ = SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +class FixedKeyLength +{ +public: + enum {KEYLENGTH=N, MIN_KEYLENGTH=N, MAX_KEYLENGTH=N, DEFAULT_KEYLENGTH=N}; + enum {IV_REQUIREMENT = IV_REQ}; + static unsigned int StaticGetValidKeyLength(unsigned int) {return KEYLENGTH;} +}; + +/// support query of variable key length, template parameters are default, min, max, multiple (default multiple 1) +template <unsigned int D, unsigned int N, unsigned int M, unsigned int Q = 1, unsigned int IV_REQ = SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +class VariableKeyLength +{ + // make these private to avoid Doxygen documenting them in all derived classes + CRYPTOPP_COMPILE_ASSERT(Q > 0); + CRYPTOPP_COMPILE_ASSERT(N % Q == 0); + CRYPTOPP_COMPILE_ASSERT(M % Q == 0); + CRYPTOPP_COMPILE_ASSERT(N < M); + CRYPTOPP_COMPILE_ASSERT(D >= N && M >= D); + +public: + enum {MIN_KEYLENGTH=N, MAX_KEYLENGTH=M, DEFAULT_KEYLENGTH=D, KEYLENGTH_MULTIPLE=Q}; + enum {IV_REQUIREMENT = IV_REQ}; + static unsigned int StaticGetValidKeyLength(unsigned int n) + { + if (n < (unsigned int)MIN_KEYLENGTH) + return MIN_KEYLENGTH; + else if (n > (unsigned int)MAX_KEYLENGTH) + return MAX_KEYLENGTH; + else + { + n += KEYLENGTH_MULTIPLE-1; + return n - n%KEYLENGTH_MULTIPLE; + } + } +}; + +/// support query of key length that's the same as another class +template <class T> +class SameKeyLengthAs +{ +public: + enum {MIN_KEYLENGTH=T::MIN_KEYLENGTH, MAX_KEYLENGTH=T::MAX_KEYLENGTH, DEFAULT_KEYLENGTH=T::DEFAULT_KEYLENGTH}; + enum {IV_REQUIREMENT = T::IV_REQUIREMENT}; + static unsigned int StaticGetValidKeyLength(unsigned int keylength) + {return T::StaticGetValidKeyLength(keylength);} +}; + +// ************** implementation helper for SimpledKeyed *************** + +template <class T> +static inline void CheckedSetKey(T *obj, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶m) +{ + obj->ThrowIfInvalidKeyLength(length); + obj->UncheckedSetKey(key, length); +} + +template <class T> +static inline void CheckedSetKey(T *obj, CipherDir dir, const byte *key, unsigned int length, const NameValuePairs ¶m) +{ + obj->ThrowIfInvalidKeyLength(length); + obj->UncheckedSetKey(dir, key, length); +} + +//! . +template <class BASE, class INFO = BASE> +class SimpleKeyingInterfaceImpl : public BASE +{ +public: + unsigned int MinKeyLength() const {return INFO::MIN_KEYLENGTH;} + unsigned int MaxKeyLength() const {return INFO::MAX_KEYLENGTH;} + unsigned int DefaultKeyLength() const {return INFO::DEFAULT_KEYLENGTH;} + unsigned int GetValidKeyLength(unsigned int n) const {return INFO::StaticGetValidKeyLength(n);} + typename BASE::IV_Requirement IVRequirement() const {return (typename BASE::IV_Requirement)INFO::IV_REQUIREMENT;} + +protected: + void AssertValidKeyLength(unsigned int length) {assert(GetValidKeyLength(length) == length);} +}; + +template <class INFO, class INTERFACE = BlockCipher> +class BlockCipherBaseTemplate : public AlgorithmImpl<SimpleKeyingInterfaceImpl<TwoBases<INFO, INTERFACE> > > +{ +public: + unsigned int BlockSize() const {return BLOCKSIZE;} +}; + +//! . +template <CipherDir DIR, class BASE> +class BlockCipherTemplate : public BASE +{ +public: + BlockCipherTemplate() {} + BlockCipherTemplate(const byte *key) + {SetKey(key, DEFAULT_KEYLENGTH);} + BlockCipherTemplate(const byte *key, unsigned int length) + {SetKey(key, length);} + BlockCipherTemplate(const byte *key, unsigned int length, unsigned int rounds) + {SetKeyWithRounds(key, length, rounds);} + + bool IsForwardTransformation() const {return DIR == ENCRYPTION;} + + void SetKey(const byte *key, unsigned int length, const NameValuePairs ¶m = g_nullNameValuePairs) + { + CheckedSetKey(this, DIR, key, length, param); + } + + Clonable * Clone() {return new BlockCipherTemplate<DIR, BASE>(*this);} +}; + +//! . +template <class BASE> +class MessageAuthenticationCodeTemplate : public +#ifdef CRYPTOPP_DOXYGEN_PROCESSING + MessageAuthenticationCode +#else + SimpleKeyingInterfaceImpl<BASE> +#endif +{ +public: + MessageAuthenticationCodeTemplate() {} + MessageAuthenticationCodeTemplate(const byte *key) + {SetKey(key, DEFAULT_KEYLENGTH);} + MessageAuthenticationCodeTemplate(const byte *key, unsigned int length) + {SetKey(key, length);} + + std::string AlgorithmName() const {return StaticAlgorithmName();} + + void SetKey(const byte *key, unsigned int length, const NameValuePairs ¶m = g_nullNameValuePairs) + { + CheckedSetKey(this, Empty(), key, length, param); + } + + Clonable * Clone() {return new MessageAuthenticationCodeTemplate<BASE>(*this);} +}; + +// ************** documentation *************** + +//! These objects usually should not be used directly. See CipherModeDocumentation instead. +/*! Each class derived from this one defines two types, Encryption and Decryption, + both of which implement the BlockCipher interface. */ +struct BlockCipherDocumentation +{ + //! implements the BlockCipher interface + typedef BlockCipher Encryption; + //! implements the BlockCipher interface + typedef BlockCipher Decryption; +}; + +/*! \brief Each class derived from this one defines two types, Encryption and Decryption, + both of which implement the SymmetricCipher interface. See CipherModeDocumentation + for information about using block ciphers. */ +struct SymmetricCipherDocumentation +{ + //! implements the SymmetricCipher interface + typedef SymmetricCipher Encryption; + //! implements the SymmetricCipher interface + typedef SymmetricCipher Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/serpent.cpp b/serpent.cpp new file mode 100644 index 0000000..bc0cb89 --- /dev/null +++ b/serpent.cpp @@ -0,0 +1,544 @@ +// serpent.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "serpent.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +// linear transformation +#define LT(i,a,b,c,d,e) {\ + a = rotlFixed(a, 13); \ + c = rotlFixed(c, 3); \ + d = rotlFixed(d ^ c ^ (a << 3), 7); \ + b = rotlFixed(b ^ a ^ c, 1); \ + a = rotlFixed(a ^ b ^ d, 5); \ + c = rotlFixed(c ^ d ^ (b << 7), 22);} + +// inverse linear transformation +#define ILT(i,a,b,c,d,e) {\ + c = rotrFixed(c, 22); \ + a = rotrFixed(a, 5); \ + c ^= d ^ (b << 7); \ + a ^= b ^ d; \ + b = rotrFixed(b, 1); \ + d = rotrFixed(d, 7) ^ c ^ (a << 3); \ + b ^= a ^ c; \ + c = rotrFixed(c, 3); \ + a = rotrFixed(a, 13);} + +// order of output from S-box functions +#define beforeS0(f) f(0,a,b,c,d,e) +#define afterS0(f) f(1,b,e,c,a,d) +#define afterS1(f) f(2,c,b,a,e,d) +#define afterS2(f) f(3,a,e,b,d,c) +#define afterS3(f) f(4,e,b,d,c,a) +#define afterS4(f) f(5,b,a,e,c,d) +#define afterS5(f) f(6,a,c,b,e,d) +#define afterS6(f) f(7,a,c,d,b,e) +#define afterS7(f) f(8,d,e,b,a,c) + +// order of output from inverse S-box functions +#define beforeI7(f) f(8,a,b,c,d,e) +#define afterI7(f) f(7,d,a,b,e,c) +#define afterI6(f) f(6,a,b,c,e,d) +#define afterI5(f) f(5,b,d,e,c,a) +#define afterI4(f) f(4,b,c,e,a,d) +#define afterI3(f) f(3,a,b,e,c,d) +#define afterI2(f) f(2,b,d,e,c,a) +#define afterI1(f) f(1,a,b,c,e,d) +#define afterI0(f) f(0,a,d,b,e,c) + +// The instruction sequences for the S-box functions +// come from Dag Arne Osvik's paper "Speeding up Serpent". + +#define S0(i, r0, r1, r2, r3, r4) \ + { \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r4 ^= r2; \ + r1 ^= r0; \ + r0 |= r3; \ + r0 ^= r4; \ + r4 ^= r3; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 ^= r4; \ + r4 = ~r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r1 ^= r4; \ + r3 |= r0; \ + r1 ^= r3; \ + r4 ^= r3; \ + } + +#define I0(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r1; \ + r1 |= r0; \ + r4 = ~r4; \ + r1 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 &= r3; \ + r4 ^= r0; \ + r0 |= r1; \ + r0 ^= r2; \ + r3 ^= r4; \ + r2 ^= r1; \ + r3 ^= r0; \ + r3 ^= r1; \ + r2 &= r3; \ + r4 ^= r2; \ + } + +#define S1(i, r0, r1, r2, r3, r4) \ + { \ + r0 = ~r0; \ + r2 = ~r2; \ + r4 = r0; \ + r0 &= r1; \ + r2 ^= r0; \ + r0 |= r3; \ + r3 ^= r2; \ + r1 ^= r0; \ + r0 ^= r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r2 |= r0; \ + r2 &= r4; \ + r0 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r2; \ + r0 ^= r4; \ + } + +#define I1(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r1; \ + r1 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r3 ^= r0; \ + r0 |= r1; \ + r2 ^= r3; \ + r0 ^= r4; \ + r0 |= r2; \ + r1 ^= r3; \ + r0 ^= r1; \ + r1 |= r3; \ + r1 ^= r0; \ + r4 = ~r4; \ + r4 ^= r1; \ + r1 |= r0; \ + r1 ^= r0; \ + r1 |= r4; \ + r3 ^= r1; \ + } + +#define S2(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 &= r2; \ + r0 ^= r3; \ + r2 ^= r1; \ + r2 ^= r0; \ + r3 |= r4; \ + r3 ^= r1; \ + r4 ^= r2; \ + r1 = r3; \ + r3 |= r4; \ + r3 ^= r0; \ + r0 &= r1; \ + r4 ^= r0; \ + r1 ^= r3; \ + r1 ^= r4; \ + r4 = ~r4; \ + } + +#define I2(i, r0, r1, r2, r3, r4) \ + { \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r3; \ + r3 &= r2; \ + r3 ^= r1; \ + r1 |= r2; \ + r1 ^= r4; \ + r4 &= r3; \ + r2 ^= r3; \ + r4 &= r0; \ + r4 ^= r2; \ + r2 &= r1; \ + r2 |= r0; \ + r3 = ~r3; \ + r2 ^= r3; \ + r0 ^= r3; \ + r0 &= r1; \ + r3 ^= r4; \ + r3 ^= r0; \ + } + +#define S3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 |= r3; \ + r3 ^= r1; \ + r1 &= r4; \ + r4 ^= r2; \ + r2 ^= r3; \ + r3 &= r0; \ + r4 |= r1; \ + r3 ^= r4; \ + r0 ^= r1; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r2; \ + r1 |= r0; \ + r1 ^= r2; \ + r0 ^= r3; \ + r2 = r1; \ + r1 |= r3; \ + r1 ^= r0; \ + } + +#define I3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r4; \ + r4 ^= r3; \ + r3 |= r1; \ + r3 ^= r2; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 |= r3; \ + r0 ^= r1; \ + r4 ^= r2; \ + r2 &= r3; \ + r1 |= r3; \ + r1 ^= r2; \ + r4 ^= r0; \ + r2 ^= r4; \ + } + +#define S4(i, r0, r1, r2, r3, r4) \ + { \ + r1 ^= r3; \ + r3 = ~r3; \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r1 ^= r2; \ + r4 ^= r3; \ + r0 ^= r4; \ + r2 &= r4; \ + r2 ^= r0; \ + r0 &= r1; \ + r3 ^= r0; \ + r4 |= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r2 &= r3; \ + r0 = ~r0; \ + r4 ^= r2; \ + } + +#define I4(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r3; \ + r2 ^= r1; \ + r1 |= r3; \ + r1 &= r0; \ + r4 ^= r2; \ + r4 ^= r1; \ + r1 &= r2; \ + r0 = ~r0; \ + r3 ^= r4; \ + r1 ^= r3; \ + r3 &= r0; \ + r3 ^= r2; \ + r0 ^= r1; \ + r2 &= r0; \ + r3 ^= r0; \ + r2 ^= r4; \ + r2 |= r3; \ + r3 ^= r0; \ + r2 ^= r1; \ + } + +#define S5(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r1; \ + r1 ^= r3; \ + r3 = ~r3; \ + r4 = r1; \ + r1 &= r0; \ + r2 ^= r3; \ + r1 ^= r2; \ + r2 |= r4; \ + r4 ^= r3; \ + r3 &= r1; \ + r3 ^= r0; \ + r4 ^= r1; \ + r4 ^= r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r0 ^= r4; \ + r4 |= r3; \ + r2 ^= r4; \ + } + +#define I5(i, r0, r1, r2, r3, r4) \ + { \ + r1 = ~r1; \ + r4 = r3; \ + r2 ^= r1; \ + r3 |= r0; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 ^= r4; \ + r4 |= r0; \ + r4 ^= r1; \ + r1 &= r2; \ + r1 ^= r3; \ + r4 ^= r2; \ + r3 &= r4; \ + r4 ^= r1; \ + r3 ^= r0; \ + r3 ^= r4; \ + r4 = ~r4; \ + } + +#define S6(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r3; \ + r3 &= r0; \ + r0 ^= r4; \ + r3 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r2 ^= r0; \ + r0 |= r1; \ + r2 ^= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r4 ^= r3; \ + r4 ^= r0; \ + r3 = ~r3; \ + r2 &= r4; \ + r2 ^= r3; \ + } + +#define I6(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r2; \ + r4 = r2; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 = ~r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r4 |= r0; \ + r0 ^= r2; \ + r3 ^= r4; \ + r4 ^= r1; \ + r1 &= r3; \ + r1 ^= r0; \ + r0 ^= r3; \ + r0 |= r2; \ + r3 ^= r1; \ + r4 ^= r0; \ + } + +#define S7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r1; \ + r2 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r2 ^= r1; \ + r1 ^= r0; \ + r0 |= r4; \ + r0 ^= r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r3 &= r0; \ + r3 ^= r4; \ + r4 ^= r2; \ + r2 &= r0; \ + r4 = ~r4; \ + r2 ^= r4; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r1; \ + } + +#define I7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r4 |= r3; \ + r3 ^= r1; \ + r1 |= r0; \ + r0 ^= r2; \ + r2 &= r4; \ + r1 ^= r2; \ + r2 ^= r0; \ + r0 |= r2; \ + r3 &= r4; \ + r0 ^= r3; \ + r4 ^= r1; \ + r3 ^= r4; \ + r4 |= r0; \ + r3 ^= r2; \ + r4 ^= r2; \ + } + +// key xor +#define KX(r, a, b, c, d, e) {\ + a ^= k[4 * r + 0]; \ + b ^= k[4 * r + 1]; \ + c ^= k[4 * r + 2]; \ + d ^= k[4 * r + 3];} + +void Serpent::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int keylen) +{ + AssertValidKeyLength(keylen); + + word32 *k = m_key; + GetUserKey(LITTLE_ENDIAN_ORDER, k, 8, userKey, keylen); + + word32 i,a,b,c,d,e; + + if (keylen < 32) + k[keylen/4] |= word32(1) << ((keylen%4)*8); + + k += 8; + word32 t = k[-1]; + for (i = 0; i < 132; ++i) + k[i] = t = rotlFixed(k[i-8] ^ k[i-5] ^ k[i-3] ^ t ^ 0x9e3779b9 ^ i, 11); + k -= 20; + +#define LK(r, a, b, c, d, e) {\ + a = k[(8-r)*4 + 0]; \ + b = k[(8-r)*4 + 1]; \ + c = k[(8-r)*4 + 2]; \ + d = k[(8-r)*4 + 3];} + +#define SK(r, a, b, c, d, e) {\ + k[(8-r)*4 + 4] = a; \ + k[(8-r)*4 + 5] = b; \ + k[(8-r)*4 + 6] = c; \ + k[(8-r)*4 + 7] = d;} \ + + for (i=0; i<4; i++) + { + afterS2(LK); afterS2(S3); afterS3(SK); + afterS1(LK); afterS1(S2); afterS2(SK); + afterS0(LK); afterS0(S1); afterS1(SK); + beforeS0(LK); beforeS0(S0); afterS0(SK); + k += 8*4; + afterS6(LK); afterS6(S7); afterS7(SK); + afterS5(LK); afterS5(S6); afterS6(SK); + afterS4(LK); afterS4(S5); afterS5(SK); + afterS3(LK); afterS3(S4); afterS4(SK); + } + afterS2(LK); afterS2(S3); afterS3(SK); +} + +typedef BlockGetAndPut<word32, LittleEndian> Block; + +void Serpent::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, e; + + Block::Get(inBlock)(a)(b)(c)(d); + + const word32 *k = m_key + 8; + unsigned int i=1; + + do + { + beforeS0(KX); beforeS0(S0); afterS0(LT); + afterS0(KX); afterS0(S1); afterS1(LT); + afterS1(KX); afterS1(S2); afterS2(LT); + afterS2(KX); afterS2(S3); afterS3(LT); + afterS3(KX); afterS3(S4); afterS4(LT); + afterS4(KX); afterS4(S5); afterS5(LT); + afterS5(KX); afterS5(S6); afterS6(LT); + afterS6(KX); afterS6(S7); + + if (i == 4) + break; + + ++i; + c = b; + b = e; + e = d; + d = a; + a = e; + k += 32; + beforeS0(LT); + } + while (true); + + afterS7(KX); + + Block::Put(xorBlock, outBlock)(d)(e)(b)(a); +} + +void Serpent::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, e; + + Block::Get(inBlock)(a)(b)(c)(d); + + const word32 *k = m_key + 104; + unsigned int i=4; + + beforeI7(KX); + goto start; + + do + { + c = b; + b = d; + d = e; + k -= 32; + beforeI7(ILT); +start: + beforeI7(I7); afterI7(KX); + afterI7(ILT); afterI7(I6); afterI6(KX); + afterI6(ILT); afterI6(I5); afterI5(KX); + afterI5(ILT); afterI5(I4); afterI4(KX); + afterI4(ILT); afterI4(I3); afterI3(KX); + afterI3(ILT); afterI3(I2); afterI2(KX); + afterI2(ILT); afterI2(I1); afterI1(KX); + afterI1(ILT); afterI1(I0); afterI0(KX); + } + while (--i != 0); + + Block::Put(xorBlock, outBlock)(a)(d)(b)(e); +} + +NAMESPACE_END diff --git a/serpent.h b/serpent.h new file mode 100644 index 0000000..bc3ac7a --- /dev/null +++ b/serpent.h @@ -0,0 +1,51 @@ +#ifndef CRYPTOPP_SERPENT_H +#define CRYPTOPP_SERPENT_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Serpent_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 1, 32>, public FixedRounds<32> +{ + static const char *StaticAlgorithmName() {return "Serpent";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Serpent">Serpent</a> +class Serpent : public Serpent_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Serpent_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + FixedSizeSecBlock<word32, 140> m_key; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Serpent::Encryption SerpentEncryption; +typedef Serpent::Decryption SerpentDecryption; + +NAMESPACE_END + +#endif diff --git a/serpentv.dat b/serpentv.dat new file mode 100644 index 0000000..06e863a --- /dev/null +++ b/serpentv.dat @@ -0,0 +1,9 @@ +00000000000000000000000000000000 d29d576fcea3a3a7ed9099f29273d78e b2288b968ae8b08648d1ce9606fd992d +00000000000000000000000000000000 d29d576fcea3a3a7ed9099f26d8c2871 563a8403ff5309d62370b1dcf5a11edd +ffeeddccbbaa99887766554433221100 1032547698badcfeefcdab8967452301 d5baa00a4bb9d8a7c981c8dc90d89d92 +ffeeddccbbaa99887766554433221100 145f0b8b663176b95dcab7e9dcd5cc24 1032547698badcfeefcdab8967452301 +000000000000000000000000000000000000000000000000 d29d576fceaba3a7ed9899f2927bd78e 130e353e1037c22405e8faefb2c3c3e9 +8899aabbccddeeffffeeddccbbaa99887766554433221100 1032547698badcfeefcdab8967452301 da860842b720802bf404a4c71034879a +8899aabbccddeeffffeeddccbbaa99887766554433221100 b2696bd0d98c17953e4239225d27202c 1032547698badcfeefcdab8967452301 +0000000000000000000000000000000000000000000000000000000000000000 92074732d84e1841a013a0034c52bf50 81c4eb7b8ad9a8d0f2aa5d7bd626b560 +00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100 1032547698badcfeefcdab8967452301 93df9a3cafe387bd999eebe393a17fca @@ -0,0 +1,277 @@ +// sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c + +// Steve Reid implemented SHA-1. Wei Dai implemented SHA-2. +// Both are in the public domain. + +#include "pch.h" +#include "sha.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void SHA::Init() +{ + m_digest[0] = 0x67452301L; + m_digest[1] = 0xEFCDAB89L; + m_digest[2] = 0x98BADCFEL; + m_digest[3] = 0x10325476L; + m_digest[4] = 0xC3D2E1F0L; +} + +// start of Steve Reid's code + +#define blk0(i) (W[i] = data[i]) +#define blk1(i) (W[i&15] = rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1)) + +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rotlFixed(v,5);w=rotlFixed(w,30); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rotlFixed(v,5);w=rotlFixed(w,30); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rotlFixed(v,5);w=rotlFixed(w,30); + +void SHA::Transform(word32 *state, const word32 *data) +{ + word32 W[16]; + /* Copy context->state[] to working vars */ + word32 a = state[0]; + word32 b = state[1]; + word32 c = state[2]; + word32 d = state[3]; + word32 e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; + memset(W, 0, sizeof(W)); +} + +// end of Steve Reid's code + +// ************************************************************* + +void SHA256::Init() +{ + m_digest[0] = 0x6a09e667; + m_digest[1] = 0xbb67ae85; + m_digest[2] = 0x3c6ef372; + m_digest[3] = 0xa54ff53a; + m_digest[4] = 0x510e527f; + m_digest[5] = 0x9b05688c; + m_digest[6] = 0x1f83d9ab; + m_digest[7] = 0x5be0cd19; +} + +#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#define a(i) T[(0-i)&7] +#define b(i) T[(1-i)&7] +#define c(i) T[(2-i)&7] +#define d(i) T[(3-i)&7] +#define e(i) T[(4-i)&7] +#define f(i) T[(5-i)&7] +#define g(i) T[(6-i)&7] +#define h(i) T[(7-i)&7] + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\ + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + +// for SHA256 +#define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22)) +#define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25)) +#define s0(x) (rotrFixed(x,7)^rotrFixed(x,18)^(x>>3)) +#define s1(x) (rotrFixed(x,17)^rotrFixed(x,19)^(x>>10)) + +void SHA256::Transform(word32 *state, const word32 *data) +{ + word32 W[16]; + word32 T[8]; + /* Copy context->state[] to working vars */ + memcpy(T, state, sizeof(T)); + /* 64 operations, partially loop unrolled */ + for (unsigned int j=0; j<64; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + /* Add the working vars back into context.state[] */ + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); + /* Wipe variables */ + memset(W, 0, sizeof(W)); + memset(T, 0, sizeof(T)); +} + +const word32 SHA256::K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#undef S0 +#undef S1 +#undef s0 +#undef s1 + +// ************************************************************* + +#ifdef WORD64_AVAILABLE + +void SHA512::Init() +{ + m_digest[0] = W64LIT(0x6a09e667f3bcc908); + m_digest[1] = W64LIT(0xbb67ae8584caa73b); + m_digest[2] = W64LIT(0x3c6ef372fe94f82b); + m_digest[3] = W64LIT(0xa54ff53a5f1d36f1); + m_digest[4] = W64LIT(0x510e527fade682d1); + m_digest[5] = W64LIT(0x9b05688c2b3e6c1f); + m_digest[6] = W64LIT(0x1f83d9abfb41bd6b); + m_digest[7] = W64LIT(0x5be0cd19137e2179); +} + +// for SHA512 +#define S0(x) (rotrFixed(x,28)^rotrFixed(x,34)^rotrFixed(x,39)) +#define S1(x) (rotrFixed(x,14)^rotrFixed(x,18)^rotrFixed(x,41)) +#define s0(x) (rotrFixed(x,1)^rotrFixed(x,8)^(x>>7)) +#define s1(x) (rotrFixed(x,19)^rotrFixed(x,61)^(x>>6)) + +void SHA512::Transform(word64 *state, const word64 *data) +{ + word64 W[16]; + word64 T[8]; + /* Copy context->state[] to working vars */ + memcpy(T, state, sizeof(T)); + /* 80 operations, partially loop unrolled */ + for (unsigned int j=0; j<80; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + /* Add the working vars back into context.state[] */ + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); + /* Wipe variables */ + memset(W, 0, sizeof(W)); + memset(T, 0, sizeof(T)); +} + +const word64 SHA512::K[80] = { + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) +}; + +void SHA384::Init() +{ + m_digest[0] = W64LIT(0xcbbb9d5dc1059ed8); + m_digest[1] = W64LIT(0x629a292a367cd507); + m_digest[2] = W64LIT(0x9159015a3070dd17); + m_digest[3] = W64LIT(0x152fecd8f70e5939); + m_digest[4] = W64LIT(0x67332667ffc00b31); + m_digest[5] = W64LIT(0x8eb44a8768581511); + m_digest[6] = W64LIT(0xdb0c2e0d64f98fa7); + m_digest[7] = W64LIT(0x47b5481dbefa4fa4); +} + +#endif + +NAMESPACE_END @@ -0,0 +1,72 @@ +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/md.html#SHA-1">SHA-1</a> +class SHA : public IteratedHashWithStaticTransform<word32, BigEndian, 64, SHA> +{ +public: + enum {DIGESTSIZE = 20}; + SHA() : IteratedHashWithStaticTransform<word32, BigEndian, 64, SHA>(DIGESTSIZE) {Init();} + static void Transform(word32 *digest, const word32 *data); + static const char *StaticAlgorithmName() {return "SHA-1";} + +protected: + void Init(); +}; + +typedef SHA SHA1; + +//! implements the SHA-256 standard +class SHA256 : public IteratedHashWithStaticTransform<word32, BigEndian, 64, SHA256> +{ +public: + enum {DIGESTSIZE = 32}; + SHA256() : IteratedHashWithStaticTransform<word32, BigEndian, 64, SHA256>(DIGESTSIZE) {Init();} + static void Transform(word32 *digest, const word32 *data); + static const char *StaticAlgorithmName() {return "SHA-256";} + +protected: + void Init(); + + static const word32 K[64]; +}; + +#ifdef WORD64_AVAILABLE + +//! implements the SHA-512 standard +class SHA512 : public IteratedHashWithStaticTransform<word64, BigEndian, 128, SHA512> +{ +public: + enum {DIGESTSIZE = 64}; + SHA512() : IteratedHashWithStaticTransform<word64, BigEndian, 128, SHA512>(DIGESTSIZE) {Init();} + static void Transform(word64 *digest, const word64 *data); + static const char *StaticAlgorithmName() {return "SHA-512";} + +protected: + void Init(); + + static const word64 K[80]; +}; + +//! implements the SHA-384 standard +class SHA384 : public IteratedHashWithStaticTransform<word64, BigEndian, 128, SHA512> +{ +public: + enum {DIGESTSIZE = 48}; + SHA384() : IteratedHashWithStaticTransform<word64, BigEndian, 128, SHA512>(64) {Init();} + unsigned int DigestSize() const {return DIGESTSIZE;}; + static const char *StaticAlgorithmName() {return "SHA-384";} + +protected: + void Init(); +}; + +#endif + +NAMESPACE_END + +#endif diff --git a/shark.cpp b/shark.cpp new file mode 100644 index 0000000..fff3bfd --- /dev/null +++ b/shark.cpp @@ -0,0 +1,142 @@ +// shark.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifdef WORD64_AVAILABLE + +#include "shark.h" +#include "misc.h" +#include "modes.h" +#include "gf256.h" + +NAMESPACE_BEGIN(CryptoPP) + +static word64 SHARKTransform(word64 a) +{ + static const byte iG[8][8] = { + 0xe7, 0x30, 0x90, 0x85, 0xd0, 0x4b, 0x91, 0x41, + 0x53, 0x95, 0x9b, 0xa5, 0x96, 0xbc, 0xa1, 0x68, + 0x02, 0x45, 0xf7, 0x65, 0x5c, 0x1f, 0xb6, 0x52, + 0xa2, 0xca, 0x22, 0x94, 0x44, 0x63, 0x2a, 0xa2, + 0xfc, 0x67, 0x8e, 0x10, 0x29, 0x75, 0x85, 0x71, + 0x24, 0x45, 0xa2, 0xcf, 0x2f, 0x22, 0xc1, 0x0e, + 0xa1, 0xf1, 0x71, 0x40, 0x91, 0x27, 0x18, 0xa5, + 0x56, 0xf4, 0xaf, 0x32, 0xd2, 0xa4, 0xdc, 0x71, + }; + + word64 result=0; + GF256 gf256(0xf5); + for (unsigned int i=0; i<8; i++) + for(unsigned int j=0; j<8; j++) + result ^= word64(gf256.Multiply(iG[i][j], a>>(56-8*j))) << (56-8*i); + return result; +} + +void SHARK::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int keyLen, unsigned int rounds) +{ + AssertValidKeyLength(keyLen); + AssertValidRounds(rounds); + + m_rounds = rounds; + m_roundKeys.New(m_rounds+1); + + // concatenate key enought times to fill a + for (unsigned int i=0; i<(m_rounds+1)*8; i++) + ((byte *)m_roundKeys.begin())[i] = key[i%keyLen]; + + SHARK::Encryption e; + e.InitForKeySetup(); + byte IV[8] = {0,0,0,0,0,0,0,0}; + CFB_Mode_ExternalCipher::Encryption cfb(e, IV); + + cfb.ProcessString((byte *)m_roundKeys.begin(), (m_rounds+1)*8); + + ConditionalByteReverse(BIG_ENDIAN_ORDER, m_roundKeys.begin(), m_roundKeys.begin(), (m_rounds+1)*8); + + m_roundKeys[m_rounds] = SHARKTransform(m_roundKeys[m_rounds]); + + if (dir == DECRYPTION) + { + unsigned int i; + + // transform encryption round keys into decryption round keys + for (i=0; i<m_rounds/2; i++) + std::swap(m_roundKeys[i], m_roundKeys[m_rounds-i]); + + for (i=1; i<m_rounds; i++) + m_roundKeys[i] = SHARKTransform(m_roundKeys[i]); + } + +#ifdef IS_LITTLE_ENDIAN + m_roundKeys[0] = ByteReverse(m_roundKeys[0]); + m_roundKeys[m_rounds] = ByteReverse(m_roundKeys[m_rounds]); +#endif +} + +// construct an SHARK_Enc object with fixed round keys, to be used to initialize actual round keys +void SHARK::Enc::InitForKeySetup() +{ + m_rounds = DEFAULT_ROUNDS; + m_roundKeys.New(DEFAULT_ROUNDS+1); + + for (unsigned int i=0; i<DEFAULT_ROUNDS; i++) + m_roundKeys[i] = cbox[0][i]; + + m_roundKeys[DEFAULT_ROUNDS] = SHARKTransform(cbox[0][DEFAULT_ROUNDS]); + +#ifdef IS_LITTLE_ENDIAN + m_roundKeys[0] = ByteReverse(m_roundKeys[0]); + m_roundKeys[m_rounds] = ByteReverse(m_roundKeys[m_rounds]); +#endif +} + +typedef word64 ArrayOf256Word64s[256]; + +template <const byte *sbox, const ArrayOf256Word64s *cbox> +struct SharkProcessAndXorBlock{ // VC60 workaround: problem with template functions +inline SharkProcessAndXorBlock(const word64 *roundKeys, unsigned int rounds, const byte *inBlock, const byte *xorBlock, byte *outBlock) +{ + word64 tmp = *(word64 *)inBlock ^ roundKeys[0]; + + ByteOrder order = GetNativeByteOrder(); + tmp = cbox[0][GetByte(order, tmp, 0)] ^ cbox[1][GetByte(order, tmp, 1)] + ^ cbox[2][GetByte(order, tmp, 2)] ^ cbox[3][GetByte(order, tmp, 3)] + ^ cbox[4][GetByte(order, tmp, 4)] ^ cbox[5][GetByte(order, tmp, 5)] + ^ cbox[6][GetByte(order, tmp, 6)] ^ cbox[7][GetByte(order, tmp, 7)] + ^ roundKeys[1]; + + for(unsigned int i=2; i<rounds; i++) + { + tmp = cbox[0][GETBYTE(tmp, 7)] ^ cbox[1][GETBYTE(tmp, 6)] + ^ cbox[2][GETBYTE(tmp, 5)] ^ cbox[3][GETBYTE(tmp, 4)] + ^ cbox[4][GETBYTE(tmp, 3)] ^ cbox[5][GETBYTE(tmp, 2)] + ^ cbox[6][GETBYTE(tmp, 1)] ^ cbox[7][GETBYTE(tmp, 0)] + ^ roundKeys[i]; + } + + PutBlock<byte, BigEndian>(xorBlock, outBlock) + (sbox[GETBYTE(tmp, 7)]) + (sbox[GETBYTE(tmp, 6)]) + (sbox[GETBYTE(tmp, 5)]) + (sbox[GETBYTE(tmp, 4)]) + (sbox[GETBYTE(tmp, 3)]) + (sbox[GETBYTE(tmp, 2)]) + (sbox[GETBYTE(tmp, 1)]) + (sbox[GETBYTE(tmp, 0)]); + + *(word64 *)outBlock ^= roundKeys[rounds]; +}}; + +void SHARK::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + SharkProcessAndXorBlock<sbox, cbox>(m_roundKeys, m_rounds, inBlock, xorBlock, outBlock); +} + +void SHARK::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + SharkProcessAndXorBlock<sbox, cbox>(m_roundKeys, m_rounds, inBlock, xorBlock, outBlock); +} + +NAMESPACE_END + +#endif // WORD64_AVAILABLE @@ -0,0 +1,68 @@ +#ifndef CRYPTOPP_SHARK_H +#define CRYPTOPP_SHARK_H + +/** \file +*/ + +#include "config.h" + +#ifdef WORD64_AVAILABLE + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct SHARK_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 16>, public VariableRounds<6, 2> +{ + static const char *StaticAlgorithmName() {return "SHARK-E";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#SHARK-E">SHARK-E</a> +class SHARK : public SHARK_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<SHARK_Info> + { + public: + void UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length, unsigned int rounds); + + protected: + unsigned int m_rounds; + SecBlock<word64> m_roundKeys; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + // used by Base to do key setup + void InitForKeySetup(); + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef SHARK::Encryption SHARKEncryption; +typedef SHARK::Decryption SHARKDecryption; + +NAMESPACE_END + +#endif +#endif diff --git a/sharkbox.cpp b/sharkbox.cpp new file mode 100644 index 0000000..ff89313 --- /dev/null +++ b/sharkbox.cpp @@ -0,0 +1,4166 @@ +#include "pch.h" +#include "shark.h" + +#ifdef WORD64_AVAILABLE + +NAMESPACE_BEGIN(CryptoPP) + +const byte SHARK::Enc::sbox[256] = { +177, 206, 195, 149, 90, 173, 231, 2, 77, 68, 251, 145, 12, 135, 161, 80, +203, 103, 84, 221, 70, 143, 225, 78, 240, 253, 252, 235, 249, 196, 26, 110, + 94, 245, 204, 141, 28, 86, 67, 254, 7, 97, 248, 117, 89, 255, 3, 34, +138, 209, 19, 238, 136, 0, 14, 52, 21, 128, 148, 227, 237, 181, 83, 35, + 75, 71, 23, 167, 144, 53, 171, 216, 184, 223, 79, 87, 154, 146, 219, 27, + 60, 200, 153, 4, 142, 224, 215, 125, 133, 187, 64, 44, 58, 69, 241, 66, +101, 32, 65, 24, 114, 37, 147, 112, 54, 5, 242, 11, 163, 121, 236, 8, + 39, 49, 50, 182, 124, 176, 10, 115, 91, 123, 183, 129, 210, 13, 106, 38, +158, 88, 156, 131, 116, 179, 172, 48, 122, 105, 119, 15, 174, 33, 222, 208, + 46, 151, 16, 164, 152, 168, 212, 104, 45, 98, 41, 109, 22, 73, 118, 199, +232, 193, 150, 55, 229, 202, 244, 233, 99, 18, 194, 166, 20, 188, 211, 40, +175, 47, 230, 36, 82, 198, 160, 9, 189, 140, 207, 93, 17, 95, 1, 197, +159, 61, 162, 155, 201, 59, 190, 81, 25, 31, 63, 92, 178, 239, 74, 205, +191, 186, 111, 100, 217, 243, 62, 180, 170, 220, 213, 6, 192, 126, 246, 102, +108, 132, 113, 56, 185, 29, 127, 157, 72, 139, 42, 218, 165, 51, 130, 57, +214, 120, 134, 250, 228, 43, 169, 30, 137, 96, 107, 234, 85, 76, 247, 226, +}; + +const byte SHARK::Dec::sbox[256] = { + 53, 190, 7, 46, 83, 105, 219, 40, 111, 183, 118, 107, 12, 125, 54, 139, +146, 188, 169, 50, 172, 56, 156, 66, 99, 200, 30, 79, 36, 229, 247, 201, + 97, 141, 47, 63, 179, 101, 127, 112, 175, 154, 234, 245, 91, 152, 144, 177, +135, 113, 114, 237, 55, 69, 104, 163, 227, 239, 92, 197, 80, 193, 214, 202, + 90, 98, 95, 38, 9, 93, 20, 65, 232, 157, 206, 64, 253, 8, 23, 74, + 15, 199, 180, 62, 18, 252, 37, 75, 129, 44, 4, 120, 203, 187, 32, 189, +249, 41, 153, 168, 211, 96, 223, 17, 151, 137, 126, 250, 224, 155, 31, 210, +103, 226, 100, 119, 132, 43, 158, 138, 241, 109, 136, 121, 116, 87, 221, 230, + 57, 123, 238, 131, 225, 88, 242, 13, 52, 248, 48, 233, 185, 35, 84, 21, + 68, 11, 77, 102, 58, 3, 162, 145, 148, 82, 76, 195, 130, 231, 128, 192, +182, 14, 194, 108, 147, 236, 171, 67, 149, 246, 216, 70, 134, 5, 140, 176, +117, 0, 204, 133, 215, 61, 115, 122, 72, 228, 209, 89, 173, 184, 198, 208, +220, 161, 170, 2, 29, 191, 181, 159, 81, 196, 165, 16, 34, 207, 1, 186, +143, 49, 124, 174, 150, 218, 240, 86, 71, 212, 235, 78, 217, 19, 142, 73, + 85, 22, 255, 59, 244, 164, 178, 6, 160, 167, 251, 27, 110, 60, 51, 205, + 24, 94, 106, 213, 166, 33, 222, 254, 42, 28, 243, 10, 26, 25, 39, 45, +}; + +const word64 SHARK::Enc::cbox[8][256] = { +/* box 0 */ +W64LIT(0x060d838f16f3a365), +W64LIT(0xa68857ee5cae56f6), +W64LIT(0xebf516353c2c4d89), +W64LIT(0x652174be88e85bdc), +W64LIT(0x0d4e9a8086c17921), +W64LIT(0x27ba7d33cffa58a1), +W64LIT(0x88d9e104a237b530), +W64LIT(0x693b8755a4fbe816), +W64LIT(0xdac9591826b254a0), +W64LIT(0x45c2e369fb336af3), +W64LIT(0xa96e1fb87b3e4ef4), +W64LIT(0xb7578f1435eb7ef0), +W64LIT(0x839af80b32056f74), +W64LIT(0xae37f55cc71f277a), +W64LIT(0xa4208538fdff37d5), +W64LIT(0x35991e74ad3cdb6f), +W64LIT(0xba191594b32a07d1), +W64LIT(0x5344d1772e572b7b), +W64LIT(0xe7efe5de103ffe43), +W64LIT(0xa3796fdc41de5e5b), +W64LIT(0x2cf9643c5fc882e5), +W64LIT(0xffdbf6fd48196d22), +W64LIT(0x33949dfbbbcf780a), +W64LIT(0x7d15679dd0cec8bd), +W64LIT(0x5f5e229c024498b1), +W64LIT(0x1223634762c683ce), +W64LIT(0xdcc4da973041f7c5), +W64LIT(0x0b43190f9032da44), +W64LIT(0xc05598eddfc5a6e2), +W64LIT(0x9e5fd31a7753f4b8), +W64LIT(0x9afa8243c0f136fe), +W64LIT(0xcc4f6b06f3d61528), +W64LIT(0xdf38612a3bc25c0d), +W64LIT(0x43cf60e6edc0c996), +W64LIT(0xcfb3d0bbf855bee0), +W64LIT(0x96e071a8ece28534), +W64LIT(0x21b7febcd909fbc4), +W64LIT(0x8ed4628bb4c41655), +W64LIT(0x30682646b04cd3c2), +W64LIT(0xb5ff5dc294ba1fd3), +W64LIT(0x75aac52f4b7fb931), +W64LIT(0xe809ad8837afe641), +W64LIT(0x0eb2213d8d42d2e9), +W64LIT(0x9852509561a057dd), +W64LIT(0xaa92a40570bde53c), +W64LIT(0x7b18e412c63d6bd8), +W64LIT(0xa7dc3e85f67c9c1d), +W64LIT(0xd8618bce87e33583), +W64LIT(0xe34ab487a79d3c05), +W64LIT(0x20e397d773db312f), +W64LIT(0x05f138321d7008ad), +W64LIT(0x17d25b757fb68b63), +W64LIT(0x8a7133d20366d413), +W64LIT(0x0000000000000000), +W64LIT(0xeaa17f5e96fe8762), +W64LIT(0xc101f18675176c09), +W64LIT(0xbebc44cd0488c597), +W64LIT(0xdb9d30738c609e4b), +W64LIT(0xabc6cd6eda6f2fd7), +W64LIT(0x5aaf1aae1f34901c), +W64LIT(0xb00e65f089ca177e), +W64LIT(0xd47b7825abf08649), +W64LIT(0x924520f15b404772), +W64LIT(0x1686321ed5644188), +W64LIT(0x618425e73f4a999a), +W64LIT(0xe21eddec0d4ff6ee), +W64LIT(0xd787c398a0732d81), +W64LIT(0x1f6df9c7e407faef), +W64LIT(0x79b036c4676c0afb), +W64LIT(0x0fe6485627901802), +W64LIT(0x9cf701ccd602959b), +W64LIT(0xbfe82da6ae5a0f7c), +W64LIT(0x990639fecb729d36), +W64LIT(0xca42e889e525b64d), +W64LIT(0xb3f2de4d8249bcb6), +W64LIT(0x4033db5be643625e), +W64LIT(0x4167b2304c91a8b5), +W64LIT(0x108bb191c397e2ed), +W64LIT(0x1834132358269361), +W64LIT(0x541d3b93927642f5), +W64LIT(0x90edf227fa112651), +W64LIT(0x1dc52b1145569bcc), +W64LIT(0xe6bb8cb5baed34a8), +W64LIT(0xd276fbaabd03252c), +W64LIT(0x313c4f2d1a9e1929), +W64LIT(0xfd73242be9480c01), +W64LIT(0x9baeeb286a23fc15), +W64LIT(0xc9be5334eea61d85), +W64LIT(0xc70c720963e4cf6c), +W64LIT(0x3eda077b3d0e012b), +W64LIT(0x97b418c346304fdf), +W64LIT(0x32c0f490111db2e1), +W64LIT(0x2ba08ed8e3e9eb6b), +W64LIT(0x8b255ab9a9b41ef8), +W64LIT(0x91b99b4c50c3ecba), +W64LIT(0xfe8f9f96e2cba7c9), +W64LIT(0x3a7f56228aacc36d), +W64LIT(0xb15a0c9b2318dd95), +W64LIT(0x5953a11314b73bd4), +W64LIT(0xf3c10516640adee8), +W64LIT(0xedf895ba2adfeeec), +W64LIT(0xadcb4ee1cc9c8cb2), +W64LIT(0xde6c0841911096e6), +W64LIT(0x84c312ef8e2406fa), +W64LIT(0xa83a76d3d1ec841f), +W64LIT(0x1c91427aef845127), +W64LIT(0x3665a5c9a6bf70a7), +W64LIT(0xf6303d24797ad645), +W64LIT(0xcd1b026d5904dfc3), +W64LIT(0x1bc8a89e53a538a9), +W64LIT(0x7ee9dc20db4d6375), +W64LIT(0x51ec03a18f064a58), +W64LIT(0xc4f0c9b4686764a4), +W64LIT(0xdd90b3fc9a933d2e), +W64LIT(0x7a4c8d796cefa133), +W64LIT(0x73a746a05d8c1a54), +W64LIT(0x0759eae4bc21698e), +W64LIT(0xc8ea3a5f4474d76e), +W64LIT(0x38d784f42bfda24e), +W64LIT(0x231f2c6a78589ae7), +W64LIT(0xc3a92350d4460d2a), +W64LIT(0x72f32fcbf75ed0bf), +W64LIT(0xbd40ff700f0b6e5f), +W64LIT(0x157a89a3dee7ea40), +W64LIT(0x873fa95285a7ad32), +W64LIT(0x4d7d41db60821b7f), +W64LIT(0x1e3990ac4ed53004), +W64LIT(0x0a1770643ae010af), +W64LIT(0x9311499af1928d99), +W64LIT(0x64751dd5223a9137), +W64LIT(0xfa2acecf5569658f), +W64LIT(0x7c410ef67a1c0256), +W64LIT(0x56b5e945332723d6), +W64LIT(0x6f3604dab2084b73), +W64LIT(0xe95dc4e39d7d2caa), +W64LIT(0x13770a2cc8144925), +W64LIT(0xbc14961ba5d9a4b4), +W64LIT(0xb9e5ae29b8a9ac19), +W64LIT(0xf169d7c0c55bbfcb), +W64LIT(0x2446c68ec479f369), +W64LIT(0x806643b63986c4bc), +W64LIT(0x7fbdb54b719fa99e), +W64LIT(0x04a55159b7a2c246), +W64LIT(0xee042e07215c4524), +W64LIT(0x5bfb73c5b5e65af7), +W64LIT(0x0c1af3eb2c13b3ca), +W64LIT(0xa22d06b7eb0c94b0), +W64LIT(0xb8b1c742127b66f2), +W64LIT(0x285c3565e86a40a3), +W64LIT(0x3b2b3f49207e0986), +W64LIT(0x3c72d5ad9c5f6008), +W64LIT(0x770217f9ea2ed812), +W64LIT(0xfc274d40439ac6ea), +W64LIT(0x4fd5930dc1d37a5c), +W64LIT(0x2e51b6eafe99e3c6), +W64LIT(0x6b93558305aa8935), +W64LIT(0x19607a48f2f4598a), +W64LIT(0x08bfa2b29bb1718c), +W64LIT(0x3f8e6e1097dccbc0), +W64LIT(0x3983ed9f812f68a5), +W64LIT(0xac9f278a664e4659), +W64LIT(0x82ce916098d7a59f), +W64LIT(0xc2fd4a3b7e94c7c1), +W64LIT(0x66ddcf03836bf014), +W64LIT(0xe1e2665106cc5d26), +W64LIT(0x74feac44e1ad73da), +W64LIT(0x8d28d936bf47bd9d), +W64LIT(0x62789e5a34c93252), +W64LIT(0x81322add93540e57), +W64LIT(0xcb1681e24ff77ca6), +W64LIT(0x2512afe56eab3982), +W64LIT(0xd18a4017b6808ee4), +W64LIT(0x705bfd1d560fb19c), +W64LIT(0x4b70c2547671b81a), +W64LIT(0x49d81082d720d939), +W64LIT(0xe0b60f3aac1e97cd), +W64LIT(0x4e81fa666b01b0b7), +W64LIT(0x951cca15e7612efc), +W64LIT(0x463e58d4f0b0c13b), +W64LIT(0x632cf7319e1bf8b9), +W64LIT(0x5ca2992109c73379), +W64LIT(0xf764544fd3a81cae), +W64LIT(0x6ac73ce8af7843de), +W64LIT(0x9f0bba71dd813e53), +W64LIT(0x85977b8424f6cc11), +W64LIT(0x5807c878be65f13f), +W64LIT(0x686fee3e0e2922fd), +W64LIT(0x78e45fafcdbec010), +W64LIT(0x6ccabf67b98be0bb), +W64LIT(0x11dfd8fa69452806), +W64LIT(0xcee7b9d05287740b), +W64LIT(0x50b86aca25d480b3), +W64LIT(0x5df6f04aa315f992), +W64LIT(0x5e0a4bf7a896525a), +W64LIT(0x03fcbbbd0b83abc8), +W64LIT(0x8f800be01e16dcbe), +W64LIT(0xd32292c117d1efc7), +W64LIT(0xe5473708b16e9f60), +W64LIT(0x224b4501d28a500c), +W64LIT(0xfb7ea7a4ffbbaf64), +W64LIT(0x3d26bcc6368daae3), +W64LIT(0x866bc0392f7567d9), +W64LIT(0x3731cca20c6dba4c), +W64LIT(0xb603e67f9f39b41b), +W64LIT(0xa1d1bd0ae08f3f78), +W64LIT(0xd935e2a52d31ff68), +W64LIT(0xaf639c376dcded91), +W64LIT(0x0154696baad2caeb), +W64LIT(0xecacfcd1800d2407), +W64LIT(0xf03dbeab6f897520), +W64LIT(0x02a8d2d6a1516123), +W64LIT(0xf498eff2d82bb766), +W64LIT(0x710f9476fcdd7b77), +W64LIT(0xf8821c19f43804ac), +W64LIT(0xf9d675725eeace47), +W64LIT(0x1a9cc1f5f977f242), +W64LIT(0x5210b81c8485e190), +W64LIT(0x6d9ed60c13592a50), +W64LIT(0xf2956c7dced81403), +W64LIT(0xbb4d7cff19f8cd3a), +W64LIT(0x4c2928b0ca50d194), +W64LIT(0x6e626db118da8198), +W64LIT(0xe4135e631bbc558b), +W64LIT(0x9da368a77cd05f70), +W64LIT(0xa574ec53572dfd3e), +W64LIT(0x09ebcbd93163bb67), +W64LIT(0x4a24ab3fdca372f1), +W64LIT(0x429b098d4712037d), +W64LIT(0x57e1802e99f5e93d), +W64LIT(0xef50476c8b8e8fcf), +W64LIT(0xa085d4614a5df593), +W64LIT(0x34cd771f07ee1184), +W64LIT(0xc6581b62c9360587), +W64LIT(0x2dad0d57f51a480e), +W64LIT(0x898d886f08e57fdb), +W64LIT(0xd6d3aaf30aa1e76a), +W64LIT(0x76567e9240fc12f9), +W64LIT(0xb4ab34a93e68d538), +W64LIT(0xb2a6b726289b765d), +W64LIT(0x8c7cb05d15957776), +W64LIT(0x554952f838a4881e), +W64LIT(0xd52f114e01224ca2), +W64LIT(0x60d04c8c95985371), +W64LIT(0x6789a66829b93aff), +W64LIT(0x2f05df81544b292d), +W64LIT(0x476a31bf5a620bd0), +W64LIT(0xf5cc869972f97d8d), +W64LIT(0x488c79e97df213d2), +W64LIT(0x44968a0251e1a018), +W64LIT(0x26ee14586528924a), +W64LIT(0xd0de297c1c52440f), +W64LIT(0xc5a4a0dfc2b5ae4f), +W64LIT(0x29085c0e42b88a48), +W64LIT(0x142ee0c8743520ab), +W64LIT(0x2af4e7b3493b2180), +W64LIT(0x9448a37e4db3e417), +/* box 1 */ +W64LIT(0xe2795ba105ba30ce), +W64LIT(0x65b5d634f5e0fbdd), +W64LIT(0x2d7d7f1464dd8c55), +W64LIT(0xeefbf778add1c20b), +W64LIT(0x1eb0fbd1f11968e7), +W64LIT(0xe6073f45ce30cd8d), +W64LIT(0x21ffd3cdccb67e90), +W64LIT(0xdf0941cfa750a262), +W64LIT(0xc61df5b1b75ef18a), +W64LIT(0xc5c7defa9dc337c6), +W64LIT(0x2581b729073c83d3), +W64LIT(0xa5e97513167173cf), +W64LIT(0xdd3673bd381526b9), +W64LIT(0xe8baa1eef91ebb93), +W64LIT(0x3b314cf8f625eb34), +W64LIT(0x579d4bc8d5fc5df8), +W64LIT(0xbb598ec2e7681b28), +W64LIT(0xc8a06b1a80708794), +W64LIT(0x1c8fc9a36e5cec3c), +W64LIT(0xf60a5a3f0807d374), +W64LIT(0x1ace9f353a9395a4), +W64LIT(0x7e9e50387aab2cee), +W64LIT(0xb5e41069d0466d36), +W64LIT(0x8cea6ee3b92602d9), +W64LIT(0xf952ddad8af1e7fd), +W64LIT(0xb19a748d1bcc9075), +W64LIT(0x2464ae10b2e4c144), +W64LIT(0xfcc9a070f4a35829), +W64LIT(0xfa88f6e6a06c21b1), +W64LIT(0x2c98662dd105cec2), +W64LIT(0x9065a740d77aeee5), +W64LIT(0xcb7a4051aaed41d8), +W64LIT(0x55a279ba4ab9d923), +W64LIT(0x27be855b98790708), +W64LIT(0xbabc97fb52b059bf), +W64LIT(0xa19711f7ddfb8e8c), +W64LIT(0x047e64e4cb8afd43), +W64LIT(0xc386886cc90c4e5e), +W64LIT(0xc422c7c3281b7551), +W64LIT(0xfb6defdf15b46326), +W64LIT(0x01e51939b5d84297), +W64LIT(0x5cbba8be9c809432), +W64LIT(0x6f762c7b09447080), +W64LIT(0xcee13d8cd4bffe0c), +W64LIT(0x54476083ff619bb4), +W64LIT(0x6e933542bc9c3217), +W64LIT(0x4af79b520e78f353), +W64LIT(0x98996f7db49be163), +W64LIT(0xa07208ce6823cc1b), +W64LIT(0x2b3c29823012f5cd), +W64LIT(0x93bf8c0bfde728a9), +W64LIT(0x2225f886e62bb8dc), +W64LIT(0x7f7b4901cf736e79), +W64LIT(0x0000000000000000), +W64LIT(0x023f32729f4584db), +W64LIT(0xd5cabb805bf4293f), +W64LIT(0x07a44fafe1173b0f), +W64LIT(0xe95fb8d74cc6f904), +W64LIT(0x7b052de504f9933a), +W64LIT(0x6aed51a67716cf54), +W64LIT(0x68d263d4e8534b8f), +W64LIT(0xa96bd9cabe1a810a), +W64LIT(0x1d6ad09adb84aeab), +W64LIT(0x0d67b5e01db3b052), +W64LIT(0x52063615abaee22c), +W64LIT(0x8f3045a893bbc495), +W64LIT(0xd8ad0e604647996d), +W64LIT(0xaf2a8f5cead5f892), +W64LIT(0x3017af8ebf5922fe), +W64LIT(0x4034611df2dc780e), +W64LIT(0x721cfce1d2c0de2b), +W64LIT(0x28e602c91a8f3381), +W64LIT(0xe1a370ea2f27f682), +W64LIT(0x29031bf0af577116), +W64LIT(0x1914b47e100e53e8), +W64LIT(0x567852f160241f6f), +W64LIT(0x793a1f979bbc17e1), +W64LIT(0xef1eee411809809c), +W64LIT(0x6211999b14f7c0d2), +W64LIT(0x059b7ddd7e52bfd4), +W64LIT(0x43ee4a56d841be42), +W64LIT(0xf1ae1590e910e87b), +W64LIT(0x33cd84c595c4e4b2), +W64LIT(0x4b12826bbba0b1c4), +W64LIT(0xeb608aa5d3837ddf), +W64LIT(0x201acaf4796e3c07), +W64LIT(0xbf27ea262ce2e66b), +W64LIT(0x58c5cc5a570a6971), +W64LIT(0x37b3e0215e4e19f1), +W64LIT(0xab54ebb8215f05d1), +W64LIT(0x8ed55c9126638602), +W64LIT(0x9aa65d0f2bde65b8), +W64LIT(0xd7f589f2c4b1ade4), +W64LIT(0x5039046734eb66f7), +W64LIT(0x6cac073023d9b6cc), +W64LIT(0x51dc1d5e81332460), +W64LIT(0x17a92ad5272025f6), +W64LIT(0x47902eb213cb4301), +W64LIT(0x1b2b860c8f4bd733), +W64LIT(0x4f6ce68f702a4c87), +W64LIT(0xcf0424b56167bc9b), +W64LIT(0x997c76440143a3f4), +W64LIT(0x7ae034dcb121d1ad), +W64LIT(0x100d657ac6371ef9), +W64LIT(0x0ac3fa4ffca48b5d), +W64LIT(0xdeec58f61288e0f5), +W64LIT(0x265b9c622da1459f), +W64LIT(0xdcd36a848dcd642e), +W64LIT(0xe4380d3751754956), +W64LIT(0x13d74e31ecaad8b5), +W64LIT(0xfd2cb949417b1abe), +W64LIT(0x9624f1d683b5977d), +W64LIT(0x4675378ba6130196), +W64LIT(0x0b26e376497cc9ca), +W64LIT(0x41d1782447043a99), +W64LIT(0xe39c4298b0627259), +W64LIT(0xcd3b16c7fe223840), +W64LIT(0x7787813cac9261ff), +W64LIT(0x492db01924e5351f), +W64LIT(0x5afafe28c84fedaa), +W64LIT(0x8b4e214c583139d6), +W64LIT(0xccde0ffe4bfa7ad7), +W64LIT(0x76629805194a2368), +W64LIT(0x7ca1624ae5eea835), +W64LIT(0x61cbb2d03e6a069e), +W64LIT(0x48c8a920913d7788), +W64LIT(0x8068c23a114df01c), +W64LIT(0xd38bed160f3b50a7), +W64LIT(0x32289dfc201ca625), +W64LIT(0xc1b9ba1e5649ca85), +W64LIT(0xed21dc33874c0447), +W64LIT(0xa3a8238542be0a57), +W64LIT(0x5b1fe7117d97af3d), +W64LIT(0x3d701a6ea2ea92ac), +W64LIT(0x73f9e5d867189cbc), +W64LIT(0x9ed839ebe05498fb), +W64LIT(0x5920d563e2d22be6), +W64LIT(0xca9f59681f35034f), +W64LIT(0x11e87c4373ef5c6e), +W64LIT(0x97c1e8ef366dd5ea), +W64LIT(0xacf0a417c0483ede), +W64LIT(0xd26ef42fbae31230), +W64LIT(0xbcfdc16d067f2027), +W64LIT(0xbec2f31f993aa4fc), +W64LIT(0x45af1cc08c8ec7da), +W64LIT(0x31f2b6b70a816069), +W64LIT(0xd9481759f39fdbfa), +W64LIT(0xe5dd140ee4ad0bc1), +W64LIT(0xa6335e583cecb583), +W64LIT(0x38eb67b3dcb82d78), +W64LIT(0xf5d07174229a1538), +W64LIT(0x5f6183f5b61d527e), +W64LIT(0x0f58879282f63489), +W64LIT(0x164c33ec92f86761), +W64LIT(0x444a05f93956854d), +W64LIT(0x818ddb03a495b28b), +W64LIT(0x4d53d4fdef6fc85c), +W64LIT(0x8d0f77da0cfe404e), +W64LIT(0x8416a6dedac70d5f), +W64LIT(0x666ffd7fdf7d3d91), +W64LIT(0xb63e3b22fadbab7a), +W64LIT(0xf2743edbc38d2e37), +W64LIT(0xa40c6c2aa3a93158), +W64LIT(0x9f3d20d2558cda6c), +W64LIT(0xfef692026be6dcf2), +W64LIT(0x2ea7545f4e404a19), +W64LIT(0xb2405fc631515639), +W64LIT(0x23c0e1bf53f3fa4b), +W64LIT(0x83b2e9713bd03650), +W64LIT(0x0641569654cf7998), +W64LIT(0xb883a589cdf5dd64), +W64LIT(0x3ad455c143fda9a3), +W64LIT(0x925a9532483f6a3e), +W64LIT(0xaab1f28194874746), +W64LIT(0xf435684d974257af), +W64LIT(0xd1b4df64907ed47c), +W64LIT(0x390e7e8a69606fef), +W64LIT(0xd051c65d25a696eb), +W64LIT(0xb4010950659e2fa1), +W64LIT(0x0c82acd9a86bf2c5), +W64LIT(0x88940a0772acff9a), +W64LIT(0xf39127e276556ca0), +W64LIT(0xaecf96655f0dba05), +W64LIT(0x03da2b4b2a9dc64c), +W64LIT(0x3f4f281c3daf1677), +W64LIT(0x3469cb6a74d3dfbd), +W64LIT(0xf04b0ca95cc8aaec), +W64LIT(0x1f55e2e844c12a70), +W64LIT(0x4cb6cdc45ab78acb), +W64LIT(0xc05ca327e3918812), +W64LIT(0x95feda9da9285131), +W64LIT(0xb966bcb0782d9ff3), +W64LIT(0xa7d647618934f714), +W64LIT(0xd61090cb7169ef73), +W64LIT(0x71c6d7aaf85d1867), +W64LIT(0xecc4c50a329446d0), +W64LIT(0x6450cf0d4038b94a), +W64LIT(0x420b536f6d99fcd5), +W64LIT(0x75b8b34e33d7e524), +W64LIT(0xc26391557cd40cc9), +W64LIT(0xda923c12d9021db6), +W64LIT(0x4e89ffb6c5f20e10), +W64LIT(0x0919d104d6394d11), +W64LIT(0x8aab3875ede97b41), +W64LIT(0xa88ec0f30bc2c39d), +W64LIT(0xb7db221b4f03e9ed), +W64LIT(0xc7f8ec880286b31d), +W64LIT(0x2f424d66fb98088e), +W64LIT(0xe04669d39affb415), +W64LIT(0x3eaa3125887754e0), +W64LIT(0x5e849acc03c510e9), +W64LIT(0x8257f0488e0874c7), +W64LIT(0xbd18d854b3a762b0), +W64LIT(0xb3a546ff848914ae), +W64LIT(0x9ce70b997f111c20), +W64LIT(0x3c9503571732d03b), +W64LIT(0xe7e2267c7be88f1a), +W64LIT(0x63f480a2a12f8245), +W64LIT(0x602eabe98bb24409), +W64LIT(0x941bc3a41cf013a6), +W64LIT(0x678ae4466aa57f06), +W64LIT(0x1232570859729a22), +W64LIT(0x6d491e099601f45b), +W64LIT(0x5d5eb1872958d6a5), +W64LIT(0x1473019e0dbde3ba), +W64LIT(0xa24d3abcf76648c0), +W64LIT(0x85f3bfe76f1f4fc8), +W64LIT(0x08fcc83d63e10f86), +W64LIT(0x745daa77860fa7b3), +W64LIT(0x9180be7962a2ac72), +W64LIT(0x87cc8d95f05acb13), +W64LIT(0x78df06ae2e645576), +W64LIT(0x18f1ad47a5d6117f), +W64LIT(0x358cd253c10b9d2a), +W64LIT(0x0ebd9eab372e761e), +W64LIT(0xf7ef4306bddf91e3), +W64LIT(0x7023ce934d855af0), +W64LIT(0xd42fa2b9ee2c6ba8), +W64LIT(0x3656f918eb965b66), +W64LIT(0x9d0212a0cac95eb7), +W64LIT(0x2ad930bb85cab75a), +W64LIT(0x862994ac45828984), +W64LIT(0x7d447b735036eaa2), +W64LIT(0xb07f6db4ae14d2e2), +W64LIT(0x6b08489fc2ce8dc3), +W64LIT(0x9b4344369e06272f), +W64LIT(0xad15bd2e75907c49), +W64LIT(0xdb77252b6cda5f21), +W64LIT(0xea85939c665b3f48), +W64LIT(0xc945722335a8c503), +W64LIT(0x159618a7b865a12d), +W64LIT(0x69377aed5d8b0918), +W64LIT(0x8971133ec774bd0d), +W64LIT(0x53e32f2c1e76a0bb), +W64LIT(0xf8b7c4943f29a56a), +W64LIT(0xff138b3bde3e9e65), +/* box 2 */ +W64LIT(0x7c6a2eb5fdabecc6), +W64LIT(0x401cda0a752bbea0), +W64LIT(0x1925217156dc57c4), +W64LIT(0x56dec6d301d70787), +W64LIT(0x41c751ff73c6ac58), +W64LIT(0xc9067697a92cb5f9), +W64LIT(0x3391c917aaa0bc85), +W64LIT(0xae0a9a4c0e742afe), +W64LIT(0xaa8ca972162a62f4), +W64LIT(0x5aa193912935df99), +W64LIT(0x86fd9135fe27e5ba), +W64LIT(0xffca074b1d3f538e), +W64LIT(0x0e3cb65d24cdfc1b), +W64LIT(0x4384b2e07fe9885d), +W64LIT(0xc73ac0ca8de149e2), +W64LIT(0x48e5bc7645972eb4), +W64LIT(0xbe0d56b46ef9ffd6), +W64LIT(0x200e6d05c0ef5f50), +W64LIT(0xe1f17dee597f7abd), +W64LIT(0x0243e31f0c2f2405), +W64LIT(0xf4ab09dd2741f567), +W64LIT(0xe4acc52547cc204f), +W64LIT(0x348f92c3b83cc272), +W64LIT(0x53837e181f645d75), +W64LIT(0xd8da319acf4c7229), +W64LIT(0x81e3cae1ecbb9b4d), +W64LIT(0xd6e687c7eb818e32), +W64LIT(0x3dad7f4a8e6d409e), +W64LIT(0x28f70b79f053cf44), +W64LIT(0x493e3783437a3c4c), +W64LIT(0xb27203f6461b27c8), +W64LIT(0xd02357e6fff0e23d), +W64LIT(0xe8d390676f2ef851), +W64LIT(0x26cbbd24d49e335f), +W64LIT(0xee1640467b5f945e), +W64LIT(0x4aa65f6949b80ab1), +W64LIT(0xb56c58225487593f), +W64LIT(0x4ffbe7a2570b5043), +W64LIT(0x0aba85633c93b411), +W64LIT(0x78ec1d8be5f5a4cc), +W64LIT(0x501b16f215a66b88), +W64LIT(0x271036d1d27321a7), +W64LIT(0x7ff2465ff769da3b), +W64LIT(0x35541936bed1d08a), +W64LIT(0xb8c886957a8893d9), +W64LIT(0x2fe950ade2cfb1b3), +W64LIT(0xf90fd76a094e3f81), +W64LIT(0x2daab3b2eee095b6), +W64LIT(0x1abd499b5c1e6139), +W64LIT(0x0c7f554228e2d81e), +W64LIT(0x425f391579049aa5), +W64LIT(0xc3bcf3f495bf01e8), +W64LIT(0xb4b7d3d7526a4bc7), +W64LIT(0x0000000000000000), +W64LIT(0xa0362c112ab9d6e5), +W64LIT(0x91e406198c364e65), +W64LIT(0x454162c16b98e452), +W64LIT(0x139fa4126a4fe3d5), +W64LIT(0x01db8bf506ed12f8), +W64LIT(0x9a85088fb648e88c), +W64LIT(0x3ab3249e9cf13e69), +W64LIT(0xd57eef2de143b8cf), +W64LIT(0xb1ea6b1c4cd91135), +W64LIT(0x7aaffe94e9da80c9), +W64LIT(0xad92f2a604b61c03), +W64LIT(0xa3ae44fb207be018), +W64LIT(0xeb4bf88d65ecceac), +W64LIT(0xc0249b1e9f7d3715), +W64LIT(0xa8cf4a6d1a0546f1), +W64LIT(0xc6e14b3f8b0c5b1a), +W64LIT(0xce182d43bbb0cb0e), +W64LIT(0xfc526fa117fd6573), +W64LIT(0x8c471456c2b451ab), +W64LIT(0xac497953025b0efb), +W64LIT(0x0486333e185e480a), +W64LIT(0x18feaa845031453c), +W64LIT(0xa1eda7e42c54c41d), +W64LIT(0x06c5d02114716c0f), +W64LIT(0x055db8cb1eb35af2), +W64LIT(0xe5774ed0412132b7), +W64LIT(0x36cc71dcb413e677), +W64LIT(0x470281de67b7c057), +W64LIT(0x58e2708e251afb9c), +W64LIT(0xa914c1981ce85409), +W64LIT(0xb3a9880340f63530), +W64LIT(0x638adfe5bf06d70d), +W64LIT(0x0b610e963a7ea6e9), +W64LIT(0x927c6ef386f47898), +W64LIT(0xed8e28ac719da2a3), +W64LIT(0x7548c33ccbfa6e2a), +W64LIT(0xf3b5520935dd8b90), +W64LIT(0x8d9c9fa3c4594353), +W64LIT(0x31d22a08a68f9880), +W64LIT(0x0da4deb72e0fcae6), +W64LIT(0x8fdf7cbcc8766756), +W64LIT(0x5dbfc8453ba9a16e), +W64LIT(0x8e04f749ce9b75ae), +W64LIT(0x83a029fee094bf48), +W64LIT(0xa4b01f2f32e79eef), +W64LIT(0x1c7899ba486f0d36), +W64LIT(0x654f0fc4ab77bb02), +W64LIT(0x7db1a540fb46fe3e), +W64LIT(0x51c09d07134b7970), +W64LIT(0xcb459588a50391fc), +W64LIT(0x3fee9c558242649b), +W64LIT(0xfe118cbe1bd24176), +W64LIT(0x76d0abd6c13858d7), +W64LIT(0x5e27a0af316b9793), +W64LIT(0x69305a868395631c), +W64LIT(0x3b68af6b9a1c2c91), +W64LIT(0x6db669b89bcb2b16), +W64LIT(0xa72877c53825a812), +W64LIT(0xd3bb3f0cf532d4c0), +W64LIT(0x6ff58aa797e40f13), +W64LIT(0x96fa5dcd9eaa3092), +W64LIT(0x2c713847e80d874e), +W64LIT(0xc57923d581ce6de7), +W64LIT(0x2b6f6393fa91f9b9), +W64LIT(0x0922ed89365182ec), +W64LIT(0x324a42e2ac4dae7d), +W64LIT(0x16c21cd974fcb927), +W64LIT(0x956235279468066f), +W64LIT(0x7b747561ef379231), +W64LIT(0x449ae9346d75f6aa), +W64LIT(0xf570822821ace79f), +W64LIT(0x5939fb7b23f7e964), +W64LIT(0x7937967ee318b634), +W64LIT(0x84be722af208c1bf), +W64LIT(0x08f9667c30bc9014), +W64LIT(0xefcdcbb37db286a6), +W64LIT(0xa6f3fc303ec8baea), +W64LIT(0xea9073786301dc54), +W64LIT(0x62515410b9ebc5f5), +W64LIT(0xd260b4f9f3dfc638), +W64LIT(0x9e033bb1ae16a086), +W64LIT(0x38f0c78190de1a6c), +W64LIT(0xc267780193521310), +W64LIT(0x80384114ea5689b5), +W64LIT(0x9b5e837ab0a5fa74), +W64LIT(0xf73361372d83c39a), +W64LIT(0x3009a1fda0628a78), +W64LIT(0xd4a564d8e7aeaa37), +W64LIT(0xfb4c347505611b84), +W64LIT(0x5b7a18642fd8cd61), +W64LIT(0x239605efca2d69ad), +W64LIT(0xf8d45c9f0fa32d79), +W64LIT(0xbb50ee7f704aa524), +W64LIT(0x392b4c7496330894), +W64LIT(0x0fe73da82220eee3), +W64LIT(0x3717fa29b2fef48f), +W64LIT(0xf26ed9fc33309968), +W64LIT(0xd73d0c32ed6c9cca), +W64LIT(0xda99d285c363562c), +W64LIT(0xde1fe1bbdb3d1e26), +W64LIT(0x738d131ddf8b0225), +W64LIT(0x292c808cf6beddbc), +W64LIT(0xbc4eb5ab62d6dbd3), +W64LIT(0x039868ea0ac236fd), +W64LIT(0xcc5bce5cb79fef0b), +W64LIT(0xb031e0e94a3403cd), +W64LIT(0xc4a2a82087237f1f), +W64LIT(0xb72fbb3d58a87d3a), +W64LIT(0xafd111b908993806), +W64LIT(0x68ebd173857871e4), +W64LIT(0x9d9b535ba4d4967b), +W64LIT(0xe9081b9269c3eaa9), +W64LIT(0x71cef002d3a42620), +W64LIT(0x93a7e50680196a60), +W64LIT(0x891aac9ddc070b59), +W64LIT(0x155a74337e3e8fda), +W64LIT(0x4e206c5751e642bb), +W64LIT(0x9721d6389847226a), +W64LIT(0x12442fe76ca2f12d), +W64LIT(0x2553d5cede5c05a2), +W64LIT(0xa275cf0e2696f2e0), +W64LIT(0x24885e3bd8b1175a), +W64LIT(0x670cecdba7589f07), +W64LIT(0x749348c9cd177cd2), +W64LIT(0x64948431ad9aa9fa), +W64LIT(0x2ab4e866fc7ceb41), +W64LIT(0xe6ef263a4be3044a), +W64LIT(0xe734adcf4d0e16b2), +W64LIT(0x903f8dec8adb5c9d), +W64LIT(0xf02d3ae33f1fbd6d), +W64LIT(0x725698e8d96610dd), +W64LIT(0x1da3124f4e821fce), +W64LIT(0x1719972c7211abdf), +W64LIT(0x11dc470d6660c7d0), +W64LIT(0xec55a3597770b05b), +W64LIT(0xbfd6dd416814ed2e), +W64LIT(0x57054d26073a157f), +W64LIT(0x1e3b7aa544402933), +W64LIT(0x5ffc2b5a3786856b), +W64LIT(0x61c93cfab329f308), +W64LIT(0x3e3517a084af7663), +W64LIT(0xf6e8eac22b6ed162), +W64LIT(0x1007ccf8608dd528), +W64LIT(0x66d7672ea1b58dff), +W64LIT(0x8b594f82d0282f5c), +W64LIT(0x1fe0f15042ad3bcb), +W64LIT(0x4b7dd49c4f551849), +W64LIT(0x4c638f485dc966be), +W64LIT(0xcfc3a6b6bd5dd9f6), +W64LIT(0x46d90a2b615ad2af), +W64LIT(0x8565f9dff4e5d347), +W64LIT(0x94b9bed292851497), +W64LIT(0xfa97bf80038c097c), +W64LIT(0xb9130d607c658121), +W64LIT(0xdc5c02a4d7123a23), +W64LIT(0x224d8e1accc07b55), +W64LIT(0x87261ac0f8caf742), +W64LIT(0xd901ba6fc9a160d1), +W64LIT(0xab57228710c7700c), +W64LIT(0x21d5e6f0c6024da8), +W64LIT(0x98c6eb90ba67cc89), +W64LIT(0x827ba20be679adb0), +W64LIT(0x991d6065bc8ade71), +W64LIT(0x5546ae390b15317a), +W64LIT(0xa56b94da340a8c17), +W64LIT(0x071e5bd4129c7ef7), +W64LIT(0xe02af61b5f926845), +W64LIT(0x6b73b9998fba4719), +W64LIT(0xdfc46a4eddd00cde), +W64LIT(0x770b2023c7d54a2f), +W64LIT(0x7e29cdaaf184c8c3), +W64LIT(0xba8b658a76a7b7dc), +W64LIT(0x9c40d8aea2398483), +W64LIT(0x9fd8b044a8fbb27e), +W64LIT(0xdb425970c58e44d4), +W64LIT(0xe269150453bd4c40), +W64LIT(0x3c76f4bf88805266), +W64LIT(0xf1f6b11639f2af95), +W64LIT(0x549d25cc0df82382), +W64LIT(0x4db804bd5b247446), +W64LIT(0x8a82c477d6c53da4), +W64LIT(0x5258f5ed19894f8d), +W64LIT(0x6e2e015291091deb), +W64LIT(0xc1ff10eb999025ed), +W64LIT(0xbd953e5e643bc92b), +W64LIT(0xc8ddfd62afc1a701), +W64LIT(0x5c6443b03d44b396), +W64LIT(0x6c6de24d9d2639ee), +W64LIT(0x1481ffc678d39d22), +W64LIT(0xd1f8dc13f91df0c5), +W64LIT(0xca9e1e7da3ee8304), +W64LIT(0xdd878951d1ff28db), +W64LIT(0x6012b70fb5c4e1f0), +W64LIT(0x1b66c26e5af373c1), +W64LIT(0xe3b29ef155505eb8), +W64LIT(0x70157bf7d54934d8), +W64LIT(0x2e32db58e422a34b), +W64LIT(0x6aa8326c895755e1), +W64LIT(0xb6f430c85e456fc2), +W64LIT(0xfd89e4541110778b), +W64LIT(0x88c12768daea19a1), +W64LIT(0xcd8045a9b172fdf3), +/* box 3 */ +W64LIT(0x99183e616655b742), +W64LIT(0xb2872032a50d6860), +W64LIT(0x0946f63b060528ef), +W64LIT(0x36612b9a141ef07d), +W64LIT(0x0634da84dd49579b), +W64LIT(0xfc9c9e9b486c8a57), +W64LIT(0xa63fe3c0744e6fd0), +W64LIT(0xf1515758d8b46bf9), +W64LIT(0x3e82559fcd5197ff), +W64LIT(0x92e12d262bc40177), +W64LIT(0xc3bb433a5a7752c5), +W64LIT(0x21c3852a5183267a), +W64LIT(0x39130725cf528f09), +W64LIT(0x9ba7db1d2dc12998), +W64LIT(0xc58f99be873e055e), +W64LIT(0xd9d424498f32656c), +W64LIT(0x27f75fae8cca71e1), +W64LIT(0x59b91019a8fc3430), +W64LIT(0xce768af9caafb36b), +W64LIT(0x9d930199f0887e03), +W64LIT(0x63b07a7ef3706a8e), +W64LIT(0xb5167288a70e7096), +W64LIT(0x40cc1a28e967d22e), +W64LIT(0x4d01d3eb79bf3380), +W64LIT(0x9e896cdb6456afb4), +W64LIT(0x2548bad2c75eef3b), +W64LIT(0xa79a6bfeab0420bd), +W64LIT(0x9f2ce4e5bb1ce0d9), +W64LIT(0x32ea146282c3393c), +W64LIT(0x6d67defff7765a97), +W64LIT(0x83775912b31080eb), +W64LIT(0xf5da68a04e69a2b8), +W64LIT(0x1196743498d4819c), +W64LIT(0x0bf913474d91b635), +W64LIT(0x43d6776a7db90399), +W64LIT(0x444725d07fba1b6f), +W64LIT(0x6584a0fa2e393d15), +W64LIT(0x3f27dda1121bd892), +W64LIT(0xf6c005e2dab7730f), +W64LIT(0x56cb3ca673b04b44), +W64LIT(0x642128c4f1737278), +W64LIT(0xbf4ae9f135d589ce), +W64LIT(0xb038c54eee99f6ba), +W64LIT(0xf47fe09e9123edd5), +W64LIT(0x75b75cf069a7f3e4), +W64LIT(0xd419ed8a1fea84c2), +W64LIT(0x73838674b4eea47f), +W64LIT(0x498aec13ef62fac1), +W64LIT(0x20660d148ec96917), +W64LIT(0xa48006bc3fdaf10a), +W64LIT(0x2f1421ab55851663), +W64LIT(0x0a5c9b7992dbf958), +W64LIT(0xd1375a4c567d02ee), +W64LIT(0x0000000000000000), +W64LIT(0xc842507d17e6e4f0), +W64LIT(0xf3eeb2249320f523), +W64LIT(0xc9e7d843c8acab9d), +W64LIT(0xff86f3d9dcb25be0), +W64LIT(0xb4b3fab678443ffb), +W64LIT(0xb19d4d7031d3b9d7), +W64LIT(0x79df1d0d26355d27), +W64LIT(0x8eba90d123c86145), +W64LIT(0xaa57a23d3bdcc113), +W64LIT(0xcb583d3f83383547), +W64LIT(0xd871ac7750782a01), +W64LIT(0xe162ab529f2aa508), +W64LIT(0x38b68f1b1018c064), +W64LIT(0x237c60561a17b8a0), +W64LIT(0xa31154063dd9e9fc), +W64LIT(0x713c6308ff7a3aa5), +W64LIT(0x1a6f6773d54537a9), +W64LIT(0x08e37e05d94f6782), +W64LIT(0x357b46d880c021ca), +W64LIT(0x6cc256c1283c15fa), +W64LIT(0xcfd302c715e5fc06), +W64LIT(0xbdf50c8d7e411714), +W64LIT(0x7cf1aacb6fa2db0b), +W64LIT(0x5240035ee56d8205), +W64LIT(0x7b60f8716da1c3fd), +W64LIT(0x01a5883edf4a4f6d), +W64LIT(0xdd5f1bb119efac2d), +W64LIT(0x5474d9da3824d59e), +W64LIT(0x0f722cbfdb4c7f74), +W64LIT(0x17a2aeb0459dd607), +W64LIT(0x37c4a3a4cb54bf10), +W64LIT(0xc21ecb04853d1da8), +W64LIT(0x4273ff54a2f34cf4), +W64LIT(0xdace490b1becb4db), +W64LIT(0x6af68c45f5754261), +W64LIT(0x46f8c0ac342e85b5), +W64LIT(0x854383966e59d770), +W64LIT(0x81c8bc6ef8841e31), +W64LIT(0x3bace25984c611d3), +W64LIT(0x1033fc0a479ecef1), +W64LIT(0x1c5bbdf7080c6032), +W64LIT(0x7412d4ceb6edbc89), +W64LIT(0xa8e8474170485fc9), +W64LIT(0xb8dbbb4b37d69138), +W64LIT(0x079152ba020318f6), +W64LIT(0x72260e4a6ba4eb12), +W64LIT(0x905ec85a60509fad), +W64LIT(0x2dabc4d71e1188b9), +W64LIT(0xd092d27289374d83), +W64LIT(0x610f9f02b8e4f454), +W64LIT(0x02bfe57c4b949eda), +W64LIT(0x95707f9c29c71981), +W64LIT(0x6fd83b83bce2c44d), +W64LIT(0x5d322fe13e21fd71), +W64LIT(0x34decee65f8a6ea7), +W64LIT(0xcd6ce7bb5e7162dc), +W64LIT(0xfb0dcc214a6f92a1), +W64LIT(0x2eb1a9958acf590e), +W64LIT(0xdcfa938fc6a5e340), +W64LIT(0x669ecdb8bae7eca2), +W64LIT(0x151d4bcc0e0948dd), +W64LIT(0xfd3916a59726c53a), +W64LIT(0x581c982777b67b5d), +W64LIT(0x1bcaef4d0a0f78c4), +W64LIT(0xdfe0fecd527b32f7), +W64LIT(0x128c19760c0a502b), +W64LIT(0x84e60ba8b113981d), +W64LIT(0x3c3db0e386c50925), +W64LIT(0x7febc789fb7c0abc), +W64LIT(0x7d5422f5b0e89466), +W64LIT(0xd70380c88b345575), +W64LIT(0xbbc1d609a308408f), +W64LIT(0xe278c6100bf474bf), +W64LIT(0x5e2842a3aaff2cc6), +W64LIT(0x6b53047b2a3f0d0c), +W64LIT(0xf7658ddc05fd3c62), +W64LIT(0x9a025323f28b66f5), +W64LIT(0x8c0575ad685cff9f), +W64LIT(0x76ad31b2fd792253), +W64LIT(0x68496939bee1dcbb), +W64LIT(0x7e4e4fb7243645d1), +W64LIT(0xe44c1c94d6bd2324), +W64LIT(0xbeef61cfea9fc6a3), +W64LIT(0x91fb4064bf1ad0c0), +W64LIT(0x052eb7c64997862c), +W64LIT(0x4a9081517bbc2b76), +W64LIT(0x8f1f18effc822e28), +W64LIT(0x3a096a675b8c5ebe), +W64LIT(0xee1087ed4466da7c), +W64LIT(0x2652d79053803e8c), +W64LIT(0x7099eb36203075c8), +W64LIT(0xc7307cc2ccaa9b84), +W64LIT(0x5c97a7dfe16bb21c), +W64LIT(0x50ffe622aef91cdf), +W64LIT(0x8da0fd93b716b0f2), +W64LIT(0x69ece10761ab93d6), +W64LIT(0x31f07920161de88b), +W64LIT(0x13299148d3401f46), +W64LIT(0x031a6d4294ded1b7), +W64LIT(0xccc96f85813b2db1), +W64LIT(0x14b8c3f2d14307b0), +W64LIT(0x8659eed4fa8706c7), +W64LIT(0xba645e377c420fe2), +W64LIT(0x2920fb2f88cc41f8), +W64LIT(0x87fc66ea25cd49aa), +W64LIT(0x1ee4588b4398fee8), +W64LIT(0xecaf62910ff244a6), +W64LIT(0xf817a163deb14316), +W64LIT(0x45e2adeea0f05402), +W64LIT(0x806d345027ce515c), +W64LIT(0x576eb498acfa0429), +W64LIT(0xa5258e82e090be67), +W64LIT(0x892bc26b21cb79b3), +W64LIT(0x6e7db3bd63a88b20), +W64LIT(0x4e1bbea9ed61e237), +W64LIT(0xadc6f08739dfd9e5), +W64LIT(0x8b9427176a5fe769), +W64LIT(0xa1aeb17a764d7726), +W64LIT(0x4b35096fa4f6641b), +W64LIT(0x22d9e868c55df7cd), +W64LIT(0x55d151e4e76e9af3), +W64LIT(0x966a12debd19c836), +W64LIT(0x0dcdc9c390d8e1ae), +W64LIT(0xf24b3a1a4c6aba4e), +W64LIT(0x24ed32ec1814a056), +W64LIT(0xaf7915fb724b473f), +W64LIT(0x2885731157860e95), +W64LIT(0x9c3689a72fc2316e), +W64LIT(0x475d4892eb64cad8), +W64LIT(0xac6378b9e6959688), +W64LIT(0xa00b3944a907384b), +W64LIT(0xc695f4fc13e0d4e9), +W64LIT(0x3055f11ec957a7e6), +W64LIT(0x6215f2402c3a25e3), +W64LIT(0xde4576f38d317d9a), +W64LIT(0x9344a518f48e4e1a), +W64LIT(0x82d2d12c6c5acf86), +W64LIT(0xefb50fd39b2c9511), +W64LIT(0xe981d5574665c28a), +W64LIT(0x5f8dca9d75b563ab), +W64LIT(0xb60c1fca33d0a121), +W64LIT(0xfe237be703f8148d), +W64LIT(0xd6a608f6547e1a18), +W64LIT(0xb97e3375e89cde55), +W64LIT(0xd388bf301de99c34), +W64LIT(0x5b06f565e368aaea), +W64LIT(0xf0f4df6607fe2494), +W64LIT(0x1607268e9ad7996a), +W64LIT(0xaedc9dc5ad010852), +W64LIT(0xe0c7236c4060ea65), +W64LIT(0xea9bb815d2bb133d), +W64LIT(0x888e4a55fe8136de), +W64LIT(0x5aa37d5b3c22e587), +W64LIT(0xc104a64611e3cc1f), +W64LIT(0x515a6e1c71b353b2), +W64LIT(0xc42a118058744a33), +W64LIT(0x7708b98c22336d3e), +W64LIT(0x2a3a966d1c12904f), +W64LIT(0x8a31af29b515a804), +W64LIT(0xed0aeaafd0b80bcb), +W64LIT(0x2c0e4ce9c15bc7d4), +W64LIT(0x0c6841fd4f92aec3), +W64LIT(0x98bdb65fb91ff82f), +W64LIT(0x1f41d0b59cd2b185), +W64LIT(0xb322a80c7a47270d), +W64LIT(0xe6f3f9e89d29bdfe), +W64LIT(0x7ac5704fb2eb8c90), +W64LIT(0xa94dcf7faf0210a4), +W64LIT(0x787a9533f97f124a), +W64LIT(0xdb6bc135c4a6fbb6), +W64LIT(0x048b3ff896ddc941), +W64LIT(0xe8245d69992f8de7), +W64LIT(0xe3dd4e2ed4be3bd2), +W64LIT(0xcafdb5015c727a2a), +W64LIT(0xb7a997f4ec9aee4c), +W64LIT(0xe75671d64263f293), +W64LIT(0x2b9f1e53c358df22), +W64LIT(0x18d0820f9ed1a973), +W64LIT(0xabf22a03e4968e7e), +W64LIT(0xa2b4dc38e293a691), +W64LIT(0x673b458665ada3cf), +W64LIT(0xf9b2295d01fb0c7b), +W64LIT(0xd22d370ec2a3d359), +W64LIT(0x97cf9ae06253875b), +W64LIT(0x0ed7a48104063019), +W64LIT(0x482f642d3028b5ac), +W64LIT(0xc0a12e78cea98372), +W64LIT(0x4fbe3697322bad5a), +W64LIT(0x19750a31419be61e), +W64LIT(0x41699216362d9d43), +W64LIT(0xd5bc65b4c0a0cbaf), +W64LIT(0xe5e994aa09f76c49), +W64LIT(0xeb3e302b0df15c50), +W64LIT(0x94d5f7a2f68d56ec), +W64LIT(0x53e58b603a27cd68), +W64LIT(0x3d9838dd598f4648), +W64LIT(0x60aa173c67aebb39), +W64LIT(0x1dfe35c9d7462f5f), +W64LIT(0x4ca45bd5a6f57ced), +W64LIT(0xbc5084b3a10b5879), +W64LIT(0xfaa8441f9525ddcc), +W64LIT(0x334f9c5c5d897651), +/* box 4 */ +W64LIT(0xda1687a883adf27e), +W64LIT(0xe35c9378578d9f22), +W64LIT(0x303ca4531637fa40), +W64LIT(0xa088321f74b20375), +W64LIT(0xc9863f3a9acb95e9), +W64LIT(0x5fcf47c57d0b0ed4), +W64LIT(0x4aa211e4e1280b4b), +W64LIT(0xe1a4c9ba871d1289), +W64LIT(0x4926664759f03a4f), +W64LIT(0xadfb36ede3707bca), +W64LIT(0xcf7bd1891f8ef7e1), +W64LIT(0x9735559e8f882792), +W64LIT(0x5932a976f84e6cdc), +W64LIT(0x9dc792bef547818a), +W64LIT(0x06fdeeb385456208), +W64LIT(0x46ad38771ea2cf5b), +W64LIT(0x5eb36aa41543b27b), +W64LIT(0x8b2eb33cd1bcb511), +W64LIT(0x71105ff6e598ebbc), +W64LIT(0x5441ad846f8c1463), +W64LIT(0x4c5fff57646d6943), +W64LIT(0xf3485c49f633c9b1), +W64LIT(0x9cbbbfdf9d0f3d25), +W64LIT(0x22d031a067192178), +W64LIT(0xca0248992213a4ed), +W64LIT(0x19627fb263a9c18f), +W64LIT(0x9330e1efda5dc831), +W64LIT(0x1390b89219666797), +W64LIT(0x2edf18339893e568), +W64LIT(0x6c779435d3e4c590), +W64LIT(0x53c06e568281cac4), +W64LIT(0x6ff3e3966b3cf494), +W64LIT(0xfe3b58bb61f1b10e), +W64LIT(0x77edb14560dd89b4), +W64LIT(0x02f85ac2d0908dab), +W64LIT(0x12ec95f3712edb38), +W64LIT(0x85d9c06dfea6fcaa), +W64LIT(0x90b4964c6285f935), +W64LIT(0xf1b0068b26a3441a), +W64LIT(0x729428555d40dab8), +W64LIT(0x5c4b3066c5d33fd0), +W64LIT(0x5d371d07ad9b837f), +W64LIT(0xa48d866e2167ecd6), +W64LIT(0xb661139d504937ee), +W64LIT(0xa27068dda4228ede), +W64LIT(0xf8c6b608e4b4d306), +W64LIT(0x6bf657e73ee91b37), +W64LIT(0xac871b8c8b38c765), +W64LIT(0x4ea7a595b4fde4e8), +W64LIT(0x0d7304f297c278bf), +W64LIT(0xb71d3efc38018b41), +W64LIT(0xae7f414e5ba84ace), +W64LIT(0xaf036c2f33e0f661), +W64LIT(0x0000000000000000), +W64LIT(0xb89660cc7f537e55), +W64LIT(0xa675dcacf1f7617d), +W64LIT(0x610490c74426bd2f), +W64LIT(0xc18ca2d83094be5a), +W64LIT(0x2adaac42cd460acb), +W64LIT(0x7d1f76651a122fac), +W64LIT(0xc58916a9654151f9), +W64LIT(0xedabe0297897d699), +W64LIT(0x2d5b6f90204bd46c), +W64LIT(0x26d585d132cccedb), +W64LIT(0x9f3fc87c25d70c21), +W64LIT(0xc60d610add9960fd), +W64LIT(0x80a0597dc33bafa6), +W64LIT(0xd0e44088f9625466), +W64LIT(0x1d67cbc3367c2e2c), +W64LIT(0x2c2742f1480368c3), +W64LIT(0x89d6e9fe012c38ba), +W64LIT(0xe9ae54582d42393a), +W64LIT(0x3ecbd702392db3fb), +W64LIT(0xb5e5643ee89106ea), +W64LIT(0xa882affddeed28c6), +W64LIT(0x1ae60811db71f08b), +W64LIT(0x924ccc8eb215749e), +W64LIT(0xfcc30279b1613ca5), +W64LIT(0x825803bf13ab220d), +W64LIT(0xd992f00b3b75c37a), +W64LIT(0xc8fa125bf2832946), +W64LIT(0x35453d432baaa94c), +W64LIT(0xf9ba9b698cfc6fa9), +W64LIT(0x37bd6781fb3a24e7), +W64LIT(0x791ac2144fc7c00f), +W64LIT(0x16e9218224fb349b), +W64LIT(0xdb6aaac9ebe54ed1), +W64LIT(0xd8eedd6a533d7fd5), +W64LIT(0x7c635b04725a9303), +W64LIT(0x553d80e507c4a8cc), +W64LIT(0x9a46516c184a5f2d), +W64LIT(0x14117b40f46bb930), +W64LIT(0x1ee3bc608ea41f28), +W64LIT(0x27a9a8b05a847274), +W64LIT(0x4050d6c49be7ad53), +W64LIT(0x7be298d69f574da4), +W64LIT(0x6a8a7a8656a1a798), +W64LIT(0x4d23d2360c25d5ec), +W64LIT(0x1014cf31a1be5693), +W64LIT(0xb264a7ec059cd84d), +W64LIT(0xea2a23fb959a083e), +W64LIT(0xf0cc2bea4eebf8b5), +W64LIT(0x76919c240895351b), +W64LIT(0x0b8eea4112871ab7), +W64LIT(0x47d1151676ea73f4), +W64LIT(0xbdeff9dc42ce2d59), +W64LIT(0x2ba68123a50eb664), +W64LIT(0x057999103d9d530c), +W64LIT(0xe759270902587081), +W64LIT(0xef53baeba8075b32), +W64LIT(0x4fdb88f4dcb55847), +W64LIT(0x6e8fcef70374483b), +W64LIT(0x1168e250c9f6ea3c), +W64LIT(0x1b9a2570b3394c24), +W64LIT(0x706c72978dd05713), +W64LIT(0x865db7ce467ecdae), +W64LIT(0x52bc4337eac9766b), +W64LIT(0x504419f53a59fbc0), +W64LIT(0x8f2b074d84695ab2), +W64LIT(0x6078bda62c6e0180), +W64LIT(0x43d4a167233f9c57), +W64LIT(0x0ef773512f1a49bb), +W64LIT(0x0c0f2993ff8ac410), +W64LIT(0x4bde3c858960b7e4), +W64LIT(0x66855315a92b6388), +W64LIT(0xd360372b41ba6562), +W64LIT(0x584e84179006d073), +W64LIT(0x9b3a7c0d7002e382), +W64LIT(0xa5f1ab0f492f5079), +W64LIT(0x2822f6801dd68760), +W64LIT(0x445562b5ce3242f0), +W64LIT(0xaa7af53f0e7da56d), +W64LIT(0x3c338dc0e9bd3e50), +W64LIT(0x3bb24e1204b0e0f7), +W64LIT(0xd59dd998c4ff076a), +W64LIT(0x91c8bb2d0acd459a), +W64LIT(0x84a5ed0c96ee4005), +W64LIT(0x33b8d3f0aeefcb44), +W64LIT(0x57c5da27d7542567), +W64LIT(0x32c4fe91c6a777eb), +W64LIT(0x3439102243e215e3), +W64LIT(0xc7714c6bb5d1dc52), +W64LIT(0x3fb7fa6351650f54), +W64LIT(0x87219aaf2e367101), +W64LIT(0xf5b5b2fa7376abb9), +W64LIT(0x412cfba5f3af11fc), +W64LIT(0xdceb691b06e89076), +W64LIT(0xbb12176fc78b4f51), +W64LIT(0x73e8053435086617), +W64LIT(0xe220be193fc5238d), +W64LIT(0xb09cfd2ed50c55e6), +W64LIT(0xb9ea4dad171bc2fa), +W64LIT(0x9e43e51d4d9fb08e), +W64LIT(0x36c14ae093729848), +W64LIT(0xa9fe829cb6a59469), +W64LIT(0x0405b47155d5efa3), +W64LIT(0x0af2c7207acfa618), +W64LIT(0x7e9b01c6a2ca1ea8), +W64LIT(0xdd97447a6ea02cd9), +W64LIT(0x0781c3d2ed0ddea7), +W64LIT(0x7866ef75278f7ca0), +W64LIT(0xd1986de9912ae8c9), +W64LIT(0xcb7e65f84a5b1842), +W64LIT(0xcd838b4bcf1e7a4a), +W64LIT(0xab06d85e663519c2), +W64LIT(0xd4e1f4f9acb7bbc5), +W64LIT(0xfdbf2f18d929800a), +W64LIT(0xf23471289e7b751e), +W64LIT(0xbc93d4bd2a8691f6), +W64LIT(0x3d4fa0a181f582ff), +W64LIT(0xba6e3a0eafc3f3fe), +W64LIT(0x5ab6ded540965dd8), +W64LIT(0xeb560e9afdd2b491), +W64LIT(0x0976b083c217971c), +W64LIT(0xecd7cd4810df6a36), +W64LIT(0x23ac1cc10f519dd7), +W64LIT(0xbe6b8e7ffa161c5d), +W64LIT(0x7fe72ca7ca82a207), +W64LIT(0xc0f08fb958dc02f5), +W64LIT(0x7a9eb5b7f71ff10b), +W64LIT(0xa709f1cd99bfddd2), +W64LIT(0x8dd35d8f54f9d719), +W64LIT(0x8caf70ee3cb16bb6), +W64LIT(0xe4dd50aaba804185), +W64LIT(0x83242ede7be39ea2), +W64LIT(0x98be0baec8dad286), +W64LIT(0x690e0d25ee79969c), +W64LIT(0x95cd0f5c5f18aa39), +W64LIT(0x56b9f746bf1c99c8), +W64LIT(0x7469c6e6d805b8b0), +W64LIT(0x8a529e5db9f409be), +W64LIT(0xe6250a686a10cc2e), +W64LIT(0x2fa33552f0db59c7), +W64LIT(0x42a88c064b7720f8), +W64LIT(0x6d0bb954bbac793f), +W64LIT(0x181e52d30be17d20), +W64LIT(0xbf17a31e925ea0f2), +W64LIT(0x94b1223d37501696), +W64LIT(0xe8d27939450a8595), +W64LIT(0xccffa62aa756c6e5), +W64LIT(0x383639b1bc68d1f3), +W64LIT(0xee2f978ac04fe79d), +W64LIT(0xa30c45bccc6a3271), +W64LIT(0x1f9f9101e6eca387), +W64LIT(0xb1e0d04fbd44e949), +W64LIT(0x242ddf13e25c4370), +W64LIT(0x156d56219c23059f), +W64LIT(0x88aac49f69648415), +W64LIT(0x6280e764fcfe8c2b), +W64LIT(0xdf6f1eb8be30a172), +W64LIT(0xe5a17dcbd2c8fd2a), +W64LIT(0xe0d8e4dbef55ae26), +W64LIT(0x63fcca0594b63084), +W64LIT(0xa1f41f7e1cfabfda), +W64LIT(0x295edbe1759e3bcf), +W64LIT(0x67f97e74c163df27), +W64LIT(0x038477a3b8d83104), +W64LIT(0xde1333d9d6781ddd), +W64LIT(0x3ace63736cf85c58), +W64LIT(0xd619ae3b7c27366e), +W64LIT(0x5bcaf3b428dee177), +W64LIT(0xb3188a8d6dd464e2), +W64LIT(0x1c1be6a25e349283), +W64LIT(0x017c2d616848bcaf), +W64LIT(0x8e572a2cec21e61d), +W64LIT(0xf631c559cbae9abd), +W64LIT(0x81dc741cab731309), +W64LIT(0xff4775da09b90da1), +W64LIT(0xb499495f80d9ba45), +W64LIT(0x0f8b5e304752f514), +W64LIT(0x394a14d0d4206d5c), +W64LIT(0xce07fce877c64b4e), +W64LIT(0xf4c99f9b1b3e1716), +W64LIT(0xc4f53bc80d09ed56), +W64LIT(0xc208d57b884c8f5e), +W64LIT(0x080a9de2aa5f2bb3), +W64LIT(0x314089327e7f46ef), +W64LIT(0xfa3eecca34245ead), +W64LIT(0x20286b62b789acd3), +W64LIT(0x7515eb87b04d041f), +W64LIT(0x513834945211476f), +W64LIT(0x650124b611f3528c), +W64LIT(0x17950ce34cb38834), +W64LIT(0x45294fd4a67afe5f), +W64LIT(0x21544603dfc1107c), +W64LIT(0x485a4b2631b886e0), +W64LIT(0x6872204486312a33), +W64LIT(0x647d09d779bbee23), +W64LIT(0x2551f2728a14ffdf), +W64LIT(0xd765835a146f8ac1), +W64LIT(0xd21c1a4a29f2d9cd), +W64LIT(0x99c226cfa0926e29), +W64LIT(0xfb42c1ab5c6ce202), +W64LIT(0xc374f81ae00433f1), +W64LIT(0x964978ffe7c09b3d), +W64LIT(0xf74de838a3e62612), +/* box 5 */ +W64LIT(0x74b87b36b0592c6a), +W64LIT(0x3d82d75dffb4b81c), +W64LIT(0x8884246715267825), +W64LIT(0xdaf2d8a77ed4e5de), +W64LIT(0xfeb118650e53f9c7), +W64LIT(0xbd2d1aea59226b06), +W64LIT(0x26ce87f6dbabb191), +W64LIT(0x32772ecbeb66bd0a), +W64LIT(0xd4bbf82bc5104c8c), +W64LIT(0x055357720c4e03a1), +W64LIT(0xef5be62a32d0f6fd), +W64LIT(0xbe1c84c45d186aca), +W64LIT(0xacc7e4a565a1643c), +W64LIT(0x8dd7731519687b84), +W64LIT(0x11eafe4f3c830f3a), +W64LIT(0x04ef8e68a358afe5), +W64LIT(0x40ad9ca1534b930d), +W64LIT(0xe44191d4855a5c0e), +W64LIT(0x6001d20b809420f1), +W64LIT(0x73666b70173b8243), +W64LIT(0x372479b9e728beab), +W64LIT(0x45fecbd35f0590ac), +W64LIT(0x7057f55e1301838f), +W64LIT(0xff0dc17fa1455583), +W64LIT(0x0cc467b810e804da), +W64LIT(0xb9c29482fa7ac4e3), +W64LIT(0xa003831d754960e6), +W64LIT(0x8a096353be0ad5ad), +W64LIT(0xdd2cc8e1d9b64bf7), +W64LIT(0xc7dc415052bfee3e), +W64LIT(0x9f0c137421d17572), +W64LIT(0x35a93e8d4c041323), +W64LIT(0x9a5f44062d9f76d3), +W64LIT(0x71eb2c44bc172fcb), +W64LIT(0x0ff5f99614d20516), +W64LIT(0x7789e518b4632da6), +W64LIT(0xc99561dce97b476c), +W64LIT(0x5276fcc06bf29dfb), +W64LIT(0x4a0b32454bd795ba), +W64LIT(0x9274add69e2fddec), +W64LIT(0x4f5865374799961b), +W64LIT(0xb2d8e37c4df06e10), +W64LIT(0xc4eddf7e5685eff2), +W64LIT(0xb3643a66e2e6c254), +W64LIT(0xd50721316a06e0c8), +W64LIT(0x8bb5ba49111c79e9), +W64LIT(0x2bb639546455190f), +W64LIT(0xf8d3d1390627fbaa), +W64LIT(0x38d1802ff3fabbbd), +W64LIT(0xdfa18fd5729ae67f), +W64LIT(0x4ee4bc2de88f3a5f), +W64LIT(0xf72628af12f5febc), +W64LIT(0x0aa6aee4189c06b7), +W64LIT(0x0000000000000000), +W64LIT(0x9eb0ca6e8ec7d936), +W64LIT(0xcb1826e84257eae4), +W64LIT(0x187dce8520250841), +W64LIT(0xc28f16225ef1ed9f), +W64LIT(0xc333cf38f1e741db), +W64LIT(0x4220db95f8673e85), +W64LIT(0xdc9011fb76a0e7b3), +W64LIT(0x105627559395a37e), +W64LIT(0x2f59b73cc70db6ea), +W64LIT(0xe112c6a689145faf), +W64LIT(0x82228a830dba7e92), +W64LIT(0x2ee56e26681b1aae), +W64LIT(0x2a0ae04ecb43b54b), +W64LIT(0x47738ce7f4293d24), +W64LIT(0xa7dd935bd22bcecf), +W64LIT(0xd2d93177cd644ee1), +W64LIT(0xebb4684291885918), +W64LIT(0x0e49208cbbc4a952), +W64LIT(0xa550d46f79076347), +W64LIT(0x411145bbfc5d3f49), +W64LIT(0xe6ccd6e02e76f186), +W64LIT(0x4bb7eb5fe4c139fe), +W64LIT(0x5d8305567f2098ed), +W64LIT(0x95aabd90394d73c5), +W64LIT(0x25ff19d8df91b05d), +W64LIT(0x86cd04ebaee2d177), +W64LIT(0x03319e2e043a01cc), +W64LIT(0x6b1ba5f5371e8a02), +W64LIT(0x76353c021b7581e2), +W64LIT(0x64ee5c6323cc8f14), +W64LIT(0x5c3fdc4cd03634a9), +W64LIT(0x6996e2c19c32278a), +W64LIT(0x8938fd7dba30d461), +W64LIT(0x7b4d82a0a48b297c), +W64LIT(0xbfa05ddef20ec68e), +W64LIT(0x8ee6ed3b1d527a48), +W64LIT(0x61bd0b112f828cb5), +W64LIT(0x66631b5788e0229c), +W64LIT(0x55a8ec86cc9033d2), +W64LIT(0x1c9240ed837da7a4), +W64LIT(0x150570279fdba0df), +W64LIT(0x53ca25dac4e431bf), +W64LIT(0xd636bf1f6e3ce104), +W64LIT(0xcaa4fff2ed4146a0), +W64LIT(0x787c1c8ea0b128b0), +W64LIT(0xad7b3dbfcab7c878), +W64LIT(0xfc3c5f51a57f544f), +W64LIT(0xb78bb40e41be6db1), +W64LIT(0x8c6baa0fb67ed7c0), +W64LIT(0xce4b719a4e19e945), +W64LIT(0xf96f0823a93157ee), +W64LIT(0x7d2f4bfcacff2b11), +W64LIT(0x3eb34973fb8eb9d0), +W64LIT(0xe39f81922238f227), +W64LIT(0x239dd084d7e5b230), +W64LIT(0x1fa3dec38747a668), +W64LIT(0xc5510664f99343b6), +W64LIT(0xc829b8c6466deb28), +W64LIT(0x85fc9ac5aad8d0bb), +W64LIT(0xb6376d14eea8c1f5), +W64LIT(0x9d8154408afdd8fa), +W64LIT(0x3be01e01f7c0ba71), +W64LIT(0x628c953f2bb88d79), +W64LIT(0x6d796ca93f6a886f), +W64LIT(0xfa5e960dad0b5622), +W64LIT(0xe5fd48ce2a4cf04a), +W64LIT(0xe7700ffa81605dc2), +W64LIT(0x2dd4f0086c211b62), +W64LIT(0x2221099e78f31e74), +W64LIT(0xdb4e01bdd1c2499a), +W64LIT(0xf417b68116cfff70), +W64LIT(0xb506f33aea92c039), +W64LIT(0x514762ee6fc89c37), +W64LIT(0x9c3d8d5a25eb74be), +W64LIT(0x396d59355cec17f9), +W64LIT(0xccc636aee53544cd), +W64LIT(0x0b1a77feb78aaaf3), +W64LIT(0xe9392f763aa4f490), +W64LIT(0xaaa52df96dd56651), +W64LIT(0x46cf55fd5b3f9160), +W64LIT(0xa4ec0d75d611cf03), +W64LIT(0xaff67a8b619b65f0), +W64LIT(0x3415e797e312bf67), +W64LIT(0x7af15bba0b9d8538), +W64LIT(0x811314ad09807f5e), +W64LIT(0x8771ddf101f47d33), +W64LIT(0x969b23be3d777209), +W64LIT(0xd365e86d6272e2a5), +W64LIT(0x58d05224736e9b4c), +W64LIT(0xc660984afda9427a), +W64LIT(0x5414359c63869f96), +W64LIT(0xe885f66c95b258d4), +W64LIT(0x655285798cda2350), +W64LIT(0x6cc5b5b3907c242b), +W64LIT(0x6ff42b9d944625e7), +W64LIT(0xc0025116f5dd4017), +W64LIT(0xa28ec429de65cd6e), +W64LIT(0x63304c2584ae213d), +W64LIT(0x7fa20cc807d38699), +W64LIT(0x996eda2829a5771f), +W64LIT(0x1b4c50ab241f098d), +W64LIT(0x1e1f07d928510a2c), +W64LIT(0x33cbf7d14470114e), +W64LIT(0xb055a448e6dcc398), +W64LIT(0x98d2033286b3db5b), +W64LIT(0xec6a780436eaf731), +W64LIT(0xa1bf5a07da5fcca2), +W64LIT(0xbaf30aacfe40c52f), +W64LIT(0xf144e1f31a81fcd1), +W64LIT(0xe0ae1fbc2602f3eb), +W64LIT(0x14b9a93d30cd0c9b), +W64LIT(0x596c8b3edc783708), +W64LIT(0x682a3bdb33248bce), +W64LIT(0xb87e4d98556c68a7), +W64LIT(0x80afcdb7a696d31a), +W64LIT(0x5725abb267bc9e5a), +W64LIT(0x914533f89a15dc20), +W64LIT(0x5eb29b787b1a9921), +W64LIT(0x01bcd91aaf16ac44), +W64LIT(0xc1be880c5acbec53), +W64LIT(0xedd6a11e99fc5b75), +W64LIT(0x028d4734ab2cad88), +W64LIT(0x8f5a3421b244d60c), +W64LIT(0x4dd52203ecb53b93), +W64LIT(0x3f0f906954981594), +W64LIT(0xae4aa391ce8dc9b4), +W64LIT(0x3698a0a3483e12ef), +W64LIT(0xf5ab6f9bb9d95334), +W64LIT(0x082be9d0b3b0ab3f), +W64LIT(0xd1e8af59c95e4f2d), +W64LIT(0xd87f9f93d5f84856), +W64LIT(0x6e48f2873b5089a3), +W64LIT(0x2443c0c270871c19), +W64LIT(0xb1e97d5249ca6fdc), +W64LIT(0x7c9392e603e98755), +W64LIT(0x839e5399a2acd2d6), +W64LIT(0x19c1179f8f33a405), +W64LIT(0xde1d56cfdd8c4a3b), +W64LIT(0x20ac4eaad3dfb3fc), +W64LIT(0x1af089b18b09a5c9), +W64LIT(0x3a5cc71b58d61635), +W64LIT(0x444212c9f0133ce8), +W64LIT(0x72dab26ab82d2e07), +W64LIT(0x4c69fb1943a397d7), +W64LIT(0xf3c9a6c7b1ad5159), +W64LIT(0x1d2e99f72c6b0be0), +W64LIT(0xb4ba2a2045846c7d), +W64LIT(0xe22358888d2e5e63), +W64LIT(0x2887a77a606f18c3), +W64LIT(0xa8286acdc6f9cbd9), +W64LIT(0x5f0e4262d40c3565), +W64LIT(0xeee73f309dc65ab9), +W64LIT(0x9be39d1c8289da97), +W64LIT(0x1634ee099be1a113), +W64LIT(0xea08b1583e9ef55c), +W64LIT(0x9727faa49261de4d), +W64LIT(0x2c682912c337b726), +W64LIT(0xcff7a880e10f4501), +W64LIT(0x1788371334f70d57), +W64LIT(0x27725eec74bd1dd5), +W64LIT(0x3146b0e5ef5cbcc6), +W64LIT(0x099730ca1ca6077b), +W64LIT(0xf2757fdd1ebbfd1d), +W64LIT(0x6aa77cef98082646), +W64LIT(0xbb4fd3b65156696b), +W64LIT(0x569972a8c8aa321e), +W64LIT(0xa3321d337173612a), +W64LIT(0x50fbbbf4c0de3073), +W64LIT(0x5a5d1510d84236c4), +W64LIT(0xfd80864b0a69f80b), +W64LIT(0x07de1046a762ae29), +W64LIT(0xa6614a417d3d628b), +W64LIT(0xd78a6605c12a4d40), +W64LIT(0x67dfc24d27f68ed8), +W64LIT(0xbc91c3f0f634c742), +W64LIT(0xd05476436648e369), +W64LIT(0x493aac6b4fed9476), +W64LIT(0x12db606138b90ef6), +W64LIT(0xa994b3d769ef679d), +W64LIT(0x211097b07cc91fb8), +W64LIT(0x30fa69ff404a1082), +W64LIT(0x3c3e0e4750a21458), +W64LIT(0x7504a22c1f4f802e), +W64LIT(0x844043df05ce7cff), +W64LIT(0xf0f838e9b5975095), +W64LIT(0x7e1ed5d2a8c52add), +W64LIT(0x90f9eae235037064), +W64LIT(0x0662c95c0874026d), +W64LIT(0x9416648a965bdf81), +W64LIT(0xf69af1b5bde352f8), +W64LIT(0x0d78bea2bffea89e), +W64LIT(0x293b7e60cf79b487), +W64LIT(0xd9c346897aeee412), +W64LIT(0xfbe24f17021dfa66), +W64LIT(0x1367b97b97afa2b2), +W64LIT(0xab19f4e3c2c3ca15), +W64LIT(0x48867571e0fb3832), +W64LIT(0x93c874cc313971a8), +W64LIT(0x79c0c5940fa784f4), +W64LIT(0xcd7aefb44a23e889), +W64LIT(0x439c028f577192c1), +W64LIT(0x5be1cc0a77549a80), +/* box 6 */ +W64LIT(0x714d28d778656928), +W64LIT(0xc88a7c6b84f64f7c), +W64LIT(0xec43cac5ab89aaca), +W64LIT(0x777fa38110dc16a3), +W64LIT(0x0f7d5c87e4213b5c), +W64LIT(0x73f051e5f3a1ef51), +W64LIT(0xea714193c330d541), +W64LIT(0x95e5f3dae016c4f3), +W64LIT(0x63d3738095a0e173), +W64LIT(0x9825d66f8ff379d6), +W64LIT(0xe8cc38a148f45338), +W64LIT(0xa840b0c025f06bb0), +W64LIT(0x944135c35f748735), +W64LIT(0x74661caa247ad31c), +W64LIT(0xe7b16426acd56864), +W64LIT(0xd1e689df6e6f0589), +W64LIT(0xa73dec47c1d150ec), +W64LIT(0x64453ecf427bdd3e), +W64LIT(0x0ed99a9e5b43789a), +W64LIT(0x7b1b402dc05be840), +W64LIT(0x0dc025b56fe5bd25), +W64LIT(0x3f183a284e22293a), +W64LIT(0xa0aba108160a6ca1), +W64LIT(0x46be033705bd4703), +W64LIT(0x86df6e94b2b10f6e), +W64LIT(0xa216d83a9dceead8), +W64LIT(0x129e5b57edc5885b), +W64LIT(0x7e3074509c445274), +W64LIT(0x7d29cb7ba8e297cb), +W64LIT(0x1611a9330eb871a9), +W64LIT(0x486799a95efe3f99), +W64LIT(0x9fb39b205828459b), +W64LIT(0xd0424fc6d10d464f), +W64LIT(0xe968feb8f79610fe), +W64LIT(0x5d6f8fb164e08b8f), +W64LIT(0xaafdc9f2ae34edc9), +W64LIT(0x02bd79328bc48679), +W64LIT(0x9b3c6944bb55bc69), +W64LIT(0x6277b5992ac2a2b5), +W64LIT(0x877ba88d0dd34ca8), +W64LIT(0xfa5263f6a531db63), +W64LIT(0x2e9fde54974164de), +W64LIT(0xcda14816d8e9f548), +W64LIT(0x675c81e476dd1881), +W64LIT(0x2a102c30743c9d2c), +W64LIT(0x37f32be07dd82e2b), +W64LIT(0x256d70b7901da670), +W64LIT(0x4ce86bcdbd83c66b), +W64LIT(0x50afaa040b0536aa), +W64LIT(0xef5a75ee9f2f6f75), +W64LIT(0xb3913c4644ada73c), +W64LIT(0x1187e47cd9634de4), +W64LIT(0xc54a59deeb13f259), +W64LIT(0x0000000000000000), +W64LIT(0x01a4c619bf6243c6), +W64LIT(0x90cec7a7bc097ec7), +W64LIT(0xf94bdcdd91971edc), +W64LIT(0x8e347f5c814b087f), +W64LIT(0xc7f720ec60d77420), +W64LIT(0x354e52d2f61ca852), +W64LIT(0x34ea94cb497eeb94), +W64LIT(0xae723b964d49143b), +W64LIT(0xf48bf968fe72a3f9), +W64LIT(0xfc60e8a0cd88a4e8), +W64LIT(0x2909931b409a5893), +W64LIT(0xbd48a6d81feedfa6), +W64LIT(0x6cae2f077181da2f), +W64LIT(0xad6b84bd79efd184), +W64LIT(0x18c833ad55fb0933), +W64LIT(0x204644cacc021c44), +W64LIT(0x392ab17e269b56b1), +W64LIT(0x14acd001857cf7d0), +W64LIT(0x8abb8d386236f18d), +W64LIT(0xeefeb3f7204d2cb3), +W64LIT(0xf636805a75b62580), +W64LIT(0x2bb4ea29cb5edeea), +W64LIT(0xc653e6f5dfb537e6), +W64LIT(0x8d2dc077b5edcdc0), +W64LIT(0x31c1a0b6156151a0), +W64LIT(0xf8ef1ac42ef55d1a), +W64LIT(0xdbb0e125d65184e1), +W64LIT(0x82509cf051ccf69c), +W64LIT(0xe33e96424fa89196), +W64LIT(0xdf3f1341352c7d13), +W64LIT(0x8f90b9453e294bb9), +W64LIT(0x1023226566010e22), +W64LIT(0xa58095754a15d695), +W64LIT(0x2c22a7661c85e2a7), +W64LIT(0xe183ef70c46c17ef), +W64LIT(0xafd6fd8ff22b57fd), +W64LIT(0x471ac52ebadf04c5), +W64LIT(0x4d4cadd402e185ad), +W64LIT(0x916a01be036b3d01), +W64LIT(0x28ad5502fff81b55), +W64LIT(0x3657edf9c2ba6ded), +W64LIT(0xd2ff36f45ac9c036), +W64LIT(0xf1a0cd15a26d19cd), +W64LIT(0xd90d98175d950298), +W64LIT(0xf7924643cad46646), +W64LIT(0xdd826a73bee8fb6a), +W64LIT(0x9d0ee212d3ecc3e2), +W64LIT(0xb6ba083b18b21d08), +W64LIT(0x3da5431ac5e6af43), +W64LIT(0x08eb11c833fa0711), +W64LIT(0x052b347d5c1fba34), +W64LIT(0x6fb7902c45271f90), +W64LIT(0x133a9d4e52a7cb9d), +W64LIT(0x6e135635fa455c56), +W64LIT(0x725497fc4cc3ac97), +W64LIT(0xf31db42729a99fb4), +W64LIT(0x846217a639758917), +W64LIT(0x4b7e26826a58fa26), +W64LIT(0x235ffbe1f8a4d9fb), +W64LIT(0xff79578bf92e6157), +W64LIT(0xda14273c6933c727), +W64LIT(0x8b1f4b21dd54b24b), +W64LIT(0x9caa240b6c8e8024), +W64LIT(0xc1c5abba086e0bab), +W64LIT(0xde9bd5588a4e3ed5), +W64LIT(0x2d86617fa3e7a161), +W64LIT(0xbff5dfea942a59df), +W64LIT(0x66f847fdc9bf5b47), +W64LIT(0x3b97c84cad5fd0c8), +W64LIT(0x3ebcfc31f1406afc), +W64LIT(0xca3705590f32c905), +W64LIT(0x24c9b6ae2f7fe5b6), +W64LIT(0x408c88616d043888), +W64LIT(0x93d7788c88afbb78), +W64LIT(0x196cf5b4ea994af5), +W64LIT(0x9a98af5d0437ffaf), +W64LIT(0x8c89066e0a8f8e06), +W64LIT(0xab590feb1156ae0f), +W64LIT(0xd7d4028906d67a02), +W64LIT(0xe4a8db0d9873addb), +W64LIT(0xc378d28883aa8dd2), +W64LIT(0x4ff1d4e6892503d4), +W64LIT(0xd670c490b9b439c4), +W64LIT(0x65e1f8d6fd199ef8), +W64LIT(0xf2b9723e96cbdc72), +W64LIT(0xb12c4574cf692145), +W64LIT(0x569d215263bc4921), +W64LIT(0x69851b7a2d9e601b), +W64LIT(0x5e76309a50464e30), +W64LIT(0x5fd2f683ef240df6), +W64LIT(0xd8a95e0ee2f7415e), +W64LIT(0xe29a505bf0cad250), +W64LIT(0x96fc4cf1d4b0014c), +W64LIT(0x8806f40ae9f277f4), +W64LIT(0x53b6152f3fa3f315), +W64LIT(0x1c47c1c9b686f0c1), +W64LIT(0x80ede5c2da0870e5), +W64LIT(0xd5697bbb8d12fc7b), +W64LIT(0xfdc42eb972eae72e), +W64LIT(0x0bf2aee3075cc2ae), +W64LIT(0x22fb3df847c69a3d), +W64LIT(0xbadeeb97c835e3eb), +W64LIT(0xdc26ac6a018ab8ac), +W64LIT(0xbcec60c1a08c9c60), +W64LIT(0x4231f153e6c0bef1), +W64LIT(0x337cd9849ea5d7d9), +W64LIT(0x5b5d04e70c59f404), +W64LIT(0x79a6391f4b9f6e39), +W64LIT(0x5212d33680c1b0d3), +W64LIT(0xb5a3b7102c14d8b7), +W64LIT(0x7f94b249232611b2), +W64LIT(0x17b56f2ab1da326f), +W64LIT(0x59e07dd5879d727d), +W64LIT(0xebd5878a7c529687), +W64LIT(0xbb7a2d8e7757a02d), +W64LIT(0x0319bf2b34a6c5bf), +W64LIT(0x5ccb49a8db82c849), +W64LIT(0x1de307d009e4b307), +W64LIT(0x49c35fb0e19c7c5f), +W64LIT(0x55849e79571a8c9e), +W64LIT(0x7abf86347f39ab86), +W64LIT(0x9273be9537cdf8be), +W64LIT(0xe615a23f13b72ba2), +W64LIT(0x6821dd6392fc23dd), +W64LIT(0x5af9c2feb33bb7c2), +W64LIT(0x06328b5668b97f8b), +W64LIT(0x44037a058e79c17a), +W64LIT(0x83f45ae9eeaeb55a), +W64LIT(0x5739e74bdcde0ae7), +W64LIT(0xfbf6a5ef1a5398a5), +W64LIT(0xe50c1d142711ee1d), +W64LIT(0x1a754a9fde3f8f4a), +W64LIT(0x7802ff06f4fd2dff), +W64LIT(0xf52f3f714110e03f), +W64LIT(0x2674cf9ca4bb63cf), +W64LIT(0x60caccaba10624cc), +W64LIT(0xb088836d700b6283), +W64LIT(0xa6992a5e7eb3132a), +W64LIT(0xa9e476d99a922876), +W64LIT(0x6b386248a65ae662), +W64LIT(0xc2dc14913cc8ce14), +W64LIT(0x76db6598afbe5565), +W64LIT(0x32d81f9d21c7941f), +W64LIT(0x21e282d373605f82), +W64LIT(0xc0616da3b70c486d), +W64LIT(0x616e0ab21e64670a), +W64LIT(0x6d0ae91ecee399e9), +W64LIT(0x27d009851bd92009), +W64LIT(0xfedd9192464c2291), +W64LIT(0x45a7bc1c311b82bc), +W64LIT(0x54205860e878cf58), +W64LIT(0xa10f6711a9682f67), +W64LIT(0x9981107630913a10), +W64LIT(0xede70cdc14ebe90c), +W64LIT(0x70e9eecec7072aee), +W64LIT(0x1f5e7ee28220357e), +W64LIT(0x2f3b184d28232718), +W64LIT(0x41284e78d2667b4e), +W64LIT(0xa424536cf5779553), +W64LIT(0xa3b21e2322aca91e), +W64LIT(0x4e5512ff36474012), +W64LIT(0x1efab8fb3d4276b8), +W64LIT(0x89a2321356903432), +W64LIT(0xcb93c340b0508ac3), +W64LIT(0x306566afaa031266), +W64LIT(0x4adae09bd53ab9e0), +W64LIT(0xc92eba723b940cba), +W64LIT(0x094fd7d18c9844d7), +W64LIT(0xcc058e0f678bb68e), +W64LIT(0xd4cdbda23270bfbd), +W64LIT(0x0a5668fab83e8168), +W64LIT(0x510b6c1db467756c), +W64LIT(0xb86392a543f16592), +W64LIT(0x048ff264e37df9f2), +W64LIT(0x3a330e55123d930e), +W64LIT(0xb235fa5ffbcfe4fa), +W64LIT(0xb9c754bcfc932654), +W64LIT(0x3c0185037a84ec85), +W64LIT(0x0c64e3acd087fee3), +W64LIT(0xe02729697b0e5429), +W64LIT(0x07964d4fd7db3c4d), +W64LIT(0x814923db656a3323), +W64LIT(0x388e776799f91577), +W64LIT(0x6a9ca4511938a5a4), +W64LIT(0x1bd18c86615dcc8c), +W64LIT(0xb407710993769b71), +W64LIT(0x150816183a1eb416), +W64LIT(0x4395374a59a2fd37), +W64LIT(0xc4ee9fc75471b19f), +W64LIT(0x5844bbcc38ff31bb), +W64LIT(0xcf1c3124532d7331), +W64LIT(0xb71ece22a7d05ece), +W64LIT(0xaccf42a4c68d9242), +W64LIT(0x97588ae86bd2428a), +W64LIT(0x75c2dab39b1890da), +W64LIT(0x9e175d39e74a065d), +W64LIT(0xf0040b0c1d0f5a0b), +W64LIT(0xceb8f73dec4f30f7), +W64LIT(0xbe5119f32b481a19), +W64LIT(0xd35bf0ede5ab83f0), +W64LIT(0x7c8d0d621780d40d), +W64LIT(0x85c6d1bf8617cad1), +/* box 7 */ +W64LIT(0xb1c742127b66f2a4), +W64LIT(0xce916098d7a59fc1), +W64LIT(0xc312ef8e2406fa70), +W64LIT(0x956c7dced81403d5), +W64LIT(0x5a0c9b2318dd9520), +W64LIT(0xad0d57f51a480e8b), +W64LIT(0xe7b9d05287740b01), +W64LIT(0x0217f9ea2ed81268), +W64LIT(0x4d7cff19f8cd3a06), +W64LIT(0x44d1772e572b7b67), +W64LIT(0xfb73c5b5e65af72e), +W64LIT(0x91427aef84512705), +W64LIT(0x0c720963e4cf6c85), +W64LIT(0x87c398a0732d8117), +W64LIT(0xa17f5e96fe87620e), +W64LIT(0x50476c8b8e8fcf1d), +W64LIT(0xcb4ee1cc9c8cb225), +W64LIT(0x67b2304c91a8b59a), +W64LIT(0x54696baad2caebcd), +W64LIT(0xddcf03836bf01437), +W64LIT(0x46c68ec479f3690f), +W64LIT(0x8f9f96e2cba7c942), +W64LIT(0xe1802e99f5e93db9), +W64LIT(0x4e9a8086c179215a), +W64LIT(0xf0c9b4686764a427), +W64LIT(0xfd4a3b7e94c7c196), +W64LIT(0xfcbbbd0b83abc8a2), +W64LIT(0xebcbd93163bb6784), +W64LIT(0xf9643c5fc882e546), +W64LIT(0xc4da973041f7c5fc), +W64LIT(0x1af3eb2c13b3ca97), +W64LIT(0x6e1fb87b3e4ef4fb), +W64LIT(0x5e229c024498b1f0), +W64LIT(0xf516353c2c4d89c3), +W64LIT(0xcc869972f97d8da9), +W64LIT(0x8d886f08e57fdb2a), +W64LIT(0x1cca15e7612efc2f), +W64LIT(0x567e9240fc12f9a5), +W64LIT(0x43190f9032da44eb), +W64LIT(0xfeac44e1ad73daca), +W64LIT(0x07c878be65f13f8c), +W64LIT(0x618bce87e3358322), +W64LIT(0xf895ba2adfeeec72), +W64LIT(0x751dd5223a913758), +W64LIT(0x59eae4bc21698e7c), +W64LIT(0xff5dc294ba1fd3fe), +W64LIT(0x03e67f9f39b41b5c), +W64LIT(0x2292c117d1efc7c9), +W64LIT(0x8a4017b6808ee4a6), +W64LIT(0xd1bd0ae08f3f78b2), +W64LIT(0x135e631bbc558bf6), +W64LIT(0xee14586528924a60), +W64LIT(0x8857ee5cae56f6ce), +W64LIT(0x0000000000000000), +W64LIT(0x0e65f089ca177eed), +W64LIT(0x34132358269361db), +W64LIT(0x15679dd0cec8bd4e), +W64LIT(0x800be01e16dcbe9b), +W64LIT(0x949dfbbbcf780ae1), +W64LIT(0xe397d773db312fd1), +W64LIT(0xedf227fa1126513c), +W64LIT(0xb5e945332723d674), +W64LIT(0x53a11314b73bd441), +W64LIT(0x23634762c683cefd), +W64LIT(0x4b4501d28a500cbe), +W64LIT(0x473708b16e9f603b), +W64LIT(0x1770643ae010af26), +W64LIT(0xa746a05d8c1a54b6), +W64LIT(0x90b3fc9a933d2e31), +W64LIT(0x35e2a52d31ff68ef), +W64LIT(0xab34a93e68d53833), +W64LIT(0xd81082d720d939d3), +W64LIT(0xb86aca25d480b3c5), +W64LIT(0xdfd8fa694528065f), +W64LIT(0x4f6b06f3d615286e), +W64LIT(0x578f1435eb7ef091), +W64LIT(0x9af80b32056f740c), +W64LIT(0x92a40570bde53c59), +W64LIT(0xdbf6fd48196d228f), +W64LIT(0x1b026d5904dfc3a3), +W64LIT(0x3c4f2d1a9e19298e), +W64LIT(0xc8a89e53a538a979), +W64LIT(0x991e74ad3cdb6f50), +W64LIT(0x042e07215c4524d0), +W64LIT(0x8e6e1097dccbc076), +W64LIT(0xe071a8ece285348d), +W64LIT(0xd784f42bfda24e0a), +W64LIT(0x7d41db60821b7f0d), +W64LIT(0x85d4614a5df5937f), +W64LIT(0xbb8cb5baed34a899), +W64LIT(0x40ff700f0b6e5fb7), +W64LIT(0x2cf7319e1bf8b924), +W64LIT(0x3a76d3d1ec841f36), +W64LIT(0x4520f15b40477253), +W64LIT(0xf138321d7008ad13), +W64LIT(0x42e889e525b64ddf), +W64LIT(0x65a5c9a6bf70a7f2), +W64LIT(0x208538fdff37d5a1), +W64LIT(0x410ef67a1c025683), +W64LIT(0x18e412c63d6bd8ff), +W64LIT(0x72d5ad9c5f6008d4), +W64LIT(0x255ab9a9b41ef845), +W64LIT(0x93558305aa89356d), +W64LIT(0x70c2547671b81abc), +W64LIT(0x3604dab2084b73b3), +W64LIT(0x05df81544b292de4), +W64LIT(0xf2de4d8249bcb64f), +W64LIT(0x0bba71dd813e5309), +W64LIT(0xa368a77cd05f7066), +W64LIT(0x796fdc41de5e5bdd), +W64LIT(0xec03a18f064a5808), +W64LIT(0x085c0e42b88a4855), +W64LIT(0x274d40439ac6ea2d), +W64LIT(0x31cca20c6dba4c3f), +W64LIT(0x322add93540e5763), +W64LIT(0xb60f3aac1e97cd28), +W64LIT(0x7cb05d1595777639), +W64LIT(0xb036c4676c0afb90), +W64LIT(0x0a4bf7a896525a3d), +W64LIT(0x73242be9480c01e0), +W64LIT(0x5bfd1d560fb19c14), +W64LIT(0x7b7825abf08649b5), +W64LIT(0xb7febcd909fbc41c), +W64LIT(0x81fa666b01b0b7af), +W64LIT(0xd25b757fb68b63ee), +W64LIT(0x0d838f16f3a365b1), +W64LIT(0x6a31bf5a620bd02b), +W64LIT(0x26bcc6368daae319), +W64LIT(0x9ed60c13592a50dc), +W64LIT(0x581b62c936058748), +W64LIT(0x9cc1f5f977f242b4), +W64LIT(0x83ed9f812f68a5c7), +W64LIT(0x74ec53572dfd3e6c), +W64LIT(0xb3d0bbf855bee0cc), +W64LIT(0xacfcd1800d2407bf), +W64LIT(0x303d24797ad6450b), +W64LIT(0x7a89a3dee7ea4081), +W64LIT(0x69d7c0c55bbfcb77), +W64LIT(0x770a2cc814492530), +W64LIT(0x0f9476fcdd7b77d9), +W64LIT(0xaeeb286a23fc15d7), +W64LIT(0x2174be88e85bdc95), +W64LIT(0xde297c1c52440f6b), +W64LIT(0xd04c8c9598537186), +W64LIT(0x2ee0c8743520ab4c), +W64LIT(0x977b8424f6cc11bd), +W64LIT(0x10b81c8485e190aa), +W64LIT(0xa4a0dfc2b5ae4fea), +W64LIT(0x98eff2d82bb76664), +W64LIT(0xa8d2d6a15161236f), +W64LIT(0xd4628bb4c4165556), +W64LIT(0x682646b04cd3c243), +W64LIT(0x2d06b7eb0c94b010), +W64LIT(0x626db118da81987e), +W64LIT(0x2928b0ca50d194c0), +W64LIT(0x6df9c7e407faefa7), +W64LIT(0x1681e24ff77ca612), +W64LIT(0x4952f838a4881ed6), +W64LIT(0x76fbaabd03252c04), +W64LIT(0xc73ce8af7843dea0), +W64LIT(0xe82da6ae5a0f7cd8), +W64LIT(0xc10516640adee818), +W64LIT(0x968a0251e1a01889), +W64LIT(0x37f55cc71f277a87), +W64LIT(0xe5ae29b8a9ac1969), +W64LIT(0xcabf67b98be0bb11), +W64LIT(0xf4e7b3493b2180f7), +W64LIT(0xe9dc20db4d6375ec), +W64LIT(0x639c376dcded914a), +W64LIT(0x12afe56eab3982c2), +W64LIT(0xc2e369fb336af344), +W64LIT(0xa6b726289b765d82), +W64LIT(0x14961ba5d9a4b47a), +W64LIT(0xbc44cd0488c59715), +W64LIT(0xd3aaf30aa1e76ada), +W64LIT(0x28d936bf47bd9df4), +W64LIT(0xaf1aae1f34901ce3), +W64LIT(0x2f114e01224ca278), +W64LIT(0xe648562790180235), +W64LIT(0x24ab3fdca372f171), +W64LIT(0x52509561a057dd75), +W64LIT(0xc6cd6eda6f2fd794), +W64LIT(0xa08ed8e3e9eb6b3a), +W64LIT(0x09ad8837afe64161), +W64LIT(0xbdb54b719fa99e21), +W64LIT(0x8c79e97df213d21e), +W64LIT(0xcf60e6edc0c996f5), +W64LIT(0x5dc4e39d7d2caaac), +W64LIT(0x11499af1928d999e), +W64LIT(0x5fd31a7753f4b8c4), +W64LIT(0x01f18675176c0934), +W64LIT(0xc52b1145569bccc8), +W64LIT(0x9f278a664e4659e8), +W64LIT(0x3dbeab6f897520ba), +W64LIT(0xa2992109c7337952), +W64LIT(0x9b098d4712037d38), +W64LIT(0xc9591826b254a04d), +W64LIT(0x3b8755a4fbe81602), +W64LIT(0xbe5334eea61d857d), +W64LIT(0x51b6eafe99e3c629), +W64LIT(0x191594b32a07d1cb), +W64LIT(0x1f2c6a78589ae773), +W64LIT(0x3fa95285a7ad32d2), +W64LIT(0x5c3565e86a40a398), +W64LIT(0xb2213d8d42d2e9f8), +W64LIT(0xefe5de103ffe4354), +W64LIT(0x4ab487a79d3c058a), +W64LIT(0xcd771f07ee11849d), +W64LIT(0xbfa2b29bb1718c49), +W64LIT(0xba7d33cffa58a1ad), +W64LIT(0x6fee3e0e2922fdcf), +W64LIT(0x64544fd3a81caec6), +W64LIT(0xd9e104a237b530e7), +W64LIT(0xf32fcbf75ed0bf7b), +W64LIT(0x3e58d4f0b0c13be6), +W64LIT(0xb418c346304fdf40), +W64LIT(0xaac52f4b7fb93107), +W64LIT(0xdc3e85f67c9c1d03), +W64LIT(0xd5930dc1d37a5c62), +W64LIT(0x0639fecb729d36b8), +W64LIT(0xc0f490111db2e12c), +W64LIT(0x7ea7a4ffbbaf6451), +W64LIT(0xf6f04aa315f9929f), +W64LIT(0x6643b63986c4bcae), +W64LIT(0x6c0841911096e693), +W64LIT(0x8425e73f4a999a4b), +W64LIT(0x7133d20366d41388), +W64LIT(0x38612a3bc25c0d5e), +W64LIT(0xb99b4c50c3ecbaf1), +W64LIT(0x1d3b93927642f51b), +W64LIT(0x7f56228aacc36d65), +W64LIT(0x9d30738c609e4b80), +W64LIT(0x48a37e4db3e417e2), +W64LIT(0x8bb191c397e2ed92), +W64LIT(0x2acecf5569658f9c), +W64LIT(0xda077b3d0e012bbb), +W64LIT(0xa55159b7a2c246de), +W64LIT(0x33db5be643625e57), +W64LIT(0x821c19f43804acf3), +W64LIT(0x3990ac4ed530046a), +W64LIT(0xd675725eeace473e), +W64LIT(0x789e5a34c93252e9), +W64LIT(0x86321ed564418823), +W64LIT(0xfa8243c0f136fe1a), +W64LIT(0xe45fafcdbec0105d), +W64LIT(0x2b3f49207e0986a8), +W64LIT(0xa92350d4460d2a5b), +W64LIT(0x1eddec0d4ff6ee47), +W64LIT(0x89a66829b93afffa), +W64LIT(0x607a48f2f4598a16), +W64LIT(0x6bc0392f7567d91f), +W64LIT(0xea3a5f4474d76eb0), +W64LIT(0x5598eddfc5a6e2f9), +W64LIT(0x4c8d796cefa13332), +W64LIT(0xf701ccd602959bab), +W64LIT(0xe2665106cc5d26e5), +}; + +const word64 SHARK::Dec::cbox[8][256] = { +/* box 0 */ +W64LIT(0xe6126af05e55aff3), +W64LIT(0x4b6c893f310b0835), +W64LIT(0xaa4c0e84ebfc8d57), +W64LIT(0xfb9b5c7bf3b3090d), +W64LIT(0x4508a6a9ccba5ce2), +W64LIT(0xe5d1d2064dc6bde9), +W64LIT(0x348343755288edde), +W64LIT(0xb684505de46b250c), +W64LIT(0xa8cede205a1e91e8), +W64LIT(0x40b89b46f9fa6acc), +W64LIT(0x8ee1ec1afab080ba), +W64LIT(0xde77d6b7408e0a45), +W64LIT(0x9a3e184c2e455802), +W64LIT(0xbe93fad23f0955ef), +W64LIT(0x3ae76ce3af39b909), +W64LIT(0xad7ee3cf6f5ea7c6), +W64LIT(0x8b51d1f5cff0b694), +W64LIT(0x70ca8d8e3c43bf99), +W64LIT(0xccdba7f8b2a8f6c9), +W64LIT(0x4c5e6474b5a922a4), +W64LIT(0x5d31adcd541ccc32), +W64LIT(0x9b7f701e8c3456a7), +W64LIT(0x2ac9cd08ecfd593a), +W64LIT(0x8fa0844858c18e1f), +W64LIT(0x32f0c66c745bc9ea), +W64LIT(0xc58d6525cbbb888f), +W64LIT(0x8c633cbe4b529c05), +W64LIT(0xf2cd9ea68aa0774b), +W64LIT(0x2cba4811ca2e7d0e), +W64LIT(0xe2e33f4dc9649778), +W64LIT(0xf4be1bbfac73537f), +W64LIT(0x22de6787379f29d9), +W64LIT(0x0956c2dd79137e46), +W64LIT(0xe061efe978868bc7), +W64LIT(0x1cc85ed90f97a85b), +W64LIT(0x31337e9a67c8dbf0), +W64LIT(0x360193d1e36af161), +W64LIT(0x7fefca4a6383e5eb), +W64LIT(0x8535fe633241e243), +W64LIT(0xc3fee03ced68acbb), +W64LIT(0x81c4abdea570dac8), +W64LIT(0x67d6c12efb25753b), +W64LIT(0xa4282112164dd980), +W64LIT(0xcf181f0ea13be4d3), +W64LIT(0xa98fb672f86f9f4d), +W64LIT(0x5c70c59ff66dc297), +W64LIT(0xb0f7d544c2b80138), +W64LIT(0x0da79760ee2246cd), +W64LIT(0x3740fb83411bffc4), +W64LIT(0x24ade29e114c0ded), +W64LIT(0xf858e48de0201b17), +W64LIT(0x0e642f96fdb154d7), +W64LIT(0xddb46e41531d185f), +W64LIT(0x25ec8accb33d0348), +W64LIT(0x0282d0a4b1e21cbf), +W64LIT(0x1bfab3928b3582ca), +W64LIT(0xaffc336bdebcbb79), +W64LIT(0x35c22b27f0f9e37b), +W64LIT(0x03c3b8f61393121a), +W64LIT(0xb8e07fcb19da71db), +W64LIT(0x99fda0ba3dd64a18), +W64LIT(0xce59775c034aea76), +W64LIT(0x49ee599b80e9148a), +W64LIT(0xfe2b6194c6f33f23), +W64LIT(0x4edcb4d0044b3e1b), +W64LIT(0xd5a3c4ce887f68bc), +W64LIT(0xdf36bee5e2ff04e0), +W64LIT(0x171c4ca0c766caa2), +W64LIT(0x0bd41279c8f162f9), +W64LIT(0xe490ba54efb7b34c), +W64LIT(0x5b4228d472cfe806), +W64LIT(0x5355825ba9ad98e5), +W64LIT(0x9f8e25a31b056e2c), +W64LIT(0xcd9acfaa10d9f86c), +W64LIT(0x88926903dc63a48e), +W64LIT(0xb40680f9558939b3), +W64LIT(0x239f0fd595ee277c), +W64LIT(0xec8710db34d5c3af), +W64LIT(0x87b72ec783a3fefc), +W64LIT(0x632794936c144db0), +W64LIT(0x46cb1e5fdf294ef8), +W64LIT(0x83467b7a1492c677), +W64LIT(0x9c4d9d5508967c36), +W64LIT(0xd6607c389bec7aa6), +W64LIT(0x165d24f26517c407), +W64LIT(0xc4cc0d7769ca862a), +W64LIT(0xcbe94ab3360adc58), +W64LIT(0x847496319030ece6), +W64LIT(0x7a5ff7a556c3d3c5), +W64LIT(0xc03d58cafefbbea1), +W64LIT(0x76b908971a909bad), +W64LIT(0x2f79f0e7d9bd6f14), +W64LIT(0x197863363ad79e75), +W64LIT(0xda86830ad7bf32ce), +W64LIT(0x5a034086d0bee6a3), +W64LIT(0x97998f2cc0671ecf), +W64LIT(0x552607428f7ebcd1), +W64LIT(0x51d752ff184f845a), +W64LIT(0xbb23c73d0a4963c1), +W64LIT(0x2b88a55a4e8c579f), +W64LIT(0xd80453ae665d2e71), +W64LIT(0xee05c07f8537df10), +W64LIT(0x423a4be248187673), +W64LIT(0xcaa822e1947bd2fd), +W64LIT(0x1abbdbc029448c6f), +W64LIT(0x96d8e77e6216106a), +W64LIT(0x6266fcc1ce654315), +W64LIT(0x89d301517e12aa2b), +W64LIT(0x730935782fd0ad83), +W64LIT(0x8085c38c0701d46d), +W64LIT(0x6b303e1cb7763d53), +W64LIT(0x3f57510c9a798f27), +W64LIT(0x4449cefb6ecb5247), +W64LIT(0x48af31c922981a2f), +W64LIT(0x98bcc8e89fa744bd), +W64LIT(0x69b2eeb8069421ec), +W64LIT(0xebb5fd90b077e93e), +W64LIT(0x6a71564e150733f6), +W64LIT(0x116fc9b9e1b5ee96), +W64LIT(0x4a2de16d937a0690), +W64LIT(0xb9a11799bbab7f7e), +W64LIT(0x9368da9157562644), +W64LIT(0x718be5dc9e32b13c), +W64LIT(0xc82af2452599ce42), +W64LIT(0xb547e8abf7f83716), +W64LIT(0x33b1ae3ed62ac74f), +W64LIT(0x799c4f534550c1df), +W64LIT(0x3e16395e38088182), +W64LIT(0x7c2c72bc7010f7f1), +W64LIT(0xf38cf6f428d179ee), +W64LIT(0xd29129850cdd422d), +W64LIT(0x41f9f3145b8b6469), +W64LIT(0x945a37dad3f40cd5), +W64LIT(0x757ab061090389b7), +W64LIT(0x6554118a4ac76984), +W64LIT(0x7d6d1aeed261f954), +W64LIT(0x01416852a2710ea5), +W64LIT(0xb27505e0735a1d87), +W64LIT(0x77f860c5b8e19508), +W64LIT(0x78dd2701e721cf7a), +W64LIT(0xe12087bbdaf78562), +W64LIT(0x86f6469521d2f059), +W64LIT(0xef44a82d2746d1b5), +W64LIT(0xbc112a768eeb4950), +W64LIT(0xc2bf886e4f19a21e), +W64LIT(0x307216c8c5b9d555), +W64LIT(0xc96b9a1787e8c0e7), +W64LIT(0xa31acc5992eff311), +W64LIT(0xa0d974af817ce10b), +W64LIT(0xdcf50613f16c16fa), +W64LIT(0xfca9b1307711239c), +W64LIT(0x57a4d7e63e9ca06e), +W64LIT(0xc64eddd3d8289a95), +W64LIT(0xa25ba40b309efdb4), +W64LIT(0x2e3898b57bcc61b1), +W64LIT(0xf5ff73ed0e025dda), +W64LIT(0xa6aaf1b6a7afc53f), +W64LIT(0xd9453bfcc42c20d4), +W64LIT(0x9d0cf507aae77293), +W64LIT(0x290a75feff6e4b20), +W64LIT(0xa7eb99e405decb9a), +W64LIT(0xa1981cfd230defae), +W64LIT(0x12ac714ff226fc8c), +W64LIT(0x743bd833ab728712), +W64LIT(0x6c02d35733d417c2), +W64LIT(0xe9372d340195f581), +W64LIT(0xf77da349bfe04165), +W64LIT(0x68f386eaa4e52f49), +W64LIT(0x211ddf71240c3bc3), +W64LIT(0x13ed191d5057f229), +W64LIT(0xe8764566a3e4fb24), +W64LIT(0xf9198cdf425115b2), +W64LIT(0xd013f921bd3f5e92), +W64LIT(0x91ea0a35e6b43afb), +W64LIT(0x0732ed4b84a22a91), +W64LIT(0xeaf495c21206e79b), +W64LIT(0x5214ea090bdc9640), +W64LIT(0x0000000000000000), +W64LIT(0xb3346db2d12b1322), +W64LIT(0x0ce6ff324c534868), +W64LIT(0xaebd5b397ccdb5dc), +W64LIT(0x0a957a2b6a806c5c), +W64LIT(0x1f0be62f1c04ba41), +W64LIT(0x14dff456d4f5d8b8), +W64LIT(0x58819022615cfa1c), +W64LIT(0x05b03def3540362e), +W64LIT(0xe3a2571f6b1599dd), +W64LIT(0x9229b2c3f52728e1), +W64LIT(0xba62af6fa8386d64), +W64LIT(0x0673851926d32434), +W64LIT(0x641579d8e8b66721), +W64LIT(0x04f155bd9731388b), +W64LIT(0x9ecf4df1b9746089), +W64LIT(0x205cb723867d3566), +W64LIT(0x102ea1eb43c4e033), +W64LIT(0x3ba604b10d48b7ac), +W64LIT(0x50963aadba3e8aff), +W64LIT(0xac3f8b9dcd2fa963), +W64LIT(0x7b1e9ff7f4b2dd60), +W64LIT(0xf63ccb1b1d914fc0), +W64LIT(0x7eaea218c1f2eb4e), +W64LIT(0x5fb37d69e5fed08d), +W64LIT(0x56e5bfb49cedaecb), +W64LIT(0x2dfb2043685f73ab), +W64LIT(0x61a54437ddf6510f), +W64LIT(0x6fc16ba1204705d8), +W64LIT(0xe75302a2fc24a156), +W64LIT(0x3dd581a82b9b9398), +W64LIT(0xdbc7eb5875ce3c6b), +W64LIT(0x90ab626744c5345e), +W64LIT(0x59c0f870c32df4b9), +W64LIT(0x6697a97c59547b9e), +W64LIT(0xfde8d962d5602d39), +W64LIT(0xd3d041d7aeac4c88), +W64LIT(0x5ef2153b478fde28), +W64LIT(0xd4e2ac9c2a0e6619), +W64LIT(0x1e4a8e7dbe75b4e4), +W64LIT(0x72485d2a8da1a326), +W64LIT(0x437b23b0ea6978d6), +W64LIT(0x159e9c047684d61d), +W64LIT(0x0f2547c45fc05a72), +W64LIT(0xf10e265099336551), +W64LIT(0x3c94e9fa89ea9d3d), +W64LIT(0xbfd292809d785b4a), +W64LIT(0x0817aa8fdb6270e3), +W64LIT(0x60e42c657f875faa), +W64LIT(0x18390b6498a690d0), +W64LIT(0x478a760d7d58405d), +W64LIT(0x284b1dac5d1f4585), +W64LIT(0xb1b6bd1660c90f9d), +W64LIT(0xd15291731f4e5037), +W64LIT(0x4d1f0c2617d82c01), +W64LIT(0xc70fb5817a599430), +W64LIT(0x6d43bb0591a51967), +W64LIT(0x6e8003f382360b7d), +W64LIT(0x1d89368bade6a6fe), +W64LIT(0x4f9ddc82a63a30be), +W64LIT(0xedc6788996a4cd0a), +W64LIT(0xab0d66d6498d83f2), +W64LIT(0x54676f102d0fb274), +W64LIT(0xc17c30985c8ab004), +W64LIT(0x3865bc471edba5b6), +W64LIT(0x3924d415bcaaab13), +W64LIT(0x951b5f8871850270), +W64LIT(0x8a10b9a76d81b831), +W64LIT(0xbd5042242c9a47f5), +W64LIT(0xa5694940b43cd725), +W64LIT(0xff6a09c664823186), +W64LIT(0x8d2254ece92392a0), +W64LIT(0xb7c5380f461a2ba9), +W64LIT(0x82071328b6e3c8d2), +W64LIT(0xd721146a399d7403), +W64LIT(0xfada342951c207a8), +W64LIT(0x262f323aa0ae1152), +W64LIT(0xf04f4e023b426bf4), +W64LIT(0x276e5a6802df1ff7), +/* box 1 */ +W64LIT(0x3b4016dbfd16e203), +W64LIT(0x9a7574c51174530a), +W64LIT(0x90012e69c02ec8d3), +W64LIT(0xf44580e3d780e076), +W64LIT(0xf81dec2b49eca14b), +W64LIT(0x26cae3e8a6e3d7ef), +W64LIT(0x0962419e0c41f6ab), +W64LIT(0x54d1eb4070ebd951), +W64LIT(0x865e884b0188eec8), +W64LIT(0xdf76067ea406fe8a), +W64LIT(0x29849412e594fba0), +W64LIT(0x461569896869c0f2), +W64LIT(0xb5ddd6b3bbd6724e), +W64LIT(0x0c586cc89e6c413d), +W64LIT(0x6b0ad97054d904ea), +W64LIT(0xa135621eec62b109), +W64LIT(0x0eef7e47087ea461), +W64LIT(0xfaaafea4dffe4417), +W64LIT(0xe0ad344e80342331), +W64LIT(0xab4138b23d382ad0), +W64LIT(0x107390468e90fcff), +W64LIT(0xbe0885a2218561b9), +W64LIT(0xdbed22957d22c132), +W64LIT(0x2251c7037fc7e857), +W64LIT(0x33835ef8ba5e9c86), +W64LIT(0xb3f1e0d7f4e0a8aa), +W64LIT(0x3fdb32302432ddbb), +W64LIT(0xa719547aa3546bed), +W64LIT(0xe10c3df3cb3dab1f), +W64LIT(0x17feaf9f8aafae35), +W64LIT(0x9df84b1c154b01c0), +W64LIT(0x8364a51d93a5595e), +W64LIT(0x535cd49974d48b9b), +W64LIT(0x01a109bd4b09882e), +W64LIT(0xc4d0c529b0c51182), +W64LIT(0x2e09abcbe1aba96a), +W64LIT(0x1f3de7bccde7d0b0), +W64LIT(0x9317355b1d35a5a1), +W64LIT(0x6c87e6a950e65620), +W64LIT(0x8910ffb142ffc287), +W64LIT(0x40395fed275f1a16), +W64LIT(0x7b794936da49f815), +W64LIT(0xf269b68798b63a92), +W64LIT(0xfd27c17ddbc116dd), +W64LIT(0x8d8bdb5a9bdbfd3f), +W64LIT(0x1ba6c35714c3ef08), +W64LIT(0x6e30f426c6f4b37c), +W64LIT(0x7fe26ddd036dc7ad), +W64LIT(0x14e8b4ad57b4c347), +W64LIT(0xb985ba7b25ba3373), +W64LIT(0xe9cf75d08c75d59a), +W64LIT(0x626898ee5898f241), +W64LIT(0x5b9f9cba339cf51e), +W64LIT(0xb250e96abfe92084), +W64LIT(0x165fa622c1a6261b), +W64LIT(0xf5e4895e9c896858), +W64LIT(0xb76ac43c2dc49712), +W64LIT(0x02b7128f9612e55c), +W64LIT(0x1d8af5335bf535ec), +W64LIT(0x36b973ae28732b10), +W64LIT(0xa8572380e02347a2), +W64LIT(0xf6f2926c4192052a), +W64LIT(0x8c2ad2e7d0d27511), +W64LIT(0xd32e6ab63a6abfb7), +W64LIT(0xbd1e9e90fc9e0ccb), +W64LIT(0x03161b32dd1b6d72), +W64LIT(0x4dc03a98f23ad305), +W64LIT(0x81d3b79205b7bc02), +W64LIT(0x450372bbb572ad80), +W64LIT(0x2d1fb0f93cb0c418), +W64LIT(0x2a928f20388f96d2), +W64LIT(0x721b08a8d6080ebe), +W64LIT(0x92b63ce6563c2d8f), +W64LIT(0xeb78675f1a6730c6), +W64LIT(0x13658b74538b918d), +W64LIT(0x428e4d62b14dff4a), +W64LIT(0x88b1f60c09f64aa9), +W64LIT(0x75963771d2375c74), +W64LIT(0x7ad8408b9140703b), +W64LIT(0x57c7f072adf0b423), +W64LIT(0xe5971918121994a7), +W64LIT(0x5666f9cfe6f93c0d), +W64LIT(0x8f3cc9d50dc91863), +W64LIT(0x1e9cee0186ee589e), +W64LIT(0x8a06e4839fe4aff5), +W64LIT(0xb824b3c66eb3bb5d), +W64LIT(0xd1997839ac785aeb), +W64LIT(0x6752b5b8cab545d7), +W64LIT(0xb47cdf0ef0dffa60), +W64LIT(0x949a0a82190af76b), +W64LIT(0xc04be1c269e12e3a), +W64LIT(0xfc86c8c090c89ef3), +W64LIT(0xe3bb2f7c5d2f4e43), +W64LIT(0x6aabd0cd1fd08cc4), +W64LIT(0x2147dc31a2dc8525), +W64LIT(0xca3fbb6eb8bbb5e3), +W64LIT(0x48fa17ce60176493), +W64LIT(0x6444ae8a17ae28a5), +W64LIT(0x2b33869d73861efc), +W64LIT(0xd0387184e771d2c5), +W64LIT(0x7cf476efde76aadf), +W64LIT(0x63c9915313917a6f), +W64LIT(0xc929a05c65a0d891), +W64LIT(0xda4c2b28362b491c), +W64LIT(0xfe31da4f06da7baf), +W64LIT(0xc1eae87f22e8a614), +W64LIT(0x5c12a36337a3a7d4), +W64LIT(0x18b0d865c9d8827a), +W64LIT(0xe7200b97840b71fb), +W64LIT(0x4bec0cfcbd0c09e1), +W64LIT(0x0f4e77fa43772c4f), +W64LIT(0x4c613325b9335b2b), +W64LIT(0xf3c8bf3ad3bfb2bc), +W64LIT(0x87ff81f64a8166e6), +W64LIT(0xa38270917a705455), +W64LIT(0x1911d1d882d10a54), +W64LIT(0x44a27b06fe7b25ae), +W64LIT(0x049b24ebd9243fb8), +W64LIT(0xbb32a8f4b3a8d62f), +W64LIT(0x91a027d48b2740fd), +W64LIT(0x3d6c20bfb22038e7), +W64LIT(0xe681022acf02f9d5), +W64LIT(0xf17fadb545ad57e0), +W64LIT(0xcc138d0af78d6f07), +W64LIT(0x495b1e732b1eecbd), +W64LIT(0x38560de9200d8f71), +W64LIT(0xa9f62a3dab2acf8c), +W64LIT(0x47b46034236048dc), +W64LIT(0x8e9dc06846c0904d), +W64LIT(0xaccc076b3907781a), +W64LIT(0x32225745f15714a8), +W64LIT(0xd4a3556f3e55ed7d), +W64LIT(0xd7b54e5de34e800f), +W64LIT(0xddc114f132141bd6), +W64LIT(0x6d26ef141befde0e), +W64LIT(0x85489379dc9383ba), +W64LIT(0x0bd553119a5313f7), +W64LIT(0x786f520407529567), +W64LIT(0xcb9eb2d3f3b23dcd), +W64LIT(0xa223792c3179dc7b), +W64LIT(0x0a745aacd15a9bd9), +W64LIT(0x710d139a0b1363cc), +W64LIT(0x681cc24289c26998), +W64LIT(0x1a07caea5fca6726), +W64LIT(0x82c5aca0d8acd170), +W64LIT(0x25dcf8da7bf8ba9d), +W64LIT(0xc7c6de1b6dde7cf0), +W64LIT(0xc35dfaf0b4fa4348), +W64LIT(0xded70fc3ef0f76a4), +W64LIT(0x504acfaba9cfe6e9), +W64LIT(0xc571cc94fbcc99ac), +W64LIT(0x5ea5b1eca1b14288), +W64LIT(0xae7b15e4af159d46), +W64LIT(0xc888a9e12ea950bf), +W64LIT(0xf7539bd10a9b8d04), +W64LIT(0x962d180d8f181237), +W64LIT(0xe43610a559101c89), +W64LIT(0x772125fe4425b928), +W64LIT(0x84e99ac4979a0b94), +W64LIT(0xc667d7a626d7f4de), +W64LIT(0xefe343b4c3430f7e), +W64LIT(0xd5025cd2755c6553), +W64LIT(0xa6b85dc7e85de3c3), +W64LIT(0xd61447e0a8470821), +W64LIT(0x3e7a3b8d6f3b5595), +W64LIT(0x52fddd243fdd03b5), +W64LIT(0x8072be2f4ebe342c), +W64LIT(0x12c482c9188219a3), +W64LIT(0x9eee502ec8506cb2), +W64LIT(0xad6d0ed6720ef034), +W64LIT(0x59288e35a58e1042), +W64LIT(0xe21a26c11626c66d), +W64LIT(0x247df16730f132b3), +W64LIT(0xf0dea4080ea4dfce), +W64LIT(0x31344c772c4c79da), +W64LIT(0x4f77281764283659), +W64LIT(0x79ce5bb94c5b1d49), +W64LIT(0x0000000000000000), +W64LIT(0x73ba01159d018690), +W64LIT(0x74373ecc993ed45a), +W64LIT(0xbcbf972db79784e5), +W64LIT(0x4ed621aa2f21be77), +W64LIT(0xd95a301aeb30246e), +W64LIT(0x9c5942a15e4289ee), +W64LIT(0x37187a13637aa33e), +W64LIT(0x276bea55edea5fc1), +W64LIT(0x1c2bfc8e10fcbdc2), +W64LIT(0xed54513b5551ea22), +W64LIT(0x20e6d58ce9d50d0b), +W64LIT(0x3ae11f66b61f6a2d), +W64LIT(0x66f3bc0581bccdf9), +W64LIT(0x2cbeb94477b94c36), +W64LIT(0x99636ff7cc6f3e78), +W64LIT(0x953b033f52037f45), +W64LIT(0xb0e7fbe529fbc5d8), +W64LIT(0x60df8a61ce8a171d), +W64LIT(0x6f91fd9b8dfd3b52), +W64LIT(0xaae0310f7631a2fe), +W64LIT(0xbfa98c1f6a8ce997), +W64LIT(0x8ba7ed3ed4ed27db), +W64LIT(0x98c2664a8766b656), +W64LIT(0x062c36644f36dae4), +W64LIT(0x5570e2fd3be2517f), +W64LIT(0xead96ee2516eb8e8), +W64LIT(0x419856506c569238), +W64LIT(0x23f0cebe34ce6079), +W64LIT(0x309545ca6745f1f4), +W64LIT(0x5a3e950778957d30), +W64LIT(0x617e83dc85839f33), +W64LIT(0xfb0bf71994f7cc39), +W64LIT(0x3ccd2902f929b0c9), +W64LIT(0x70ac1a27401aebe2), +W64LIT(0xcea49f85619f8a5b), +W64LIT(0x39f704546b04075f), +W64LIT(0x0df96575d565c913), +W64LIT(0x08c3482347487e85), +W64LIT(0xd28f630b71633799), +W64LIT(0xecf558861e58620c), +W64LIT(0xc2fcf34dfff3cb66), +W64LIT(0x978c11b0c4119a19), +W64LIT(0x69bdcbffc2cbe1b6), +W64LIT(0xba93a149f8a15e01), +W64LIT(0x51ebc616e2c66ec7), +W64LIT(0x078d3fd9043f52ca), +W64LIT(0x58898788ee87986c), +W64LIT(0x4a4d0541f60581cf), +W64LIT(0xe86e7c6dc77c5db4), +W64LIT(0xee424a09884a8750), +W64LIT(0xcdb284b7bc84e729), +W64LIT(0x65e5a7375ca7a08b), +W64LIT(0x2fa8a276aaa22144), +W64LIT(0xa0946ba3a76b3927), +W64LIT(0xa5ae46f535468eb1), +W64LIT(0x35af689cf5684662), +W64LIT(0x28259dafae9d738e), +W64LIT(0xcf0596382a960275), +W64LIT(0xb6cbcd8166cd1f3c), +W64LIT(0x7e43646048644f83), +W64LIT(0x9bd47d785a7ddb24), +W64LIT(0x432f44dffa447764), +W64LIT(0x9f4f59938359e49c), +W64LIT(0x7d557f52957f22f1), +W64LIT(0x76802c430f2c3106), +W64LIT(0xdc601d4c791d93f8), +W64LIT(0x053a2d56922db796), +W64LIT(0x11d299fbc59974d1), +W64LIT(0xf9bce59602e52965), +W64LIT(0xd8fb39a7a039ac40), +W64LIT(0x340e6121be61ce4c), +W64LIT(0x5f04b851eab8caa6), +W64LIT(0x5db3aade7caa2ffa), +W64LIT(0x1549bd101cbd4b69), +W64LIT(0xff90d3f24dd3f381), +W64LIT(0xafda1c59e41c1568), +W64LIT(0xb146f25862f24df6), +W64LIT(0xa40f4f487e4f069f), +/* box 2 */ +W64LIT(0xa1a35cebf8f0f94c), +W64LIT(0x2c203d650f3f095d), +W64LIT(0x1a2bdaee4084a2a7), +W64LIT(0xd32404574d7bcc68), +W64LIT(0xf785bea594a9adc4), +W64LIT(0xf2eb54456206949c), +W64LIT(0x3f5e334d0475ced1), +W64LIT(0x5994299b835d1f60), +W64LIT(0x785b7989ac204794), +W64LIT(0x025da6a2cf461a41), +W64LIT(0xdf1f3a71f01a901b), +W64LIT(0x27284f018bb77637), +W64LIT(0xe1955a6d694c5310), +W64LIT(0x24a1baf2d9d261ac), +W64LIT(0xe4fbb08d9fe36a48), +W64LIT(0x8d83618ef7cff011), +W64LIT(0x2ac72276abf5279e), +W64LIT(0xf9e32621e68eebf6), +W64LIT(0xbf323fb4d3f86f69), +W64LIT(0xbb888605b8745beb), +W64LIT(0x70dafe1e7acd2f65), +W64LIT(0xd0adf1a41f1edbf3), +W64LIT(0x1e91635f2b089625), +W64LIT(0xee2791b8864818f8), +W64LIT(0x99ce23e4c56c1484), +W64LIT(0xf33f0714ff259946), +W64LIT(0xbd6f99161cbe7528), +W64LIT(0x9f293cf761a63a47), +W64LIT(0xb80173f6ea114c70), +W64LIT(0x6543ef25d54dc62a), +W64LIT(0x39b92c5ea0bfe012), +W64LIT(0x63a4f0367187e8e9), +W64LIT(0x4c0d38a02cddf62f), +W64LIT(0x07334c4239e92319), +W64LIT(0x43bff375c3d9bdc7), +W64LIT(0xca862b4a5f9a7954), +W64LIT(0x5d2e902ae8d12be2), +W64LIT(0x137e0e280b4ac78c), +W64LIT(0xf162a1b630638307), +W64LIT(0x55af17bd3e3c4313), +W64LIT(0x358212781ddebc61), +W64LIT(0x94214e93e52e452d), +W64LIT(0xc18e592edb12063e), +W64LIT(0xec7a371a490e02b9), +W64LIT(0x4963d240da72cf77), +W64LIT(0x41e255d70c9fa786), +W64LIT(0xff0439324244c535), +W64LIT(0x88ed8b6e0160c949), +W64LIT(0x6c163be39e83a301), +W64LIT(0xc534e09fb09e32bc), +W64LIT(0x806c0cf9d78da1b8), +W64LIT(0xdba583c09b96a499), +W64LIT(0x746047af11411be7), +W64LIT(0xf40c4b56c6ccba5f), +W64LIT(0x6270a367eca4e533), +W64LIT(0xd41748157492ef71), +W64LIT(0xeff3c2e91b6b1522), +W64LIT(0x0e66988472274632), +W64LIT(0x534808ae9af66dd0), +W64LIT(0x8231aa5b18cbbbf9), +W64LIT(0xb2dd52c3f3ba3ec0), +W64LIT(0xdd429cd33f5c8a5a), +W64LIT(0x4e509e02e39bec6e), +W64LIT(0x26fc1c5016947bed), +W64LIT(0xd9f8256254d0bed8), +W64LIT(0x0955d4c64bce652b), +W64LIT(0x1610e4c8fde5fed4), +W64LIT(0x6dc268b203a0aedb), +W64LIT(0x2e7d9bc7c079131c), +W64LIT(0xc3d3ff8c14541c7f), +W64LIT(0xd64aeeb7bbd4f530), +W64LIT(0xab7f7ddee15b8bfc), +W64LIT(0x144d426a32a3e495), +W64LIT(0x8e0a947da5aae78a), +W64LIT(0x798f2ad831034a4e), +W64LIT(0x3be48afc6ff9fa53), +W64LIT(0x529c5bff07d5600a), +W64LIT(0xbee66ce54edb62b3), +W64LIT(0x931202d1dcc76634), +W64LIT(0x50c1fd5dc8937a4b), +W64LIT(0xa4cdb60b0e5fc014), +W64LIT(0x57f2b11ff17a5952), +W64LIT(0x47054ac4a8558945), +W64LIT(0x5a1ddc68d13808fb), +W64LIT(0x5cfac37b75f22638), +W64LIT(0xc207acdd897711a5), +W64LIT(0x289a84d464b33ddf), +W64LIT(0xc05a0a7f46310be4), +W64LIT(0xe6a6162f50a57009), +W64LIT(0x06e71f13a4ca2ec3), +W64LIT(0x5f733688279731a3), +W64LIT(0xeb497b5870e721a0), +W64LIT(0xb667eb7298360a42), +W64LIT(0xe3c8fccfa60a4951), +W64LIT(0xe772457ecd867dd3), +W64LIT(0x6978d103682c9a59), +W64LIT(0x0def6d77204251a9), +W64LIT(0xc90fdeb90dff6ecf), +W64LIT(0xd179a2f5823dd629), +W64LIT(0x2fa9c8965d5a1ec6), +W64LIT(0x81b85fa84aaeac62), +W64LIT(0xdc96cf82a27f8780), +W64LIT(0x602d05c523e2ff72), +W64LIT(0x19a22f1d12e1b53c), +W64LIT(0xe52fe3dc02c06792), +W64LIT(0x58407aca1e7e12ba), +W64LIT(0x61f95694bec1f2a8), +W64LIT(0x48b781114751c2ad), +W64LIT(0xaaab2e8f7c788626), +W64LIT(0x04bab9b16b8c3482), +W64LIT(0x2df46e34921c0487), +W64LIT(0x1123a88ac40cddcd), +W64LIT(0xc6bd156ce2fb2527), +W64LIT(0x7f6835cb95c9648d), +W64LIT(0x83e5f90a85e8b623), +W64LIT(0x4f84cd537eb8e1b4), +W64LIT(0x294ed785f9903005), +W64LIT(0x1cccc5fde44e8c64), +W64LIT(0xcb52781bc2b9748e), +W64LIT(0x1d1896ac796d81be), +W64LIT(0xb30901926e99331a), +W64LIT(0xad9862cd4591a53f), +W64LIT(0xc8db8de890dc6315), +W64LIT(0x7bd28c7afe45500f), +W64LIT(0x0adc213519ab72b0), +W64LIT(0xa8f6882db33e9c67), +W64LIT(0xb5ee1e81ca531dd9), +W64LIT(0x201b0343b25e552e), +W64LIT(0x4036068691bcaa5c), +W64LIT(0xae11973e17f4b2a4), +W64LIT(0x9efd6fa6fc85379d), +W64LIT(0x33650d6bb91492a2), +W64LIT(0x3a30d9adf2daf789), +W64LIT(0x0c3b3e26bd615c73), +W64LIT(0xf651edf4098aa01e), +W64LIT(0x710ead4fe7ee22bf), +W64LIT(0x3138abc9765288e3), +W64LIT(0x9d749a55aee02006), +W64LIT(0x6e4b9d4151c5b940), +W64LIT(0x84d6b548bc01953a), +W64LIT(0x360be78b4fbbabfa), +W64LIT(0xa22aa918aa95eed7), +W64LIT(0xedae644bd42d0f63), +W64LIT(0x46d119953576849f), +W64LIT(0x6497bc74486ecbf0), +W64LIT(0xfbbe808329c8f1b7), +W64LIT(0x4aea27b38817d8ec), +W64LIT(0x5626e24e6c595488), +W64LIT(0x056eeae0f6af3958), +W64LIT(0x4558ec6667139304), +W64LIT(0x448cbf37fa309ede), +W64LIT(0x6f9fce10cce6b49a), +W64LIT(0xa0770fba65d3f496), +W64LIT(0x671e49871a0bdc6b), +W64LIT(0xda71d09106b5a943), +W64LIT(0x08818797d6ed68f1), +W64LIT(0xa3fefa4937b6e30d), +W64LIT(0xb080f4613cfc2481), +W64LIT(0x763de10dde0701a6), +W64LIT(0x4dd96bf1b1fefbf5), +W64LIT(0x92c6518041e46bee), +W64LIT(0x3456412980fdb1bb), +W64LIT(0x981a70b5584f195e), +W64LIT(0x3d0395efcb33d490), +W64LIT(0xba5cd55425575631), +W64LIT(0x4b3e74e21534d536), +W64LIT(0x6af124f03a498dc2), +W64LIT(0x7ebc669a08ea6957), +W64LIT(0x30ecf898eb718539), +W64LIT(0xa922db7c2e1d91bd), +W64LIT(0x7a06df2b63665dd5), +W64LIT(0xb154a730a1df295b), +W64LIT(0xfc8dccc11021d2ae), +W64LIT(0xcfe8c1aaa935400c), +W64LIT(0x97a8bb60b74b52b6), +W64LIT(0x18767c4c8fc2b8e6), +W64LIT(0x9a47d6179709031f), +W64LIT(0x0000000000000000), +W64LIT(0xac4c319cd8b2a8e5), +W64LIT(0xb9d520a7773241aa), +W64LIT(0xdecb69206d399dc1), +W64LIT(0x1f45300eb62b9bff), +W64LIT(0x10f7fbdb592fd017), +W64LIT(0x3e8a601c9956c30b), +W64LIT(0x8502e619212298e0), +W64LIT(0xf5d818075befb785), +W64LIT(0x547b44eca31f4ec9), +W64LIT(0x9ca0c90433c32ddc), +W64LIT(0xe041093cf46f5eca), +W64LIT(0xa69010a9c119da55), +W64LIT(0xc769463d7fd828fd), +W64LIT(0xc4e0b3ce2dbd3f66), +W64LIT(0x2575e9a344f16c76), +W64LIT(0x01d453519d230dda), +W64LIT(0xfa6ad3d2b4ebfc6d), +W64LIT(0xd5c31b44e9b1e2ab), +W64LIT(0xf83775707bade62c), +W64LIT(0xbcbbca47819d78f2), +W64LIT(0xd79ebde626f7f8ea), +W64LIT(0x5bc98f394c1b0521), +W64LIT(0x2246a5e17d184f6f), +W64LIT(0x12aa5d799669ca56), +W64LIT(0x5ea765d9bab43c79), +W64LIT(0x8939d83f9c43c493), +W64LIT(0x32b15e3a24379f78), +W64LIT(0xe914ddfabfa13be1), +W64LIT(0x909bf7228ea271af), +W64LIT(0x73530bed28a838fe), +W64LIT(0xd2f05706d058c1b2), +W64LIT(0xfed06a63df67c8ef), +W64LIT(0xb43a4dd057701003), +W64LIT(0xa519e55a937ccdce), +W64LIT(0x75b414fe8c62163d), +W64LIT(0xafc5c46f8ad7bf7e), +W64LIT(0x2392f6b0e03b42b5), +W64LIT(0x386d7f0f3d9cedc8), +W64LIT(0x21cf50122f7d58f4), +W64LIT(0x9b9385460a2a0ec5), +W64LIT(0x5115ae0c55b07791), +W64LIT(0x0fb2cbd5ef044be8), +W64LIT(0xea9d2809edc42c7a), +W64LIT(0xcc613459fb505797), +W64LIT(0x426ba0245efab01d), +W64LIT(0x1599113baf80e94f), +W64LIT(0x7d3593695a8f7ecc), +W64LIT(0x0389f5f35265179b), +W64LIT(0x875f40bbee6482a1), +W64LIT(0x95f51dc2780d48f7), +W64LIT(0x7ce1c038c7ac7316), +W64LIT(0xce3c92fb34164dd6), +W64LIT(0xcdb5670866735a4d), +W64LIT(0x8ab02dccce26d308), +W64LIT(0x914fa47313817c75), +W64LIT(0x8b647e9d5305ded2), +W64LIT(0xd82c7633c9f3b302), +W64LIT(0x728758bcb58b3524), +W64LIT(0xe8c08eab2282363b), +W64LIT(0x8fdec72c3889ea50), +W64LIT(0x2b13712736d62a44), +W64LIT(0x3cd7c6be5610d94a), +W64LIT(0x37dfb4dad298a620), +W64LIT(0x868b13ea73478f7b), +W64LIT(0xb7b3b82305150798), +W64LIT(0x0b08726484887f6a), +W64LIT(0x1bff89bfdda7af7d), +W64LIT(0x77e9b25c43240c7c), +W64LIT(0xf0b6f2e7ad408edd), +W64LIT(0x17c4b79960c6f30e), +W64LIT(0x8c5732df6aecfdcb), +W64LIT(0x68ac8252f50f9783), +W64LIT(0x66ca1ad68728d1b1), +W64LIT(0x6b2577a1a76a8018), +W64LIT(0xe21caf9e3b29448b), +W64LIT(0xa74443f85c3ad78f), +W64LIT(0xfd599f908d02df74), +W64LIT(0x967ce8312a685f6c), +/* box 3 */ +W64LIT(0xfa7b9775ba3af751), +W64LIT(0x03ef98cb769c2d13), +W64LIT(0x7191ce067072359e), +W64LIT(0xbab18b6bff7516a8), +W64LIT(0xe6e5ef4efbc1065e), +W64LIT(0x7bec74a3b1d0dbf4), +W64LIT(0x656b4fb907c31c4a), +W64LIT(0x4e8520f99fc86304), +W64LIT(0x8fd8df31d16dae58), +W64LIT(0x90a93fc1e60a7244), +W64LIT(0x30ad09f2b449cfc5), +W64LIT(0x8453be7e91bb5b90), +W64LIT(0x1d68a3d1c08feaad), +W64LIT(0x5c54642504b410f6), +W64LIT(0x8061383c8a9e3707), +W64LIT(0xf9940fbecca6da42), +W64LIT(0x46e1d97da982bbdf), +W64LIT(0xfc50521656f7ad77), +W64LIT(0x5e4d2704f35c2647), +W64LIT(0x8bea5973ca48c2cf), +W64LIT(0xd06323dfa34593bd), +W64LIT(0x62b651306a7a5dce), +W64LIT(0xa436b0714966d116), +W64LIT(0x4f73fb131ebc78a6), +W64LIT(0x92b07ce011e244f5), +W64LIT(0x33429139c2d5e2d6), +W64LIT(0xcee418c515565403), +W64LIT(0xd7be3d56cefcd239), +W64LIT(0x53ed83285f4789a9), +W64LIT(0xf3e9b51b0d043428), +W64LIT(0x20650e0fd8dd8a86), +W64LIT(0xb6e7f4add21aa2e4), +W64LIT(0x6d0fb63d3189c491), +W64LIT(0x0da0a42cac1bafee), +W64LIT(0x3f14eeffefba569a), +W64LIT(0x13279f361a086850), +W64LIT(0x9b225e8ea6dc878c), +W64LIT(0x6684d772715f3159), +W64LIT(0xa3ebaef824df9092), +W64LIT(0xc499a260d4f4ba69), +W64LIT(0xaa798c9693e153eb), +W64LIT(0x50021be329dba4ba), +W64LIT(0x949bb983fd2f1ed3), +W64LIT(0xdfdac4d2f8b60ae2), +W64LIT(0xf0062dd07b98193b), +W64LIT(0xafbdd13e09b024de), +W64LIT(0xb95e13a089e93bbb), +W64LIT(0x649d945386b707e8), +W64LIT(0xe4fcac6f0c2930ef), +W64LIT(0x413cc7f4c43bfa5b), +W64LIT(0x3b2668bdf49f3a0d), +W64LIT(0xe50a77858d5d2b4d), +W64LIT(0x05c45da89a517735), +W64LIT(0x3ee235156ece4d38), +W64LIT(0xfe491137a11f9bc6), +W64LIT(0xb7112f47536eb946), +W64LIT(0x07dd1e896db94184), +W64LIT(0x1ab5bd58ad36ab29), +W64LIT(0x8197e3d60bea2ca5), +W64LIT(0xab8f577c12954849), +W64LIT(0x9cff4007cb65c608), +W64LIT(0xa00436335243bd81), +W64LIT(0xfda689fcd783b6d5), +W64LIT(0xccfd5be4e2be62b2), +W64LIT(0x75a348446b575909), +W64LIT(0x17151974012d04c7), +W64LIT(0xfb8d4c9f3b4eecf3), +W64LIT(0xac5249f57f2c09cd), +W64LIT(0x9346a70a90965f57), +W64LIT(0x043286421b256c97), +W64LIT(0x27b81086b564cb02), +W64LIT(0x3569545a2e18b8f0), +W64LIT(0x6b24735edd449eb7), +W64LIT(0x2193d5e559a99124), +W64LIT(0xc7763aaba268977a), +W64LIT(0xb0cc31ce3ed7f8c2), +W64LIT(0xc939064c78ef1587), +W64LIT(0x16e3c29e80591f65), +W64LIT(0x5da2bfcf85c00b54), +W64LIT(0x5990398d9ee567c3), +W64LIT(0x67720c98f02b2afb), +W64LIT(0x54309da132fec82d), +W64LIT(0xeab39088d6aeb212), +W64LIT(0x9682faa20ac72862), +W64LIT(0xd38cbb14d5d9beae), +W64LIT(0x4c9c63d8682055b5), +W64LIT(0xd648e6bc4f88c99b), +W64LIT(0xdc355c198e2a27f1), +W64LIT(0x10c807fd6c944543), +W64LIT(0x450e41b6df1e96cc), +W64LIT(0x0b8b614f40d6f5c8), +W64LIT(0xd27a60fe54ada50c), +W64LIT(0x49583e70f2712280), +W64LIT(0x8dc19c10268598e9), +W64LIT(0x5866e2671f917c61), +W64LIT(0x79f537824638ed45), +W64LIT(0xc2b267033839e04f), +W64LIT(0xcb20456d8f072336), +W64LIT(0x2a18b4aa197f64ec), +W64LIT(0xdbe84290e3936675), +W64LIT(0x73888d27879a032f), +W64LIT(0xe8aad3a9214684a3), +W64LIT(0x6ee02ef64715e982), +W64LIT(0xa996145de57d7ef8), +W64LIT(0xc8cfdda6f99b0e25), +W64LIT(0x062bc563eccd5a26), +W64LIT(0x264ecb6c3410d0a0), +W64LIT(0xb8a8c84a089d2019), +W64LIT(0x7dc7b1c05d1d81d2), +W64LIT(0xd5a77e773914e488), +W64LIT(0x4b417d5105991431), +W64LIT(0xf62de8b39755431d), +W64LIT(0x993b1daf5134b13d), +W64LIT(0x82787b1d7d7601b6), +W64LIT(0xe321b2e66190716b), +W64LIT(0xb5086c66a4868ff7), +W64LIT(0x9ee603263c8df0b9), +W64LIT(0x349f8fb0af6ca352), +W64LIT(0x5b897aac690d5172), +W64LIT(0x7c316a2adc699a70), +W64LIT(0xd451a59db860ff2a), +W64LIT(0x706715ecf1062e3c), +W64LIT(0x838ea0f7fc021a14), +W64LIT(0x57df056a4462e53e), +W64LIT(0xcf12c32f94224fa1), +W64LIT(0xed6e8e01bb17f396), +W64LIT(0x915fe42b677e69e6), +W64LIT(0x89f31a523da0f47e), +W64LIT(0xe71334a47ab51dfc), +W64LIT(0xa860cfb76409655a), +W64LIT(0x9f10d8ccbdf9eb1b), +W64LIT(0xef77cd204cffc527), +W64LIT(0xf862d4544dd2c1e0), +W64LIT(0x8a1c82994b3cd96d), +W64LIT(0xae4b0ad488c43f7c), +W64LIT(0x98cdc645d040aa9f), +W64LIT(0x7fdef2e1aaf5b763), +W64LIT(0x4717029728f6a07d), +W64LIT(0x745593aeea2342ab), +W64LIT(0xee8116cacd8bde85), +W64LIT(0x727e56cd06ee188d), +W64LIT(0x227c4d2e2f35bc37), +W64LIT(0x977421488bb333c0), +W64LIT(0xa21d7512a5ab8b30), +W64LIT(0xbb4750817e010d0a), +W64LIT(0x6cf96dd7b0fddf33), +W64LIT(0x2801f78bee97525d), +W64LIT(0x1c9e783b41fbf10f), +W64LIT(0x9d099bed4a11ddaa), +W64LIT(0x7a1aaf4930a4c056), +W64LIT(0x32b44ad343a1f974), +W64LIT(0x3cfb763499267b89), +W64LIT(0xb2d572efc93fce73), +W64LIT(0x63408adaeb0e466c), +W64LIT(0xada4921ffe58126f), +W64LIT(0x5fbbfcee72283de5), +W64LIT(0x6ad2a8b45c308515), +W64LIT(0x0c567fc62d6fb44c), +W64LIT(0x956d62697c5b0571), +W64LIT(0x25a153a7428cfdb3), +W64LIT(0x150c5a55f6c53276), +W64LIT(0xe2d7690ce0e46ac9), +W64LIT(0xda1e997a62e77dd7), +W64LIT(0xf5c27078e1c96e0e), +W64LIT(0xc344bce9b94dfbed), +W64LIT(0x60af12119d926b7f), +W64LIT(0xa1f2edd9d337a623), +W64LIT(0xcad69e870e733894), +W64LIT(0x3770177bd9f08e41), +W64LIT(0xa5c06b9bc812cab4), +W64LIT(0x1f71e0f03767dc1c), +W64LIT(0x44f89a5c5e6a8d6e), +W64LIT(0x6159c9fb1ce670dd), +W64LIT(0x8e2e04db5019b5fa), +W64LIT(0x8805c1b8bcd4efdc), +W64LIT(0xe138f1c7967847da), +W64LIT(0x4ab7a6bb84ed0f93), +W64LIT(0x0000000000000000), +W64LIT(0x38c9f0768203171e), +W64LIT(0x1b4366b22c42b08b), +W64LIT(0x7803ec68c74cf6e7), +W64LIT(0xec9855eb3a63e834), +W64LIT(0xbe830d29e4507a3f), +W64LIT(0x2dc5aa2374c62568), +W64LIT(0xa62ff350be8ee7a7), +W64LIT(0x764cd08f1dcb741a), +W64LIT(0x8c3747faa7f1834b), +W64LIT(0x0fb9e70d5bf3995f), +W64LIT(0x55c6464bb38ad38f), +W64LIT(0xf7db3359162158bf), +W64LIT(0xd195f8352231881f), +W64LIT(0x0992226eb73ec379), +W64LIT(0x14fa81bf77b129d4), +W64LIT(0x48aee59a73053922), +W64LIT(0x2457884dc3f8e611), +W64LIT(0xffbfcadd206b8064), +W64LIT(0xb4feb78c25f29455), +W64LIT(0x864afd5f66536d21), +W64LIT(0x6f16f51cc661f220), +W64LIT(0xde2c1f3879c21140), +W64LIT(0x195a2593dbaa863a), +W64LIT(0x2e2a32e8025a087b), +W64LIT(0x432584d533d3ccea), +W64LIT(0x2c3371c9f5b23eca), +W64LIT(0xa7d928ba3ffafc05), +W64LIT(0x42d35f3fb2a7d748), +W64LIT(0x85a5659410cf4032), +W64LIT(0x0864f984364ad8db), +W64LIT(0xf21f6ef18c702f8a), +W64LIT(0xf1f0f63afaec0299), +W64LIT(0xd9f101b1147b50c4), +W64LIT(0x2fdce902832e13d9), +W64LIT(0x4d6ab832e9544e17), +W64LIT(0xe0ce2a2d170c5c78), +W64LIT(0x51f4c009a8afbf18), +W64LIT(0x68cbeb95abd8b3a4), +W64LIT(0xc15dffc84ea5cd5c), +W64LIT(0x02194321f7e836b1), +W64LIT(0x113edc17ede05ee1), +W64LIT(0x521b58c2de33920b), +W64LIT(0x9ad4856427a89c2e), +W64LIT(0x5629de80c516fe9c), +W64LIT(0x77ba0b659cbf6fb8), +W64LIT(0x238a96c4ae41a795), +W64LIT(0x12d144dc9b7c73f2), +W64LIT(0xd807da5b950f4b66), +W64LIT(0x3686cc91588495e3), +W64LIT(0x18acfe795ade9d98), +W64LIT(0x5a7fa146e8794ad0), +W64LIT(0xc680e141231c8cd8), +W64LIT(0x1e873b1ab613c7be), +W64LIT(0xf434ab9260bd75ac), +W64LIT(0xcd0b800e63ca7910), +W64LIT(0xbc9a4e0813b84c8e), +W64LIT(0x3d0dadde1852602b), +W64LIT(0x40ca1c1e454fe1f9), +W64LIT(0x0a7dbaa5c1a2ee6a), +W64LIT(0x693d307f2aaca806), +W64LIT(0x0e4f3ce7da8782fd), +W64LIT(0xbd6c95e292cc572c), +W64LIT(0x3ad0b35775eb21af), +W64LIT(0x7e28290b2b81acc1), +W64LIT(0x01f6dbea81741ba2), +W64LIT(0x87bc26b5e7277683), +W64LIT(0x393f2b9c03770cbc), +W64LIT(0xddc387f30f5e3c53), +W64LIT(0xeb454b6257daa9b0), +W64LIT(0xb323a905484bd5d1), +W64LIT(0xb13aea24bfa3e360), +W64LIT(0x315bd218353dd467), +W64LIT(0x2bee6f40980b7f4e), +W64LIT(0xe95c0843a0329f01), +W64LIT(0xc56f798a5580a1cb), +W64LIT(0xbf75d6c36524619d), +W64LIT(0x29f72c616fe349ff), +W64LIT(0xc0ab2422cfd1d6fe), +/* box 4 */ +W64LIT(0x561fc423e957943c), +W64LIT(0x014287ca69079288), +W64LIT(0x2f086129dfcd1d21), +W64LIT(0xc537d4aea044fd99), +W64LIT(0xf1e8c3bfd7c8a457), +W64LIT(0x2971998a5cdf9bfb), +W64LIT(0x23fa649a2ce9e460), +W64LIT(0x3aa9e9c356a6716a), +W64LIT(0xd6efa4e7aa3d1708), +W64LIT(0x705a24b1fda5b5eb), +W64LIT(0x101e0ce2b170a9fc), +W64LIT(0x7ca821020e814caa), +W64LIT(0x0bc97ada1931ed13), +W64LIT(0x34df1711778c59ce), +W64LIT(0xd35020ef9226d2bf), +W64LIT(0x575d43e9805006b4), +W64LIT(0x91acebec9b1db840), +W64LIT(0x549b3f423b5945d9), +W64LIT(0x99a3ed9d3925163e), +W64LIT(0x7917a50a369a891d), +W64LIT(0xe372343cb4b6dc4e), +W64LIT(0x8d40e2bdd949e8fd), +W64LIT(0xcfbc29bed0728202), +W64LIT(0x969794857108ac12), +W64LIT(0xdd26de3db30cfa1b), +W64LIT(0x115c8b28d8773b74), +W64LIT(0xe9f9c92cc480a3d5), +W64LIT(0x4dc8b21b4116d0d3), +W64LIT(0x316093194f979c79), +W64LIT(0x5124bb4a0342806e), +W64LIT(0xb31408bcdef3cea8), +W64LIT(0xc1cad76cf158aaa6), +W64LIT(0x88ff66b5e1522d4a), +W64LIT(0xa8c37e8476b28a47), +W64LIT(0x15a188ea896b6c4b), +W64LIT(0xa24883940684f5dc), +W64LIT(0xda1da1545919ee49), +W64LIT(0x22b8e35045ee76e8), +W64LIT(0x6106af9925d28e9f), +W64LIT(0xef80318f4792250f), +W64LIT(0x663dd0f0cfc79acd), +W64LIT(0x302214d326900ef1), +W64LIT(0xdfa2255c61022bfe), +W64LIT(0xe6cdb0348cad19f9), +W64LIT(0x50663c806a4512e6), +W64LIT(0x65fbac5b74ced9a0), +W64LIT(0xc4755364c9436f11), +W64LIT(0x8fc419dc0b473918), +W64LIT(0x5c9439339961eba7), +W64LIT(0x3f166dcb6ebdb4dd), +W64LIT(0xba59890715ccf25e), +W64LIT(0xf0aa4475becf36df), +W64LIT(0x03c67cabbb09436d), +W64LIT(0xb99ff5acaec5b133), +W64LIT(0xf9e7c5ce75f00a29), +W64LIT(0x6df4aa2ad6f677de), +W64LIT(0xaeba8627f5a00c9d), +W64LIT(0xa573fcfdec91e18e), +W64LIT(0x7f6e5da9b5880fc7), +W64LIT(0xca03adb6e86947b5), +W64LIT(0x74a72773acb9e2d4), +W64LIT(0x604428534cd51c17), +W64LIT(0xf8a542041cf798a1), +W64LIT(0x448533a08a29ec25), +W64LIT(0x80f060c4436a8334), +W64LIT(0x0db082799a236bc9), +W64LIT(0xfa21b965cef94944), +W64LIT(0x64b92b911dc94b28), +W64LIT(0x7118a37b94a22763), +W64LIT(0xaff801ed9ca79e15), +W64LIT(0x1dae8e9b2b53c235), +W64LIT(0x13d870490a79ea91), +W64LIT(0x8a7b9dd4335cfcaf), +W64LIT(0x1f2a75faf95d13d0), +W64LIT(0xeec2b6452e95b787), +W64LIT(0xc34e2c0d23567b43), +W64LIT(0x47434f0b3120af48), +W64LIT(0xa18eff3fbd8db6b1), +W64LIT(0x98e16a57502284b6), +W64LIT(0x37196bbacc851aa3), +W64LIT(0x8e869e166240ab90), +W64LIT(0x9fda153eba3790e4), +W64LIT(0xf515c07d86d4f368), +W64LIT(0x72dedfd02fab640e), +W64LIT(0xe230b3f6ddb14ec6), +W64LIT(0x97d5134f180f3e9a), +W64LIT(0xe1f6cf5d66b80dab), +W64LIT(0xe78f37fee5aa8b71), +W64LIT(0xa30a045e6f836754), +W64LIT(0x90ee6c26f21a2ac8), +W64LIT(0xaa4785e5a4bc5ba2), +W64LIT(0x4e0eceb0fa1f93be), +W64LIT(0x94136fe4a3067df7), +W64LIT(0x7b935e6be49458f8), +W64LIT(0x9b2716fceb2bc7db), +W64LIT(0x840d63061276d40b), +W64LIT(0xed04caee959cf4ea), +W64LIT(0xea3fb5877f89e0b8), +W64LIT(0xb56df01f5de14872), +W64LIT(0x4935b1d9100a87ec), +W64LIT(0x82749ba5916452d1), +W64LIT(0x58693af1c87dbc98), +W64LIT(0x89bde17f8855bfc2), +W64LIT(0x677f573aa6c00845), +W64LIT(0xeb7d324d168e7230), +W64LIT(0x0284fb61d20ed1e5), +W64LIT(0xb190f3dd0cfd1f4d), +W64LIT(0x684b2e22eeedb269), +W64LIT(0x2bf562eb8ed14a1e), +W64LIT(0xe0b448970fbf9f23), +W64LIT(0x396f9568edaf3207), +W64LIT(0x52e2c7e1b84bc303), +W64LIT(0x77615bd817b0a1b9), +W64LIT(0x7e2cda63dc8f9d4f), +W64LIT(0xf22ebf146cc1e73a), +W64LIT(0xc08850a6985f382e), +W64LIT(0xd9dbddffe210ad24), +W64LIT(0xbfe60d0f2dd737e9), +W64LIT(0x9a659136822c5553), +W64LIT(0x87cb1fada97f9766), +W64LIT(0x4c8a35d12811425b), +W64LIT(0x83361c6ff863c059), +W64LIT(0xd212a725fb214037), +W64LIT(0x9e9892f4d330026c), +W64LIT(0x45c7b46ae32e7ead), +W64LIT(0x5baf465a7374fff5), +W64LIT(0xdc6459f7da0b6893), +W64LIT(0xd46b5f867833c6ed), +W64LIT(0x5dd6bef9f066792f), +W64LIT(0xcb412a7c816ed53d), +W64LIT(0x75e5a0b9c5be705c), +W64LIT(0xf6d3bcd63dddb005), +W64LIT(0xfb633eafa7fedbcc), +W64LIT(0xd529d84c11345465), +W64LIT(0xc9c5d11d536004d8), +W64LIT(0xdb5f269e301e7cc1), +W64LIT(0x86899867c07805ee), +W64LIT(0x3d9296aabcb36538), +W64LIT(0x2cce1d8264c45e4c), +W64LIT(0x5aedc1901a736d7d), +W64LIT(0x2e4ae6e3b6ca8fa9), +W64LIT(0x1e68f230905a8158), +W64LIT(0xdee0a2960805b976), +W64LIT(0xcd38d2df027c53e7), +W64LIT(0x6909a9e887ea20e1), +W64LIT(0x24c11bf3c6fcf032), +W64LIT(0x18110a9313480782), +W64LIT(0xa7f7079c3e9f306b), +W64LIT(0xd8995a358b173fac), +W64LIT(0x854fe4cc7b714683), +W64LIT(0xbd62f66effd9e60c), +W64LIT(0x14e30f20e06cfec3), +W64LIT(0x6e32d6816dff34b3), +W64LIT(0x217e9ffbfee73585), +W64LIT(0xc88756d73a679650), +W64LIT(0x359d90db1e8bcb46), +W64LIT(0x2645e09214f221d7), +W64LIT(0x04fd03c2511c573f), +W64LIT(0x739c581a46acf686), +W64LIT(0xb0d2741765fa8dc5), +W64LIT(0xa0cc78f5d48a2439), +W64LIT(0x5e10c2524b6f3a42), +W64LIT(0xe50bcc9f37a45a94), +W64LIT(0x53a0402bd14c518b), +W64LIT(0x413ab7a8b2322992), +W64LIT(0x203c183197e0a70d), +W64LIT(0xcc7a55156b7bc16f), +W64LIT(0x4601c8c158273dc0), +W64LIT(0xbea48ac544d0a561), +W64LIT(0x638254f8f7dc5f7a), +W64LIT(0xa6b580565798a2e3), +W64LIT(0x3cd01160d5b4f7b0), +W64LIT(0x8c026577b04e7a75), +W64LIT(0x7ad1d9a18d93ca70), +W64LIT(0x785522c05f9d1b95), +W64LIT(0x5f5245982268a8ca), +W64LIT(0x9551e82eca01ef7f), +W64LIT(0x0000000000000000), +W64LIT(0xbb1b0ecd7ccb60d6), +W64LIT(0x094d81bbcb3f3cf6), +W64LIT(0x28331e4035d80973), +W64LIT(0xf7913b1c54da228d), +W64LIT(0x6acfd5433ce3638c), +W64LIT(0x1bd77638a84144ef), +W64LIT(0x62c0d3329edbcdf2), +W64LIT(0x81b2e70e2a6d11bc), +W64LIT(0xd7ad232dc33a8580), +W64LIT(0x05bf8408381bc5b7), +W64LIT(0x33e468789d994d9c), +W64LIT(0xfedcbaa79fe51e7b), +W64LIT(0x4f4c497a93180136), +W64LIT(0x073b7f69ea151452), +W64LIT(0x0cf205b3f324f941), +W64LIT(0x382d12a284a8a08f), +W64LIT(0x1cec0951425450bd), +W64LIT(0x55d9b888525ed751), +W64LIT(0x6cb62de0bff1e556), +W64LIT(0xd1d4db8e4028035a), +W64LIT(0x25839c39affb62ba), +W64LIT(0x4af3cd72ab03c481), +W64LIT(0xa4317b3785967306), +W64LIT(0x1a95f1f2c146d667), +W64LIT(0x926a97472014fb2d), +W64LIT(0xb7e90b7e8fef9997), +W64LIT(0xcefeae74b975108a), +W64LIT(0x3e54ea0107ba2655), +W64LIT(0xd0965c44292f91d2), +W64LIT(0xab05022fcdbbc92a), +W64LIT(0xfd1ac60c24ec5d16), +W64LIT(0xfc5841c64debcf9e), +W64LIT(0xe4494b555ea3c81c), +W64LIT(0xb6ab8cb4e6e80b1f), +W64LIT(0x3beb6e093fa1e3e2), +W64LIT(0xf36c38de05c675b2), +W64LIT(0x9c1c6995013ed389), +W64LIT(0x8b391a1e5a5b6e27), +W64LIT(0xec464d24fc9b6662), +W64LIT(0xad7cfa8c4ea94ff0), +W64LIT(0x0f347918482dba2c), +W64LIT(0x9d5eee5f68394101), +W64LIT(0x7623dc127eb73331), +W64LIT(0x32a6efb2f49edf14), +W64LIT(0x2d8c9a480dc3ccc4), +W64LIT(0xb2568f76b7f45c20), +W64LIT(0x0e76fed2212a28a4), +W64LIT(0x48773613790d1564), +W64LIT(0x129af783637e7819), +W64LIT(0x080f0671a238ae7e), +W64LIT(0x365bec70a582882b), +W64LIT(0x42fccb03093b6aff), +W64LIT(0x0a8bfd1070367f9b), +W64LIT(0xff9e3d6df6e28cf3), +W64LIT(0xe8bb4ee6ad87315d), +W64LIT(0xc7b32fcf724a2c7c), +W64LIT(0xb8dd7266c7c223bb), +W64LIT(0x9328108d491369a5), +W64LIT(0x0679f8a3831286da), +W64LIT(0x270767587df5b35f), +W64LIT(0xa981f94e1fb518cf), +W64LIT(0x6b8d528955e4f104), +W64LIT(0x1667f44132622f26), +W64LIT(0x2ab7e521e7d6d896), +W64LIT(0xac3e7d4627aedd78), +W64LIT(0x7deaa6c86786de22), +W64LIT(0x1725738b5b65bdae), +W64LIT(0x4bb14ab8c2045609), +W64LIT(0x592bbd3ba17a2e10), +W64LIT(0xc20cabc74a51e9cb), +W64LIT(0x6f70514b04f8a63b), +W64LIT(0xbc2071a496de7484), +W64LIT(0x19538d597a4f950a), +W64LIT(0xf45747b7efd361e0), +W64LIT(0x43be4cc9603cf877), +W64LIT(0xc6f1a8051b4dbef4), +W64LIT(0xb42f77d534e6dafa), +W64LIT(0x40783062db35bb1a), +/* box 5 */ +W64LIT(0xf5a96c292deb0a4e), +W64LIT(0x211c9df6ee653c51), +W64LIT(0x04de5ddcbeeef596), +W64LIT(0xe1e5b06f7457c19f), +W64LIT(0x74ca30f014a54fb6), +W64LIT(0xc296f9f7c5457d85), +W64LIT(0x7d4ee08a484d10b0), +W64LIT(0xae87f2d0bf9b13ad), +W64LIT(0x8df4bb480e89afb7), +W64LIT(0x2d8b7a67d9a2d61e), +W64LIT(0x0f3559c8bd712adb), +W64LIT(0x541bc7312f013338), +W64LIT(0x9ec4848b636d5164), +W64LIT(0x952f809f60f28e29), +W64LIT(0x28984d8cb28d6357), +W64LIT(0xd4b5f1dfc38e361f), +W64LIT(0x5674135f7076b373), +W64LIT(0xb791a330042172ec), +W64LIT(0xab94c53bd4b4a6e4), +W64LIT(0xf17731f59305ffd8), +W64LIT(0x39c7a621801e1dcf), +W64LIT(0x20d1f7c13ba47c8e), +W64LIT(0x5e3da912f95facaa), +W64LIT(0xb1202a82e5b80731), +W64LIT(0x13303fc36de4fed3), +W64LIT(0x2e29c43e5314168a), +W64LIT(0x861fbf5c0d1670fa), +W64LIT(0x6458b16af3f771f1), +W64LIT(0x3043765bdcf642c9), +W64LIT(0x12fd55f4b825be0c), +W64LIT(0x0a266e23d65e9f92), +W64LIT(0x6595db5d2636312e), +W64LIT(0x85bd010587a0b06e), +W64LIT(0x9bd7b3600842e42d), +W64LIT(0xaa59af0c0175e63b), +W64LIT(0x240faa1d854a8918), +W64LIT(0xf464061ef82a4a91), +W64LIT(0x5c527d7ca6282ce1), +W64LIT(0x03a2be598ab6c094), +W64LIT(0x40571b7776bdf8e9), +W64LIT(0xe4f687841f7874d6), +W64LIT(0x115febad32937e98), +W64LIT(0x5108f0da442e8671), +W64LIT(0x9cab50e53c1ad12f), +W64LIT(0x33e1c8025640825d), +W64LIT(0x87d2d56bd8d73025), +W64LIT(0xc0f92d999a32fdce), +W64LIT(0x62e938d8126e042c), +W64LIT(0x4a717554a0e3677b), +W64LIT(0x0beb0414039fdf4d), +W64LIT(0xd6da25b19cf9b654), +W64LIT(0x55d6ad06fac073e7), +W64LIT(0x632452efc7af44f3), +W64LIT(0xb5fe775e5b56f2a7), +W64LIT(0x892ae694b0675a21), +W64LIT(0x7a32030f7c1525b2), +W64LIT(0x5d9f174b73e96c3e), +W64LIT(0xc35b93c010843d5a), +W64LIT(0x373f95dee8ae77cb), +W64LIT(0xfb515fd6455b604a), +W64LIT(0xa9fb11558bc326af), +W64LIT(0x22be23af64d3fcc5), +W64LIT(0xa8367b625e026670), +W64LIT(0xb8a4faf8b9505837), +W64LIT(0x785dd7612362a5f9), +W64LIT(0x588c20a018c6d977), +W64LIT(0xea0eb47b77c81ed2), +W64LIT(0xa6ce489d36b20c74), +W64LIT(0x0c97e79137c7ea4f), +W64LIT(0x7c838abd9d8c506f), +W64LIT(0x57b97968a5b7f3ac), +W64LIT(0x6c110b277ade6e28), +W64LIT(0xc785ce1cae6ac8cc), +W64LIT(0x1581b6718c7d8b0e), +W64LIT(0x614b868198d8c4b8), +W64LIT(0x27ad14440ffc498c), +W64LIT(0xdb80a8177eff1cc4), +W64LIT(0x472bf8f242e5cdeb), +W64LIT(0x8a8858cd3ad19ab5), +W64LIT(0xf60bd270a75dcada), +W64LIT(0x43f5a52efc0b387d), +W64LIT(0x6ddc6110af1f2ef7), +W64LIT(0xf0ba5bc246c4bf07), +W64LIT(0x6fb3b57ef068aebc), +W64LIT(0x18db3bd76e7b219e), +W64LIT(0x903cb7740bdd3b60), +W64LIT(0x7bff6938a9d4656d), +W64LIT(0xbdb7cd13d27fed7e), +W64LIT(0x051337eb6b2fb549), +W64LIT(0x77688ea99e138f22), +W64LIT(0xd9ef7c7921889c8f), +W64LIT(0x077ce38534583502), +W64LIT(0xf318e59bcc727f93), +W64LIT(0xb34ffeecbacf877a), +W64LIT(0xe9ac0a22fd7ede46), +W64LIT(0xfc2dbc5371035548), +W64LIT(0x026fd46e5f77804b), +W64LIT(0xe53bedb3cab93409), +W64LIT(0xcc6eca08adf51781), +W64LIT(0xe028da58a1968140), +W64LIT(0x3a6518780aa8dd5b), +W64LIT(0xce011e66f28297ca), +W64LIT(0xa4a19cf369c58c3f), +W64LIT(0xc5ea1a72f11d4887), +W64LIT(0xc427704524dc0858), +W64LIT(0x4238cf1929ca78a2), +W64LIT(0x481ea13aff94e730), +W64LIT(0xdf5ef5cbc011e952), +W64LIT(0x80ae36eeec8f0527), +W64LIT(0x5ae3f4ce47b1593c), +W64LIT(0xcda3a03f7834575e), +W64LIT(0x71d9071b7f8afaff), +W64LIT(0xcadf43ba4c6c625c), +W64LIT(0x1623082806cb4b9a), +W64LIT(0x17ee621fd30a0b45), +W64LIT(0x448946abc8530d7f), +W64LIT(0x974054f13f850e62), +W64LIT(0x73b6d37520fd7ab4), +W64LIT(0xc8b097d4131be217), +W64LIT(0x9f09eebcb6ac11bb), +W64LIT(0x45442c9c1d924da0), +W64LIT(0x1b79858ee4cde10a), +W64LIT(0x0984d07a5ce85f06), +W64LIT(0x4cc0fce6417a12a6), +W64LIT(0x99b8670e57356466), +W64LIT(0xad254c89352dd339), +W64LIT(0x322ca2358381c282), +W64LIT(0xcfcc74512743d715), +W64LIT(0x6b6de8a24e865b2a), +W64LIT(0xda4dc220ab3e5c1b), +W64LIT(0x88e78ca365a61afe), +W64LIT(0x939e092d816bfbf4), +W64LIT(0xcb12298d99ad2283), +W64LIT(0xeed0e9a7c926eb44), +W64LIT(0x98750d3982f424b9), +W64LIT(0xd5789be8164f76c0), +W64LIT(0xbe15734a58c92dea), +W64LIT(0x49d3cb0d2a55a7ef), +W64LIT(0x67fa0f337941b165), +W64LIT(0x8c39d17fdb48ef68), +W64LIT(0x25c2c02a508bc9c7), +W64LIT(0x349d2b876218b75f), +W64LIT(0x70146d2caa4bba20), +W64LIT(0x1c05660bd095d408), +W64LIT(0xfe42683d2e74d503), +W64LIT(0x9a1ad957dd83a4f2), +W64LIT(0xf2d58fac19b33f4c), +W64LIT(0x81635cd9394e45f8), +W64LIT(0xb65cc907d1e03233), +W64LIT(0xdd3121a59f666919), +W64LIT(0x318e1c6c09370216), +W64LIT(0x8b4532faef10da6a), +W64LIT(0x191651e0bbba6141), +W64LIT(0x3f762f9361876812), +W64LIT(0xb96990cf6c9118e8), +W64LIT(0xb4331d698e97b278), +W64LIT(0xd822164ef449dc50), +W64LIT(0x84706b325261f0b1), +W64LIT(0x4eaf28881e0d92ed), +W64LIT(0x69023ccc11f1db61), +W64LIT(0x66376504ac80f1ba), +W64LIT(0x0849ba4d89291fd9), +W64LIT(0xff8f020afbb595dc), +W64LIT(0x50c59aed91efc6ae), +W64LIT(0x1dc80c3c055494d7), +W64LIT(0x1e6ab2658fe25443), +W64LIT(0x3d19fbfd3ef0e859), +W64LIT(0xfa9c35e1909a2095), +W64LIT(0x52aa4e83ce9846e5), +W64LIT(0x419a7140a37cb836), +W64LIT(0xa07fc12fd72b79a9), +W64LIT(0x68cf56fbc4309bbe), +W64LIT(0x01cd6a37d5c140df), +W64LIT(0x9253631a54aabb2b), +W64LIT(0xd06bac037d60c389), +W64LIT(0x295527bb674c2388), +W64LIT(0xd204786d221743c2), +W64LIT(0x0000000000000000), +W64LIT(0xf7c6b847729c8a05), +W64LIT(0xdcfc4b924aa729c6), +W64LIT(0xe38a64012b2041d4), +W64LIT(0xb28294db6f0ec7a5), +W64LIT(0x9d663ad2e9db91f0), +W64LIT(0x91f1dd43de1c7bbf), +W64LIT(0x6086ecb64d198467), +W64LIT(0x59414a97cd0799a8), +W64LIT(0xace826bee0ec93e6), +W64LIT(0xa56cf6c4bc04cce0), +W64LIT(0x727bb942f53c3a6b), +W64LIT(0x6e7edf4925a9ee63), +W64LIT(0x26607e73da3d0953), +W64LIT(0xe75439dd95ceb442), +W64LIT(0x7990bd56f6a3e526), +W64LIT(0xecbf3dc996516b0f), +W64LIT(0x76a5e49e4bd2cffd), +W64LIT(0x968d3ec6ea444ebd), +W64LIT(0x5b2e9ef9927019e3), +W64LIT(0x6aa082959b471bf5), +W64LIT(0xbb0644a133e698a3), +W64LIT(0x830c88b76639c5b3), +W64LIT(0xe2470e36fee1010b), +W64LIT(0xb0ed40b5307947ee), +W64LIT(0x355041b0b7d9f780), +W64LIT(0x8e560511843f6f23), +W64LIT(0x7f2134e4173a90fb), +W64LIT(0x2af799e2edfae31c), +W64LIT(0x4bbc1f63752227a4), +W64LIT(0xf8f3e18fcfeda0de), +W64LIT(0x0d5a8da6e206aa90), +W64LIT(0x2c4610500c6396c1), +W64LIT(0xde939ffc15d0a98d), +W64LIT(0xaf4a98e76a5a5372), +W64LIT(0x8f9b6f2651fe2ffc), +W64LIT(0x36f2ffe93d6f3714), +W64LIT(0x0ef833ff68b06a04), +W64LIT(0xe69953ea400ff49d), +W64LIT(0x23734998b112bc1a), +W64LIT(0x3ebb45a4b44628cd), +W64LIT(0x1ab4efb9310ca1d5), +W64LIT(0x2fe4ae0986d55655), +W64LIT(0xebc3de4ca2095e0d), +W64LIT(0x536724b41b59063a), +W64LIT(0x46e692c597248d34), +W64LIT(0x2b3af3d5383ba3c3), +W64LIT(0x3ba8724fdf699d84), +W64LIT(0xc13447ae4ff3bd11), +W64LIT(0x4d0d96d194bb5279), +W64LIT(0xfde0d664a4c21597), +W64LIT(0xd7174f864938f68b), +W64LIT(0x7eec5ed3c2fbd024), +W64LIT(0xbfd8197d8d086d35), +W64LIT(0x4f6242bfcbccd232), +W64LIT(0xa70322aae3734cab), +W64LIT(0xa3dd7f765d9db93d), +W64LIT(0x94e2eaa8b533cef6), +W64LIT(0x144cdc4659bccbd1), +W64LIT(0xc648a42b7bab8813), +W64LIT(0xf93e8bb81a2ce001), +W64LIT(0xbacb2e96e627d87c), +W64LIT(0xbc7aa72407beada1), +W64LIT(0xc97dfde3c6daa2c8), +W64LIT(0xa1b2ab1802ea3976), +W64LIT(0x1fa7d8525a23149c), +W64LIT(0x75075ac7c1640f69), +W64LIT(0xe861601528bf9e99), +W64LIT(0xa2101541885cf9e2), +W64LIT(0xef1d83901ce7ab9b), +W64LIT(0x06b189b2e19975dd), +W64LIT(0x380acc1655df5d10), +W64LIT(0x1092819ae7523e47), +W64LIT(0xd3c9125af7d6031d), +W64LIT(0xd1a6c634a8a18356), +W64LIT(0x5ff0c3252c9eec75), +W64LIT(0x82c1e280b3f8856c), +W64LIT(0xed7257fe43902bd0), +W64LIT(0x3cd491caeb31a886), +/* box 6 */ +W64LIT(0x94af9eb6fad9e7df), +W64LIT(0x9208ae5e03c94ddd), +W64LIT(0x1d8de8d67158480b), +W64LIT(0xfd093cd2ba147af8), +W64LIT(0xa45ceb22e6597ccf), +W64LIT(0x9bbde6e77bf113da), +W64LIT(0xe4edf4b465fffe5c), +W64LIT(0x7125622e4e8d2a2f), +W64LIT(0x1791b81b8f68430d), +W64LIT(0xb56a63d1902195c0), +W64LIT(0xa980832b30d2ee67), +W64LIT(0x4c0a7fb384862397), +W64LIT(0xed58bc0d1dc7a05b), +W64LIT(0x5955d7f05c4d0637), +W64LIT(0xd2b9b1c8806fcf4e), +W64LIT(0x06a730e8f910aa02), +W64LIT(0xb8b60bd846aa0768), +W64LIT(0x45bf370afcbe7d90), +W64LIT(0x16f6b0375ec370a1), +W64LIT(0x892276608b81afd4), +W64LIT(0xdcccc1b5d0ec08e7), +W64LIT(0xe856949162df5f58), +W64LIT(0x82592e81a41a977e), +W64LIT(0xac8eabb74fca1164), +W64LIT(0xfac9041692afe356), +W64LIT(0x3b882d75331ba3ba), +W64LIT(0xa39cd3e6cee2e561), +W64LIT(0xd077a190d7cca9e3), +W64LIT(0x9c7dde23534a8a74), +W64LIT(0x80973ed9f3b9f1d3), +W64LIT(0xce535132209cb4e9), +W64LIT(0xaa299b5fb6dabb66), +W64LIT(0x2d7e9d426dd8d31b), +W64LIT(0x8a8b6e140d89fad5), +W64LIT(0x6ca88af83fd56224), +W64LIT(0xf5db7c4713871753), +W64LIT(0xeef1a4799bcff55a), +W64LIT(0x76e55aea6636b381), +W64LIT(0x8ee24ea4a33a367a), +W64LIT(0x25acddd7c44bbeb0), +W64LIT(0x9adaeecbaa5a2076), +W64LIT(0x0e75707d5083c7a9), +W64LIT(0x2bd9adaa94c87919), +W64LIT(0x19e4c866dfeb84a4), +W64LIT(0x129f9087f070bc0e), +W64LIT(0xd9c2e929aff4f7e4), +W64LIT(0x6f01928cb9dd3725), +W64LIT(0x39463d2d64b8c517), +W64LIT(0xebff8ce5e4d70a59), +W64LIT(0xb40d6bfd418aa66c), +W64LIT(0xf21b44833b3c8efd), +W64LIT(0x3654457ce5903112), +W64LIT(0x431807e205aed792), +W64LIT(0xb10343613e92596f), +W64LIT(0x0a1c50cdfe300b06), +W64LIT(0x778252c6b79d802d), +W64LIT(0x0cbb60250720a104), +W64LIT(0xe1e3dc281ae7015f), +W64LIT(0x0f1278518128f405), +W64LIT(0x47712752ab1d1b3d), +W64LIT(0xe24ac45c9cef545e), +W64LIT(0x1ceae0faa0f37ba7), +W64LIT(0x9814fe93fdf946db), +W64LIT(0xec3fb421cc6c93f7), +W64LIT(0x833e26ad75b1a4d2), +W64LIT(0x6b68b23c176efb8a), +W64LIT(0x4904572ffb9edc94), +W64LIT(0x4bca4777ac3dba39), +W64LIT(0x2762cd8f93e8d81d), +W64LIT(0x9eb3ce7b04e9ecd9), +W64LIT(0xc2e8311727bc15ed), +W64LIT(0xea9884c9357c39f5), +W64LIT(0xfc6e34fe6bbf4954), +W64LIT(0x13f898ab21db8fa2), +W64LIT(0xb7a47389c782f36d), +W64LIT(0x7b3932e3b0bd2129), +W64LIT(0xaf27b3c3c9c24465), +W64LIT(0xb6c37ba51629c0c1), +W64LIT(0x84fe1e695d0a3d7c), +W64LIT(0x1a4dd01259e3d1a5), +W64LIT(0xab4e9373677188ca), +W64LIT(0x90c6be06546a2b70), +W64LIT(0xf37c4cafea97bd51), +W64LIT(0x647aca6d96460f8f), +W64LIT(0x4ec46febd325453a), +W64LIT(0x3e8605e94c035cb9), +W64LIT(0x0ddc6809d68b92a8), +W64LIT(0x8bec6638dc22c979), +W64LIT(0x67d3d219104e5a8e), +W64LIT(0x2abea58645634ab5), +W64LIT(0x5b9bc7a80bee609a), +W64LIT(0x936fa672d2627e71), +W64LIT(0x7d9e020b49ad8b2b), +W64LIT(0x5832dfdc8de6359b), +W64LIT(0xc7e6198b58a4eaee), +W64LIT(0xd41e8120797f654c), +W64LIT(0xf4bc746bc22c24ff), +W64LIT(0xe084d404cb4c32f3), +W64LIT(0x48635f032a35ef38), +W64LIT(0x8757061ddb02687d), +W64LIT(0x522e8f1173d63e9d), +W64LIT(0xbcdf2b68e819cbc7), +W64LIT(0xbf76331c6e119ec6), +W64LIT(0x08d24095a9936dab), +W64LIT(0x728c7a5ac8857f2e), +W64LIT(0xd110a9bc06679a4f), +W64LIT(0x1f43f88e26fb2ea6), +W64LIT(0xb2aa5b15b89a0c6e), +W64LIT(0x4aad4f5b7d968995), +W64LIT(0x9fd4c657d542df75), +W64LIT(0x323d65cc4b23fdbd), +W64LIT(0xc38f393bf6172641), +W64LIT(0xa152c3be994183cc), +W64LIT(0x9d1ad60f82e1b9d8), +W64LIT(0xe744ecc0e3f7ab5d), +W64LIT(0x38213501b513f6bb), +W64LIT(0xade9a39b9e6122c8), +W64LIT(0x37334d50343b02be), +W64LIT(0x55eeb7d55b6da733), +W64LIT(0x970686c27cd1b2de), +W64LIT(0x427f0fced405e43e), +W64LIT(0xc026214f701f7340), +W64LIT(0x40b11f9683a68293), +W64LIT(0x02ce105857a366ad), +W64LIT(0x7e371a7fcfa5de2a), +W64LIT(0xffc72c8aedb71c55), +W64LIT(0x68c1aa489166ae8b), +W64LIT(0xc68111a7890fd942), +W64LIT(0x79f722bbe71e4784), +W64LIT(0xd579890ca8d456e0), +W64LIT(0x70426a029f261983), +W64LIT(0xb0644b4def396ac3), +W64LIT(0xdb0cf971f8579149), +W64LIT(0x5489bff98ac6949f), +W64LIT(0x046920b0aeb3ccaf), +W64LIT(0x7cf90a279806b887), +W64LIT(0x050e289c7f18ff03), +W64LIT(0x651dc24147ed3c23), +W64LIT(0x5e95ef3474f69f99), +W64LIT(0x6dcf82d4ee7e5188), +W64LIT(0x8f854688729105d6), +W64LIT(0x81f036f52212c27f), +W64LIT(0xb9d103f4970134c4), +W64LIT(0x5349873da27d0d31), +W64LIT(0x20a2f54bbb5341b3), +W64LIT(0xf0d554db6c9fe850), +W64LIT(0x07c038c428bb99ae), +W64LIT(0x30f375941c809b10), +W64LIT(0x3fe10dc59da86f15), +W64LIT(0x46162f7e7ab62891), +W64LIT(0xe623e4ec325c98f1), +W64LIT(0xfea024a63c1c2ff9), +W64LIT(0x349a5524b23357bf), +W64LIT(0x35fd5d0863986413), +W64LIT(0x96618eeead7a8172), +W64LIT(0xcb5d79ae5f844bea), +W64LIT(0x21c5fd676af8721f), +W64LIT(0x5720a78d0ccec19e), +W64LIT(0xf6726433958f4252), +W64LIT(0x8d4b56d02532637b), +W64LIT(0x24cbd5fb15e08d1c), +W64LIT(0x3aef2559e2b09016), +W64LIT(0x5afccf84da455336), +W64LIT(0x51879765f5de6b9c), +W64LIT(0x2917bdf2c36b1fb4), +W64LIT(0xa7f5f356605129ce), +W64LIT(0xc1412963a1b440ec), +W64LIT(0x3d2f1d9dca0b09b8), +W64LIT(0xa53be30e37f24f63), +W64LIT(0x5ff2e718a55dac35), +W64LIT(0xa2fbdbca1f49d6cd), +W64LIT(0xf7156c1f442471fe), +W64LIT(0x7a5e3acf61161285), +W64LIT(0xca3a71828e2f7846), +W64LIT(0x1b2ad83e8848e209), +W64LIT(0xa8e78b07e179ddcb), +W64LIT(0xef96ac554a64c6f6), +W64LIT(0x0000000000000000), +W64LIT(0x6013eadd38f5c320), +W64LIT(0x3c4815b11ba03a14), +W64LIT(0x09b548b978385e07), +W64LIT(0x226ce513ecf0271e), +W64LIT(0x63baf2a9befd9621), +W64LIT(0x44d83f262d154e3c), +W64LIT(0xcdfa4946a694e1e8), +W64LIT(0x113688f37678e90f), +W64LIT(0x859916458ca10ed0), +W64LIT(0xc52809d30f078c43), +W64LIT(0x4d6d779f552d103b), +W64LIT(0x1e24f0a2f7501d0a), +W64LIT(0x0167082cd1ab33ac), +W64LIT(0x1438a06f0960160c), +W64LIT(0xf9601c6214a7b657), +W64LIT(0xa035cb9248eab060), +W64LIT(0x50e09f4924755830), +W64LIT(0xd7b79954ff77304d), +W64LIT(0xe58afc98b454cdf0), +W64LIT(0x03a9187486085501), +W64LIT(0x62ddfa856f56a58d), +W64LIT(0xc44f01ffdeacbfef), +W64LIT(0x73eb7276192e4c82), +W64LIT(0xd6d091782edc03e1), +W64LIT(0xfbae0c3a4304d0fa), +W64LIT(0x9973f6bf2c527577), +W64LIT(0x105180dfa7d3daa3), +W64LIT(0x2605c5a34243ebb1), +W64LIT(0x91a1b62a85c118dc), +W64LIT(0xc99369f608272d47), +W64LIT(0x5d3cf740f2feca98), +W64LIT(0xcf34591ef1378745), +W64LIT(0xc8f461dad98c1eeb), +W64LIT(0x0b7b58e12f9b38aa), +W64LIT(0xe32dcc704d4467f2), +W64LIT(0x754c429ee03ee680), +W64LIT(0xd3deb9e451c4fce2), +W64LIT(0x6e669aa068760489), +W64LIT(0x66b4da35c1e56922), +W64LIT(0x4fa367c7028e7696), +W64LIT(0xba781b80110961c5), +W64LIT(0x41d617ba520db13f), +W64LIT(0x335a6de09a88ce11), +W64LIT(0xdf65d9c156e45de6), +W64LIT(0xcc9d416a773fd244), +W64LIT(0x5c5bff6c2355f934), +W64LIT(0x2870b5de12c02c18), +W64LIT(0x155fa843d8cb25a0), +W64LIT(0x78902a9736b57428), +W64LIT(0xae40bbef186977c9), +W64LIT(0x88457e4c5a2a9c78), +W64LIT(0x6a0fba10c6c5c826), +W64LIT(0x7f5012531e0eed86), +W64LIT(0x8c2c5efcf49950d7), +W64LIT(0x31947db8cd2ba8bc), +W64LIT(0x2c19956ebc73e0b7), +W64LIT(0x230bed3f3d5b14b2), +W64LIT(0x69a6a26440cd9d27), +W64LIT(0x86300e310aa95bd1), +W64LIT(0xb3cd533969313fc2), +W64LIT(0x1883c04a0e40b708), +W64LIT(0xf1b25cf7bd34dbfc), +W64LIT(0x2fb08d1a3a7bb5b6), +W64LIT(0xd8a5e1057e5fc448), +W64LIT(0xddabc99901473b4b), +W64LIT(0xde02d1ed874f6e4a), +W64LIT(0xbdb8234439b2f86b), +W64LIT(0x5647afa1dd65f232), +W64LIT(0x2ed78536ebd0861a), +W64LIT(0xe9319cbdb3746cf4), +W64LIT(0xa692fb7ab1fa1a62), +W64LIT(0x742b4ab23195d52c), +W64LIT(0x95c8969a2b72d473), +W64LIT(0x6174e2f1e95ef08c), +W64LIT(0xf807144ec50c85fb), +W64LIT(0xbe113b30bfbaad6a), +W64LIT(0xda6bf15d29fca2e5), +W64LIT(0xbb1f13acc0a25269), +/* box 7 */ +W64LIT(0xc22b27f0f9e37bf9), +W64LIT(0x93fad23f0955ef09), +W64LIT(0x32ed4b84a22a91a2), +W64LIT(0x3898b57bcc61b1cc), +W64LIT(0x55825ba9ad98e5ad), +W64LIT(0xb2eeb8069421ec94), +W64LIT(0xc7eb5875ce3c6bce), +W64LIT(0x4b1dac5d1f45851f), +W64LIT(0xc16ba1204705d847), +W64LIT(0xc5380f461a2ba91a), +W64LIT(0xb908971a909bad90), +W64LIT(0x303e1cb7763d5376), +W64LIT(0xe6ff324c53486853), +W64LIT(0x6d1aeed261f95461), +W64LIT(0x0193d1e36af1616a), +W64LIT(0x51d1f5cff0b694f0), +W64LIT(0x29b2c3f52728e127), +W64LIT(0x112a768eeb4950eb), +W64LIT(0x8fb672f86f9f4d6f), +W64LIT(0xf0c66c745bc9ea5b), +W64LIT(0x3f8b9dcd2fa9632f), +W64LIT(0x65bc471edba5b6db), +W64LIT(0x4d9d5508967c3696), +W64LIT(0x3a4be24818767318), +W64LIT(0x2794936c144db014), +W64LIT(0x2af2452599ce4299), +W64LIT(0x4a8e7dbe75b4e475), +W64LIT(0x9ddc82a63a30be3a), +W64LIT(0xade29e114c0ded4c), +W64LIT(0xd1d2064dc6bde9c6), +W64LIT(0x7da349bfe04165e0), +W64LIT(0x6b9a1787e8c0e7e8), +W64LIT(0xa54437ddf6510ff6), +W64LIT(0x2254ece92392a023), +W64LIT(0x79f0e7d9bd6f14bd), +W64LIT(0x57510c9a798f2779), +W64LIT(0x346db2d12b13222b), +W64LIT(0x54118a4ac76984c7), +W64LIT(0xefca4a6383e5eb83), +W64LIT(0xca8d8e3c43bf9943), +W64LIT(0xfc336bdebcbb79bc), +W64LIT(0x3e184c2e45580245), +W64LIT(0xf495c21206e79b06), +W64LIT(0xff73ed0e025dda02), +W64LIT(0x4228d472cfe806cf), +W64LIT(0xbcc8e89fa744bda7), +W64LIT(0xab626744c5345ec5), +W64LIT(0xb6bd1660c90f9dc9), +W64LIT(0xb72ec783a3fefca3), +W64LIT(0x8be5dc9e32b13c32), +W64LIT(0x485d2a8da1a326a1), +W64LIT(0xc6788996a4cd0aa4), +W64LIT(0x40fb83411bffc41b), +W64LIT(0x08a6a9ccba5ce2ba), +W64LIT(0xf386eaa4e52f49e5), +W64LIT(0x1acc5992eff311ef), +W64LIT(0xa2571f6b1599dd15), +W64LIT(0x44a82d2746d1b546), +W64LIT(0x70c59ff66dc2976d), +W64LIT(0x8d6525cbbb888fbb), +W64LIT(0x963aadba3e8aff3e), +W64LIT(0x7c30985c8ab0048a), +W64LIT(0x607c389bec7aa6ec), +W64LIT(0xa822e1947bd2fd7b), +W64LIT(0x034086d0bee6a3be), +W64LIT(0x66fcc1ce65431565), +W64LIT(0xb37d69e5fed08dfe), +W64LIT(0x2f323aa0ae1152ae), +W64LIT(0x56c2dd79137e4613), +W64LIT(0x31adcd541ccc321c), +W64LIT(0xdff456d4f5d8b8f5), +W64LIT(0xf9f3145b8b64698b), +W64LIT(0x764566a3e4fb24e4), +W64LIT(0x0cf507aae77293e7), +W64LIT(0x59775c034aea764a), +W64LIT(0xb89b46f9fa6accfa), +W64LIT(0xe8d962d5602d3960), +W64LIT(0x17aa8fdb6270e362), +W64LIT(0x1c4ca0c766caa266), +W64LIT(0x2de16d937a06907a), +W64LIT(0x2547c45fc05a72c0), +W64LIT(0x0fb5817a59943059), +W64LIT(0x0680f9558939b389), +W64LIT(0x16395e3808818208), +W64LIT(0xac714ff226fc8c26), +W64LIT(0xa9b1307711239c11), +W64LIT(0xec8accb33d03483d), +W64LIT(0x6c893f310b08350b), +W64LIT(0xc4abdea570dac870), +W64LIT(0xba4811ca2e7d0e2e), +W64LIT(0xf155bd9731388b31), +W64LIT(0xdd2701e721cf7a21), +W64LIT(0xe94ab3360adc580a), +W64LIT(0x23c73d0a4963c149), +W64LIT(0x5cb723867d35667d), +W64LIT(0x5042242c9a47f59a), +W64LIT(0x198cdf425115b251), +W64LIT(0x0a75feff6e4b206e), +W64LIT(0xfda0ba3dd64a18d6), +W64LIT(0xcede205a1e91e81e), +W64LIT(0xd041d7aeac4c88ac), +W64LIT(0xe42c657f875faa87), +W64LIT(0x36bee5e2ff04e0ff), +W64LIT(0x6fc9b9e1b5ee96b5), +W64LIT(0x998f2cc0671ecf67), +W64LIT(0xd301517e12aa2b12), +W64LIT(0xaea218c1f2eb4ef2), +W64LIT(0xda342951c207a8c2), +W64LIT(0x61efe978868bc786), +W64LIT(0x7f701e8c3456a734), +W64LIT(0x0be62f1c04ba4104), +W64LIT(0x9129850cdd422ddd), +W64LIT(0xd6c12efb25753b25), +W64LIT(0xe33f4dc964977864), +W64LIT(0x1579d8e8b66721b6), +W64LIT(0xf860c5b8e19508e1), +W64LIT(0x7496319030ece630), +W64LIT(0x88a55a4e8c579f8c), +W64LIT(0xcf4df1b974608974), +W64LIT(0x10b9a76d81b83181), +W64LIT(0x0e26509933655133), +W64LIT(0x43bb0591a51967a5), +W64LIT(0x926903dc63a48e63), +W64LIT(0x9c4f534550c1df50), +W64LIT(0x3bd833ab72871272), +W64LIT(0xa4d7e63e9ca06e9c), +W64LIT(0xb46e41531d185f1d), +W64LIT(0x126af05e55aff355), +W64LIT(0x24d415bcaaab13aa), +W64LIT(0x1e9ff7f4b2dd60b2), +W64LIT(0x05c07f8537df1037), +W64LIT(0x467b7a1492c67792), +W64LIT(0x2087bbdaf78562f7), +W64LIT(0x819022615cfa1c5c), +W64LIT(0xcd9ea68aa0774ba0), +W64LIT(0xa79760ee2246cd22), +W64LIT(0x8343755288edde88), +W64LIT(0x58e48de0201b1720), +W64LIT(0x7216c8c5b9d555b9), +W64LIT(0x372d340195f58195), +W64LIT(0xa11799bbab7f7eab), +W64LIT(0x9f0fd595ee277cee), +W64LIT(0x676f102d0fb2740f), +W64LIT(0x9e9c047684d61d84), +W64LIT(0x49cefb6ecb5247cb), +W64LIT(0xd41279c8f162f9f1), +W64LIT(0x1f0c2617d82c01d8), +W64LIT(0x97a97c59547b9e54), +W64LIT(0xe76ce3af39b90939), +W64LIT(0xc3b8f61393121a93), +W64LIT(0x5ba40b309efdb49e), +W64LIT(0xea0a35e6b43afbb4), +W64LIT(0x5a37dad3f40cd5f4), +W64LIT(0x14ea090bdc9640dc), +W64LIT(0x5e6474b5a922a4a9), +W64LIT(0xfee03ced68acbb68), +W64LIT(0x071328b6e3c8d2e3), +W64LIT(0x5302a2fc24a15624), +W64LIT(0x85c38c0701d46d01), +W64LIT(0x3d58cafefbbea1fb), +W64LIT(0x84505de46b250c6b), +W64LIT(0x642f96fdb154d7b1), +W64LIT(0xbf886e4f19a21e19), +W64LIT(0x02d35733d417c2d4), +W64LIT(0x68da915756264456), +W64LIT(0x8710db34d5c3afd5), +W64LIT(0x0d66d6498d83f28d), +W64LIT(0x7b23b0ea6978d669), +W64LIT(0x1b5f887185027085), +W64LIT(0x3ccb1b1d914fc091), +W64LIT(0x0453ae665d2e715d), +W64LIT(0xcb1e5fdf294ef829), +W64LIT(0xf6469521d2f059d2), +W64LIT(0xb03def3540362e40), +W64LIT(0x633cbe4b529c0552), +W64LIT(0xf7d544c2b80138b8), +W64LIT(0x7ab061090389b703), +W64LIT(0x0000000000000000), +W64LIT(0xdba7f8b2a8f6c9a8), +W64LIT(0x35fe633241e24341), +W64LIT(0x21146a399d74039d), +W64LIT(0xd581a82b9b93989b), +W64LIT(0x0935782fd0ad83d0), +W64LIT(0x5ff7a556c3d3c5c3), +W64LIT(0xaf31c922981a2f98), +W64LIT(0x90ba54efb7b34cb7), +W64LIT(0x5291731f4e50374e), +W64LIT(0xc0f870c32df4b92d), +W64LIT(0x7ee3cf6f5ea7c65e), +W64LIT(0xe07fcb19da71dbda), +W64LIT(0x4eddd3d8289a9528), +W64LIT(0x13f921bd3f5e923f), +W64LIT(0xf50613f16c16fa6c), +W64LIT(0x981cfd230defae0d), +W64LIT(0x4c0e84ebfc8d57fc), +W64LIT(0x82d0a4b1e21cbfe2), +W64LIT(0x89368bade6a6fee6), +W64LIT(0xd292809d785b4a78), +W64LIT(0x47e8abf7f83716f8), +W64LIT(0x8e25a31b056e2c05), +W64LIT(0xd752ff184f845a4f), +W64LIT(0xcc0d7769ca862aca), +W64LIT(0x694940b43cd7253c), +W64LIT(0x2ea1eb43c4e033c4), +W64LIT(0xde6787379f29d99f), +W64LIT(0x181f0ea13be4d33b), +W64LIT(0x416852a2710ea571), +W64LIT(0x62af6fa8386d6438), +W64LIT(0xa0844858c18e1fc1), +W64LIT(0x337e9a67c8dbf0c8), +W64LIT(0x2c72bc7010f7f110), +W64LIT(0xbd5b397ccdb5dccd), +W64LIT(0xd8e77e6216106a16), +W64LIT(0x86830ad7bf32cebf), +W64LIT(0x4f4e023b426bf442), +W64LIT(0xe5bfb49cedaecbed), +W64LIT(0x8a760d7d58405d58), +W64LIT(0xe2ac9c2a0e66190e), +W64LIT(0xb5fd90b077e93e77), +W64LIT(0xdcb4d0044b3e1b4b), +W64LIT(0x453bfcc42c20d42c), +W64LIT(0xed191d5057f22957), +W64LIT(0xe1ec1afab080bab0), +W64LIT(0xee599b80e9148ae9), +W64LIT(0x2607428f7ebcd17e), +W64LIT(0x5d24f26517c40717), +W64LIT(0x6a09c66482318682), +W64LIT(0xa604b10d48b7ac48), +W64LIT(0xbe1bbfac73537f73), +W64LIT(0x282112164dd9804d), +W64LIT(0x7505e0735a1d875a), +W64LIT(0x73851926d32434d3), +W64LIT(0xd974af817ce10b7c), +W64LIT(0xeb99e405decb9ade), +W64LIT(0x9b5c7bf3b3090db3), +W64LIT(0xfab3928b3582ca35), +W64LIT(0x8003f382360b7d36), +W64LIT(0x94e9fa89ea9d3dea), +W64LIT(0xb1ae3ed62ac74f2a), +W64LIT(0x9acfaa10d9f86cd9), +W64LIT(0x390b6498a690d0a6), +W64LIT(0xf2153b478fde288f), +W64LIT(0x71564e150733f607), +W64LIT(0xa3c4ce887f68bc7f), +W64LIT(0xaaf1b6a7afc53faf), +W64LIT(0x1ddf71240c3bc30c), +W64LIT(0x77d6b7408e0a458e), +W64LIT(0x2b6194c6f33f23f3), +W64LIT(0xc9cd08ecfd593afd), +W64LIT(0xc85ed90f97a85b97), +W64LIT(0x8cf6f428d179eed1), +W64LIT(0x957a2b6a806c5c80), +W64LIT(0xbbdbc029448c6f44), +W64LIT(0x7863363ad79e75d7), +W64LIT(0x6e5a6802df1ff7df), +W64LIT(0xfb2043685f73ab5f), +}; + +NAMESPACE_END + +#endif // WORD64_AVAILABLE diff --git a/sharkval.dat b/sharkval.dat new file mode 100644 index 0000000..637387a --- /dev/null +++ b/sharkval.dat @@ -0,0 +1,7 @@ +00000000000000000000000000000000 0000000000000000 214BCF4E7716420A +000102030405060708090A0B0C0D0E0F 0000000000000000 C76C696289898137 +000102030405060708090A0B0C0D0E0F C76C696289898137 077A4A59FAEEEA4D +915F4619BE41B2516355A50110A9CE91 21A5DBEE154B8F6D 6FF33B98F448E95A +783348E75AEB0F2FD7B169BB8DC16787 F7C013AC5B2B8952 E5E554ABE9CED2D2 +DC49DB1375A5584F6485B413B5F12BAF 2F42B3B70369FC92 9AE068313F343A7A +5269F149D41BA0152497574D7F153125 65C178B284D197CC D3F111A282F17F29 diff --git a/simple.cpp b/simple.cpp new file mode 100644 index 0000000..ee5ab0c --- /dev/null +++ b/simple.cpp @@ -0,0 +1,23 @@ +// simple.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "simple.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +void HashTransformationWithDefaultTruncation::TruncatedFinal(byte *digest, unsigned int digestSize) +{ + ThrowIfInvalidTruncatedSize(digestSize); + unsigned int fullDigestSize = DigestSize(); + if (digestSize == fullDigestSize) + Final(digest); + else + { + SecByteBlock buffer(fullDigestSize); + Final(buffer); + memcpy(digest, buffer, digestSize); + } +} + +NAMESPACE_END diff --git a/simple.h b/simple.h new file mode 100644 index 0000000..a9d4f42 --- /dev/null +++ b/simple.h @@ -0,0 +1,228 @@ +// simple.h - written and placed in the public domain by Wei Dai +/*! \file + Simple non-interface classes derived from classes in cryptlib.h. +*/ + +#ifndef CRYPTOPP_SIMPLE_H +#define CRYPTOPP_SIMPLE_H + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class BASE, class ALGORITHM_INFO = BASE> +class AlgorithmImpl : public BASE +{ +public: + std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();} +}; + +//! . +class InvalidKeyLength : public InvalidArgument +{ +public: + explicit InvalidKeyLength(const std::string &algorithm, unsigned int length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {} +}; + +//! . +class InvalidRounds : public InvalidArgument +{ +public: + explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {} +}; + +class HashTransformationWithDefaultTruncation : public HashTransformation +{ +public: + virtual void Final(byte *digest) =0; + void TruncatedFinal(byte *digest, unsigned int digestSize); +}; + +//! . +// TODO: look into this virtual inheritance +class ASN1CryptoMaterial : virtual public ASN1Object, virtual public CryptoMaterial +{ +public: + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} +}; + +// ***************************** + +template <class T> +class Bufferless : public T +{ +public: + Bufferless() {} + Bufferless(BufferedTransformation *q) : T(q) {} + bool IsolatedFlush(bool hardFlush, bool blocking) {return false;} +}; + +template <class T> +class Unflushable : public T +{ +public: + Unflushable() {} + Unflushable(BufferedTransformation *q) : T(q) {} + bool Flush(bool completeFlush, int propagation=-1, bool blocking=true) + {return ChannelFlush(NULL_CHANNEL, completeFlush, propagation);} + bool IsolatedFlush(bool hardFlush, bool blocking) + {assert(false); return false;} + bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) + { + if (hardFlush && !InputBufferIsEmpty()) + throw CannotFlush("Unflushable<T>: this object has buffered input that cannot be flushed"); + else + { + BufferedTransformation *attached = AttachedTransformation(); + return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false; + } + } + +protected: + virtual bool InputBufferIsEmpty() const {return false;} +}; + +template <class T> +class InputRejecting : public T +{ +public: + InputRejecting() {} + InputRejecting(BufferedTransformation *q) : T(q) {} + +protected: + struct InputRejected : public NotImplemented + {InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}}; + + // shouldn't be calling these functions on this class + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + {throw InputRejected();} + bool IsolatedFlush(bool, bool) {return false;} + bool IsolatedMessageSeriesEnd(bool) {throw InputRejected();} + + unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) + {throw InputRejected();} + bool ChannelMessageSeriesEnd(const std::string &, int, bool) {throw InputRejected();} +}; + +template <class T> +class CustomSignalPropagation : public T +{ +public: + CustomSignalPropagation() {} + CustomSignalPropagation(BufferedTransformation *q) : T(q) {} + + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0; + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0; + +private: + void IsolatedInitialize(const NameValuePairs ¶meters) {assert(false);} + bool IsolatedFlush(bool hardFlush, bool blocking) {assert(false); return false;} +}; + +template <class T> +class Multichannel : public CustomSignalPropagation<T> +{ +public: + Multichannel() {} + Multichannel(BufferedTransformation *q) : CustomSignalPropagation<T>(q) {} + + void Initialize(const NameValuePairs ¶meters, int propagation) + {ChannelInitialize(NULL_CHANNEL, parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return ChannelFlush(NULL_CHANNEL, hardFlush, propagation, blocking);} + void MessageSeriesEnd(int propagation) + {ChannelMessageSeriesEnd(NULL_CHANNEL, propagation);} + byte * CreatePutSpace(unsigned int &size) + {return ChannelCreatePutSpace(NULL_CHANNEL, size);} + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return ChannelPut2(NULL_CHANNEL, begin, length, messageEnd, blocking);} + unsigned int PutModifiable2(byte *begin, byte *end, int messageEnd, bool blocking) + {return ChannelPutModifiable2(NULL_CHANNEL, begin, end, messageEnd, blocking);} + +// void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1) +// {PropagateMessageSeriesEnd(propagation, channel);} + byte * ChannelCreatePutSpace(const std::string &channel, unsigned int &size) + {size = 0; return NULL;} + bool ChannelPutModifiable(const std::string &channel, byte *inString, unsigned int length) + {ChannelPut(channel, inString, length); return false;} + + virtual unsigned int ChannelPut2(const std::string &channel, const byte *begin, unsigned int length, int messageEnd, bool blocking) =0; + + virtual void ChannelInitialize(const std::string &channel, const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0; + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0; +}; + +template <class T> +class AutoSignaling : public T +{ +public: + AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {} + AutoSignaling(BufferedTransformation *q, int propagation=-1) : T(q), m_autoSignalPropagation(propagation) {} + + void SetAutoSignalPropagation(int propagation) + {m_autoSignalPropagation = propagation;} + int GetAutoSignalPropagation() const + {return m_autoSignalPropagation;} + +private: + int m_autoSignalPropagation; +}; + +//! A BufferedTransformation that only contains pre-existing data as "output" +class Store : public AutoSignaling<InputRejecting<BufferedTransformation> > +{ +public: + Store() : m_messageEnd(false) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) + { + m_messageEnd = false; + StoreInitialize(parameters); + } + + unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;} + bool GetNextMessage(); + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=NULL_CHANNEL) const; + +protected: + virtual void StoreInitialize(const NameValuePairs ¶meters) =0; + + bool m_messageEnd; +}; + +//! A BufferedTransformation that doesn't produce any retrievable output +class Sink : public BufferedTransformation +{ +protected: + // make these functions protected to help prevent unintentional calls to them + BufferedTransformation::Get; + BufferedTransformation::Peek; + BufferedTransformation::TransferTo; + BufferedTransformation::CopyTo; + BufferedTransformation::CopyRangeTo; + BufferedTransformation::TransferMessagesTo; + BufferedTransformation::CopyMessagesTo; + BufferedTransformation::TransferAllTo; + BufferedTransformation::CopyAllTo; + unsigned int TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true) + {transferBytes = 0; return 0;} + unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const + {return 0;} +}; + +class BitBucket : public Bufferless<Sink> +{ +public: + std::string AlgorithmName() const {return "BitBucket";} + void IsolatedInitialize(const NameValuePairs ¶meters) {} + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) + {return 0;} +}; + +NAMESPACE_END + +#endif diff --git a/skipjack.cpp b/skipjack.cpp new file mode 100644 index 0000000..10c53c9 --- /dev/null +++ b/skipjack.cpp @@ -0,0 +1,197 @@ +// skipjack.cpp - modified by Wei Dai from Paulo Barreto's skipjack32.c, +// which is public domain according to his web site. + +#include "pch.h" +#include "skipjack.h" + +/* + * Optimized implementation of SKIPJACK algorithm + * + * originally written by Panu Rissanen <bande@lut.fi> 1998.06.24 + * optimized by Mark Tillotson <markt@chaos.org.uk> 1998.06.25 + * optimized by Paulo Barreto <pbarreto@nw.com.br> 1998.06.30 + */ + +NAMESPACE_BEGIN(CryptoPP) + +/** + * The F-table byte permutation (see description of the G-box permutation) + */ +const byte SKIPJACK::Base::fTable[256] = { + 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 +}; + +/** + * The key-dependent permutation G on V^16 is a four-round Feistel network. + * The round function is a fixed byte-substitution table (permutation on V^8), + * the F-table. Each round of G incorporates a single byte from the key. + */ +#define g(tab, w, i, j, k, l) \ +{ \ + w ^= (word)tab[i][w & 0xff] << 8; \ + w ^= (word)tab[j][w >> 8]; \ + w ^= (word)tab[k][w & 0xff] << 8; \ + w ^= (word)tab[l][w >> 8]; \ +} + +#define g0(tab, w) g(tab, w, 0, 1, 2, 3) +#define g1(tab, w) g(tab, w, 4, 5, 6, 7) +#define g2(tab, w) g(tab, w, 8, 9, 0, 1) +#define g3(tab, w) g(tab, w, 2, 3, 4, 5) +#define g4(tab, w) g(tab, w, 6, 7, 8, 9) + +/** + * The inverse of the G permutation. + */ +#define h(tab, w, i, j, k, l) \ +{ \ + w ^= (word)tab[l][w >> 8]; \ + w ^= (word)tab[k][w & 0xff] << 8; \ + w ^= (word)tab[j][w >> 8]; \ + w ^= (word)tab[i][w & 0xff] << 8; \ +} + +#define h0(tab, w) h(tab, w, 0, 1, 2, 3) +#define h1(tab, w) h(tab, w, 4, 5, 6, 7) +#define h2(tab, w) h(tab, w, 8, 9, 0, 1) +#define h3(tab, w) h(tab, w, 2, 3, 4, 5) +#define h4(tab, w) h(tab, w, 6, 7, 8, 9) + +/** + * Preprocess a user key into a table to save an XOR at each F-table access. + */ +void SKIPJACK::Base::UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length) +{ + AssertValidKeyLength(length); + + /* tab[i][c] = fTable[c ^ key[i]] */ + int i; + for (i = 0; i < 10; i++) { + byte *t = tab[i], k = key[9-i]; + int c; + for (c = 0; c < 256; c++) { + t[c] = fTable[c ^ k]; + } + } +} + +typedef BlockGetAndPut<word16, LittleEndian> Block; + +/** + * Encrypt a single block of data. + */ +void SKIPJACK::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word w1, w2, w3, w4; + Block::Get(inBlock)(w4)(w3)(w2)(w1); + + /* stepping rule A: */ + g0(tab, w1); w4 ^= w1 ^ 1; + g1(tab, w4); w3 ^= w4 ^ 2; + g2(tab, w3); w2 ^= w3 ^ 3; + g3(tab, w2); w1 ^= w2 ^ 4; + g4(tab, w1); w4 ^= w1 ^ 5; + g0(tab, w4); w3 ^= w4 ^ 6; + g1(tab, w3); w2 ^= w3 ^ 7; + g2(tab, w2); w1 ^= w2 ^ 8; + + /* stepping rule B: */ + w2 ^= w1 ^ 9; g3(tab, w1); + w1 ^= w4 ^ 10; g4(tab, w4); + w4 ^= w3 ^ 11; g0(tab, w3); + w3 ^= w2 ^ 12; g1(tab, w2); + w2 ^= w1 ^ 13; g2(tab, w1); + w1 ^= w4 ^ 14; g3(tab, w4); + w4 ^= w3 ^ 15; g4(tab, w3); + w3 ^= w2 ^ 16; g0(tab, w2); + + /* stepping rule A: */ + g1(tab, w1); w4 ^= w1 ^ 17; + g2(tab, w4); w3 ^= w4 ^ 18; + g3(tab, w3); w2 ^= w3 ^ 19; + g4(tab, w2); w1 ^= w2 ^ 20; + g0(tab, w1); w4 ^= w1 ^ 21; + g1(tab, w4); w3 ^= w4 ^ 22; + g2(tab, w3); w2 ^= w3 ^ 23; + g3(tab, w2); w1 ^= w2 ^ 24; + + /* stepping rule B: */ + w2 ^= w1 ^ 25; g4(tab, w1); + w1 ^= w4 ^ 26; g0(tab, w4); + w4 ^= w3 ^ 27; g1(tab, w3); + w3 ^= w2 ^ 28; g2(tab, w2); + w2 ^= w1 ^ 29; g3(tab, w1); + w1 ^= w4 ^ 30; g4(tab, w4); + w4 ^= w3 ^ 31; g0(tab, w3); + w3 ^= w2 ^ 32; g1(tab, w2); + + Block::Put(xorBlock, outBlock)(w4)(w3)(w2)(w1); +} + +/** + * Decrypt a single block of data. + */ +void SKIPJACK::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word w1, w2, w3, w4; + Block::Get(inBlock)(w4)(w3)(w2)(w1); + + /* stepping rule A: */ + h1(tab, w2); w3 ^= w2 ^ 32; + h0(tab, w3); w4 ^= w3 ^ 31; + h4(tab, w4); w1 ^= w4 ^ 30; + h3(tab, w1); w2 ^= w1 ^ 29; + h2(tab, w2); w3 ^= w2 ^ 28; + h1(tab, w3); w4 ^= w3 ^ 27; + h0(tab, w4); w1 ^= w4 ^ 26; + h4(tab, w1); w2 ^= w1 ^ 25; + + /* stepping rule B: */ + w1 ^= w2 ^ 24; h3(tab, w2); + w2 ^= w3 ^ 23; h2(tab, w3); + w3 ^= w4 ^ 22; h1(tab, w4); + w4 ^= w1 ^ 21; h0(tab, w1); + w1 ^= w2 ^ 20; h4(tab, w2); + w2 ^= w3 ^ 19; h3(tab, w3); + w3 ^= w4 ^ 18; h2(tab, w4); + w4 ^= w1 ^ 17; h1(tab, w1); + + /* stepping rule A: */ + h0(tab, w2); w3 ^= w2 ^ 16; + h4(tab, w3); w4 ^= w3 ^ 15; + h3(tab, w4); w1 ^= w4 ^ 14; + h2(tab, w1); w2 ^= w1 ^ 13; + h1(tab, w2); w3 ^= w2 ^ 12; + h0(tab, w3); w4 ^= w3 ^ 11; + h4(tab, w4); w1 ^= w4 ^ 10; + h3(tab, w1); w2 ^= w1 ^ 9; + + /* stepping rule B: */ + w1 ^= w2 ^ 8; h2(tab, w2); + w2 ^= w3 ^ 7; h1(tab, w3); + w3 ^= w4 ^ 6; h0(tab, w4); + w4 ^= w1 ^ 5; h4(tab, w1); + w1 ^= w2 ^ 4; h3(tab, w2); + w2 ^= w3 ^ 3; h2(tab, w3); + w3 ^= w4 ^ 2; h1(tab, w4); + w4 ^= w1 ^ 1; h0(tab, w1); + + Block::Put(xorBlock, outBlock)(w4)(w3)(w2)(w1); +} + +NAMESPACE_END diff --git a/skipjack.dat b/skipjack.dat new file mode 100644 index 0000000..6991a1e --- /dev/null +++ b/skipjack.dat @@ -0,0 +1 @@ +11223344556677889900 aabbccdd00112233 00d3127ae2ca8725 diff --git a/skipjack.h b/skipjack.h new file mode 100644 index 0000000..0f6fe94 --- /dev/null +++ b/skipjack.h @@ -0,0 +1,59 @@ +#ifndef CRYPTOPP_SKIPJACK_H +#define CRYPTOPP_SKIPJACK_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct SKIPJACK_Info : public FixedBlockSize<8>, public FixedKeyLength<10> +{ + static const char *StaticAlgorithmName() {return "SKIPJACK";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#SKIPJACK">SKIPJACK</a> +class SKIPJACK : public SKIPJACK_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<SKIPJACK_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static const byte fTable[256]; + + FixedSizeSecBlock<byte[256], 10> tab; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef SKIPJACK::Encryption SKIPJACKEncryption; +typedef SKIPJACK::Decryption SKIPJACKDecryption; + +NAMESPACE_END + +#endif diff --git a/smartptr.h b/smartptr.h new file mode 100644 index 0000000..00dab21 --- /dev/null +++ b/smartptr.h @@ -0,0 +1,215 @@ +#ifndef CRYPTOPP_SMARTPTR_H +#define CRYPTOPP_SMARTPTR_H + +#include "config.h" +#include <algorithm> + +NAMESPACE_BEGIN(CryptoPP) + +template<class T> class member_ptr +{ +public: + explicit member_ptr(T *p = NULL) : m_p(p) {} + + ~member_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return m_p; } + + const T* get() const { return m_p; } + T* get() { return m_p; } + + T* release() + { + T *old_p = m_p; + m_p = 0; + return old_p; + } + + void reset(T *p = 0); + +protected: + member_ptr(const member_ptr<T>& rhs); // copy not allowed + void operator=(const member_ptr<T>& rhs); // assignment not allowed + + T *m_p; +}; + +template <class T> member_ptr<T>::~member_ptr() {delete m_p;} +template <class T> void member_ptr<T>::reset(T *p) {delete m_p; m_p = p;} + +// ******************************************************** + +template<class T> class value_ptr : public member_ptr<T> +{ +public: + value_ptr(const T &obj) : member_ptr<T>(new T(obj)) {} + value_ptr(T *p = NULL) : member_ptr<T>(p) {} + value_ptr(const value_ptr<T>& rhs) + : member_ptr<T>(rhs.m_p ? new T(*rhs.m_p) : NULL) {} + + value_ptr<T>& operator=(const value_ptr<T>& rhs); + bool operator==(const value_ptr<T>& rhs) + { + return (!m_p && !rhs.m_p) || (m_p && rhs.m_p && *m_p == *rhs.m_p); + } +}; + +template <class T> value_ptr<T>& value_ptr<T>::operator=(const value_ptr<T>& rhs) +{ + T *old_p = m_p; + m_p = rhs.m_p ? new T(*rhs.m_p) : NULL; + delete old_p; + return *this; +} + +// ******************************************************** + +template<class T> class clonable_ptr : public member_ptr<T> +{ +public: + clonable_ptr(const T &obj) : member_ptr<T>(obj.Clone()) {} + clonable_ptr(T *p = NULL) : member_ptr<T>(p) {} + clonable_ptr(const clonable_ptr<T>& rhs) + : member_ptr<T>(rhs.m_p ? rhs.m_p->Clone() : NULL) {} + + clonable_ptr<T>& operator=(const clonable_ptr<T>& rhs); +}; + +template <class T> clonable_ptr<T>& clonable_ptr<T>::operator=(const clonable_ptr<T>& rhs) +{ + T *old_p = m_p; + m_p = rhs.m_p ? rhs.m_p->Clone() : NULL; + delete old_p; + return *this; +} + +// ******************************************************** + +template<class T> class counted_ptr +{ +public: + explicit counted_ptr(T *p = 0); + counted_ptr(const T &r) : m_p(0) {attach(r);} + counted_ptr(const counted_ptr<T>& rhs); + + ~counted_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return get(); } + + const T* get() const { return m_p; } + T* get(); + + void attach(const T &p); + + counted_ptr<T> & operator=(const counted_ptr<T>& rhs); + +private: + T *m_p; +}; + +template <class T> counted_ptr<T>::counted_ptr(T *p) + : m_p(p) +{ + if (m_p) + m_p->m_referenceCount = 1; +} + +template <class T> counted_ptr<T>::counted_ptr(const counted_ptr<T>& rhs) + : m_p(rhs.m_p) +{ + if (m_p) + m_p->m_referenceCount++; +} + +template <class T> counted_ptr<T>::~counted_ptr() +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; +} + +template <class T> void counted_ptr<T>::attach(const T &r) +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + if (r.m_referenceCount == 0) + { + m_p = r.clone(); + m_p->m_referenceCount = 1; + } + else + { + m_p = const_cast<T *>(&r); + m_p->m_referenceCount++; + } +} + +template <class T> T* counted_ptr<T>::get() +{ + if (m_p && m_p->m_referenceCount > 1) + { + T *temp = m_p->clone(); + m_p->m_referenceCount--; + m_p = temp; + m_p->m_referenceCount = 1; + } + return m_p; +} + +template <class T> counted_ptr<T> & counted_ptr<T>::operator=(const counted_ptr<T>& rhs) +{ + if (m_p != rhs.m_p) + { + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + m_p = rhs.m_p; + if (m_p) + m_p->m_referenceCount++; + } + return *this; +} + +// ******************************************************** + +template <class T> class vector_member_ptrs +{ +public: + vector_member_ptrs(unsigned int size=0) + : _size(size) {ptr = new member_ptr<T>[_size];} + ~vector_member_ptrs() + {delete [] ptr;} + + member_ptr<T>& operator[](unsigned int index) + {assert(index<_size); return ptr[index];} + const member_ptr<T>& operator[](unsigned int index) const + {assert(index<_size); return ptr[index];} + + unsigned int size() const {return _size;} + void resize(unsigned int newSize) + { + member_ptr<T> *newPtr = new member_ptr<T>[newSize]; + for (unsigned int i=0; i<STDMIN(_size, newSize); i++) + newPtr[i].reset(ptr[i].release()); + delete [] ptr; + _size = newSize; + ptr = newPtr; + } + +private: + vector_member_ptrs(const vector_member_ptrs<T> &c); // copy not allowed + void operator=(const vector_member_ptrs<T> &x); // assignment not allowed + + unsigned int _size; + member_ptr<T> *ptr; +}; + +NAMESPACE_END + +#endif diff --git a/socketft.cpp b/socketft.cpp new file mode 100644 index 0000000..0f7b7eb --- /dev/null +++ b/socketft.cpp @@ -0,0 +1,475 @@ +// socketft.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "socketft.h" + +#ifdef SOCKETS_AVAILABLE + +#include "wait.h" + +#ifdef USE_BERKELEY_STYLE_SOCKETS +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef USE_WINDOWS_STYLE_SOCKETS +const int SOCKET_EINVAL = WSAEINVAL; +const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK; +typedef int socklen_t; +#else +const int SOCKET_EINVAL = EINVAL; +const int SOCKET_EWOULDBLOCK = EWOULDBLOCK; +#endif + +Socket::Err::Err(socket_t s, const std::string& operation, int error) + : OS_Error(IO_ERROR, "Socket: " + operation + " operation failed with error " + IntToString(error), operation, error) + , m_s(s) +{ +} + +Socket::~Socket() +{ + if (m_own) + { + try + { + CloseSocket(); + } + catch (...) + { + } + } +} + +void Socket::AttachSocket(socket_t s, bool own) +{ + if (m_own) + CloseSocket(); + + m_s = s; + m_own = own; + SocketChanged(); +} + +socket_t Socket::DetachSocket() +{ + socket_t s = m_s; + m_s = INVALID_SOCKET; + SocketChanged(); + return s; +} + +void Socket::Create(int nType) +{ + assert(m_s == INVALID_SOCKET); + m_s = socket(AF_INET, nType, 0); + CheckAndHandleError("socket", m_s); + m_own = true; + SocketChanged(); +} + +void Socket::CloseSocket() +{ + if (m_s != INVALID_SOCKET) + { +#ifdef USE_WINDOWS_STYLE_SOCKETS + CheckAndHandleError_int("closesocket", closesocket(m_s)); +#else + CheckAndHandleError_int("close", close(m_s)); +#endif + m_s = INVALID_SOCKET; + SocketChanged(); + } +} + +void Socket::Bind(unsigned int port, const char *addr) +{ + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + + if (addr == NULL) + sa.sin_addr.s_addr = htonl(INADDR_ANY); + else + { + unsigned long result = inet_addr(addr); + if (result == -1) // Solaris doesn't have INADDR_NONE + { + SetLastError(SOCKET_EINVAL); + CheckAndHandleError_int("inet_addr", SOCKET_ERROR); + } + sa.sin_addr.s_addr = result; + } + + sa.sin_port = htons((u_short)port); + + Bind((sockaddr *)&sa, sizeof(sa)); +} + +void Socket::Bind(const sockaddr *psa, socklen_t saLen) +{ + assert(m_s != INVALID_SOCKET); + // cygwin workaround: needs const_cast + CheckAndHandleError_int("bind", bind(m_s, const_cast<sockaddr *>(psa), saLen)); +} + +void Socket::Listen(int backlog) +{ + assert(m_s != INVALID_SOCKET); + CheckAndHandleError_int("listen", listen(m_s, backlog)); +} + +bool Socket::Connect(const char *addr, unsigned int port) +{ + assert(addr != NULL); + + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr(addr); + + if (sa.sin_addr.s_addr == -1) // Solaris doesn't have INADDR_NONE + { + hostent *lphost = gethostbyname(addr); + if (lphost == NULL) + { + SetLastError(SOCKET_EINVAL); + CheckAndHandleError_int("gethostbyname", SOCKET_ERROR); + } + + sa.sin_addr.s_addr = ((in_addr *)lphost->h_addr)->s_addr; + } + + sa.sin_port = htons((u_short)port); + + return Connect((const sockaddr *)&sa, sizeof(sa)); +} + +bool Socket::Connect(const sockaddr* psa, socklen_t saLen) +{ + assert(m_s != INVALID_SOCKET); + int result = connect(m_s, const_cast<sockaddr*>(psa), saLen); + if (result == SOCKET_ERROR && GetLastError() == SOCKET_EWOULDBLOCK) + return false; + CheckAndHandleError_int("connect", result); + return true; +} + +bool Socket::Accept(Socket& target, sockaddr *psa, socklen_t *psaLen) +{ + assert(m_s != INVALID_SOCKET); + socket_t s = accept(m_s, psa, psaLen); + if (s == INVALID_SOCKET && GetLastError() == SOCKET_EWOULDBLOCK) + return false; + CheckAndHandleError_int("accept", s); + target.AttachSocket(s, true); + return true; +} + +void Socket::GetSockName(sockaddr *psa, socklen_t *psaLen) +{ + assert(m_s != INVALID_SOCKET); + CheckAndHandleError_int("getsockname", getsockname(m_s, psa, psaLen)); +} + +unsigned int Socket::Send(const byte* buf, unsigned int bufLen, int flags) +{ + assert(m_s != INVALID_SOCKET); + int result = send(m_s, (const char *)buf, bufLen, flags); + CheckAndHandleError_int("send", result); + return result; +} + +unsigned int Socket::Receive(byte* buf, unsigned int bufLen, int flags) +{ + assert(m_s != INVALID_SOCKET); + int result = recv(m_s, (char *)buf, bufLen, flags); + CheckAndHandleError_int("recv", result); + return result; +} + +void Socket::ShutDown(int how) +{ + assert(m_s != INVALID_SOCKET); + int result = shutdown(m_s, how); + CheckAndHandleError_int("shutdown", result); +} + +void Socket::IOCtl(long cmd, unsigned long *argp) +{ + assert(m_s != INVALID_SOCKET); +#ifdef USE_WINDOWS_STYLE_SOCKETS + CheckAndHandleError_int("ioctlsocket", ioctlsocket(m_s, cmd, argp)); +#else + CheckAndHandleError_int("ioctl", ioctl(m_s, cmd, argp)); +#endif +} + +bool Socket::SendReady(const timeval *timeout) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_s, &fds); + int ready; + if (timeout == NULL) + ready = select(m_s+1, NULL, &fds, NULL, NULL); + else + { + timeval timeoutCopy = *timeout; // select() modified timeout on Linux + ready = select(m_s+1, NULL, &fds, NULL, &timeoutCopy); + } + CheckAndHandleError_int("select", ready); + return ready > 0; +} + +bool Socket::ReceiveReady(const timeval *timeout) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_s, &fds); + int ready; + if (timeout == NULL) + ready = select(m_s+1, &fds, NULL, NULL, NULL); + else + { + timeval timeoutCopy = *timeout; // select() modified timeout on Linux + ready = select(m_s+1, &fds, NULL, NULL, &timeoutCopy); + } + CheckAndHandleError_int("select", ready); + return ready > 0; +} + +unsigned int Socket::PortNameToNumber(const char *name, const char *protocol) +{ + int port = atoi(name); + if (IntToString(port) == name) + return port; + + servent *se = getservbyname(name, protocol); + if (!se) + throw Err(INVALID_SOCKET, "getservbyname", SOCKET_EINVAL); + return ntohs(se->s_port); +} + +void Socket::StartSockets() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + WSADATA wsd; + int result = WSAStartup(0x0002, &wsd); + if (result != 0) + throw Err(INVALID_SOCKET, "WSAStartup", result); +#endif +} + +void Socket::ShutdownSockets() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + int result = WSACleanup(); + if (result != 0) + throw Err(INVALID_SOCKET, "WSACleanup", result); +#endif +} + +int Socket::GetLastError() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + return WSAGetLastError(); +#else + return errno; +#endif +} + +void Socket::SetLastError(int errorCode) +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + WSASetLastError(errorCode); +#else + errno = errorCode; +#endif +} + +void Socket::HandleError(const char *operation) const +{ + int err = GetLastError(); + throw Err(m_s, operation, err); +} + +#ifdef USE_WINDOWS_STYLE_SOCKETS + +SocketReceiver::SocketReceiver(Socket &s) + : m_s(s), m_resultPending(false), m_eofReceived(false) +{ + m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); + m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid()); + memset(&m_overlapped, 0, sizeof(m_overlapped)); + m_overlapped.hEvent = m_event; +} + +void SocketReceiver::Receive(byte* buf, unsigned int bufLen) +{ + assert(!m_resultPending && !m_eofReceived); + + DWORD flags = 0; + WSABUF wsabuf = {bufLen, (char *)buf}; + if (WSARecv(m_s, &wsabuf, 1, &m_lastResult, &flags, &m_overlapped, NULL) == 0) + { + if (m_lastResult == 0) + m_eofReceived = true; + } + else + { + switch (WSAGetLastError()) + { + default: + m_s.CheckAndHandleError_int("WSARecv", SOCKET_ERROR); + case WSAEDISCON: + m_lastResult = 0; + m_eofReceived = true; + break; + case WSA_IO_PENDING: + m_resultPending = true; + } + } +} + +void SocketReceiver::GetWaitObjects(WaitObjectContainer &container) +{ + if (m_resultPending) + container.AddHandle(m_event); + else if (!m_eofReceived) + container.SetNoWait(); +} + +unsigned int SocketReceiver::GetReceiveResult() +{ + if (m_resultPending) + { + DWORD flags = 0; + if (WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags)) + { + if (m_lastResult == 0) + m_eofReceived = true; + } + else + { + switch (WSAGetLastError()) + { + default: + m_s.CheckAndHandleError("WSAGetOverlappedResult", FALSE); + case WSAEDISCON: + m_lastResult = 0; + m_eofReceived = true; + } + } + m_resultPending = false; + } + return m_lastResult; +} + +// ************************************************************* + +SocketSender::SocketSender(Socket &s) + : m_s(s), m_resultPending(false), m_lastResult(0) +{ + m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); + m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid()); + memset(&m_overlapped, 0, sizeof(m_overlapped)); + m_overlapped.hEvent = m_event; +} + +void SocketSender::Send(const byte* buf, unsigned int bufLen) +{ + DWORD written = 0; + WSABUF wsabuf = {bufLen, (char *)buf}; + if (WSASend(m_s, &wsabuf, 1, &written, 0, &m_overlapped, NULL) == 0) + { + m_resultPending = false; + m_lastResult = written; + } + else + { + if (WSAGetLastError() != WSA_IO_PENDING) + m_s.CheckAndHandleError_int("WSASend", SOCKET_ERROR); + + m_resultPending = true; + } +} + +void SocketSender::GetWaitObjects(WaitObjectContainer &container) +{ + if (m_resultPending) + container.AddHandle(m_event); + else + container.SetNoWait(); +} + +unsigned int SocketSender::GetSendResult() +{ + if (m_resultPending) + { + DWORD flags = 0; + BOOL result = WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags); + m_s.CheckAndHandleError("WSAGetOverlappedResult", result); + m_resultPending = false; + } + return m_lastResult; +} + +#endif + +#ifdef USE_BERKELEY_STYLE_SOCKETS + +SocketReceiver::SocketReceiver(Socket &s) + : m_s(s), m_lastResult(0), m_eofReceived(false) +{ +} + +void SocketReceiver::GetWaitObjects(WaitObjectContainer &container) +{ + if (!m_eofReceived) + container.AddReadFd(m_s); +} + +void SocketReceiver::Receive(byte* buf, unsigned int bufLen) +{ + m_lastResult = m_s.Receive(buf, bufLen); + if (bufLen > 0 && m_lastResult == 0) + m_eofReceived = true; +} + +unsigned int SocketReceiver::GetReceiveResult() +{ + return m_lastResult; +} + +SocketSender::SocketSender(Socket &s) + : m_s(s), m_lastResult(0) +{ +} + +void SocketSender::Send(const byte* buf, unsigned int bufLen) +{ + m_lastResult = m_s.Send(buf, bufLen); +} + +unsigned int SocketSender::GetSendResult() +{ + return m_lastResult; +} + +void SocketSender::GetWaitObjects(WaitObjectContainer &container) +{ + container.AddWriteFd(m_s); +} + +#endif + +NAMESPACE_END + +#endif // #ifdef SOCKETS_AVAILABLE diff --git a/socketft.h b/socketft.h new file mode 100644 index 0000000..58f2702 --- /dev/null +++ b/socketft.h @@ -0,0 +1,218 @@ +#ifndef CRYPTOPP_SOCKETFT_H +#define CRYPTOPP_SOCKETFT_H + +#include "config.h" + +#ifdef SOCKETS_AVAILABLE + +#include "network.h" +#include "queue.h" + +#ifdef USE_WINDOWS_STYLE_SOCKETS +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error Winsock 1 is not supported by this library. Please include this file or winsock2.h before windows.h. +# endif +#include <winsock2.h> +#include "winpipes.h" +#else +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef USE_WINDOWS_STYLE_SOCKETS +typedef ::SOCKET socket_t; +#else +typedef int socket_t; +const socket_t INVALID_SOCKET = -1; +// cygwin 1.1.4 doesn't have SHUT_RD +const int SD_RECEIVE = 0; +const int SD_SEND = 1; +const int SD_BOTH = 2; +const int SOCKET_ERROR = -1; +#endif + +#ifndef socklen_t +typedef TYPE_OF_SOCKLEN_T socklen_t; // see config.h +#endif + +//! wrapper for Windows or Berkeley Sockets +class Socket +{ +public: + //! exception thrown by Socket class + class Err : public OS_Error + { + public: + Err(socket_t s, const std::string& operation, int error); + socket_t GetSocket() const {return m_s;} + + private: + socket_t m_s; + }; + + Socket(socket_t s = INVALID_SOCKET, bool own=false) : m_s(s), m_own(own) {} + Socket(const Socket &s) : m_s(s.m_s), m_own(false) {} + virtual ~Socket(); + + bool GetOwnership() const {return m_own;} + void SetOwnership(bool own) {m_own = own;} + + operator socket_t() {return m_s;} + socket_t GetSocket() const {return m_s;} + void AttachSocket(socket_t s, bool own=false); + socket_t DetachSocket(); + void CloseSocket(); + + void Create(int nType = SOCK_STREAM); + void Bind(unsigned int port, const char *addr=NULL); + void Bind(const sockaddr* psa, socklen_t saLen); + void Listen(int backlog=5); + // the next three functions return false if the socket is in nonblocking mode + // and the operation cannot be completed immediately + bool Connect(const char *addr, unsigned int port); + bool Connect(const sockaddr* psa, socklen_t saLen); + bool Accept(Socket& s, sockaddr *psa=NULL, socklen_t *psaLen=NULL); + void GetSockName(sockaddr *psa, socklen_t *psaLen); + unsigned int Send(const byte* buf, unsigned int bufLen, int flags=0); + unsigned int Receive(byte* buf, unsigned int bufLen, int flags=0); + void ShutDown(int how = SD_SEND); + + void IOCtl(long cmd, unsigned long *argp); + bool SendReady(const timeval *timeout); + bool ReceiveReady(const timeval *timeout); + + virtual void HandleError(const char *operation) const; + void CheckAndHandleError_int(const char *operation, int result) const + {if (result == SOCKET_ERROR) HandleError(operation);} + void CheckAndHandleError(const char *operation, socket_t result) const + {if (result == SOCKET_ERROR) HandleError(operation);} +#ifdef USE_WINDOWS_STYLE_SOCKETS + void CheckAndHandleError(const char *operation, BOOL result) const + {assert(result==TRUE || result==FALSE); if (!result) HandleError(operation);} +#endif + + //! look up the port number given its name, returns 0 if not found + static unsigned int PortNameToNumber(const char *name, const char *protocol="tcp"); + //! start Windows Sockets 2 + static void StartSockets(); + //! calls WSACleanup for Windows Sockets + static void ShutdownSockets(); + //! returns errno or WSAGetLastError + static int GetLastError(); + //! sets errno or calls WSASetLastError + static void SetLastError(int errorCode); + +protected: + virtual void SocketChanged() {} + + socket_t m_s; + bool m_own; +}; + +//! contributed by Denis Bider +class SocketsInitializer +{ +public: + SocketsInitializer() {Socket::StartSockets();} + ~SocketsInitializer() {try {Socket::ShutdownSockets();} catch (...) {}} +}; + +class SocketReceiver : public NetworkReceiver +{ +public: + SocketReceiver(Socket &s); + +#ifdef USE_BERKELEY_STYLE_SOCKETS + bool MustWaitToReceive() {return true;} +#else + bool MustWaitForResult() {return true;} +#endif + void Receive(byte* buf, unsigned int bufLen); + unsigned int GetReceiveResult(); + bool EofReceived() const {return m_eofReceived;} + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container); + +private: + Socket &m_s; + bool m_eofReceived; + +#ifdef USE_WINDOWS_STYLE_SOCKETS + WindowsHandle m_event; + OVERLAPPED m_overlapped; + bool m_resultPending; + DWORD m_lastResult; +#else + unsigned int m_lastResult; +#endif +}; + +class SocketSender : public NetworkSender +{ +public: + SocketSender(Socket &s); + +#ifdef USE_BERKELEY_STYLE_SOCKETS + bool MustWaitToSend() {return true;} +#else + bool MustWaitForResult() {return true;} +#endif + void Send(const byte* buf, unsigned int bufLen); + unsigned int GetSendResult(); + void SendEof() {m_s.ShutDown(SD_SEND);} + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container); + +private: + Socket &m_s; +#ifdef USE_WINDOWS_STYLE_SOCKETS + WindowsHandle m_event; + OVERLAPPED m_overlapped; + bool m_resultPending; + DWORD m_lastResult; +#else + unsigned int m_lastResult; +#endif +}; + +//! . +class SocketSource : public NetworkSource, public Socket +{ +public: + SocketSource(socket_t s = INVALID_SOCKET, bool pumpAll = false, BufferedTransformation *attachment = NULL) + : NetworkSource(attachment), Socket(s), m_receiver(*this) + { + if (pumpAll) + PumpAll(); + } + +private: + NetworkReceiver & AccessReceiver() {return m_receiver;} + SocketReceiver m_receiver; +}; + +//! . +class SocketSink : public NetworkSink, public Socket +{ +public: + SocketSink(socket_t s = INVALID_SOCKET, unsigned int maxBufferSize=0, bool autoFlush=false) + : NetworkSink(maxBufferSize, autoFlush), Socket(s), m_sender(*this) {} + + void SendEof() {ShutDown(SD_SEND);} + +private: + NetworkSender & AccessSender() {return m_sender;} + SocketSender m_sender; +}; + +NAMESPACE_END + +#endif // #ifdef SOCKETS_AVAILABLE + +#endif diff --git a/square.cpp b/square.cpp new file mode 100644 index 0000000..9d5466f --- /dev/null +++ b/square.cpp @@ -0,0 +1,174 @@ +// square.cpp - written and placed in the public domain by Wei Dai +// Based on Paulo S.L.M. Barreto's public domain implementation + +#include "pch.h" +#include "square.h" +#include "misc.h" +#include "gf256.h" + +NAMESPACE_BEGIN(CryptoPP) + +// apply theta to a roundkey +static void SquareTransform (word32 in[4], word32 out[4]) +{ + static const byte G[4][4] = + { + 0x02U, 0x01U, 0x01U, 0x03U, + 0x03U, 0x02U, 0x01U, 0x01U, + 0x01U, 0x03U, 0x02U, 0x01U, + 0x01U, 0x01U, 0x03U, 0x02U + }; + + GF256 gf256(0xf5); + + for (int i = 0; i < 4; i++) + { + word32 temp = 0; + for (int j = 0; j < 4; j++) + for (int k = 0; k < 4; k++) + temp ^= (word32)gf256.Multiply(GETBYTE(in[i], 3-k), G[k][j]) << ((3-j)*8); + out[i] = temp; + } +} + +void Square::Base::UncheckedSetKey(CipherDir dir, const byte *userKey, unsigned int length) +{ + AssertValidKeyLength(length); + + static const word32 offset[ROUNDS] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + }; + + GetUserKey(BIG_ENDIAN_ORDER, roundkeys[0], KEYLENGTH/4, userKey, KEYLENGTH); + + /* apply the key evolution function */ + for (int i = 1; i < ROUNDS+1; i++) + { + roundkeys[i][0] = roundkeys[i-1][0] ^ rotlFixed(roundkeys[i-1][3], 8U) ^ offset[i-1]; + roundkeys[i][1] = roundkeys[i-1][1] ^ roundkeys[i][0]; + roundkeys[i][2] = roundkeys[i-1][2] ^ roundkeys[i][1]; + roundkeys[i][3] = roundkeys[i-1][3] ^ roundkeys[i][2]; + } + + /* produce the round keys */ + if (dir == ENCRYPTION) + { + for (int i = 0; i < ROUNDS; i++) + SquareTransform (roundkeys[i], roundkeys[i]); + } + else + { + for (int i = 0; i < ROUNDS/2; i++) + for (int j = 0; j < 4; j++) + std::swap(roundkeys[i][j], roundkeys[ROUNDS-i][j]); + SquareTransform (roundkeys[ROUNDS], roundkeys[ROUNDS]); + } +} + +#define MSB(x) (((x) >> 24) & 0xffU) /* most significant byte */ +#define SSB(x) (((x) >> 16) & 0xffU) /* second in significance */ +#define TSB(x) (((x) >> 8) & 0xffU) /* third in significance */ +#define LSB(x) (((x) ) & 0xffU) /* least significant byte */ + +#define squareRound(text, temp, T0, T1, T2, T3, roundkey) \ +{ \ + temp[0] = T0[MSB (text[0])] \ + ^ T1[MSB (text[1])] \ + ^ T2[MSB (text[2])] \ + ^ T3[MSB (text[3])] \ + ^ roundkey[0]; \ + temp[1] = T0[SSB (text[0])] \ + ^ T1[SSB (text[1])] \ + ^ T2[SSB (text[2])] \ + ^ T3[SSB (text[3])] \ + ^ roundkey[1]; \ + temp[2] = T0[TSB (text[0])] \ + ^ T1[TSB (text[1])] \ + ^ T2[TSB (text[2])] \ + ^ T3[TSB (text[3])] \ + ^ roundkey[2]; \ + temp[3] = T0[LSB (text[0])] \ + ^ T1[LSB (text[1])] \ + ^ T2[LSB (text[2])] \ + ^ T3[LSB (text[3])] \ + ^ roundkey[3]; \ +} /* squareRound */ + +#define squareFinal(text, temp, S, roundkey) \ +{ \ + text[0] = ((word32) (S[MSB (temp[0])]) << 24) \ + ^ ((word32) (S[MSB (temp[1])]) << 16) \ + ^ ((word32) (S[MSB (temp[2])]) << 8) \ + ^ (word32) (S[MSB (temp[3])]) \ + ^ roundkey[0]; \ + text[1] = ((word32) (S[SSB (temp[0])]) << 24) \ + ^ ((word32) (S[SSB (temp[1])]) << 16) \ + ^ ((word32) (S[SSB (temp[2])]) << 8) \ + ^ (word32) (S[SSB (temp[3])]) \ + ^ roundkey[1]; \ + text[2] = ((word32) (S[TSB (temp[0])]) << 24) \ + ^ ((word32) (S[TSB (temp[1])]) << 16) \ + ^ ((word32) (S[TSB (temp[2])]) << 8) \ + ^ (word32) (S[TSB (temp[3])]) \ + ^ roundkey[2]; \ + text[3] = ((word32) (S[LSB (temp[0])]) << 24) \ + ^ ((word32) (S[LSB (temp[1])]) << 16) \ + ^ ((word32) (S[LSB (temp[2])]) << 8) \ + ^ (word32) (S[LSB (temp[3])]) \ + ^ roundkey[3]; \ +} /* squareFinal */ + +typedef BlockGetAndPut<word32, BigEndian> Block; + +void Square::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 text[4], temp[4]; + Block::Get(inBlock)(text[0])(text[1])(text[2])(text[3]); + + /* initial key addition */ + text[0] ^= roundkeys[0][0]; + text[1] ^= roundkeys[0][1]; + text[2] ^= roundkeys[0][2]; + text[3] ^= roundkeys[0][3]; + + /* ROUNDS - 1 full rounds */ + for (int i=1; i+1<ROUNDS; i+=2) + { + squareRound (text, temp, Te[0], Te[1], Te[2], Te[3], roundkeys[i]); + squareRound (temp, text, Te[0], Te[1], Te[2], Te[3], roundkeys[i+1]); + } + squareRound (text, temp, Te[0], Te[1], Te[2], Te[3], roundkeys[ROUNDS-1]); + + /* last round (diffusion becomes only transposition) */ + squareFinal (text, temp, Se, roundkeys[ROUNDS]); + + Block::Put(xorBlock, outBlock)(text[0])(text[1])(text[2])(text[3]); +} + +void Square::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 text[4], temp[4]; + Block::Get(inBlock)(text[0])(text[1])(text[2])(text[3]); + + /* initial key addition */ + text[0] ^= roundkeys[0][0]; + text[1] ^= roundkeys[0][1]; + text[2] ^= roundkeys[0][2]; + text[3] ^= roundkeys[0][3]; + + /* ROUNDS - 1 full rounds */ + for (int i=1; i+1<ROUNDS; i+=2) + { + squareRound (text, temp, Td[0], Td[1], Td[2], Td[3], roundkeys[i]); + squareRound (temp, text, Td[0], Td[1], Td[2], Td[3], roundkeys[i+1]); + } + squareRound (text, temp, Td[0], Td[1], Td[2], Td[3], roundkeys[ROUNDS-1]); + + /* last round (diffusion becomes only transposition) */ + squareFinal (text, temp, Sd, roundkeys[ROUNDS]); + + Block::Put(xorBlock, outBlock)(text[0])(text[1])(text[2])(text[3]); +} + +NAMESPACE_END diff --git a/square.h b/square.h new file mode 100644 index 0000000..5ec9007 --- /dev/null +++ b/square.h @@ -0,0 +1,57 @@ +#ifndef CRYPTOPP_SQUARE_H +#define CRYPTOPP_SQUARE_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Square_Info : public FixedBlockSize<16>, public FixedKeyLength<16>, FixedRounds<8> +{ + static const char *StaticAlgorithmName() {return "Square";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Square">Square</a> +class Square : public Square_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Square_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + FixedSizeSecBlock<word32[4], ROUNDS+1> roundkeys; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Square::Encryption SquareEncryption; +typedef Square::Decryption SquareDecryption; + +NAMESPACE_END + +#endif diff --git a/squaretb.cpp b/squaretb.cpp new file mode 100644 index 0000000..bc3bee7 --- /dev/null +++ b/squaretb.cpp @@ -0,0 +1,582 @@ +#include "pch.h" +#include "square.h" + +NAMESPACE_BEGIN(CryptoPP) + +const byte Square::Enc::Se[256] = { +177, 206, 195, 149, 90, 173, 231, 2, 77, 68, 251, 145, 12, 135, 161, 80, +203, 103, 84, 221, 70, 143, 225, 78, 240, 253, 252, 235, 249, 196, 26, 110, + 94, 245, 204, 141, 28, 86, 67, 254, 7, 97, 248, 117, 89, 255, 3, 34, +138, 209, 19, 238, 136, 0, 14, 52, 21, 128, 148, 227, 237, 181, 83, 35, + 75, 71, 23, 167, 144, 53, 171, 216, 184, 223, 79, 87, 154, 146, 219, 27, + 60, 200, 153, 4, 142, 224, 215, 125, 133, 187, 64, 44, 58, 69, 241, 66, +101, 32, 65, 24, 114, 37, 147, 112, 54, 5, 242, 11, 163, 121, 236, 8, + 39, 49, 50, 182, 124, 176, 10, 115, 91, 123, 183, 129, 210, 13, 106, 38, +158, 88, 156, 131, 116, 179, 172, 48, 122, 105, 119, 15, 174, 33, 222, 208, + 46, 151, 16, 164, 152, 168, 212, 104, 45, 98, 41, 109, 22, 73, 118, 199, +232, 193, 150, 55, 229, 202, 244, 233, 99, 18, 194, 166, 20, 188, 211, 40, +175, 47, 230, 36, 82, 198, 160, 9, 189, 140, 207, 93, 17, 95, 1, 197, +159, 61, 162, 155, 201, 59, 190, 81, 25, 31, 63, 92, 178, 239, 74, 205, +191, 186, 111, 100, 217, 243, 62, 180, 170, 220, 213, 6, 192, 126, 246, 102, +108, 132, 113, 56, 185, 29, 127, 157, 72, 139, 42, 218, 165, 51, 130, 57, +214, 120, 134, 250, 228, 43, 169, 30, 137, 96, 107, 234, 85, 76, 247, 226, +}; + +const byte Square::Dec::Sd[256] = { + 53, 190, 7, 46, 83, 105, 219, 40, 111, 183, 118, 107, 12, 125, 54, 139, +146, 188, 169, 50, 172, 56, 156, 66, 99, 200, 30, 79, 36, 229, 247, 201, + 97, 141, 47, 63, 179, 101, 127, 112, 175, 154, 234, 245, 91, 152, 144, 177, +135, 113, 114, 237, 55, 69, 104, 163, 227, 239, 92, 197, 80, 193, 214, 202, + 90, 98, 95, 38, 9, 93, 20, 65, 232, 157, 206, 64, 253, 8, 23, 74, + 15, 199, 180, 62, 18, 252, 37, 75, 129, 44, 4, 120, 203, 187, 32, 189, +249, 41, 153, 168, 211, 96, 223, 17, 151, 137, 126, 250, 224, 155, 31, 210, +103, 226, 100, 119, 132, 43, 158, 138, 241, 109, 136, 121, 116, 87, 221, 230, + 57, 123, 238, 131, 225, 88, 242, 13, 52, 248, 48, 233, 185, 35, 84, 21, + 68, 11, 77, 102, 58, 3, 162, 145, 148, 82, 76, 195, 130, 231, 128, 192, +182, 14, 194, 108, 147, 236, 171, 67, 149, 246, 216, 70, 134, 5, 140, 176, +117, 0, 204, 133, 215, 61, 115, 122, 72, 228, 209, 89, 173, 184, 198, 208, +220, 161, 170, 2, 29, 191, 181, 159, 81, 196, 165, 16, 34, 207, 1, 186, +143, 49, 124, 174, 150, 218, 240, 86, 71, 212, 235, 78, 217, 19, 142, 73, + 85, 22, 255, 59, 244, 164, 178, 6, 160, 167, 251, 27, 110, 60, 51, 205, + 24, 94, 106, 213, 166, 33, 222, 254, 42, 28, 243, 10, 26, 25, 39, 45, +}; + +const word32 Square::Enc::Te[4][256] = { +{ +0x97b1b126UL, 0x69cecea7UL, 0x73c3c3b0UL, 0xdf95954aUL, +0xb45a5aeeUL, 0xafadad02UL, 0x3be7e7dcUL, 0x04020206UL, +0x9a4d4dd7UL, 0x884444ccUL, 0x03fbfbf8UL, 0xd7919146UL, +0x180c0c14UL, 0xfb87877cUL, 0xb7a1a116UL, 0xa05050f0UL, +0x63cbcba8UL, 0xce6767a9UL, 0xa85454fcUL, 0x4fdddd92UL, +0x8c4646caUL, 0xeb8f8f64UL, 0x37e1e1d6UL, 0x9c4e4ed2UL, +0x15f0f0e5UL, 0x0ffdfdf2UL, 0x0dfcfcf1UL, 0x23ebebc8UL, +0x07f9f9feUL, 0x7dc4c4b9UL, 0x341a1a2eUL, 0xdc6e6eb2UL, +0xbc5e5ee2UL, 0x1ff5f5eaUL, 0x6dcccca1UL, 0xef8d8d62UL, +0x381c1c24UL, 0xac5656faUL, 0x864343c5UL, 0x09fefef7UL, +0x0e070709UL, 0xc26161a3UL, 0x05f8f8fdUL, 0xea75759fUL, +0xb25959ebUL, 0x0bfffff4UL, 0x06030305UL, 0x44222266UL, +0xe18a8a6bUL, 0x57d1d186UL, 0x26131335UL, 0x29eeeec7UL, +0xe588886dUL, 0x00000000UL, 0x1c0e0e12UL, 0x6834345cUL, +0x2a15153fUL, 0xf5808075UL, 0xdd949449UL, 0x33e3e3d0UL, +0x2fededc2UL, 0x9fb5b52aUL, 0xa65353f5UL, 0x46232365UL, +0x964b4bddUL, 0x8e4747c9UL, 0x2e171739UL, 0xbba7a71cUL, +0xd5909045UL, 0x6a35355fUL, 0xa3abab08UL, 0x45d8d89dUL, +0x85b8b83dUL, 0x4bdfdf94UL, 0x9e4f4fd1UL, 0xae5757f9UL, +0xc19a9a5bUL, 0xd1929243UL, 0x43dbdb98UL, 0x361b1b2dUL, +0x783c3c44UL, 0x65c8c8adUL, 0xc799995eUL, 0x0804040cUL, +0xe98e8e67UL, 0x35e0e0d5UL, 0x5bd7d78cUL, 0xfa7d7d87UL, +0xff85857aUL, 0x83bbbb38UL, 0x804040c0UL, 0x582c2c74UL, +0x743a3a4eUL, 0x8a4545cfUL, 0x17f1f1e6UL, 0x844242c6UL, +0xca6565afUL, 0x40202060UL, 0x824141c3UL, 0x30181828UL, +0xe4727296UL, 0x4a25256fUL, 0xd3939340UL, 0xe0707090UL, +0x6c36365aUL, 0x0a05050fUL, 0x11f2f2e3UL, 0x160b0b1dUL, +0xb3a3a310UL, 0xf279798bUL, 0x2dececc1UL, 0x10080818UL, +0x4e272769UL, 0x62313153UL, 0x64323256UL, 0x99b6b62fUL, +0xf87c7c84UL, 0x95b0b025UL, 0x140a0a1eUL, 0xe6737395UL, +0xb65b5bedUL, 0xf67b7b8dUL, 0x9bb7b72cUL, 0xf7818176UL, +0x51d2d283UL, 0x1a0d0d17UL, 0xd46a6abeUL, 0x4c26266aUL, +0xc99e9e57UL, 0xb05858e8UL, 0xcd9c9c51UL, 0xf3838370UL, +0xe874749cUL, 0x93b3b320UL, 0xadacac01UL, 0x60303050UL, +0xf47a7a8eUL, 0xd26969bbUL, 0xee777799UL, 0x1e0f0f11UL, +0xa9aeae07UL, 0x42212163UL, 0x49dede97UL, 0x55d0d085UL, +0x5c2e2e72UL, 0xdb97974cUL, 0x20101030UL, 0xbda4a419UL, +0xc598985dUL, 0xa5a8a80dUL, 0x5dd4d489UL, 0xd06868b8UL, +0x5a2d2d77UL, 0xc46262a6UL, 0x5229297bUL, 0xda6d6db7UL, +0x2c16163aUL, 0x924949dbUL, 0xec76769aUL, 0x7bc7c7bcUL, +0x25e8e8cdUL, 0x77c1c1b6UL, 0xd996964fUL, 0x6e373759UL, +0x3fe5e5daUL, 0x61cacaabUL, 0x1df4f4e9UL, 0x27e9e9ceUL, +0xc66363a5UL, 0x24121236UL, 0x71c2c2b3UL, 0xb9a6a61fUL, +0x2814143cUL, 0x8dbcbc31UL, 0x53d3d380UL, 0x50282878UL, +0xabafaf04UL, 0x5e2f2f71UL, 0x39e6e6dfUL, 0x4824246cUL, +0xa45252f6UL, 0x79c6c6bfUL, 0xb5a0a015UL, 0x1209091bUL, +0x8fbdbd32UL, 0xed8c8c61UL, 0x6bcfcfa4UL, 0xba5d5de7UL, +0x22111133UL, 0xbe5f5fe1UL, 0x02010103UL, 0x7fc5c5baUL, +0xcb9f9f54UL, 0x7a3d3d47UL, 0xb1a2a213UL, 0xc39b9b58UL, +0x67c9c9aeUL, 0x763b3b4dUL, 0x89bebe37UL, 0xa25151f3UL, +0x3219192bUL, 0x3e1f1f21UL, 0x7e3f3f41UL, 0xb85c5ce4UL, +0x91b2b223UL, 0x2befefc4UL, 0x944a4adeUL, 0x6fcdcda2UL, +0x8bbfbf34UL, 0x81baba3bUL, 0xde6f6fb1UL, 0xc86464acUL, +0x47d9d99eUL, 0x13f3f3e0UL, 0x7c3e3e42UL, 0x9db4b429UL, +0xa1aaaa0bUL, 0x4ddcdc91UL, 0x5fd5d58aUL, 0x0c06060aUL, +0x75c0c0b5UL, 0xfc7e7e82UL, 0x19f6f6efUL, 0xcc6666aaUL, +0xd86c6cb4UL, 0xfd848479UL, 0xe2717193UL, 0x70383848UL, +0x87b9b93eUL, 0x3a1d1d27UL, 0xfe7f7f81UL, 0xcf9d9d52UL, +0x904848d8UL, 0xe38b8b68UL, 0x542a2a7eUL, 0x41dada9bUL, +0xbfa5a51aUL, 0x66333355UL, 0xf1828273UL, 0x7239394bUL, +0x59d6d68fUL, 0xf0787888UL, 0xf986867fUL, 0x01fafafbUL, +0x3de4e4d9UL, 0x562b2b7dUL, 0xa7a9a90eUL, 0x3c1e1e22UL, +0xe789896eUL, 0xc06060a0UL, 0xd66b6bbdUL, 0x21eaeacbUL, +0xaa5555ffUL, 0x984c4cd4UL, 0x1bf7f7ecUL, 0x31e2e2d3UL, +}, + +{ +0x2697b1b1UL, 0xa769ceceUL, 0xb073c3c3UL, 0x4adf9595UL, +0xeeb45a5aUL, 0x02afadadUL, 0xdc3be7e7UL, 0x06040202UL, +0xd79a4d4dUL, 0xcc884444UL, 0xf803fbfbUL, 0x46d79191UL, +0x14180c0cUL, 0x7cfb8787UL, 0x16b7a1a1UL, 0xf0a05050UL, +0xa863cbcbUL, 0xa9ce6767UL, 0xfca85454UL, 0x924fddddUL, +0xca8c4646UL, 0x64eb8f8fUL, 0xd637e1e1UL, 0xd29c4e4eUL, +0xe515f0f0UL, 0xf20ffdfdUL, 0xf10dfcfcUL, 0xc823ebebUL, +0xfe07f9f9UL, 0xb97dc4c4UL, 0x2e341a1aUL, 0xb2dc6e6eUL, +0xe2bc5e5eUL, 0xea1ff5f5UL, 0xa16dccccUL, 0x62ef8d8dUL, +0x24381c1cUL, 0xfaac5656UL, 0xc5864343UL, 0xf709fefeUL, +0x090e0707UL, 0xa3c26161UL, 0xfd05f8f8UL, 0x9fea7575UL, +0xebb25959UL, 0xf40bffffUL, 0x05060303UL, 0x66442222UL, +0x6be18a8aUL, 0x8657d1d1UL, 0x35261313UL, 0xc729eeeeUL, +0x6de58888UL, 0x00000000UL, 0x121c0e0eUL, 0x5c683434UL, +0x3f2a1515UL, 0x75f58080UL, 0x49dd9494UL, 0xd033e3e3UL, +0xc22fededUL, 0x2a9fb5b5UL, 0xf5a65353UL, 0x65462323UL, +0xdd964b4bUL, 0xc98e4747UL, 0x392e1717UL, 0x1cbba7a7UL, +0x45d59090UL, 0x5f6a3535UL, 0x08a3ababUL, 0x9d45d8d8UL, +0x3d85b8b8UL, 0x944bdfdfUL, 0xd19e4f4fUL, 0xf9ae5757UL, +0x5bc19a9aUL, 0x43d19292UL, 0x9843dbdbUL, 0x2d361b1bUL, +0x44783c3cUL, 0xad65c8c8UL, 0x5ec79999UL, 0x0c080404UL, +0x67e98e8eUL, 0xd535e0e0UL, 0x8c5bd7d7UL, 0x87fa7d7dUL, +0x7aff8585UL, 0x3883bbbbUL, 0xc0804040UL, 0x74582c2cUL, +0x4e743a3aUL, 0xcf8a4545UL, 0xe617f1f1UL, 0xc6844242UL, +0xafca6565UL, 0x60402020UL, 0xc3824141UL, 0x28301818UL, +0x96e47272UL, 0x6f4a2525UL, 0x40d39393UL, 0x90e07070UL, +0x5a6c3636UL, 0x0f0a0505UL, 0xe311f2f2UL, 0x1d160b0bUL, +0x10b3a3a3UL, 0x8bf27979UL, 0xc12dececUL, 0x18100808UL, +0x694e2727UL, 0x53623131UL, 0x56643232UL, 0x2f99b6b6UL, +0x84f87c7cUL, 0x2595b0b0UL, 0x1e140a0aUL, 0x95e67373UL, +0xedb65b5bUL, 0x8df67b7bUL, 0x2c9bb7b7UL, 0x76f78181UL, +0x8351d2d2UL, 0x171a0d0dUL, 0xbed46a6aUL, 0x6a4c2626UL, +0x57c99e9eUL, 0xe8b05858UL, 0x51cd9c9cUL, 0x70f38383UL, +0x9ce87474UL, 0x2093b3b3UL, 0x01adacacUL, 0x50603030UL, +0x8ef47a7aUL, 0xbbd26969UL, 0x99ee7777UL, 0x111e0f0fUL, +0x07a9aeaeUL, 0x63422121UL, 0x9749dedeUL, 0x8555d0d0UL, +0x725c2e2eUL, 0x4cdb9797UL, 0x30201010UL, 0x19bda4a4UL, +0x5dc59898UL, 0x0da5a8a8UL, 0x895dd4d4UL, 0xb8d06868UL, +0x775a2d2dUL, 0xa6c46262UL, 0x7b522929UL, 0xb7da6d6dUL, +0x3a2c1616UL, 0xdb924949UL, 0x9aec7676UL, 0xbc7bc7c7UL, +0xcd25e8e8UL, 0xb677c1c1UL, 0x4fd99696UL, 0x596e3737UL, +0xda3fe5e5UL, 0xab61cacaUL, 0xe91df4f4UL, 0xce27e9e9UL, +0xa5c66363UL, 0x36241212UL, 0xb371c2c2UL, 0x1fb9a6a6UL, +0x3c281414UL, 0x318dbcbcUL, 0x8053d3d3UL, 0x78502828UL, +0x04abafafUL, 0x715e2f2fUL, 0xdf39e6e6UL, 0x6c482424UL, +0xf6a45252UL, 0xbf79c6c6UL, 0x15b5a0a0UL, 0x1b120909UL, +0x328fbdbdUL, 0x61ed8c8cUL, 0xa46bcfcfUL, 0xe7ba5d5dUL, +0x33221111UL, 0xe1be5f5fUL, 0x03020101UL, 0xba7fc5c5UL, +0x54cb9f9fUL, 0x477a3d3dUL, 0x13b1a2a2UL, 0x58c39b9bUL, +0xae67c9c9UL, 0x4d763b3bUL, 0x3789bebeUL, 0xf3a25151UL, +0x2b321919UL, 0x213e1f1fUL, 0x417e3f3fUL, 0xe4b85c5cUL, +0x2391b2b2UL, 0xc42befefUL, 0xde944a4aUL, 0xa26fcdcdUL, +0x348bbfbfUL, 0x3b81babaUL, 0xb1de6f6fUL, 0xacc86464UL, +0x9e47d9d9UL, 0xe013f3f3UL, 0x427c3e3eUL, 0x299db4b4UL, +0x0ba1aaaaUL, 0x914ddcdcUL, 0x8a5fd5d5UL, 0x0a0c0606UL, +0xb575c0c0UL, 0x82fc7e7eUL, 0xef19f6f6UL, 0xaacc6666UL, +0xb4d86c6cUL, 0x79fd8484UL, 0x93e27171UL, 0x48703838UL, +0x3e87b9b9UL, 0x273a1d1dUL, 0x81fe7f7fUL, 0x52cf9d9dUL, +0xd8904848UL, 0x68e38b8bUL, 0x7e542a2aUL, 0x9b41dadaUL, +0x1abfa5a5UL, 0x55663333UL, 0x73f18282UL, 0x4b723939UL, +0x8f59d6d6UL, 0x88f07878UL, 0x7ff98686UL, 0xfb01fafaUL, +0xd93de4e4UL, 0x7d562b2bUL, 0x0ea7a9a9UL, 0x223c1e1eUL, +0x6ee78989UL, 0xa0c06060UL, 0xbdd66b6bUL, 0xcb21eaeaUL, +0xffaa5555UL, 0xd4984c4cUL, 0xec1bf7f7UL, 0xd331e2e2UL, +}, + +{ +0xb12697b1UL, 0xcea769ceUL, 0xc3b073c3UL, 0x954adf95UL, +0x5aeeb45aUL, 0xad02afadUL, 0xe7dc3be7UL, 0x02060402UL, +0x4dd79a4dUL, 0x44cc8844UL, 0xfbf803fbUL, 0x9146d791UL, +0x0c14180cUL, 0x877cfb87UL, 0xa116b7a1UL, 0x50f0a050UL, +0xcba863cbUL, 0x67a9ce67UL, 0x54fca854UL, 0xdd924fddUL, +0x46ca8c46UL, 0x8f64eb8fUL, 0xe1d637e1UL, 0x4ed29c4eUL, +0xf0e515f0UL, 0xfdf20ffdUL, 0xfcf10dfcUL, 0xebc823ebUL, +0xf9fe07f9UL, 0xc4b97dc4UL, 0x1a2e341aUL, 0x6eb2dc6eUL, +0x5ee2bc5eUL, 0xf5ea1ff5UL, 0xcca16dccUL, 0x8d62ef8dUL, +0x1c24381cUL, 0x56faac56UL, 0x43c58643UL, 0xfef709feUL, +0x07090e07UL, 0x61a3c261UL, 0xf8fd05f8UL, 0x759fea75UL, +0x59ebb259UL, 0xfff40bffUL, 0x03050603UL, 0x22664422UL, +0x8a6be18aUL, 0xd18657d1UL, 0x13352613UL, 0xeec729eeUL, +0x886de588UL, 0x00000000UL, 0x0e121c0eUL, 0x345c6834UL, +0x153f2a15UL, 0x8075f580UL, 0x9449dd94UL, 0xe3d033e3UL, +0xedc22fedUL, 0xb52a9fb5UL, 0x53f5a653UL, 0x23654623UL, +0x4bdd964bUL, 0x47c98e47UL, 0x17392e17UL, 0xa71cbba7UL, +0x9045d590UL, 0x355f6a35UL, 0xab08a3abUL, 0xd89d45d8UL, +0xb83d85b8UL, 0xdf944bdfUL, 0x4fd19e4fUL, 0x57f9ae57UL, +0x9a5bc19aUL, 0x9243d192UL, 0xdb9843dbUL, 0x1b2d361bUL, +0x3c44783cUL, 0xc8ad65c8UL, 0x995ec799UL, 0x040c0804UL, +0x8e67e98eUL, 0xe0d535e0UL, 0xd78c5bd7UL, 0x7d87fa7dUL, +0x857aff85UL, 0xbb3883bbUL, 0x40c08040UL, 0x2c74582cUL, +0x3a4e743aUL, 0x45cf8a45UL, 0xf1e617f1UL, 0x42c68442UL, +0x65afca65UL, 0x20604020UL, 0x41c38241UL, 0x18283018UL, +0x7296e472UL, 0x256f4a25UL, 0x9340d393UL, 0x7090e070UL, +0x365a6c36UL, 0x050f0a05UL, 0xf2e311f2UL, 0x0b1d160bUL, +0xa310b3a3UL, 0x798bf279UL, 0xecc12decUL, 0x08181008UL, +0x27694e27UL, 0x31536231UL, 0x32566432UL, 0xb62f99b6UL, +0x7c84f87cUL, 0xb02595b0UL, 0x0a1e140aUL, 0x7395e673UL, +0x5bedb65bUL, 0x7b8df67bUL, 0xb72c9bb7UL, 0x8176f781UL, +0xd28351d2UL, 0x0d171a0dUL, 0x6abed46aUL, 0x266a4c26UL, +0x9e57c99eUL, 0x58e8b058UL, 0x9c51cd9cUL, 0x8370f383UL, +0x749ce874UL, 0xb32093b3UL, 0xac01adacUL, 0x30506030UL, +0x7a8ef47aUL, 0x69bbd269UL, 0x7799ee77UL, 0x0f111e0fUL, +0xae07a9aeUL, 0x21634221UL, 0xde9749deUL, 0xd08555d0UL, +0x2e725c2eUL, 0x974cdb97UL, 0x10302010UL, 0xa419bda4UL, +0x985dc598UL, 0xa80da5a8UL, 0xd4895dd4UL, 0x68b8d068UL, +0x2d775a2dUL, 0x62a6c462UL, 0x297b5229UL, 0x6db7da6dUL, +0x163a2c16UL, 0x49db9249UL, 0x769aec76UL, 0xc7bc7bc7UL, +0xe8cd25e8UL, 0xc1b677c1UL, 0x964fd996UL, 0x37596e37UL, +0xe5da3fe5UL, 0xcaab61caUL, 0xf4e91df4UL, 0xe9ce27e9UL, +0x63a5c663UL, 0x12362412UL, 0xc2b371c2UL, 0xa61fb9a6UL, +0x143c2814UL, 0xbc318dbcUL, 0xd38053d3UL, 0x28785028UL, +0xaf04abafUL, 0x2f715e2fUL, 0xe6df39e6UL, 0x246c4824UL, +0x52f6a452UL, 0xc6bf79c6UL, 0xa015b5a0UL, 0x091b1209UL, +0xbd328fbdUL, 0x8c61ed8cUL, 0xcfa46bcfUL, 0x5de7ba5dUL, +0x11332211UL, 0x5fe1be5fUL, 0x01030201UL, 0xc5ba7fc5UL, +0x9f54cb9fUL, 0x3d477a3dUL, 0xa213b1a2UL, 0x9b58c39bUL, +0xc9ae67c9UL, 0x3b4d763bUL, 0xbe3789beUL, 0x51f3a251UL, +0x192b3219UL, 0x1f213e1fUL, 0x3f417e3fUL, 0x5ce4b85cUL, +0xb22391b2UL, 0xefc42befUL, 0x4ade944aUL, 0xcda26fcdUL, +0xbf348bbfUL, 0xba3b81baUL, 0x6fb1de6fUL, 0x64acc864UL, +0xd99e47d9UL, 0xf3e013f3UL, 0x3e427c3eUL, 0xb4299db4UL, +0xaa0ba1aaUL, 0xdc914ddcUL, 0xd58a5fd5UL, 0x060a0c06UL, +0xc0b575c0UL, 0x7e82fc7eUL, 0xf6ef19f6UL, 0x66aacc66UL, +0x6cb4d86cUL, 0x8479fd84UL, 0x7193e271UL, 0x38487038UL, +0xb93e87b9UL, 0x1d273a1dUL, 0x7f81fe7fUL, 0x9d52cf9dUL, +0x48d89048UL, 0x8b68e38bUL, 0x2a7e542aUL, 0xda9b41daUL, +0xa51abfa5UL, 0x33556633UL, 0x8273f182UL, 0x394b7239UL, +0xd68f59d6UL, 0x7888f078UL, 0x867ff986UL, 0xfafb01faUL, +0xe4d93de4UL, 0x2b7d562bUL, 0xa90ea7a9UL, 0x1e223c1eUL, +0x896ee789UL, 0x60a0c060UL, 0x6bbdd66bUL, 0xeacb21eaUL, +0x55ffaa55UL, 0x4cd4984cUL, 0xf7ec1bf7UL, 0xe2d331e2UL, +}, + +{ +0xb1b12697UL, 0xcecea769UL, 0xc3c3b073UL, 0x95954adfUL, +0x5a5aeeb4UL, 0xadad02afUL, 0xe7e7dc3bUL, 0x02020604UL, +0x4d4dd79aUL, 0x4444cc88UL, 0xfbfbf803UL, 0x919146d7UL, +0x0c0c1418UL, 0x87877cfbUL, 0xa1a116b7UL, 0x5050f0a0UL, +0xcbcba863UL, 0x6767a9ceUL, 0x5454fca8UL, 0xdddd924fUL, +0x4646ca8cUL, 0x8f8f64ebUL, 0xe1e1d637UL, 0x4e4ed29cUL, +0xf0f0e515UL, 0xfdfdf20fUL, 0xfcfcf10dUL, 0xebebc823UL, +0xf9f9fe07UL, 0xc4c4b97dUL, 0x1a1a2e34UL, 0x6e6eb2dcUL, +0x5e5ee2bcUL, 0xf5f5ea1fUL, 0xcccca16dUL, 0x8d8d62efUL, +0x1c1c2438UL, 0x5656faacUL, 0x4343c586UL, 0xfefef709UL, +0x0707090eUL, 0x6161a3c2UL, 0xf8f8fd05UL, 0x75759feaUL, +0x5959ebb2UL, 0xfffff40bUL, 0x03030506UL, 0x22226644UL, +0x8a8a6be1UL, 0xd1d18657UL, 0x13133526UL, 0xeeeec729UL, +0x88886de5UL, 0x00000000UL, 0x0e0e121cUL, 0x34345c68UL, +0x15153f2aUL, 0x808075f5UL, 0x949449ddUL, 0xe3e3d033UL, +0xededc22fUL, 0xb5b52a9fUL, 0x5353f5a6UL, 0x23236546UL, +0x4b4bdd96UL, 0x4747c98eUL, 0x1717392eUL, 0xa7a71cbbUL, +0x909045d5UL, 0x35355f6aUL, 0xabab08a3UL, 0xd8d89d45UL, +0xb8b83d85UL, 0xdfdf944bUL, 0x4f4fd19eUL, 0x5757f9aeUL, +0x9a9a5bc1UL, 0x929243d1UL, 0xdbdb9843UL, 0x1b1b2d36UL, +0x3c3c4478UL, 0xc8c8ad65UL, 0x99995ec7UL, 0x04040c08UL, +0x8e8e67e9UL, 0xe0e0d535UL, 0xd7d78c5bUL, 0x7d7d87faUL, +0x85857affUL, 0xbbbb3883UL, 0x4040c080UL, 0x2c2c7458UL, +0x3a3a4e74UL, 0x4545cf8aUL, 0xf1f1e617UL, 0x4242c684UL, +0x6565afcaUL, 0x20206040UL, 0x4141c382UL, 0x18182830UL, +0x727296e4UL, 0x25256f4aUL, 0x939340d3UL, 0x707090e0UL, +0x36365a6cUL, 0x05050f0aUL, 0xf2f2e311UL, 0x0b0b1d16UL, +0xa3a310b3UL, 0x79798bf2UL, 0xececc12dUL, 0x08081810UL, +0x2727694eUL, 0x31315362UL, 0x32325664UL, 0xb6b62f99UL, +0x7c7c84f8UL, 0xb0b02595UL, 0x0a0a1e14UL, 0x737395e6UL, +0x5b5bedb6UL, 0x7b7b8df6UL, 0xb7b72c9bUL, 0x818176f7UL, +0xd2d28351UL, 0x0d0d171aUL, 0x6a6abed4UL, 0x26266a4cUL, +0x9e9e57c9UL, 0x5858e8b0UL, 0x9c9c51cdUL, 0x838370f3UL, +0x74749ce8UL, 0xb3b32093UL, 0xacac01adUL, 0x30305060UL, +0x7a7a8ef4UL, 0x6969bbd2UL, 0x777799eeUL, 0x0f0f111eUL, +0xaeae07a9UL, 0x21216342UL, 0xdede9749UL, 0xd0d08555UL, +0x2e2e725cUL, 0x97974cdbUL, 0x10103020UL, 0xa4a419bdUL, +0x98985dc5UL, 0xa8a80da5UL, 0xd4d4895dUL, 0x6868b8d0UL, +0x2d2d775aUL, 0x6262a6c4UL, 0x29297b52UL, 0x6d6db7daUL, +0x16163a2cUL, 0x4949db92UL, 0x76769aecUL, 0xc7c7bc7bUL, +0xe8e8cd25UL, 0xc1c1b677UL, 0x96964fd9UL, 0x3737596eUL, +0xe5e5da3fUL, 0xcacaab61UL, 0xf4f4e91dUL, 0xe9e9ce27UL, +0x6363a5c6UL, 0x12123624UL, 0xc2c2b371UL, 0xa6a61fb9UL, +0x14143c28UL, 0xbcbc318dUL, 0xd3d38053UL, 0x28287850UL, +0xafaf04abUL, 0x2f2f715eUL, 0xe6e6df39UL, 0x24246c48UL, +0x5252f6a4UL, 0xc6c6bf79UL, 0xa0a015b5UL, 0x09091b12UL, +0xbdbd328fUL, 0x8c8c61edUL, 0xcfcfa46bUL, 0x5d5de7baUL, +0x11113322UL, 0x5f5fe1beUL, 0x01010302UL, 0xc5c5ba7fUL, +0x9f9f54cbUL, 0x3d3d477aUL, 0xa2a213b1UL, 0x9b9b58c3UL, +0xc9c9ae67UL, 0x3b3b4d76UL, 0xbebe3789UL, 0x5151f3a2UL, +0x19192b32UL, 0x1f1f213eUL, 0x3f3f417eUL, 0x5c5ce4b8UL, +0xb2b22391UL, 0xefefc42bUL, 0x4a4ade94UL, 0xcdcda26fUL, +0xbfbf348bUL, 0xbaba3b81UL, 0x6f6fb1deUL, 0x6464acc8UL, +0xd9d99e47UL, 0xf3f3e013UL, 0x3e3e427cUL, 0xb4b4299dUL, +0xaaaa0ba1UL, 0xdcdc914dUL, 0xd5d58a5fUL, 0x06060a0cUL, +0xc0c0b575UL, 0x7e7e82fcUL, 0xf6f6ef19UL, 0x6666aaccUL, +0x6c6cb4d8UL, 0x848479fdUL, 0x717193e2UL, 0x38384870UL, +0xb9b93e87UL, 0x1d1d273aUL, 0x7f7f81feUL, 0x9d9d52cfUL, +0x4848d890UL, 0x8b8b68e3UL, 0x2a2a7e54UL, 0xdada9b41UL, +0xa5a51abfUL, 0x33335566UL, 0x828273f1UL, 0x39394b72UL, +0xd6d68f59UL, 0x787888f0UL, 0x86867ff9UL, 0xfafafb01UL, +0xe4e4d93dUL, 0x2b2b7d56UL, 0xa9a90ea7UL, 0x1e1e223cUL, +0x89896ee7UL, 0x6060a0c0UL, 0x6b6bbdd6UL, 0xeaeacb21UL, +0x5555ffaaUL, 0x4c4cd498UL, 0xf7f7ec1bUL, 0xe2e2d331UL, +}}; + +const word32 Square::Dec::Td[4][256] = { +{ +0xe368bc02UL, 0x5585620cUL, 0x2a3f2331UL, 0x61ab13f7UL, +0x98d46d72UL, 0x21cb9a19UL, 0x3c22a461UL, 0x459d3dcdUL, +0x05fdb423UL, 0x2bc4075fUL, 0x9b2c01c0UL, 0x3dd9800fUL, +0x486c5c74UL, 0xf97f7e85UL, 0xf173ab1fUL, 0xb6edde0eUL, +0x283c6bedUL, 0x4997781aUL, 0x9f2a918dUL, 0xc9579f33UL, +0xa907a8aaUL, 0xa50ded7dUL, 0x7c422d8fUL, 0x764db0c9UL, +0x4d91e857UL, 0xcea963ccUL, 0xb4ee96d2UL, 0x3028e1b6UL, +0x0df161b9UL, 0xbd196726UL, 0x419bad80UL, 0xc0a06ec7UL, +0x5183f241UL, 0x92dbf034UL, 0x6fa21efcUL, 0x8f32ce4cUL, +0x13e03373UL, 0x69a7c66dUL, 0xe56d6493UL, 0xbf1a2ffaUL, +0xbb1cbfb7UL, 0x587403b5UL, 0xe76e2c4fUL, 0x5d89b796UL, +0xe89c052aUL, 0x446619a3UL, 0x342e71fbUL, 0x0ff22965UL, +0xfe81827aUL, 0xb11322f1UL, 0xa30835ecUL, 0xcd510f7eUL, +0xff7aa614UL, 0x5c7293f8UL, 0x2fc29712UL, 0xf370e3c3UL, +0x992f491cUL, 0xd1431568UL, 0xc2a3261bUL, 0x88cc32b3UL, +0x8acf7a6fUL, 0xb0e8069fUL, 0x7a47f51eUL, 0xd2bb79daUL, +0xe6950821UL, 0x4398e55cUL, 0xd0b83106UL, 0x11e37bafUL, +0x7e416553UL, 0xccaa2b10UL, 0xd8b4e49cUL, 0x6456a7d4UL, +0xfb7c3659UL, 0x724b2084UL, 0xea9f4df6UL, 0x6a5faadfUL, +0x2dc1dfceUL, 0x70486858UL, 0xcaaff381UL, 0x0605d891UL, +0x5a774b69UL, 0x94de28a5UL, 0x39df1042UL, 0x813bc347UL, +0xfc82caa6UL, 0x23c8d2c5UL, 0x03f86cb2UL, 0x080cd59aUL, +0xdab7ac40UL, 0x7db909e1UL, 0x3824342cUL, 0xcf5247a2UL, +0xdcb274d1UL, 0x63a85b2bUL, 0x35d55595UL, 0x479e7511UL, +0x15e5ebe2UL, 0x4b9430c6UL, 0x4a6f14a8UL, 0x91239c86UL, +0x4c6acc39UL, 0x5f8aff4aUL, 0x0406904dUL, 0xee99ddbbUL, +0x1e1152caUL, 0xaaffc418UL, 0xeb646998UL, 0x07fefcffUL, +0x8b345e01UL, 0x567d0ebeUL, 0xbae79bd9UL, 0x4263c132UL, +0x75b5dc7bUL, 0x97264417UL, 0x67aecb66UL, 0x95250ccbUL, +0xec9a9567UL, 0x57862ad0UL, 0x60503799UL, 0xb8e4d305UL, +0x65ad83baUL, 0x19efae35UL, 0xa4f6c913UL, 0xc15b4aa9UL, +0x873e1bd6UL, 0xa0f0595eUL, 0x18148a5bUL, 0xaf02703bUL, +0xab04e076UL, 0xdd4950bfUL, 0xdf4a1863UL, 0xc6a5b656UL, +0x853d530aUL, 0xfa871237UL, 0x77b694a7UL, 0x4665517fUL, +0xed61b109UL, 0x1bece6e9UL, 0xd5458525UL, 0xf5753b52UL, +0x7fba413dUL, 0x27ce4288UL, 0xb2eb4e43UL, 0xd6bde997UL, +0x527b9ef3UL, 0x62537f45UL, 0x2c3afba0UL, 0x7bbcd170UL, +0xb91ff76bUL, 0x121b171dUL, 0xfd79eec8UL, 0x3a277cf0UL, +0x0c0a45d7UL, 0x96dd6079UL, 0x2233f6abUL, 0xacfa1c89UL, +0xc8acbb5dUL, 0xa10b7d30UL, 0xd4bea14bUL, 0xbee10b94UL, +0x25cd0a54UL, 0x547e4662UL, 0xa2f31182UL, 0x17e6a33eUL, +0x263566e6UL, 0xc3580275UL, 0x83388b9bUL, 0x7844bdc2UL, +0x020348dcUL, 0x4f92a08bUL, 0x2e39b37cUL, 0x4e6984e5UL, +0xf0888f71UL, 0x362d3927UL, 0x9cd2fd3fUL, 0x01fb246eUL, +0x893716ddUL, 0x00000000UL, 0xf68d57e0UL, 0xe293986cUL, +0x744ef815UL, 0x9320d45aUL, 0xad0138e7UL, 0xd3405db4UL, +0x1a17c287UL, 0xb3106a2dUL, 0x5078d62fUL, 0xf48e1f3cUL, +0xa70ea5a1UL, 0x71b34c36UL, 0x9ad725aeUL, 0x5e71db24UL, +0x161d8750UL, 0xef62f9d5UL, 0x8d318690UL, 0x1c121a16UL, +0xa6f581cfUL, 0x5b8c6f07UL, 0x37d61d49UL, 0x6e593a92UL, +0x84c67764UL, 0x86c53fb8UL, 0xd746cdf9UL, 0xe090d0b0UL, +0x29c74f83UL, 0xe49640fdUL, 0x0e090d0bUL, 0x6da15620UL, +0x8ec9ea22UL, 0xdb4c882eUL, 0xf776738eUL, 0xb515b2bcUL, +0x10185fc1UL, 0x322ba96aUL, 0x6ba48eb1UL, 0xaef95455UL, +0x406089eeUL, 0x6655ef08UL, 0xe9672144UL, 0x3e21ecbdUL, +0x2030be77UL, 0xf28bc7adUL, 0x80c0e729UL, 0x141ecf8cUL, +0xbce24348UL, 0xc4a6fe8aUL, 0x31d3c5d8UL, 0xb716fa60UL, +0x5380ba9dUL, 0xd94fc0f2UL, 0x1de93e78UL, 0x24362e3aUL, +0xe16bf4deUL, 0xcb54d7efUL, 0x09f7f1f4UL, 0x82c3aff5UL, +0x0bf4b928UL, 0x9d29d951UL, 0xc75e9238UL, 0xf8845aebUL, +0x90d8b8e8UL, 0xdeb13c0dUL, 0x33d08d04UL, 0x685ce203UL, +0xc55ddae4UL, 0x3bdc589eUL, 0x0a0f9d46UL, 0x3fdac8d3UL, +0x598f27dbUL, 0xa8fc8cc4UL, 0x79bf99acUL, 0x6c5a724eUL, +0x8ccaa2feUL, 0x9ed1b5e3UL, 0x1fea76a4UL, 0x73b004eaUL, +}, + +{ +0x02e368bcUL, 0x0c558562UL, 0x312a3f23UL, 0xf761ab13UL, +0x7298d46dUL, 0x1921cb9aUL, 0x613c22a4UL, 0xcd459d3dUL, +0x2305fdb4UL, 0x5f2bc407UL, 0xc09b2c01UL, 0x0f3dd980UL, +0x74486c5cUL, 0x85f97f7eUL, 0x1ff173abUL, 0x0eb6eddeUL, +0xed283c6bUL, 0x1a499778UL, 0x8d9f2a91UL, 0x33c9579fUL, +0xaaa907a8UL, 0x7da50dedUL, 0x8f7c422dUL, 0xc9764db0UL, +0x574d91e8UL, 0xcccea963UL, 0xd2b4ee96UL, 0xb63028e1UL, +0xb90df161UL, 0x26bd1967UL, 0x80419badUL, 0xc7c0a06eUL, +0x415183f2UL, 0x3492dbf0UL, 0xfc6fa21eUL, 0x4c8f32ceUL, +0x7313e033UL, 0x6d69a7c6UL, 0x93e56d64UL, 0xfabf1a2fUL, +0xb7bb1cbfUL, 0xb5587403UL, 0x4fe76e2cUL, 0x965d89b7UL, +0x2ae89c05UL, 0xa3446619UL, 0xfb342e71UL, 0x650ff229UL, +0x7afe8182UL, 0xf1b11322UL, 0xeca30835UL, 0x7ecd510fUL, +0x14ff7aa6UL, 0xf85c7293UL, 0x122fc297UL, 0xc3f370e3UL, +0x1c992f49UL, 0x68d14315UL, 0x1bc2a326UL, 0xb388cc32UL, +0x6f8acf7aUL, 0x9fb0e806UL, 0x1e7a47f5UL, 0xdad2bb79UL, +0x21e69508UL, 0x5c4398e5UL, 0x06d0b831UL, 0xaf11e37bUL, +0x537e4165UL, 0x10ccaa2bUL, 0x9cd8b4e4UL, 0xd46456a7UL, +0x59fb7c36UL, 0x84724b20UL, 0xf6ea9f4dUL, 0xdf6a5faaUL, +0xce2dc1dfUL, 0x58704868UL, 0x81caaff3UL, 0x910605d8UL, +0x695a774bUL, 0xa594de28UL, 0x4239df10UL, 0x47813bc3UL, +0xa6fc82caUL, 0xc523c8d2UL, 0xb203f86cUL, 0x9a080cd5UL, +0x40dab7acUL, 0xe17db909UL, 0x2c382434UL, 0xa2cf5247UL, +0xd1dcb274UL, 0x2b63a85bUL, 0x9535d555UL, 0x11479e75UL, +0xe215e5ebUL, 0xc64b9430UL, 0xa84a6f14UL, 0x8691239cUL, +0x394c6accUL, 0x4a5f8affUL, 0x4d040690UL, 0xbbee99ddUL, +0xca1e1152UL, 0x18aaffc4UL, 0x98eb6469UL, 0xff07fefcUL, +0x018b345eUL, 0xbe567d0eUL, 0xd9bae79bUL, 0x324263c1UL, +0x7b75b5dcUL, 0x17972644UL, 0x6667aecbUL, 0xcb95250cUL, +0x67ec9a95UL, 0xd057862aUL, 0x99605037UL, 0x05b8e4d3UL, +0xba65ad83UL, 0x3519efaeUL, 0x13a4f6c9UL, 0xa9c15b4aUL, +0xd6873e1bUL, 0x5ea0f059UL, 0x5b18148aUL, 0x3baf0270UL, +0x76ab04e0UL, 0xbfdd4950UL, 0x63df4a18UL, 0x56c6a5b6UL, +0x0a853d53UL, 0x37fa8712UL, 0xa777b694UL, 0x7f466551UL, +0x09ed61b1UL, 0xe91bece6UL, 0x25d54585UL, 0x52f5753bUL, +0x3d7fba41UL, 0x8827ce42UL, 0x43b2eb4eUL, 0x97d6bde9UL, +0xf3527b9eUL, 0x4562537fUL, 0xa02c3afbUL, 0x707bbcd1UL, +0x6bb91ff7UL, 0x1d121b17UL, 0xc8fd79eeUL, 0xf03a277cUL, +0xd70c0a45UL, 0x7996dd60UL, 0xab2233f6UL, 0x89acfa1cUL, +0x5dc8acbbUL, 0x30a10b7dUL, 0x4bd4bea1UL, 0x94bee10bUL, +0x5425cd0aUL, 0x62547e46UL, 0x82a2f311UL, 0x3e17e6a3UL, +0xe6263566UL, 0x75c35802UL, 0x9b83388bUL, 0xc27844bdUL, +0xdc020348UL, 0x8b4f92a0UL, 0x7c2e39b3UL, 0xe54e6984UL, +0x71f0888fUL, 0x27362d39UL, 0x3f9cd2fdUL, 0x6e01fb24UL, +0xdd893716UL, 0x00000000UL, 0xe0f68d57UL, 0x6ce29398UL, +0x15744ef8UL, 0x5a9320d4UL, 0xe7ad0138UL, 0xb4d3405dUL, +0x871a17c2UL, 0x2db3106aUL, 0x2f5078d6UL, 0x3cf48e1fUL, +0xa1a70ea5UL, 0x3671b34cUL, 0xae9ad725UL, 0x245e71dbUL, +0x50161d87UL, 0xd5ef62f9UL, 0x908d3186UL, 0x161c121aUL, +0xcfa6f581UL, 0x075b8c6fUL, 0x4937d61dUL, 0x926e593aUL, +0x6484c677UL, 0xb886c53fUL, 0xf9d746cdUL, 0xb0e090d0UL, +0x8329c74fUL, 0xfde49640UL, 0x0b0e090dUL, 0x206da156UL, +0x228ec9eaUL, 0x2edb4c88UL, 0x8ef77673UL, 0xbcb515b2UL, +0xc110185fUL, 0x6a322ba9UL, 0xb16ba48eUL, 0x55aef954UL, +0xee406089UL, 0x086655efUL, 0x44e96721UL, 0xbd3e21ecUL, +0x772030beUL, 0xadf28bc7UL, 0x2980c0e7UL, 0x8c141ecfUL, +0x48bce243UL, 0x8ac4a6feUL, 0xd831d3c5UL, 0x60b716faUL, +0x9d5380baUL, 0xf2d94fc0UL, 0x781de93eUL, 0x3a24362eUL, +0xdee16bf4UL, 0xefcb54d7UL, 0xf409f7f1UL, 0xf582c3afUL, +0x280bf4b9UL, 0x519d29d9UL, 0x38c75e92UL, 0xebf8845aUL, +0xe890d8b8UL, 0x0ddeb13cUL, 0x0433d08dUL, 0x03685ce2UL, +0xe4c55ddaUL, 0x9e3bdc58UL, 0x460a0f9dUL, 0xd33fdac8UL, +0xdb598f27UL, 0xc4a8fc8cUL, 0xac79bf99UL, 0x4e6c5a72UL, +0xfe8ccaa2UL, 0xe39ed1b5UL, 0xa41fea76UL, 0xea73b004UL, +}, + +{ +0xbc02e368UL, 0x620c5585UL, 0x23312a3fUL, 0x13f761abUL, +0x6d7298d4UL, 0x9a1921cbUL, 0xa4613c22UL, 0x3dcd459dUL, +0xb42305fdUL, 0x075f2bc4UL, 0x01c09b2cUL, 0x800f3dd9UL, +0x5c74486cUL, 0x7e85f97fUL, 0xab1ff173UL, 0xde0eb6edUL, +0x6bed283cUL, 0x781a4997UL, 0x918d9f2aUL, 0x9f33c957UL, +0xa8aaa907UL, 0xed7da50dUL, 0x2d8f7c42UL, 0xb0c9764dUL, +0xe8574d91UL, 0x63cccea9UL, 0x96d2b4eeUL, 0xe1b63028UL, +0x61b90df1UL, 0x6726bd19UL, 0xad80419bUL, 0x6ec7c0a0UL, +0xf2415183UL, 0xf03492dbUL, 0x1efc6fa2UL, 0xce4c8f32UL, +0x337313e0UL, 0xc66d69a7UL, 0x6493e56dUL, 0x2ffabf1aUL, +0xbfb7bb1cUL, 0x03b55874UL, 0x2c4fe76eUL, 0xb7965d89UL, +0x052ae89cUL, 0x19a34466UL, 0x71fb342eUL, 0x29650ff2UL, +0x827afe81UL, 0x22f1b113UL, 0x35eca308UL, 0x0f7ecd51UL, +0xa614ff7aUL, 0x93f85c72UL, 0x97122fc2UL, 0xe3c3f370UL, +0x491c992fUL, 0x1568d143UL, 0x261bc2a3UL, 0x32b388ccUL, +0x7a6f8acfUL, 0x069fb0e8UL, 0xf51e7a47UL, 0x79dad2bbUL, +0x0821e695UL, 0xe55c4398UL, 0x3106d0b8UL, 0x7baf11e3UL, +0x65537e41UL, 0x2b10ccaaUL, 0xe49cd8b4UL, 0xa7d46456UL, +0x3659fb7cUL, 0x2084724bUL, 0x4df6ea9fUL, 0xaadf6a5fUL, +0xdfce2dc1UL, 0x68587048UL, 0xf381caafUL, 0xd8910605UL, +0x4b695a77UL, 0x28a594deUL, 0x104239dfUL, 0xc347813bUL, +0xcaa6fc82UL, 0xd2c523c8UL, 0x6cb203f8UL, 0xd59a080cUL, +0xac40dab7UL, 0x09e17db9UL, 0x342c3824UL, 0x47a2cf52UL, +0x74d1dcb2UL, 0x5b2b63a8UL, 0x559535d5UL, 0x7511479eUL, +0xebe215e5UL, 0x30c64b94UL, 0x14a84a6fUL, 0x9c869123UL, +0xcc394c6aUL, 0xff4a5f8aUL, 0x904d0406UL, 0xddbbee99UL, +0x52ca1e11UL, 0xc418aaffUL, 0x6998eb64UL, 0xfcff07feUL, +0x5e018b34UL, 0x0ebe567dUL, 0x9bd9bae7UL, 0xc1324263UL, +0xdc7b75b5UL, 0x44179726UL, 0xcb6667aeUL, 0x0ccb9525UL, +0x9567ec9aUL, 0x2ad05786UL, 0x37996050UL, 0xd305b8e4UL, +0x83ba65adUL, 0xae3519efUL, 0xc913a4f6UL, 0x4aa9c15bUL, +0x1bd6873eUL, 0x595ea0f0UL, 0x8a5b1814UL, 0x703baf02UL, +0xe076ab04UL, 0x50bfdd49UL, 0x1863df4aUL, 0xb656c6a5UL, +0x530a853dUL, 0x1237fa87UL, 0x94a777b6UL, 0x517f4665UL, +0xb109ed61UL, 0xe6e91becUL, 0x8525d545UL, 0x3b52f575UL, +0x413d7fbaUL, 0x428827ceUL, 0x4e43b2ebUL, 0xe997d6bdUL, +0x9ef3527bUL, 0x7f456253UL, 0xfba02c3aUL, 0xd1707bbcUL, +0xf76bb91fUL, 0x171d121bUL, 0xeec8fd79UL, 0x7cf03a27UL, +0x45d70c0aUL, 0x607996ddUL, 0xf6ab2233UL, 0x1c89acfaUL, +0xbb5dc8acUL, 0x7d30a10bUL, 0xa14bd4beUL, 0x0b94bee1UL, +0x0a5425cdUL, 0x4662547eUL, 0x1182a2f3UL, 0xa33e17e6UL, +0x66e62635UL, 0x0275c358UL, 0x8b9b8338UL, 0xbdc27844UL, +0x48dc0203UL, 0xa08b4f92UL, 0xb37c2e39UL, 0x84e54e69UL, +0x8f71f088UL, 0x3927362dUL, 0xfd3f9cd2UL, 0x246e01fbUL, +0x16dd8937UL, 0x00000000UL, 0x57e0f68dUL, 0x986ce293UL, +0xf815744eUL, 0xd45a9320UL, 0x38e7ad01UL, 0x5db4d340UL, +0xc2871a17UL, 0x6a2db310UL, 0xd62f5078UL, 0x1f3cf48eUL, +0xa5a1a70eUL, 0x4c3671b3UL, 0x25ae9ad7UL, 0xdb245e71UL, +0x8750161dUL, 0xf9d5ef62UL, 0x86908d31UL, 0x1a161c12UL, +0x81cfa6f5UL, 0x6f075b8cUL, 0x1d4937d6UL, 0x3a926e59UL, +0x776484c6UL, 0x3fb886c5UL, 0xcdf9d746UL, 0xd0b0e090UL, +0x4f8329c7UL, 0x40fde496UL, 0x0d0b0e09UL, 0x56206da1UL, +0xea228ec9UL, 0x882edb4cUL, 0x738ef776UL, 0xb2bcb515UL, +0x5fc11018UL, 0xa96a322bUL, 0x8eb16ba4UL, 0x5455aef9UL, +0x89ee4060UL, 0xef086655UL, 0x2144e967UL, 0xecbd3e21UL, +0xbe772030UL, 0xc7adf28bUL, 0xe72980c0UL, 0xcf8c141eUL, +0x4348bce2UL, 0xfe8ac4a6UL, 0xc5d831d3UL, 0xfa60b716UL, +0xba9d5380UL, 0xc0f2d94fUL, 0x3e781de9UL, 0x2e3a2436UL, +0xf4dee16bUL, 0xd7efcb54UL, 0xf1f409f7UL, 0xaff582c3UL, +0xb9280bf4UL, 0xd9519d29UL, 0x9238c75eUL, 0x5aebf884UL, +0xb8e890d8UL, 0x3c0ddeb1UL, 0x8d0433d0UL, 0xe203685cUL, +0xdae4c55dUL, 0x589e3bdcUL, 0x9d460a0fUL, 0xc8d33fdaUL, +0x27db598fUL, 0x8cc4a8fcUL, 0x99ac79bfUL, 0x724e6c5aUL, +0xa2fe8ccaUL, 0xb5e39ed1UL, 0x76a41feaUL, 0x04ea73b0UL, +}, + +{ +0x68bc02e3UL, 0x85620c55UL, 0x3f23312aUL, 0xab13f761UL, +0xd46d7298UL, 0xcb9a1921UL, 0x22a4613cUL, 0x9d3dcd45UL, +0xfdb42305UL, 0xc4075f2bUL, 0x2c01c09bUL, 0xd9800f3dUL, +0x6c5c7448UL, 0x7f7e85f9UL, 0x73ab1ff1UL, 0xedde0eb6UL, +0x3c6bed28UL, 0x97781a49UL, 0x2a918d9fUL, 0x579f33c9UL, +0x07a8aaa9UL, 0x0ded7da5UL, 0x422d8f7cUL, 0x4db0c976UL, +0x91e8574dUL, 0xa963ccceUL, 0xee96d2b4UL, 0x28e1b630UL, +0xf161b90dUL, 0x196726bdUL, 0x9bad8041UL, 0xa06ec7c0UL, +0x83f24151UL, 0xdbf03492UL, 0xa21efc6fUL, 0x32ce4c8fUL, +0xe0337313UL, 0xa7c66d69UL, 0x6d6493e5UL, 0x1a2ffabfUL, +0x1cbfb7bbUL, 0x7403b558UL, 0x6e2c4fe7UL, 0x89b7965dUL, +0x9c052ae8UL, 0x6619a344UL, 0x2e71fb34UL, 0xf229650fUL, +0x81827afeUL, 0x1322f1b1UL, 0x0835eca3UL, 0x510f7ecdUL, +0x7aa614ffUL, 0x7293f85cUL, 0xc297122fUL, 0x70e3c3f3UL, +0x2f491c99UL, 0x431568d1UL, 0xa3261bc2UL, 0xcc32b388UL, +0xcf7a6f8aUL, 0xe8069fb0UL, 0x47f51e7aUL, 0xbb79dad2UL, +0x950821e6UL, 0x98e55c43UL, 0xb83106d0UL, 0xe37baf11UL, +0x4165537eUL, 0xaa2b10ccUL, 0xb4e49cd8UL, 0x56a7d464UL, +0x7c3659fbUL, 0x4b208472UL, 0x9f4df6eaUL, 0x5faadf6aUL, +0xc1dfce2dUL, 0x48685870UL, 0xaff381caUL, 0x05d89106UL, +0x774b695aUL, 0xde28a594UL, 0xdf104239UL, 0x3bc34781UL, +0x82caa6fcUL, 0xc8d2c523UL, 0xf86cb203UL, 0x0cd59a08UL, +0xb7ac40daUL, 0xb909e17dUL, 0x24342c38UL, 0x5247a2cfUL, +0xb274d1dcUL, 0xa85b2b63UL, 0xd5559535UL, 0x9e751147UL, +0xe5ebe215UL, 0x9430c64bUL, 0x6f14a84aUL, 0x239c8691UL, +0x6acc394cUL, 0x8aff4a5fUL, 0x06904d04UL, 0x99ddbbeeUL, +0x1152ca1eUL, 0xffc418aaUL, 0x646998ebUL, 0xfefcff07UL, +0x345e018bUL, 0x7d0ebe56UL, 0xe79bd9baUL, 0x63c13242UL, +0xb5dc7b75UL, 0x26441797UL, 0xaecb6667UL, 0x250ccb95UL, +0x9a9567ecUL, 0x862ad057UL, 0x50379960UL, 0xe4d305b8UL, +0xad83ba65UL, 0xefae3519UL, 0xf6c913a4UL, 0x5b4aa9c1UL, +0x3e1bd687UL, 0xf0595ea0UL, 0x148a5b18UL, 0x02703bafUL, +0x04e076abUL, 0x4950bfddUL, 0x4a1863dfUL, 0xa5b656c6UL, +0x3d530a85UL, 0x871237faUL, 0xb694a777UL, 0x65517f46UL, +0x61b109edUL, 0xece6e91bUL, 0x458525d5UL, 0x753b52f5UL, +0xba413d7fUL, 0xce428827UL, 0xeb4e43b2UL, 0xbde997d6UL, +0x7b9ef352UL, 0x537f4562UL, 0x3afba02cUL, 0xbcd1707bUL, +0x1ff76bb9UL, 0x1b171d12UL, 0x79eec8fdUL, 0x277cf03aUL, +0x0a45d70cUL, 0xdd607996UL, 0x33f6ab22UL, 0xfa1c89acUL, +0xacbb5dc8UL, 0x0b7d30a1UL, 0xbea14bd4UL, 0xe10b94beUL, +0xcd0a5425UL, 0x7e466254UL, 0xf31182a2UL, 0xe6a33e17UL, +0x3566e626UL, 0x580275c3UL, 0x388b9b83UL, 0x44bdc278UL, +0x0348dc02UL, 0x92a08b4fUL, 0x39b37c2eUL, 0x6984e54eUL, +0x888f71f0UL, 0x2d392736UL, 0xd2fd3f9cUL, 0xfb246e01UL, +0x3716dd89UL, 0x00000000UL, 0x8d57e0f6UL, 0x93986ce2UL, +0x4ef81574UL, 0x20d45a93UL, 0x0138e7adUL, 0x405db4d3UL, +0x17c2871aUL, 0x106a2db3UL, 0x78d62f50UL, 0x8e1f3cf4UL, +0x0ea5a1a7UL, 0xb34c3671UL, 0xd725ae9aUL, 0x71db245eUL, +0x1d875016UL, 0x62f9d5efUL, 0x3186908dUL, 0x121a161cUL, +0xf581cfa6UL, 0x8c6f075bUL, 0xd61d4937UL, 0x593a926eUL, +0xc6776484UL, 0xc53fb886UL, 0x46cdf9d7UL, 0x90d0b0e0UL, +0xc74f8329UL, 0x9640fde4UL, 0x090d0b0eUL, 0xa156206dUL, +0xc9ea228eUL, 0x4c882edbUL, 0x76738ef7UL, 0x15b2bcb5UL, +0x185fc110UL, 0x2ba96a32UL, 0xa48eb16bUL, 0xf95455aeUL, +0x6089ee40UL, 0x55ef0866UL, 0x672144e9UL, 0x21ecbd3eUL, +0x30be7720UL, 0x8bc7adf2UL, 0xc0e72980UL, 0x1ecf8c14UL, +0xe24348bcUL, 0xa6fe8ac4UL, 0xd3c5d831UL, 0x16fa60b7UL, +0x80ba9d53UL, 0x4fc0f2d9UL, 0xe93e781dUL, 0x362e3a24UL, +0x6bf4dee1UL, 0x54d7efcbUL, 0xf7f1f409UL, 0xc3aff582UL, +0xf4b9280bUL, 0x29d9519dUL, 0x5e9238c7UL, 0x845aebf8UL, +0xd8b8e890UL, 0xb13c0ddeUL, 0xd08d0433UL, 0x5ce20368UL, +0x5ddae4c5UL, 0xdc589e3bUL, 0x0f9d460aUL, 0xdac8d33fUL, +0x8f27db59UL, 0xfc8cc4a8UL, 0xbf99ac79UL, 0x5a724e6cUL, +0xcaa2fe8cUL, 0xd1b5e39eUL, 0xea76a41fUL, 0xb004ea73UL, +}}; + +NAMESPACE_END diff --git a/squareva.dat b/squareva.dat new file mode 100644 index 0000000..4eddd1a --- /dev/null +++ b/squareva.dat @@ -0,0 +1,8 @@ +00000000000000000000000000000000 00000000000000000000000000000000 3C00428F8ABBC0B84F057CC19C26F8CF +000102030405060708090A0B0C0D0E0F 00000000000000000000000000000000 FF596FA668BFC3014200AE01E2BBA0A0 +000102030405060708090A0B0C0D0E0F 000102030405060708090A0B0C0D0E0F 7C3491D94994E70F0EC2E7A5CCB5A14F +000102030405060708090A0B0C0D0E0F C76C696289898137077A4A59FAEEEA4D 88C6FF4B92604C6E66656B02DDAF9F40 +915F4619BE41B2516355A50110A9CE91 21A5DBEE154B8F6D6FF33B98F448E95A 3388801F66E7FCC0BCE522A23A4F0C7F +783348E75AEB0F2FD7B169BB8DC16787 F7C013AC5B2B8952E5E554ABE9CED2D2 A1C0E9215141343DEC2B556942C92BDE +DC49DB1375A5584F6485B413B5F12BAF 2F42B3B70369FC929AE068313F343A7A 3FBE6811B998CDF3E50ABDE2F3C075E3 +5269F149D41BA0152497574D7F153125 65C178B284D197CCD3F111A282F17F29 D7B7209E0879744C782809B6D2E0B1B0 diff --git a/strciphr.cpp b/strciphr.cpp new file mode 100644 index 0000000..694d158 --- /dev/null +++ b/strciphr.cpp @@ -0,0 +1,188 @@ +// strciphr.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class S> +byte AdditiveCipherTemplate<S>::GenerateByte() +{ + PolicyInterface &policy = AccessPolicy(); + + if (m_leftOver == 0) + { + policy.WriteKeystream(m_buffer, policy.GetIterationsToBuffer()); + m_leftOver = policy.GetBytesPerIteration(); + } + + return KeystreamBufferEnd()[-m_leftOver--]; +} + +template <class S> +inline void AdditiveCipherTemplate<S>::ProcessData(byte *outString, const byte *inString, unsigned int length) +{ + if (m_leftOver > 0) + { + unsigned int len = STDMIN(m_leftOver, length); + xorbuf(outString, inString, KeystreamBufferEnd()-m_leftOver, len); + length -= len; + m_leftOver -= len; + inString += len; + outString += len; + } + + if (!length) + return; + + assert(m_leftOver == 0); + + PolicyInterface &policy = AccessPolicy(); + unsigned int bytesPerIteration = policy.GetBytesPerIteration(); + unsigned int alignment = policy.GetAlignment(); + + if (policy.CanOperateKeystream() && length >= bytesPerIteration && IsAlignedOn(outString, alignment)) + { + if (IsAlignedOn(inString, alignment)) + policy.OperateKeystream(XOR_KEYSTREAM, outString, inString, length / bytesPerIteration); + else + { + memcpy(outString, inString, length); + policy.OperateKeystream(XOR_KEYSTREAM_INPLACE, outString, outString, length / bytesPerIteration); + } + inString += length - length % bytesPerIteration; + outString += length - length % bytesPerIteration; + length %= bytesPerIteration; + + if (!length) + return; + } + + unsigned int bufferByteSize = GetBufferByteSize(policy); + unsigned int bufferIterations = policy.GetIterationsToBuffer(); + + while (length >= bufferByteSize) + { + policy.WriteKeystream(m_buffer, bufferIterations); + xorbuf(outString, inString, KeystreamBufferBegin(), bufferByteSize); + length -= bufferByteSize; + inString += bufferByteSize; + outString += bufferByteSize; + } + + if (length > 0) + { + policy.WriteKeystream(m_buffer, bufferIterations); + xorbuf(outString, inString, KeystreamBufferBegin(), length); + m_leftOver = bytesPerIteration - length; + } +} + +template <class S> +void AdditiveCipherTemplate<S>::Resynchronize(const byte *iv) +{ + PolicyInterface &policy = AccessPolicy(); + m_leftOver = 0; + m_buffer.New(GetBufferByteSize(policy)); + policy.CipherResynchronize(m_buffer, iv); +} + +template <class BASE> +void AdditiveCipherTemplate<BASE>::Seek(dword position) +{ + PolicyInterface &policy = AccessPolicy(); + unsigned int bytesPerIteration = policy.GetBytesPerIteration(); + + policy.SeekToIteration(position / bytesPerIteration); + position %= bytesPerIteration; + + if (position > 0) + { + policy.WriteKeystream(m_buffer, 1); + m_leftOver = bytesPerIteration - position; + } + else + m_leftOver = 0; +} + +template <class BASE> +void CFB_CipherTemplate<BASE>::Resynchronize(const byte *iv) +{ + PolicyInterface &policy = AccessPolicy(); + policy.CipherResynchronize(iv); + m_leftOver = policy.GetBytesPerIteration(); +} + +template <class BASE> +void CFB_CipherTemplate<BASE>::ProcessData(byte *outString, const byte *inString, unsigned int length) +{ + PolicyInterface &policy = AccessPolicy(); + unsigned int bytesPerIteration = policy.GetBytesPerIteration(); + unsigned int alignment = policy.GetAlignment(); + byte *reg = policy.GetRegisterBegin(); + + if (m_leftOver) + { + unsigned int len = STDMIN(m_leftOver, length); + CombineMessageAndShiftRegister(outString, reg + bytesPerIteration - m_leftOver, inString, len); + m_leftOver -= len; + length -= len; + inString += len; + outString += len; + } + + if (!length) + return; + + assert(m_leftOver == 0); + + if (policy.CanIterate() && length >= bytesPerIteration && IsAlignedOn(outString, alignment)) + { + if (IsAlignedOn(inString, alignment)) + policy.Iterate(outString, inString, GetCipherDir(*this), length / bytesPerIteration); + else + { + memcpy(outString, inString, length); + policy.Iterate(outString, outString, GetCipherDir(*this), length / bytesPerIteration); + } + inString += length - length % bytesPerIteration; + outString += length - length % bytesPerIteration; + length %= bytesPerIteration; + } + + while (length >= bytesPerIteration) + { + policy.TransformRegister(); + CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration); + length -= bytesPerIteration; + inString += bytesPerIteration; + outString += bytesPerIteration; + } + + if (length > 0) + { + policy.TransformRegister(); + CombineMessageAndShiftRegister(outString, reg, inString, length); + m_leftOver = bytesPerIteration - length; + } +} + +template <class BASE> +void CFB_EncryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length) +{ + xorbuf(reg, message, length); + memcpy(output, reg, length); +} + +template <class BASE> +void CFB_DecryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length) +{ + for (unsigned int i=0; i<length; i++) + { + byte b = message[i]; + output[i] = reg[i] ^ b; + reg[i] = b; + } +} + +NAMESPACE_END diff --git a/strciphr.h b/strciphr.h new file mode 100644 index 0000000..12fb95e --- /dev/null +++ b/strciphr.h @@ -0,0 +1,287 @@ +/*! \file + This file contains helper classes for implementing stream ciphers. + + All this infrastructure may look very complex compared to what's in Crypto++ 4.x, + but stream ciphers implementations now support a lot of new functionality, + including better performance (minimizing copying), resetting of keys and IVs, and methods to + query which features are supported by a cipher. + + Here's an explanation of these classes. The word "policy" is used here to mean a class with a + set of methods that must be implemented by individual stream cipher implementations. + This is usually much simpler than the full stream cipher API, which is implemented by + either AdditiveCipherTemplate or CFB_CipherTemplate using the policy. So for example, an + implementation of SEAL only needs to implement the AdditiveCipherAbstractPolicy interface + (since it's an additive cipher, i.e., it xors a keystream into the plaintext). + See this line in seal.h: + + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<SEAL_Policy<B>, AdditiveCipherTemplate<> > > Encryption; + + AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't need + to take a policy class as a template parameter (although this is allowed), so that + their code is not duplicated for each new cipher. Instead they each + get a reference to an abstract policy interface by calling AccessPolicy() on itself, so + AccessPolicy() must be overriden to return the actual policy reference. This is done + by the ConceretePolicyHolder class. Finally, SymmetricCipherFinalTemplate implements the constructors and + other functions that must be implemented by the most derived class. +*/ + +#ifndef CRYPTOPP_STRCIPHR_H +#define CRYPTOPP_STRCIPHR_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class POLICY_INTERFACE, class BASE = Empty> +class AbstractPolicyHolder : public BASE +{ +protected: + typedef POLICY_INTERFACE PolicyInterface; + + virtual const POLICY_INTERFACE & GetPolicy() const =0; + virtual POLICY_INTERFACE & AccessPolicy() =0; +}; + +template <class POLICY, class BASE, class POLICY_INTERFACE = CPP_TYPENAME BASE::PolicyInterface> +class ConcretePolicyHolder : public BASE, protected POLICY +{ +protected: + const POLICY_INTERFACE & GetPolicy() const {return *this;} + POLICY_INTERFACE & AccessPolicy() {return *this;} +}; + +enum KeystreamOperation {WRITE_KEYSTREAM, XOR_KEYSTREAM, XOR_KEYSTREAM_INPLACE}; + +struct AdditiveCipherAbstractPolicy +{ + virtual unsigned int GetAlignment() const =0; + virtual unsigned int GetBytesPerIteration() const =0; + virtual unsigned int GetIterationsToBuffer() const =0; + virtual void WriteKeystream(byte *keystreamBuffer, unsigned int iterationCount) =0; + virtual bool CanOperateKeystream() const {return false;} + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) {assert(false);} + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) =0; + virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv) {throw NotImplemented("StreamTransformation: this object doesn't support resynchronization");} + virtual bool IsRandomAccess() const =0; + virtual void SeekToIteration(dword iterationCount) {assert(!IsRandomAccess()); throw NotImplemented("StreamTransformation: this object doesn't support random access");} +}; + +template <typename WT, unsigned int W, unsigned int X = 1, class BASE = AdditiveCipherAbstractPolicy> +struct AdditiveCipherConcretePolicy : public BASE +{ + typedef WT WordType; + + unsigned int GetAlignment() const {return sizeof(WordType);} + unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} + unsigned int GetIterationsToBuffer() const {return X;} + void WriteKeystream(byte *buffer, unsigned int iterationCount) + {OperateKeystream(WRITE_KEYSTREAM, buffer, NULL, iterationCount);} + bool CanOperateKeystream() const {return true;} + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) =0; + + template <class B> + struct KeystreamOutput + { + KeystreamOutput(KeystreamOperation operation, byte *output, const byte *input) + : m_operation(operation), m_output(output), m_input(input) {} + + inline KeystreamOutput & operator()(WordType keystreamWord) + { + assert(IsAligned<WordType>(m_input)); + assert(IsAligned<WordType>(m_output)); + + if (!NativeByteOrderIs(B::ToEnum())) + keystreamWord = ByteReverse(keystreamWord); + + if (m_operation == WRITE_KEYSTREAM) + *(WordType*)m_output = keystreamWord; + else if (m_operation == XOR_KEYSTREAM) + { + *(WordType*)m_output = keystreamWord ^ *(WordType*)m_input; + m_input += sizeof(WordType); + } + else if (m_operation == XOR_KEYSTREAM_INPLACE) + *(WordType*)m_output ^= keystreamWord; + + m_output += sizeof(WordType); + + return *this; + } + + KeystreamOperation m_operation; + byte *m_output; + const byte *m_input; + }; +}; + +template <class BASE = AbstractPolicyHolder<AdditiveCipherAbstractPolicy, TwoBases<SymmetricCipher, RandomNumberGenerator> > > +class AdditiveCipherTemplate : public BASE +{ +public: + byte GenerateByte(); + void ProcessData(byte *outString, const byte *inString, unsigned int length); + void Resynchronize(const byte *iv); + unsigned int OptimalBlockSize() const {return GetPolicy().GetBytesPerIteration();} + unsigned int GetOptimalNextBlockSize() const {return m_leftOver;} + unsigned int OptimalDataAlignment() const {return GetPolicy().GetAlignment();} + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + bool IsRandomAccess() const {return GetPolicy().IsRandomAccess();} + void Seek(dword position); + +protected: + typedef typename BASE::PolicyInterface PolicyInterface; + + void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + + unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();} + + inline byte * KeystreamBufferBegin() {return m_buffer.data();} + inline byte * KeystreamBufferEnd() {return (m_buffer.data() + m_buffer.size());} + + SecByteBlock m_buffer; + unsigned int m_leftOver; +}; + +struct CFB_CipherAbstractPolicy +{ + virtual unsigned int GetAlignment() const =0; + virtual unsigned int GetBytesPerIteration() const =0; + virtual byte * GetRegisterBegin() =0; + virtual void TransformRegister() =0; + virtual bool CanIterate() const {return false;} + virtual void Iterate(byte *output, const byte *input, CipherDir dir, unsigned int iterationCount) {assert(false);} + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) =0; + virtual void CipherResynchronize(const byte *iv) {throw NotImplemented("StreamTransformation: this object doesn't support resynchronization");} +}; + +template <typename WT, unsigned int W, class BASE = CFB_CipherAbstractPolicy> +struct CFB_CipherConcretePolicy : public BASE +{ + typedef WT WordType; + + unsigned int GetAlignment() const {return sizeof(WordType);} + unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} + bool CanIterate() const {return true;} + void TransformRegister() {Iterate(NULL, NULL, ENCRYPTION, 1);} + + template <class B> + struct RegisterOutput + { + RegisterOutput(byte *output, const byte *input, CipherDir dir) + : m_output(output), m_input(input), m_dir(dir) {} + + inline RegisterOutput& operator()(WordType ®isterWord) + { + assert(IsAligned<WordType>(m_output)); + assert(IsAligned<WordType>(m_input)); + + if (!NativeByteOrderIs(B::ToEnum())) + registerWord = ByteReverse(registerWord); + + if (m_dir == ENCRYPTION) + { + WordType ct = *(const WordType *)m_input ^ registerWord; + registerWord = ct; + *(WordType*)m_output = ct; + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + else + { + WordType ct = *(const WordType *)m_input; + *(WordType*)m_output = registerWord ^ ct; + registerWord = ct; + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + + // registerWord is left unreversed so it can be xor-ed with further input + + return *this; + } + + byte *m_output; + const byte *m_input; + CipherDir m_dir; + }; +}; + +template <class BASE> +class CFB_CipherTemplate : public BASE +{ +public: + void ProcessData(byte *outString, const byte *inString, unsigned int length); + void Resynchronize(const byte *iv); + unsigned int OptimalBlockSize() const {return GetPolicy().GetBytesPerIteration();} + unsigned int GetOptimalNextBlockSize() const {return m_leftOver;} + unsigned int OptimalDataAlignment() const {return GetPolicy().GetAlignment();} + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return false;} + +protected: + typedef typename BASE::PolicyInterface PolicyInterface; + + virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length) =0; + + void UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + + unsigned int m_leftOver; +}; + +template <class BASE = AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> > +class CFB_EncryptionTemplate : public CFB_CipherTemplate<BASE> +{ + bool IsForwardTransformation() const {return true;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length); +}; + +template <class BASE = AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> > +class CFB_DecryptionTemplate : public CFB_CipherTemplate<BASE> +{ + bool IsForwardTransformation() const {return false;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length); +}; + +template <class BASE, class INFO = BASE> +class SymmetricCipherFinalTemplate : public AlgorithmImpl<SimpleKeyingInterfaceImpl<BASE, INFO>, INFO> +{ +public: + SymmetricCipherFinalTemplate() {} + SymmetricCipherFinalTemplate(const byte *key) + {SetKey(key, DEFAULT_KEYLENGTH);} + SymmetricCipherFinalTemplate(const byte *key, unsigned int length) + {SetKey(key, length);} + SymmetricCipherFinalTemplate(const byte *key, unsigned int length, const byte *iv) + {SetKey(key, length); Resynchronize(iv);} + + void SetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms = g_nullNameValuePairs) + { + ThrowIfInvalidKeyLength(length); + UncheckedSetKey(params, key, length); + } + + Clonable * Clone() {return new SymmetricCipherFinalTemplate<BASE, INFO>(*this);} +}; + +template <class S> +void AdditiveCipherTemplate<S>::UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + PolicyInterface &policy = AccessPolicy(); + policy.CipherSetKey(params, key, length); + m_buffer.New(GetBufferByteSize(policy)); + m_leftOver = 0; +} + +template <class BASE> +void CFB_CipherTemplate<BASE>::UncheckedSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + PolicyInterface &policy = AccessPolicy(); + policy.CipherSetKey(params, key, length); + m_leftOver = policy.GetBytesPerIteration(); +} + +NAMESPACE_END + +#endif @@ -0,0 +1,54 @@ +// tea.cpp - modified by Wei Dai from code in the original paper + +#include "pch.h" +#include "tea.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 TEA::Base::DELTA = 0x9e3779b9; + +void TEA::Base::UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length) +{ + AssertValidKeyLength(length); + + GetUserKey(BIG_ENDIAN_ORDER, k.begin(), 4, userKey, KEYLENGTH); +} + +typedef BlockGetAndPut<word32, BigEndian> Block; + +void TEA::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z; + Block::Get(inBlock)(y)(z); + + word32 sum = 0; + for (int i=0; i<ROUNDS; i++) + { + sum += DELTA; + y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1]; + z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3]; + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +typedef BlockGetAndPut<word32, BigEndian> Block; + +void TEA::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z; + Block::Get(inBlock)(y)(z); + + word32 sum = DELTA << LOG_ROUNDS; + for (int i=0; i<ROUNDS; i++) + { + z -= (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3]; + y -= (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1]; + sum -= DELTA; + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +NAMESPACE_END @@ -0,0 +1,53 @@ +#ifndef CRYPTOPP_TEA_H +#define CRYPTOPP_TEA_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct TEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<32> +{ + enum {LOG_ROUNDS=5}; + static const char *StaticAlgorithmName() {return "TEA";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#TEA">TEA</a> +class TEA : public TEA_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<TEA_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static const word32 DELTA; + FixedSizeSecBlock<word32, 4> k; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef TEA::Encryption TEAEncryption; +typedef TEA::Decryption TEADecryption; + +NAMESPACE_END + +#endif diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..e5c87c9 --- /dev/null +++ b/test.cpp @@ -0,0 +1,917 @@ +// test.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "md5.h" +#include "sha.h" +#include "ripemd.h" +#include "files.h" +#include "rng.h" +#include "hex.h" +#include "gzip.h" +#include "default.h" +#include "rsa.h" +#include "randpool.h" +#include "ida.h" +#include "base64.h" +#include "socketft.h" +#include "dsa.h" +#include "rsa.h" +#include "osrng.h" +#include "wait.h" +#include "fips140.h" + +#include "validate.h" +#include "bench.h" + +#include <iostream> +#include <time.h> + +#if defined(_WIN32) || defined(__CYGWIN__) +#include <windows.h> +#endif + +#if (_MSC_VER >= 1000) +#include <crtdbg.h> // for the debug heap +#endif + +#if defined(__MWERKS__) && defined(macintosh) +#include <console.h> +#endif + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +const int MAX_PHRASE_LENGTH=250; + +void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed); +string RSAEncryptString(const char *pubFilename, const char *seed, const char *message); +string RSADecryptString(const char *privFilename, const char *ciphertext); +void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename); +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename); + +void DigestFile(const char *file); + +string EncryptString(const char *plaintext, const char *passPhrase); +string DecryptString(const char *ciphertext, const char *passPhrase); + +void EncryptFile(const char *in, const char *out, const char *passPhrase); +void DecryptFile(const char *in, const char *out, const char *passPhrase); + +void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed); +void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames); + +void InformationDisperseFile(int threshold, int nShares, const char *filename); +void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames); + +void GzipFile(const char *in, const char *out, int deflate_level); +void GunzipFile(const char *in, const char *out); + +void Base64Encode(const char *in, const char *out); +void Base64Decode(const char *in, const char *out); +void HexEncode(const char *in, const char *out); +void HexDecode(const char *in, const char *out); + +void ForwardTcpPort(const char *sourcePort, const char *destinationHost, const char *destinationPort); + +void FIPS140_SampleApplication(const char *moduleFilename, const char *edcFilename); +void FIPS140_GenerateRandomFiles(); + +bool Validate(int, bool, const char *); + +#ifdef __BCPLUSPLUS__ +int cmain(int argc, char *argv[]) +#elif defined(_MSC_VER) +int __cdecl main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ +#ifdef _CRTDBG_LEAK_CHECK_DF + // Turn on leak-checking + int tempflag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); + tempflag |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag( tempflag ); +#endif + +#if defined(__MWERKS__) && defined(macintosh) + argc = ccommand(&argv); +#endif + + try + { + std::string command, executableName, edcFilename; + + if (argc < 2) + command = 'h'; + else + command = argv[1]; + + if (FIPS_140_2_ComplianceEnabled()) + { + edcFilename = "edc.dat"; + +#if defined(_WIN32) || defined(__CYGWIN__) + TCHAR filename[MAX_PATH]; + GetModuleFileName(GetModuleHandle(NULL), filename, sizeof(filename)); + executableName = filename; + std::string::size_type pos = executableName.rfind('\\'); + if (pos != std::string::npos) + edcFilename = executableName.substr(0, pos+1) + edcFilename; +#else + executableName = argv[0]; +#endif + + if (command.substr(0, 4) != "fips") + { + byte expectedModuleDigest[SHA1::DIGESTSIZE]; + FileSource(edcFilename.c_str(), true, new HexDecoder(new ArraySink(expectedModuleDigest, sizeof(expectedModuleDigest)))); + + DoPowerUpSelfTest(executableName.c_str(), expectedModuleDigest); + } + } + + switch (command[0]) + { + case 'g': + { + char seed[1024], privFilename[128], pubFilename[128]; + unsigned int keyLength; + + cout << "Key length in bits: "; + cin >> keyLength; + + cout << "\nSave private key to file: "; + cin >> privFilename; + + cout << "\nSave public key to file: "; + cin >> pubFilename; + + cout << "\nRandom Seed: "; + ws(cin); + cin.getline(seed, 1024); + + GenerateRSAKey(keyLength, privFilename, pubFilename, seed); + return 0; + } + case 'r': + { + switch (argv[1][1]) + { + case 's': + RSASignFile(argv[2], argv[3], argv[4]); + return 0; + case 'v': + { + bool verified = RSAVerifyFile(argv[2], argv[3], argv[4]); + cout << (verified ? "valid signature" : "invalid signature") << endl; + return 0; + } + default: + { + char privFilename[128], pubFilename[128]; + char seed[1024], message[1024]; + + cout << "Private key file: "; + cin >> privFilename; + + cout << "\nPublic key file: "; + cin >> pubFilename; + + cout << "\nRandom Seed: "; + ws(cin); + cin.getline(seed, 1024); + + cout << "\nMessage: "; + cin.getline(message, 1024); + + string ciphertext = RSAEncryptString(pubFilename, seed, message); + cout << "\nCiphertext: " << ciphertext << endl; + + string decrypted = RSADecryptString(privFilename, ciphertext.c_str()); + cout << "\nDecrypted: " << decrypted << endl; + + return 0; + } + } + } + case 'm': + DigestFile(argv[2]); + return 0; + case 't': + { + // VC60 workaround: use char array instead of std::string to workaround MSVC's getline bug + char passPhrase[MAX_PHRASE_LENGTH], plaintext[1024]; + + cout << "Passphrase: "; + cin.getline(passPhrase, MAX_PHRASE_LENGTH); + + cout << "\nPlaintext: "; + cin.getline(plaintext, 1024); + + string ciphertext = EncryptString(plaintext, passPhrase); + cout << "\nCiphertext: " << ciphertext << endl; + + string decrypted = DecryptString(ciphertext.c_str(), passPhrase); + cout << "\nDecrypted: " << decrypted << endl; + + return 0; + } + case 'e': + case 'd': + if (command == "e64") + Base64Encode(argv[2], argv[3]); + else if (command == "d64") + Base64Decode(argv[2], argv[3]); + else if (command == "e16") + HexEncode(argv[2], argv[3]); + else if (command == "d16") + HexDecode(argv[2], argv[3]); + else + { + char passPhrase[MAX_PHRASE_LENGTH]; + cout << "Passphrase: "; + cin.getline(passPhrase, MAX_PHRASE_LENGTH); + if (command == "e") + EncryptFile(argv[2], argv[3], passPhrase); + else + DecryptFile(argv[2], argv[3], passPhrase); + } + return 0; + case 's': + if (argv[1][1] == 's') + { + char seed[1024]; + cout << "\nRandom Seed: "; + ws(cin); + cin.getline(seed, 1024); + SecretShareFile(atoi(argv[2]), atoi(argv[3]), argv[4], seed); + } + else + SecretRecoverFile(argc-3, argv[2], argv+3); + return 0; + case 'i': + if (argv[1][1] == 'd') + InformationDisperseFile(atoi(argv[2]), atoi(argv[3]), argv[4]); + else + InformationRecoverFile(argc-3, argv[2], argv+3); + return 0; + case 'v': + return !Validate(argc>2 ? atoi(argv[2]) : 0, argv[1][1] == 'v', argc>3 ? argv[3] : NULL); + case 'b': + if (argc<3) + BenchMarkAll(); + else + BenchMarkAll((float)atof(argv[2])); + return 0; + case 'z': + GzipFile(argv[3], argv[4], argv[2][0]-'0'); + return 0; + case 'u': + GunzipFile(argv[2], argv[3]); + return 0; + case 'f': + if (command == "fips") + FIPS140_SampleApplication(executableName.c_str(), edcFilename.c_str()); + else if (command == "fips-rand") + FIPS140_GenerateRandomFiles(); + else if (command == "ft") + ForwardTcpPort(argv[2], argv[3], argv[4]); + return 0; + default: + FileSource usage("usage.dat", true, new FileSink(cout)); + return 1; + } + } + catch(CryptoPP::Exception &e) + { + cout << "\nCryptoPP::Exception caught: " << e.what() << endl; + return -1; + } + catch(std::exception &e) + { + cout << "\nstd::exception caught: " << e.what() << endl; + return -2; + } +} + +void FIPS140_SampleApplication(const char *moduleFilename, const char *edcFilename) +{ + if (!FIPS_140_2_ComplianceEnabled()) + { + cerr << "FIPS-140-2 compliance was turned off at compile time.\n"; + abort(); + } + + // try to use a crypto algorithm before doing a self test + try + { + // trying to use a crypto algorithm before power-up self test will result in an exception + DES::Encryption des; + + // should not be here + cerr << "Use of DES before power-up test failed to cause an exception.\n"; + abort(); + } + catch (SelfTestFailure &e) + { + cout << "0. Caught expected exception. Exception message follows: "; + cout << e.what() << endl; + } + + // simulate a power-up self test error + SimulatePowerUpSelfTestFailure(); + try + { + // trying to use a crypto algorithm after power-up self test error will result in an exception + DES::Encryption des; + + // should not be here + cerr << "Use of DES failed to cause an exception after power-up self test error.\n"; + abort(); + } + catch (SelfTestFailure &e) + { + cout << "1. Caught expected exception when simulating self test failure. Exception message follows: "; + cout << e.what() << endl; + } + + // clear the self test error state and do power-up self test + byte expectedModuleDigest[SHA1::DIGESTSIZE]; + FileSource(edcFilename, true, new HexDecoder(new ArraySink(expectedModuleDigest, sizeof(expectedModuleDigest)))); + + DoPowerUpSelfTest(moduleFilename, expectedModuleDigest); + if (GetPowerUpSelfTestStatus() != POWER_UP_SELF_TEST_PASSED) + { + cerr << "Power-up self test failed.\n"; + abort(); + } + cout << "2. Power-up self test passed.\n"; + + // encrypt and decrypt + const byte key[] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + const byte iv[] = {0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef}; + const byte plaintext[] = { // "Now is the time for all " without tailing 0 + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20}; + byte ciphertext[24]; + byte decrypted[24]; + + CFB_Mode<DES>::Encryption encryption_DES_CBC; + encryption_DES_CBC.SetKeyWithIV(key, 8, iv); + encryption_DES_CBC.ProcessString(ciphertext, plaintext, 24); + + CFB_Mode<DES>::Decryption decryption_DES_CBC; + decryption_DES_CBC.SetKeyWithIV(key, 8, iv); + decryption_DES_CBC.ProcessString(decrypted, ciphertext, 24); + + if (memcmp(plaintext, decrypted, 24) != 0) + { + cerr << "DES-CBC Encryption/decryption failed.\n"; + abort(); + } + cout << "3. DES-CBC Encryption/decryption succeeded.\n"; + + // hash + const byte message[] = {'a', 'b', 'c'}; + const byte expectedDigest[] = {0xA9,0x99,0x3E,0x36,0x47,0x06,0x81,0x6A,0xBA,0x3E,0x25,0x71,0x78,0x50,0xC2,0x6C,0x9C,0xD0,0xD8,0x9D}; + byte digest[20]; + + SHA1 sha; + sha.Update(message, 3); + sha.Final(digest); + + if (memcmp(digest, expectedDigest, 20) != 0) + { + cerr << "SHA-1 hash failed.\n"; + abort(); + } + cout << "4. SHA-1 hash succeeded.\n"; + + // create auto-seeded X9.17 RNG object, if available +#ifdef OS_RNG_AVAILABLE + AutoSeededX917RNG<DES_EDE3> rng; +#else + // this is used to allow this function to compile on platforms that don't have auto-seeded RNGs + RandomNumberGenerator &rng(NullRNG()); +#endif + + // generate DSA key + DSA::PrivateKey dsaPrivateKey; + dsaPrivateKey.GenerateRandomWithKeySize(rng, 1024); + DSA::PublicKey dsaPublicKey; + dsaPublicKey.AssignFrom(dsaPrivateKey); + if (!dsaPrivateKey.Validate(rng, 3) || !dsaPublicKey.Validate(rng, 3)) + { + cerr << "DSA key generation failed.\n"; + abort(); + } + cout << "5. DSA key generation succeeded.\n"; + + // encode DSA key + std::string encodedDsaPublicKey, encodedDsaPrivateKey; + dsaPublicKey.DEREncode(StringSink(encodedDsaPublicKey).Ref()); + dsaPrivateKey.DEREncode(StringSink(encodedDsaPrivateKey).Ref()); + + // decode DSA key + DSA::PrivateKey decodedDsaPrivateKey; + decodedDsaPrivateKey.BERDecode(StringStore(encodedDsaPrivateKey).Ref()); + DSA::PublicKey decodedDsaPublicKey; + decodedDsaPublicKey.BERDecode(StringStore(encodedDsaPublicKey).Ref()); + + if (!decodedDsaPrivateKey.Validate(rng, 3) || !decodedDsaPublicKey.Validate(rng, 3)) + { + cerr << "DSA key encode/decode failed.\n"; + abort(); + } + cout << "6. DSA key encode/decode succeeded.\n"; + + // sign and verify + byte signature[40]; + DSA::Signer signer(dsaPrivateKey); + assert(signer.SignatureLength() == 40); + signer.SignMessage(rng, message, 3, signature); + + DSA::Verifier verifier(dsaPublicKey); + if (!verifier.VerifyMessage(message, 3, signature)) + { + cerr << "DSA signature and verification failed.\n"; + abort(); + } + cout << "7. DSA signature and verification succeeded.\n"; + + + // try to verify an invalid signature + signature[0] ^= 1; + if (verifier.VerifyMessage(message, 3, signature)) + { + cerr << "DSA signature verification failed to detect bad signature.\n"; + abort(); + } + cout << "8. DSA signature verification successfully detected bad signature.\n"; + + // try to use an invalid key length + try + { + encryption_DES_CBC.SetKey(key, 5); + + // should not be here + cerr << "DES implementation did not detect use of invalid key length.\n"; + abort(); + } + catch (InvalidArgument &e) + { + cout << "9. Caught expected exception when using invalid key length. Exception message follows: "; + cout << e.what() << endl; + } + + cout << "\nFIPS 140-2 Sample Application completed normally.\n"; +} + +void FIPS140_GenerateRandomFiles() +{ +#ifdef OS_RNG_AVAILABLE + AutoSeededX917RNG<DES_EDE3> rng; + RandomNumberStore store(rng, ULONG_MAX); + + for (unsigned int i=0; i<100000; i++) + store.TransferTo(FileSink((IntToString(i) + ".rnd").c_str()).Ref(), 20000); +#else + cout << "OS provided RNG not available.\n"; + exit(-1); +#endif +} + +RandomPool & GlobalRNG() +{ + static RandomPool randomPool; + return randomPool; +} + +void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed) +{ + RandomPool randPool; + randPool.Put((byte *)seed, strlen(seed)); + + RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength); + HexEncoder privFile(new FileSink(privFilename)); + priv.DEREncode(privFile); + privFile.MessageEnd(); + + RSAES_OAEP_SHA_Encryptor pub(priv); + HexEncoder pubFile(new FileSink(pubFilename)); + pub.DEREncode(pubFile); + pubFile.MessageEnd(); +} + +string RSAEncryptString(const char *pubFilename, const char *seed, const char *message) +{ + FileSource pubFile(pubFilename, true, new HexDecoder); + RSAES_OAEP_SHA_Encryptor pub(pubFile); + + RandomPool randPool; + randPool.Put((byte *)seed, strlen(seed)); + + string result; + StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result)))); + return result; +} + +string RSADecryptString(const char *privFilename, const char *ciphertext) +{ + FileSource privFile(privFilename, true, new HexDecoder); + RSAES_OAEP_SHA_Decryptor priv(privFile); + + string result; + StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(priv, new StringSink(result)))); + return result; +} + +void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource privFile(privFilename, true, new HexDecoder); + RSASSA_PKCS1v15_SHA_Signer priv(privFile); + // RSASSA_PKCS1v15_SHA_Signer ignores the rng. Use a real RNG for other signature schemes! + FileSource f(messageFilename, true, new SignerFilter(NullRNG(), priv, new HexEncoder(new FileSink(signatureFilename)))); +} + +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource pubFile(pubFilename, true, new HexDecoder); + RSASSA_PKCS1v15_SHA_Verifier pub(pubFile); + + FileSource signatureFile(signatureFilename, true, new HexDecoder); + if (signatureFile.MaxRetrievable() != pub.SignatureLength()) + return false; + SecByteBlock signature(pub.SignatureLength()); + signatureFile.Get(signature, signature.size()); + + VerifierFilter *verifierFilter = new VerifierFilter(pub); + verifierFilter->Put(signature, pub.SignatureLength()); + FileSource f(messageFilename, true, verifierFilter); + + return verifierFilter->GetLastResult(); +} + +void DigestFile(const char *filename) +{ + MD5 md5; + SHA sha; + RIPEMD160 ripemd; + SHA256 sha256; + HashFilter md5Filter(md5), shaFilter(sha), ripemdFilter(ripemd), sha256Filter(sha256); + + auto_ptr<ChannelSwitch> channelSwitch(new ChannelSwitch); + channelSwitch->AddDefaultRoute(md5Filter); + channelSwitch->AddDefaultRoute(shaFilter); + channelSwitch->AddDefaultRoute(ripemdFilter); + channelSwitch->AddDefaultRoute(sha256Filter); + FileSource(filename, true, channelSwitch.release()); + + HexEncoder encoder(new FileSink(cout), false); + cout << "\nMD5: "; + md5Filter.TransferTo(encoder); + cout << "\nSHA-1: "; + shaFilter.TransferTo(encoder); + cout << "\nRIPEMD-160: "; + ripemdFilter.TransferTo(encoder); + cout << "\nSHA-256: "; + sha256Filter.TransferTo(encoder); +} + +string EncryptString(const char *instr, const char *passPhrase) +{ + string outstr; + + DefaultEncryptorWithMAC encryptor(passPhrase, new HexEncoder(new StringSink(outstr))); + encryptor.Put((byte *)instr, strlen(instr)); + encryptor.MessageEnd(); + + return outstr; +} + +string DecryptString(const char *instr, const char *passPhrase) +{ + string outstr; + + HexDecoder decryptor(new DefaultDecryptorWithMAC(passPhrase, new StringSink(outstr))); + decryptor.Put((byte *)instr, strlen(instr)); + decryptor.MessageEnd(); + + return outstr; +} + +void EncryptFile(const char *in, const char *out, const char *passPhrase) +{ + FileSource f(in, true, new DefaultEncryptorWithMAC(passPhrase, new FileSink(out))); +} + +void DecryptFile(const char *in, const char *out, const char *passPhrase) +{ + FileSource f(in, true, new DefaultDecryptorWithMAC(passPhrase, new FileSink(out))); +} + +void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed) +{ + assert(nShares<=1000); + + RandomPool rng; + rng.Put((byte *)seed, strlen(seed)); + + ChannelSwitch *channelSwitch; + FileSource source(filename, false, new SecretSharing(rng, threshold, nShares, channelSwitch = new ChannelSwitch)); + + vector_member_ptrs<FileSink> fileSinks(nShares); + string channel; + for (unsigned int i=0; i<nShares; i++) + { + char extension[5] = ".000"; + extension[1]='0'+byte(i/100); + extension[2]='0'+byte((i/10)%10); + extension[3]='0'+byte(i%10); + fileSinks[i].reset(new FileSink((string(filename)+extension).c_str())); + + channel = WordToString<word32>(i); + fileSinks[i]->Put((byte *)channel.data(), 4); + channelSwitch->AddRoute(channel, *fileSinks[i], BufferedTransformation::NULL_CHANNEL); + } + + source.PumpAll(); +} + +void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames) +{ + assert(threshold<=1000); + + SecretRecovery recovery(threshold, new FileSink(outFilename)); + + vector_member_ptrs<FileSource> fileSources(threshold); + SecByteBlock channel(4); + unsigned int i; + for (i=0; i<threshold; i++) + { + fileSources[i].reset(new FileSource(inFilenames[i], false)); + fileSources[i]->Pump(4); + fileSources[i]->Get(channel, 4); + fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4))); + } + + while (fileSources[0]->Pump(256)) + for (i=1; i<threshold; i++) + fileSources[i]->Pump(256); + + for (i=0; i<threshold; i++) + fileSources[i]->PumpAll(); +} + +void InformationDisperseFile(int threshold, int nShares, const char *filename) +{ + assert(nShares<=1000); + + ChannelSwitch *channelSwitch; + FileSource source(filename, false, new InformationDispersal(threshold, nShares, channelSwitch = new ChannelSwitch)); + + vector_member_ptrs<FileSink> fileSinks(nShares); + string channel; + for (unsigned int i=0; i<nShares; i++) + { + char extension[5] = ".000"; + extension[1]='0'+byte(i/100); + extension[2]='0'+byte((i/10)%10); + extension[3]='0'+byte(i%10); + fileSinks[i].reset(new FileSink((string(filename)+extension).c_str())); + + channel = WordToString<word32>(i); + fileSinks[i]->Put((byte *)channel.data(), 4); + channelSwitch->AddRoute(channel, *fileSinks[i], BufferedTransformation::NULL_CHANNEL); + } + + source.PumpAll(); +} + +void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames) +{ + assert(threshold<=1000); + + InformationRecovery recovery(threshold, new FileSink(outFilename)); + + vector_member_ptrs<FileSource> fileSources(threshold); + SecByteBlock channel(4); + unsigned int i; + for (i=0; i<threshold; i++) + { + fileSources[i].reset(new FileSource(inFilenames[i], false)); + fileSources[i]->Pump(4); + fileSources[i]->Get(channel, 4); + fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4))); + } + + while (fileSources[0]->Pump(256)) + for (i=1; i<threshold; i++) + fileSources[i]->Pump(256); + + for (i=0; i<threshold; i++) + fileSources[i]->PumpAll(); +} + +void GzipFile(const char *in, const char *out, int deflate_level) +{ +// FileSource(in, true, new Gzip(new FileSink(out), deflate_level)); + + // use a filter graph to compare decompressed data with original + // + // Source ----> Gzip ------> Sink + // \ | + // \ Gunzip + // \ | + // \ v + // > ComparisonFilter + + EqualityComparisonFilter comparison; + + Gunzip gunzip(new ChannelSwitch(comparison, "0")); + gunzip.SetAutoSignalPropagation(0); + + FileSink sink(out); + + ChannelSwitch *cs; + Gzip gzip(cs = new ChannelSwitch(sink), deflate_level); + cs->AddDefaultRoute(gunzip); + + cs = new ChannelSwitch(gzip); + cs->AddDefaultRoute(comparison, "1"); + FileSource source(in, true, cs); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +void GunzipFile(const char *in, const char *out) +{ + FileSource(in, true, new Gunzip(new FileSink(out))); +} + +void Base64Encode(const char *in, const char *out) +{ + FileSource(in, true, new Base64Encoder(new FileSink(out))); +} + +void Base64Decode(const char *in, const char *out) +{ + FileSource(in, true, new Base64Decoder(new FileSink(out))); +} + +void HexEncode(const char *in, const char *out) +{ + FileSource(in, true, new HexEncoder(new FileSink(out))); +} + +void HexDecode(const char *in, const char *out) +{ + FileSource(in, true, new HexDecoder(new FileSink(out))); +} + +void ForwardTcpPort(const char *sourcePortName, const char *destinationHost, const char *destinationPortName) +{ +#ifdef SOCKETS_AVAILABLE + SocketsInitializer sockInit; + + Socket sockListen, sockSource, sockDestination; + + int sourcePort = Socket::PortNameToNumber(sourcePortName); + int destinationPort = Socket::PortNameToNumber(destinationPortName); + + sockListen.Create(); + sockListen.Bind(sourcePort); + + cout << "Listing on port " << sourcePort << ".\n"; + sockListen.Listen(); + + sockListen.Accept(sockSource); + cout << "Connection accepted on port " << sourcePort << ".\n"; + sockListen.CloseSocket(); + + cout << "Making connection to " << destinationHost << ", port " << destinationPort << ".\n"; + sockDestination.Create(); + sockDestination.Connect(destinationHost, destinationPort); + + cout << "Connection made to " << destinationHost << ", starting to forward.\n"; + + SocketSource out(sockSource, false, new SocketSink(sockDestination)); + SocketSource in(sockDestination, false, new SocketSink(sockSource)); + + WaitObjectContainer waitObjects; + + while (!(in.SourceExhausted() && out.SourceExhausted())) + { + waitObjects.Clear(); + + out.GetWaitObjects(waitObjects); + in.GetWaitObjects(waitObjects); + + waitObjects.Wait(INFINITE_TIME); + + if (!out.SourceExhausted()) + { + cout << "o" << flush; + out.PumpAll2(false); + if (out.SourceExhausted()) + cout << "EOF received on source socket.\n"; + } + + if (!in.SourceExhausted()) + { + cout << "i" << flush; + in.PumpAll2(false); + if (in.SourceExhausted()) + cout << "EOF received on destination socket.\n"; + } + } +#else + cout << "Socket support was not enabled at compile time.\n"; + exit(-1); +#endif +} + +bool Validate(int alg, bool thorough, const char *seed) +{ + bool result; + + std::string timeSeed; + if (!seed) + { + timeSeed = IntToString(time(NULL)); + seed = timeSeed.c_str(); + } + + cout << "Using seed: " << seed << endl << endl; + GlobalRNG().Put((const byte *)seed, strlen(seed)); + + switch (alg) + { + case 1: result = TestSettings(); break; + case 2: result = TestOS_RNG(); break; + case 3: result = ValidateMD5(); break; + case 4: result = ValidateSHA(); break; + case 5: result = ValidateDES(); break; + case 6: result = ValidateIDEA(); break; + case 7: result = ValidateARC4(); break; + case 8: result = ValidateRC5(); break; + case 9: result = ValidateBlowfish(); break; + case 10: result = ValidateDiamond2(); break; + case 11: result = ValidateThreeWay(); break; + case 12: result = ValidateBBS(); break; + case 13: result = ValidateDH(); break; + case 14: result = ValidateRSA(); break; + case 15: result = ValidateElGamal(); break; + case 16: result = ValidateDSA(thorough); break; + case 17: result = ValidateHAVAL(); break; + case 18: result = ValidateSAFER(); break; + case 19: result = ValidateLUC(); break; + case 20: result = ValidateRabin(); break; +// case 21: result = ValidateBlumGoldwasser(); break; + case 22: result = ValidateECP(); break; + case 23: result = ValidateEC2N(); break; + case 24: result = ValidateMD5MAC(); break; + case 25: result = ValidateGOST(); break; + case 26: result = ValidateTiger(); break; + case 27: result = ValidateRIPEMD(); break; + case 28: result = ValidateHMAC(); break; + case 29: result = ValidateXMACC(); break; + case 30: result = ValidateSHARK(); break; + case 32: result = ValidateLUC_DH(); break; + case 33: result = ValidateLUC_DL(); break; + case 34: result = ValidateSEAL(); break; + case 35: result = ValidateCAST(); break; + case 36: result = ValidateSquare(); break; + case 37: result = ValidateRC2(); break; + case 38: result = ValidateRC6(); break; + case 39: result = ValidateMARS(); break; + case 40: result = ValidateRW(); break; + case 41: result = ValidateMD2(); break; + case 42: result = ValidateNR(); break; + case 43: result = ValidateMQV(); break; + case 44: result = ValidateRijndael(); break; + case 45: result = ValidateTwofish(); break; + case 46: result = ValidateSerpent(); break; + case 47: result = ValidateCipherModes(); break; + case 48: result = ValidateCRC32(); break; + case 49: result = ValidateECDSA(); break; + case 50: result = ValidateXTR_DH(); break; + case 51: result = ValidateSKIPJACK(); break; + case 52: result = ValidateSHA2(); break; + case 53: result = ValidatePanama(); break; + case 54: result = ValidateAdler32(); break; + case 55: result = ValidateMD4(); break; + case 56: result = ValidatePBKDF(); break; + case 57: result = ValidateESIGN(); break; + case 58: result = ValidateDLIES(); break; + default: result = ValidateAll(thorough); break; + } + + time_t endTime = time(NULL); + cout << "\nTest ended at " << asctime(localtime(&endTime)); + cout << "Seed used was: " << seed << endl; + + return result; +} diff --git a/tftables.cpp b/tftables.cpp new file mode 100644 index 0000000..dc654cf --- /dev/null +++ b/tftables.cpp @@ -0,0 +1,317 @@ +// Twofish tables + +#include "pch.h" +#include "twofish.h" + +NAMESPACE_BEGIN(CryptoPP) + +const byte Twofish::Base::q[2][256] = { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0, + + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 +}; + +const word32 Twofish::Base::mds[4][256] = { + 0xbcbc3275, 0xecec21f3, 0x202043c6, 0xb3b3c9f4, + 0xdada03db, 0x02028b7b, 0xe2e22bfb, 0x9e9efac8, + 0xc9c9ec4a, 0xd4d409d3, 0x18186be6, 0x1e1e9f6b, + 0x98980e45, 0xb2b2387d, 0xa6a6d2e8, 0x2626b74b, + 0x3c3c57d6, 0x93938a32, 0x8282eed8, 0x525298fd, + 0x7b7bd437, 0xbbbb3771, 0x5b5b97f1, 0x474783e1, + 0x24243c30, 0x5151e20f, 0xbabac6f8, 0x4a4af31b, + 0xbfbf4887, 0x0d0d70fa, 0xb0b0b306, 0x7575de3f, + 0xd2d2fd5e, 0x7d7d20ba, 0x666631ae, 0x3a3aa35b, + 0x59591c8a, 0x00000000, 0xcdcd93bc, 0x1a1ae09d, + 0xaeae2c6d, 0x7f7fabc1, 0x2b2bc7b1, 0xbebeb90e, + 0xe0e0a080, 0x8a8a105d, 0x3b3b52d2, 0x6464bad5, + 0xd8d888a0, 0xe7e7a584, 0x5f5fe807, 0x1b1b1114, + 0x2c2cc2b5, 0xfcfcb490, 0x3131272c, 0x808065a3, + 0x73732ab2, 0x0c0c8173, 0x79795f4c, 0x6b6b4154, + 0x4b4b0292, 0x53536974, 0x94948f36, 0x83831f51, + 0x2a2a3638, 0xc4c49cb0, 0x2222c8bd, 0xd5d5f85a, + 0xbdbdc3fc, 0x48487860, 0xffffce62, 0x4c4c0796, + 0x4141776c, 0xc7c7e642, 0xebeb24f7, 0x1c1c1410, + 0x5d5d637c, 0x36362228, 0x6767c027, 0xe9e9af8c, + 0x4444f913, 0x1414ea95, 0xf5f5bb9c, 0xcfcf18c7, + 0x3f3f2d24, 0xc0c0e346, 0x7272db3b, 0x54546c70, + 0x29294cca, 0xf0f035e3, 0x0808fe85, 0xc6c617cb, + 0xf3f34f11, 0x8c8ce4d0, 0xa4a45993, 0xcaca96b8, + 0x68683ba6, 0xb8b84d83, 0x38382820, 0xe5e52eff, + 0xadad569f, 0x0b0b8477, 0xc8c81dc3, 0x9999ffcc, + 0x5858ed03, 0x19199a6f, 0x0e0e0a08, 0x95957ebf, + 0x70705040, 0xf7f730e7, 0x6e6ecf2b, 0x1f1f6ee2, + 0xb5b53d79, 0x09090f0c, 0x616134aa, 0x57571682, + 0x9f9f0b41, 0x9d9d803a, 0x111164ea, 0x2525cdb9, + 0xafafdde4, 0x4545089a, 0xdfdf8da4, 0xa3a35c97, + 0xeaead57e, 0x353558da, 0xededd07a, 0x4343fc17, + 0xf8f8cb66, 0xfbfbb194, 0x3737d3a1, 0xfafa401d, + 0xc2c2683d, 0xb4b4ccf0, 0x32325dde, 0x9c9c71b3, + 0x5656e70b, 0xe3e3da72, 0x878760a7, 0x15151b1c, + 0xf9f93aef, 0x6363bfd1, 0x3434a953, 0x9a9a853e, + 0xb1b1428f, 0x7c7cd133, 0x88889b26, 0x3d3da65f, + 0xa1a1d7ec, 0xe4e4df76, 0x8181942a, 0x91910149, + 0x0f0ffb81, 0xeeeeaa88, 0x161661ee, 0xd7d77321, + 0x9797f5c4, 0xa5a5a81a, 0xfefe3feb, 0x6d6db5d9, + 0x7878aec5, 0xc5c56d39, 0x1d1de599, 0x7676a4cd, + 0x3e3edcad, 0xcbcb6731, 0xb6b6478b, 0xefef5b01, + 0x12121e18, 0x6060c523, 0x6a6ab0dd, 0x4d4df61f, + 0xcecee94e, 0xdede7c2d, 0x55559df9, 0x7e7e5a48, + 0x2121b24f, 0x03037af2, 0xa0a02665, 0x5e5e198e, + 0x5a5a6678, 0x65654b5c, 0x62624e58, 0xfdfd4519, + 0x0606f48d, 0x404086e5, 0xf2f2be98, 0x3333ac57, + 0x17179067, 0x05058e7f, 0xe8e85e05, 0x4f4f7d64, + 0x89896aaf, 0x10109563, 0x74742fb6, 0x0a0a75fe, + 0x5c5c92f5, 0x9b9b74b7, 0x2d2d333c, 0x3030d6a5, + 0x2e2e49ce, 0x494989e9, 0x46467268, 0x77775544, + 0xa8a8d8e0, 0x9696044d, 0x2828bd43, 0xa9a92969, + 0xd9d97929, 0x8686912e, 0xd1d187ac, 0xf4f44a15, + 0x8d8d1559, 0xd6d682a8, 0xb9b9bc0a, 0x42420d9e, + 0xf6f6c16e, 0x2f2fb847, 0xdddd06df, 0x23233934, + 0xcccc6235, 0xf1f1c46a, 0xc1c112cf, 0x8585ebdc, + 0x8f8f9e22, 0x7171a1c9, 0x9090f0c0, 0xaaaa539b, + 0x0101f189, 0x8b8be1d4, 0x4e4e8ced, 0x8e8e6fab, + 0xababa212, 0x6f6f3ea2, 0xe6e6540d, 0xdbdbf252, + 0x92927bbb, 0xb7b7b602, 0x6969ca2f, 0x3939d9a9, + 0xd3d30cd7, 0xa7a72361, 0xa2a2ad1e, 0xc3c399b4, + 0x6c6c4450, 0x07070504, 0x04047ff6, 0x272746c2, + 0xacaca716, 0xd0d07625, 0x50501386, 0xdcdcf756, + 0x84841a55, 0xe1e15109, 0x7a7a25be, 0x1313ef91, + + 0xa9d93939, 0x67901717, 0xb3719c9c, 0xe8d2a6a6, + 0x04050707, 0xfd985252, 0xa3658080, 0x76dfe4e4, + 0x9a084545, 0x92024b4b, 0x80a0e0e0, 0x78665a5a, + 0xe4ddafaf, 0xddb06a6a, 0xd1bf6363, 0x38362a2a, + 0x0d54e6e6, 0xc6432020, 0x3562cccc, 0x98bef2f2, + 0x181e1212, 0xf724ebeb, 0xecd7a1a1, 0x6c774141, + 0x43bd2828, 0x7532bcbc, 0x37d47b7b, 0x269b8888, + 0xfa700d0d, 0x13f94444, 0x94b1fbfb, 0x485a7e7e, + 0xf27a0303, 0xd0e48c8c, 0x8b47b6b6, 0x303c2424, + 0x84a5e7e7, 0x54416b6b, 0xdf06dddd, 0x23c56060, + 0x1945fdfd, 0x5ba33a3a, 0x3d68c2c2, 0x59158d8d, + 0xf321ecec, 0xae316666, 0xa23e6f6f, 0x82165757, + 0x63951010, 0x015befef, 0x834db8b8, 0x2e918686, + 0xd9b56d6d, 0x511f8383, 0x9b53aaaa, 0x7c635d5d, + 0xa63b6868, 0xeb3ffefe, 0xa5d63030, 0xbe257a7a, + 0x16a7acac, 0x0c0f0909, 0xe335f0f0, 0x6123a7a7, + 0xc0f09090, 0x8cafe9e9, 0x3a809d9d, 0xf5925c5c, + 0x73810c0c, 0x2c273131, 0x2576d0d0, 0x0be75656, + 0xbb7b9292, 0x4ee9cece, 0x89f10101, 0x6b9f1e1e, + 0x53a93434, 0x6ac4f1f1, 0xb499c3c3, 0xf1975b5b, + 0xe1834747, 0xe66b1818, 0xbdc82222, 0x450e9898, + 0xe26e1f1f, 0xf4c9b3b3, 0xb62f7474, 0x66cbf8f8, + 0xccff9999, 0x95ea1414, 0x03ed5858, 0x56f7dcdc, + 0xd4e18b8b, 0x1c1b1515, 0x1eada2a2, 0xd70cd3d3, + 0xfb2be2e2, 0xc31dc8c8, 0x8e195e5e, 0xb5c22c2c, + 0xe9894949, 0xcf12c1c1, 0xbf7e9595, 0xba207d7d, + 0xea641111, 0x77840b0b, 0x396dc5c5, 0xaf6a8989, + 0x33d17c7c, 0xc9a17171, 0x62ceffff, 0x7137bbbb, + 0x81fb0f0f, 0x793db5b5, 0x0951e1e1, 0xaddc3e3e, + 0x242d3f3f, 0xcda47676, 0xf99d5555, 0xd8ee8282, + 0xe5864040, 0xc5ae7878, 0xb9cd2525, 0x4d049696, + 0x44557777, 0x080a0e0e, 0x86135050, 0xe730f7f7, + 0xa1d33737, 0x1d40fafa, 0xaa346161, 0xed8c4e4e, + 0x06b3b0b0, 0x706c5454, 0xb22a7373, 0xd2523b3b, + 0x410b9f9f, 0x7b8b0202, 0xa088d8d8, 0x114ff3f3, + 0x3167cbcb, 0xc2462727, 0x27c06767, 0x90b4fcfc, + 0x20283838, 0xf67f0404, 0x60784848, 0xff2ee5e5, + 0x96074c4c, 0x5c4b6565, 0xb1c72b2b, 0xab6f8e8e, + 0x9e0d4242, 0x9cbbf5f5, 0x52f2dbdb, 0x1bf34a4a, + 0x5fa63d3d, 0x9359a4a4, 0x0abcb9b9, 0xef3af9f9, + 0x91ef1313, 0x85fe0808, 0x49019191, 0xee611616, + 0x2d7cdede, 0x4fb22121, 0x8f42b1b1, 0x3bdb7272, + 0x47b82f2f, 0x8748bfbf, 0x6d2caeae, 0x46e3c0c0, + 0xd6573c3c, 0x3e859a9a, 0x6929a9a9, 0x647d4f4f, + 0x2a948181, 0xce492e2e, 0xcb17c6c6, 0x2fca6969, + 0xfcc3bdbd, 0x975ca3a3, 0x055ee8e8, 0x7ad0eded, + 0xac87d1d1, 0x7f8e0505, 0xd5ba6464, 0x1aa8a5a5, + 0x4bb72626, 0x0eb9bebe, 0xa7608787, 0x5af8d5d5, + 0x28223636, 0x14111b1b, 0x3fde7575, 0x2979d9d9, + 0x88aaeeee, 0x3c332d2d, 0x4c5f7979, 0x02b6b7b7, + 0xb896caca, 0xda583535, 0xb09cc4c4, 0x17fc4343, + 0x551a8484, 0x1ff64d4d, 0x8a1c5959, 0x7d38b2b2, + 0x57ac3333, 0xc718cfcf, 0x8df40606, 0x74695353, + 0xb7749b9b, 0xc4f59797, 0x9f56adad, 0x72dae3e3, + 0x7ed5eaea, 0x154af4f4, 0x229e8f8f, 0x12a2abab, + 0x584e6262, 0x07e85f5f, 0x99e51d1d, 0x34392323, + 0x6ec1f6f6, 0x50446c6c, 0xde5d3232, 0x68724646, + 0x6526a0a0, 0xbc93cdcd, 0xdb03dada, 0xf8c6baba, + 0xc8fa9e9e, 0xa882d6d6, 0x2bcf6e6e, 0x40507070, + 0xdceb8585, 0xfe750a0a, 0x328a9393, 0xa48ddfdf, + 0xca4c2929, 0x10141c1c, 0x2173d7d7, 0xf0ccb4b4, + 0xd309d4d4, 0x5d108a8a, 0x0fe25151, 0x00000000, + 0x6f9a1919, 0x9de01a1a, 0x368f9494, 0x42e6c7c7, + 0x4aecc9c9, 0x5efdd2d2, 0xc1ab7f7f, 0xe0d8a8a8, + + 0xbc75bc32, 0xecf3ec21, 0x20c62043, 0xb3f4b3c9, + 0xdadbda03, 0x027b028b, 0xe2fbe22b, 0x9ec89efa, + 0xc94ac9ec, 0xd4d3d409, 0x18e6186b, 0x1e6b1e9f, + 0x9845980e, 0xb27db238, 0xa6e8a6d2, 0x264b26b7, + 0x3cd63c57, 0x9332938a, 0x82d882ee, 0x52fd5298, + 0x7b377bd4, 0xbb71bb37, 0x5bf15b97, 0x47e14783, + 0x2430243c, 0x510f51e2, 0xbaf8bac6, 0x4a1b4af3, + 0xbf87bf48, 0x0dfa0d70, 0xb006b0b3, 0x753f75de, + 0xd25ed2fd, 0x7dba7d20, 0x66ae6631, 0x3a5b3aa3, + 0x598a591c, 0x00000000, 0xcdbccd93, 0x1a9d1ae0, + 0xae6dae2c, 0x7fc17fab, 0x2bb12bc7, 0xbe0ebeb9, + 0xe080e0a0, 0x8a5d8a10, 0x3bd23b52, 0x64d564ba, + 0xd8a0d888, 0xe784e7a5, 0x5f075fe8, 0x1b141b11, + 0x2cb52cc2, 0xfc90fcb4, 0x312c3127, 0x80a38065, + 0x73b2732a, 0x0c730c81, 0x794c795f, 0x6b546b41, + 0x4b924b02, 0x53745369, 0x9436948f, 0x8351831f, + 0x2a382a36, 0xc4b0c49c, 0x22bd22c8, 0xd55ad5f8, + 0xbdfcbdc3, 0x48604878, 0xff62ffce, 0x4c964c07, + 0x416c4177, 0xc742c7e6, 0xebf7eb24, 0x1c101c14, + 0x5d7c5d63, 0x36283622, 0x672767c0, 0xe98ce9af, + 0x441344f9, 0x149514ea, 0xf59cf5bb, 0xcfc7cf18, + 0x3f243f2d, 0xc046c0e3, 0x723b72db, 0x5470546c, + 0x29ca294c, 0xf0e3f035, 0x088508fe, 0xc6cbc617, + 0xf311f34f, 0x8cd08ce4, 0xa493a459, 0xcab8ca96, + 0x68a6683b, 0xb883b84d, 0x38203828, 0xe5ffe52e, + 0xad9fad56, 0x0b770b84, 0xc8c3c81d, 0x99cc99ff, + 0x580358ed, 0x196f199a, 0x0e080e0a, 0x95bf957e, + 0x70407050, 0xf7e7f730, 0x6e2b6ecf, 0x1fe21f6e, + 0xb579b53d, 0x090c090f, 0x61aa6134, 0x57825716, + 0x9f419f0b, 0x9d3a9d80, 0x11ea1164, 0x25b925cd, + 0xafe4afdd, 0x459a4508, 0xdfa4df8d, 0xa397a35c, + 0xea7eead5, 0x35da3558, 0xed7aedd0, 0x431743fc, + 0xf866f8cb, 0xfb94fbb1, 0x37a137d3, 0xfa1dfa40, + 0xc23dc268, 0xb4f0b4cc, 0x32de325d, 0x9cb39c71, + 0x560b56e7, 0xe372e3da, 0x87a78760, 0x151c151b, + 0xf9eff93a, 0x63d163bf, 0x345334a9, 0x9a3e9a85, + 0xb18fb142, 0x7c337cd1, 0x8826889b, 0x3d5f3da6, + 0xa1eca1d7, 0xe476e4df, 0x812a8194, 0x91499101, + 0x0f810ffb, 0xee88eeaa, 0x16ee1661, 0xd721d773, + 0x97c497f5, 0xa51aa5a8, 0xfeebfe3f, 0x6dd96db5, + 0x78c578ae, 0xc539c56d, 0x1d991de5, 0x76cd76a4, + 0x3ead3edc, 0xcb31cb67, 0xb68bb647, 0xef01ef5b, + 0x1218121e, 0x602360c5, 0x6add6ab0, 0x4d1f4df6, + 0xce4ecee9, 0xde2dde7c, 0x55f9559d, 0x7e487e5a, + 0x214f21b2, 0x03f2037a, 0xa065a026, 0x5e8e5e19, + 0x5a785a66, 0x655c654b, 0x6258624e, 0xfd19fd45, + 0x068d06f4, 0x40e54086, 0xf298f2be, 0x335733ac, + 0x17671790, 0x057f058e, 0xe805e85e, 0x4f644f7d, + 0x89af896a, 0x10631095, 0x74b6742f, 0x0afe0a75, + 0x5cf55c92, 0x9bb79b74, 0x2d3c2d33, 0x30a530d6, + 0x2ece2e49, 0x49e94989, 0x46684672, 0x77447755, + 0xa8e0a8d8, 0x964d9604, 0x284328bd, 0xa969a929, + 0xd929d979, 0x862e8691, 0xd1acd187, 0xf415f44a, + 0x8d598d15, 0xd6a8d682, 0xb90ab9bc, 0x429e420d, + 0xf66ef6c1, 0x2f472fb8, 0xdddfdd06, 0x23342339, + 0xcc35cc62, 0xf16af1c4, 0xc1cfc112, 0x85dc85eb, + 0x8f228f9e, 0x71c971a1, 0x90c090f0, 0xaa9baa53, + 0x018901f1, 0x8bd48be1, 0x4eed4e8c, 0x8eab8e6f, + 0xab12aba2, 0x6fa26f3e, 0xe60de654, 0xdb52dbf2, + 0x92bb927b, 0xb702b7b6, 0x692f69ca, 0x39a939d9, + 0xd3d7d30c, 0xa761a723, 0xa21ea2ad, 0xc3b4c399, + 0x6c506c44, 0x07040705, 0x04f6047f, 0x27c22746, + 0xac16aca7, 0xd025d076, 0x50865013, 0xdc56dcf7, + 0x8455841a, 0xe109e151, 0x7abe7a25, 0x139113ef, + + 0xd939a9d9, 0x90176790, 0x719cb371, 0xd2a6e8d2, + 0x05070405, 0x9852fd98, 0x6580a365, 0xdfe476df, + 0x08459a08, 0x024b9202, 0xa0e080a0, 0x665a7866, + 0xddafe4dd, 0xb06addb0, 0xbf63d1bf, 0x362a3836, + 0x54e60d54, 0x4320c643, 0x62cc3562, 0xbef298be, + 0x1e12181e, 0x24ebf724, 0xd7a1ecd7, 0x77416c77, + 0xbd2843bd, 0x32bc7532, 0xd47b37d4, 0x9b88269b, + 0x700dfa70, 0xf94413f9, 0xb1fb94b1, 0x5a7e485a, + 0x7a03f27a, 0xe48cd0e4, 0x47b68b47, 0x3c24303c, + 0xa5e784a5, 0x416b5441, 0x06dddf06, 0xc56023c5, + 0x45fd1945, 0xa33a5ba3, 0x68c23d68, 0x158d5915, + 0x21ecf321, 0x3166ae31, 0x3e6fa23e, 0x16578216, + 0x95106395, 0x5bef015b, 0x4db8834d, 0x91862e91, + 0xb56dd9b5, 0x1f83511f, 0x53aa9b53, 0x635d7c63, + 0x3b68a63b, 0x3ffeeb3f, 0xd630a5d6, 0x257abe25, + 0xa7ac16a7, 0x0f090c0f, 0x35f0e335, 0x23a76123, + 0xf090c0f0, 0xafe98caf, 0x809d3a80, 0x925cf592, + 0x810c7381, 0x27312c27, 0x76d02576, 0xe7560be7, + 0x7b92bb7b, 0xe9ce4ee9, 0xf10189f1, 0x9f1e6b9f, + 0xa93453a9, 0xc4f16ac4, 0x99c3b499, 0x975bf197, + 0x8347e183, 0x6b18e66b, 0xc822bdc8, 0x0e98450e, + 0x6e1fe26e, 0xc9b3f4c9, 0x2f74b62f, 0xcbf866cb, + 0xff99ccff, 0xea1495ea, 0xed5803ed, 0xf7dc56f7, + 0xe18bd4e1, 0x1b151c1b, 0xada21ead, 0x0cd3d70c, + 0x2be2fb2b, 0x1dc8c31d, 0x195e8e19, 0xc22cb5c2, + 0x8949e989, 0x12c1cf12, 0x7e95bf7e, 0x207dba20, + 0x6411ea64, 0x840b7784, 0x6dc5396d, 0x6a89af6a, + 0xd17c33d1, 0xa171c9a1, 0xceff62ce, 0x37bb7137, + 0xfb0f81fb, 0x3db5793d, 0x51e10951, 0xdc3eaddc, + 0x2d3f242d, 0xa476cda4, 0x9d55f99d, 0xee82d8ee, + 0x8640e586, 0xae78c5ae, 0xcd25b9cd, 0x04964d04, + 0x55774455, 0x0a0e080a, 0x13508613, 0x30f7e730, + 0xd337a1d3, 0x40fa1d40, 0x3461aa34, 0x8c4eed8c, + 0xb3b006b3, 0x6c54706c, 0x2a73b22a, 0x523bd252, + 0x0b9f410b, 0x8b027b8b, 0x88d8a088, 0x4ff3114f, + 0x67cb3167, 0x4627c246, 0xc06727c0, 0xb4fc90b4, + 0x28382028, 0x7f04f67f, 0x78486078, 0x2ee5ff2e, + 0x074c9607, 0x4b655c4b, 0xc72bb1c7, 0x6f8eab6f, + 0x0d429e0d, 0xbbf59cbb, 0xf2db52f2, 0xf34a1bf3, + 0xa63d5fa6, 0x59a49359, 0xbcb90abc, 0x3af9ef3a, + 0xef1391ef, 0xfe0885fe, 0x01914901, 0x6116ee61, + 0x7cde2d7c, 0xb2214fb2, 0x42b18f42, 0xdb723bdb, + 0xb82f47b8, 0x48bf8748, 0x2cae6d2c, 0xe3c046e3, + 0x573cd657, 0x859a3e85, 0x29a96929, 0x7d4f647d, + 0x94812a94, 0x492ece49, 0x17c6cb17, 0xca692fca, + 0xc3bdfcc3, 0x5ca3975c, 0x5ee8055e, 0xd0ed7ad0, + 0x87d1ac87, 0x8e057f8e, 0xba64d5ba, 0xa8a51aa8, + 0xb7264bb7, 0xb9be0eb9, 0x6087a760, 0xf8d55af8, + 0x22362822, 0x111b1411, 0xde753fde, 0x79d92979, + 0xaaee88aa, 0x332d3c33, 0x5f794c5f, 0xb6b702b6, + 0x96cab896, 0x5835da58, 0x9cc4b09c, 0xfc4317fc, + 0x1a84551a, 0xf64d1ff6, 0x1c598a1c, 0x38b27d38, + 0xac3357ac, 0x18cfc718, 0xf4068df4, 0x69537469, + 0x749bb774, 0xf597c4f5, 0x56ad9f56, 0xdae372da, + 0xd5ea7ed5, 0x4af4154a, 0x9e8f229e, 0xa2ab12a2, + 0x4e62584e, 0xe85f07e8, 0xe51d99e5, 0x39233439, + 0xc1f66ec1, 0x446c5044, 0x5d32de5d, 0x72466872, + 0x26a06526, 0x93cdbc93, 0x03dadb03, 0xc6baf8c6, + 0xfa9ec8fa, 0x82d6a882, 0xcf6e2bcf, 0x50704050, + 0xeb85dceb, 0x750afe75, 0x8a93328a, 0x8ddfa48d, + 0x4c29ca4c, 0x141c1014, 0x73d72173, 0xccb4f0cc, + 0x09d4d309, 0x108a5d10, 0xe2510fe2, 0x00000000, + 0x9a196f9a, 0xe01a9de0, 0x8f94368f, 0xe6c742e6, + 0xecc94aec, 0xfdd25efd, 0xab7fc1ab, 0xd8a8e0d8}; + +NAMESPACE_END diff --git a/tiger.cpp b/tiger.cpp new file mode 100644 index 0000000..1251974 --- /dev/null +++ b/tiger.cpp @@ -0,0 +1,95 @@ +// tiger.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "tiger.h" +#include "misc.h" + +#ifdef WORD64_AVAILABLE + +NAMESPACE_BEGIN(CryptoPP) + +void Tiger::Init() +{ + m_digest[0] = W64LIT(0x0123456789ABCDEF); + m_digest[1] = W64LIT(0xFEDCBA9876543210); + m_digest[2] = W64LIT(0xF096A5B4C3B2E187); +} + +void Tiger::TruncatedFinal(byte *hash, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(56, 0x01); + CorrectEndianess(m_data, m_data, 56); + + m_data[7] = GetBitCountLo(); + + Transform(m_digest, m_data); + CorrectEndianess(m_digest, m_digest, DigestSize()); + memcpy(hash, m_digest, size); + + Restart(); // reinit for next use +} + +#define t1 (table) +#define t2 (table+256) +#define t3 (table+256*2) +#define t4 (table+256*3) + +#define round(a,b,c,x,mul) \ + c ^= x; \ + a -= t1[GETBYTE(c,0)] ^ t2[GETBYTE(c,2)] ^ t3[GETBYTE(c,4)] ^ t4[GETBYTE(c,6)]; \ + b += t4[GETBYTE(c,1)] ^ t3[GETBYTE(c,3)] ^ t2[GETBYTE(c,5)] ^ t1[GETBYTE(c,7)]; \ + b *= mul + +#define pass(a,b,c,mul,X) \ + round(a,b,c,X[0],mul); \ + round(b,c,a,X[1],mul); \ + round(c,a,b,X[2],mul); \ + round(a,b,c,X[3],mul); \ + round(b,c,a,X[4],mul); \ + round(c,a,b,X[5],mul); \ + round(a,b,c,X[6],mul); \ + round(b,c,a,X[7],mul) + +#define key_schedule(Y,X) \ + Y[0] = X[0] - (X[7]^W64LIT(0xA5A5A5A5A5A5A5A5)); \ + Y[1] = X[1] ^ Y[0]; \ + Y[2] = X[2] + Y[1]; \ + Y[3] = X[3] - (Y[2] ^ ((~Y[1])<<19)); \ + Y[4] = X[4] ^ Y[3]; \ + Y[5] = X[5] + Y[4]; \ + Y[6] = X[6] - (Y[5] ^ ((~Y[4])>>23)); \ + Y[7] = X[7] ^ Y[6]; \ + Y[0] += Y[7]; \ + Y[1] -= Y[0] ^ ((~Y[7])<<19); \ + Y[2] ^= Y[1]; \ + Y[3] += Y[2]; \ + Y[4] -= Y[3] ^ ((~Y[2])>>23); \ + Y[5] ^= Y[4]; \ + Y[6] += Y[5]; \ + Y[7] -= Y[6] ^ W64LIT(0x0123456789ABCDEF) + +void Tiger::Transform (word64 *digest, const word64 *X) +{ + word64 a = digest[0]; + word64 b = digest[1]; + word64 c = digest[2]; + word64 Y[8]; + + pass(a,b,c,5,X); + key_schedule(Y,X); + pass(c,a,b,7,Y); + key_schedule(Y,Y); + pass(b,c,a,9,Y); + + digest[0] = a ^ digest[0]; + digest[1] = b - digest[1]; + digest[2] = c + digest[2]; + + Y[0] = Y[1] = Y[2] = Y[3] = Y[4] = Y[5] = Y[6] = Y[7] = 0; +} + +NAMESPACE_END + +#endif // WORD64_AVAILABLE @@ -0,0 +1,32 @@ +#ifndef CRYPTOPP_TIGER_H +#define CRYPTOPP_TIGER_H + +#include "config.h" + +#ifdef WORD64_AVAILABLE + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// <a href="http://www.weidai.com/scan-mirror/md.html#Tiger">Tiger</a> +class Tiger : public IteratedHashWithStaticTransform<word64, LittleEndian, 64, Tiger> +{ +public: + enum {DIGESTSIZE = 24}; + Tiger() : IteratedHashWithStaticTransform<word64, LittleEndian, 64, Tiger>(DIGESTSIZE) {Init();} + static void Transform(word64 *digest, const word64 *data); + void TruncatedFinal(byte *hash, unsigned int size); + static const char * StaticAlgorithmName() {return "Tiger";} + +protected: + void Init(); + + static const word64 table[4*256]; +}; + +NAMESPACE_END + +#endif + +#endif diff --git a/tigertab.cpp b/tigertab.cpp new file mode 100644 index 0000000..c6d543c --- /dev/null +++ b/tigertab.cpp @@ -0,0 +1,526 @@ +#include "pch.h" +#include "tiger.h" + +#ifdef WORD64_AVAILABLE + +NAMESPACE_BEGIN(CryptoPP) + +const word64 Tiger::table[4*256] = +{ + W64LIT(0x02AAB17CF7E90C5E) /* 0 */, W64LIT(0xAC424B03E243A8EC) /* 1 */, + W64LIT(0x72CD5BE30DD5FCD3) /* 2 */, W64LIT(0x6D019B93F6F97F3A) /* 3 */, + W64LIT(0xCD9978FFD21F9193) /* 4 */, W64LIT(0x7573A1C9708029E2) /* 5 */, + W64LIT(0xB164326B922A83C3) /* 6 */, W64LIT(0x46883EEE04915870) /* 7 */, + W64LIT(0xEAACE3057103ECE6) /* 8 */, W64LIT(0xC54169B808A3535C) /* 9 */, + W64LIT(0x4CE754918DDEC47C) /* 10 */, W64LIT(0x0AA2F4DFDC0DF40C) /* 11 */, + W64LIT(0x10B76F18A74DBEFA) /* 12 */, W64LIT(0xC6CCB6235AD1AB6A) /* 13 */, + W64LIT(0x13726121572FE2FF) /* 14 */, W64LIT(0x1A488C6F199D921E) /* 15 */, + W64LIT(0x4BC9F9F4DA0007CA) /* 16 */, W64LIT(0x26F5E6F6E85241C7) /* 17 */, + W64LIT(0x859079DBEA5947B6) /* 18 */, W64LIT(0x4F1885C5C99E8C92) /* 19 */, + W64LIT(0xD78E761EA96F864B) /* 20 */, W64LIT(0x8E36428C52B5C17D) /* 21 */, + W64LIT(0x69CF6827373063C1) /* 22 */, W64LIT(0xB607C93D9BB4C56E) /* 23 */, + W64LIT(0x7D820E760E76B5EA) /* 24 */, W64LIT(0x645C9CC6F07FDC42) /* 25 */, + W64LIT(0xBF38A078243342E0) /* 26 */, W64LIT(0x5F6B343C9D2E7D04) /* 27 */, + W64LIT(0xF2C28AEB600B0EC6) /* 28 */, W64LIT(0x6C0ED85F7254BCAC) /* 29 */, + W64LIT(0x71592281A4DB4FE5) /* 30 */, W64LIT(0x1967FA69CE0FED9F) /* 31 */, + W64LIT(0xFD5293F8B96545DB) /* 32 */, W64LIT(0xC879E9D7F2A7600B) /* 33 */, + W64LIT(0x860248920193194E) /* 34 */, W64LIT(0xA4F9533B2D9CC0B3) /* 35 */, + W64LIT(0x9053836C15957613) /* 36 */, W64LIT(0xDB6DCF8AFC357BF1) /* 37 */, + W64LIT(0x18BEEA7A7A370F57) /* 38 */, W64LIT(0x037117CA50B99066) /* 39 */, + W64LIT(0x6AB30A9774424A35) /* 40 */, W64LIT(0xF4E92F02E325249B) /* 41 */, + W64LIT(0x7739DB07061CCAE1) /* 42 */, W64LIT(0xD8F3B49CECA42A05) /* 43 */, + W64LIT(0xBD56BE3F51382F73) /* 44 */, W64LIT(0x45FAED5843B0BB28) /* 45 */, + W64LIT(0x1C813D5C11BF1F83) /* 46 */, W64LIT(0x8AF0E4B6D75FA169) /* 47 */, + W64LIT(0x33EE18A487AD9999) /* 48 */, W64LIT(0x3C26E8EAB1C94410) /* 49 */, + W64LIT(0xB510102BC0A822F9) /* 50 */, W64LIT(0x141EEF310CE6123B) /* 51 */, + W64LIT(0xFC65B90059DDB154) /* 52 */, W64LIT(0xE0158640C5E0E607) /* 53 */, + W64LIT(0x884E079826C3A3CF) /* 54 */, W64LIT(0x930D0D9523C535FD) /* 55 */, + W64LIT(0x35638D754E9A2B00) /* 56 */, W64LIT(0x4085FCCF40469DD5) /* 57 */, + W64LIT(0xC4B17AD28BE23A4C) /* 58 */, W64LIT(0xCAB2F0FC6A3E6A2E) /* 59 */, + W64LIT(0x2860971A6B943FCD) /* 60 */, W64LIT(0x3DDE6EE212E30446) /* 61 */, + W64LIT(0x6222F32AE01765AE) /* 62 */, W64LIT(0x5D550BB5478308FE) /* 63 */, + W64LIT(0xA9EFA98DA0EDA22A) /* 64 */, W64LIT(0xC351A71686C40DA7) /* 65 */, + W64LIT(0x1105586D9C867C84) /* 66 */, W64LIT(0xDCFFEE85FDA22853) /* 67 */, + W64LIT(0xCCFBD0262C5EEF76) /* 68 */, W64LIT(0xBAF294CB8990D201) /* 69 */, + W64LIT(0xE69464F52AFAD975) /* 70 */, W64LIT(0x94B013AFDF133E14) /* 71 */, + W64LIT(0x06A7D1A32823C958) /* 72 */, W64LIT(0x6F95FE5130F61119) /* 73 */, + W64LIT(0xD92AB34E462C06C0) /* 74 */, W64LIT(0xED7BDE33887C71D2) /* 75 */, + W64LIT(0x79746D6E6518393E) /* 76 */, W64LIT(0x5BA419385D713329) /* 77 */, + W64LIT(0x7C1BA6B948A97564) /* 78 */, W64LIT(0x31987C197BFDAC67) /* 79 */, + W64LIT(0xDE6C23C44B053D02) /* 80 */, W64LIT(0x581C49FED002D64D) /* 81 */, + W64LIT(0xDD474D6338261571) /* 82 */, W64LIT(0xAA4546C3E473D062) /* 83 */, + W64LIT(0x928FCE349455F860) /* 84 */, W64LIT(0x48161BBACAAB94D9) /* 85 */, + W64LIT(0x63912430770E6F68) /* 86 */, W64LIT(0x6EC8A5E602C6641C) /* 87 */, + W64LIT(0x87282515337DDD2B) /* 88 */, W64LIT(0x2CDA6B42034B701B) /* 89 */, + W64LIT(0xB03D37C181CB096D) /* 90 */, W64LIT(0xE108438266C71C6F) /* 91 */, + W64LIT(0x2B3180C7EB51B255) /* 92 */, W64LIT(0xDF92B82F96C08BBC) /* 93 */, + W64LIT(0x5C68C8C0A632F3BA) /* 94 */, W64LIT(0x5504CC861C3D0556) /* 95 */, + W64LIT(0xABBFA4E55FB26B8F) /* 96 */, W64LIT(0x41848B0AB3BACEB4) /* 97 */, + W64LIT(0xB334A273AA445D32) /* 98 */, W64LIT(0xBCA696F0A85AD881) /* 99 */, + W64LIT(0x24F6EC65B528D56C) /* 100 */, W64LIT(0x0CE1512E90F4524A) /* 101 */, + W64LIT(0x4E9DD79D5506D35A) /* 102 */, W64LIT(0x258905FAC6CE9779) /* 103 */, + W64LIT(0x2019295B3E109B33) /* 104 */, W64LIT(0xF8A9478B73A054CC) /* 105 */, + W64LIT(0x2924F2F934417EB0) /* 106 */, W64LIT(0x3993357D536D1BC4) /* 107 */, + W64LIT(0x38A81AC21DB6FF8B) /* 108 */, W64LIT(0x47C4FBF17D6016BF) /* 109 */, + W64LIT(0x1E0FAADD7667E3F5) /* 110 */, W64LIT(0x7ABCFF62938BEB96) /* 111 */, + W64LIT(0xA78DAD948FC179C9) /* 112 */, W64LIT(0x8F1F98B72911E50D) /* 113 */, + W64LIT(0x61E48EAE27121A91) /* 114 */, W64LIT(0x4D62F7AD31859808) /* 115 */, + W64LIT(0xECEBA345EF5CEAEB) /* 116 */, W64LIT(0xF5CEB25EBC9684CE) /* 117 */, + W64LIT(0xF633E20CB7F76221) /* 118 */, W64LIT(0xA32CDF06AB8293E4) /* 119 */, + W64LIT(0x985A202CA5EE2CA4) /* 120 */, W64LIT(0xCF0B8447CC8A8FB1) /* 121 */, + W64LIT(0x9F765244979859A3) /* 122 */, W64LIT(0xA8D516B1A1240017) /* 123 */, + W64LIT(0x0BD7BA3EBB5DC726) /* 124 */, W64LIT(0xE54BCA55B86ADB39) /* 125 */, + W64LIT(0x1D7A3AFD6C478063) /* 126 */, W64LIT(0x519EC608E7669EDD) /* 127 */, + W64LIT(0x0E5715A2D149AA23) /* 128 */, W64LIT(0x177D4571848FF194) /* 129 */, + W64LIT(0xEEB55F3241014C22) /* 130 */, W64LIT(0x0F5E5CA13A6E2EC2) /* 131 */, + W64LIT(0x8029927B75F5C361) /* 132 */, W64LIT(0xAD139FABC3D6E436) /* 133 */, + W64LIT(0x0D5DF1A94CCF402F) /* 134 */, W64LIT(0x3E8BD948BEA5DFC8) /* 135 */, + W64LIT(0xA5A0D357BD3FF77E) /* 136 */, W64LIT(0xA2D12E251F74F645) /* 137 */, + W64LIT(0x66FD9E525E81A082) /* 138 */, W64LIT(0x2E0C90CE7F687A49) /* 139 */, + W64LIT(0xC2E8BCBEBA973BC5) /* 140 */, W64LIT(0x000001BCE509745F) /* 141 */, + W64LIT(0x423777BBE6DAB3D6) /* 142 */, W64LIT(0xD1661C7EAEF06EB5) /* 143 */, + W64LIT(0xA1781F354DAACFD8) /* 144 */, W64LIT(0x2D11284A2B16AFFC) /* 145 */, + W64LIT(0xF1FC4F67FA891D1F) /* 146 */, W64LIT(0x73ECC25DCB920ADA) /* 147 */, + W64LIT(0xAE610C22C2A12651) /* 148 */, W64LIT(0x96E0A810D356B78A) /* 149 */, + W64LIT(0x5A9A381F2FE7870F) /* 150 */, W64LIT(0xD5AD62EDE94E5530) /* 151 */, + W64LIT(0xD225E5E8368D1427) /* 152 */, W64LIT(0x65977B70C7AF4631) /* 153 */, + W64LIT(0x99F889B2DE39D74F) /* 154 */, W64LIT(0x233F30BF54E1D143) /* 155 */, + W64LIT(0x9A9675D3D9A63C97) /* 156 */, W64LIT(0x5470554FF334F9A8) /* 157 */, + W64LIT(0x166ACB744A4F5688) /* 158 */, W64LIT(0x70C74CAAB2E4AEAD) /* 159 */, + W64LIT(0xF0D091646F294D12) /* 160 */, W64LIT(0x57B82A89684031D1) /* 161 */, + W64LIT(0xEFD95A5A61BE0B6B) /* 162 */, W64LIT(0x2FBD12E969F2F29A) /* 163 */, + W64LIT(0x9BD37013FEFF9FE8) /* 164 */, W64LIT(0x3F9B0404D6085A06) /* 165 */, + W64LIT(0x4940C1F3166CFE15) /* 166 */, W64LIT(0x09542C4DCDF3DEFB) /* 167 */, + W64LIT(0xB4C5218385CD5CE3) /* 168 */, W64LIT(0xC935B7DC4462A641) /* 169 */, + W64LIT(0x3417F8A68ED3B63F) /* 170 */, W64LIT(0xB80959295B215B40) /* 171 */, + W64LIT(0xF99CDAEF3B8C8572) /* 172 */, W64LIT(0x018C0614F8FCB95D) /* 173 */, + W64LIT(0x1B14ACCD1A3ACDF3) /* 174 */, W64LIT(0x84D471F200BB732D) /* 175 */, + W64LIT(0xC1A3110E95E8DA16) /* 176 */, W64LIT(0x430A7220BF1A82B8) /* 177 */, + W64LIT(0xB77E090D39DF210E) /* 178 */, W64LIT(0x5EF4BD9F3CD05E9D) /* 179 */, + W64LIT(0x9D4FF6DA7E57A444) /* 180 */, W64LIT(0xDA1D60E183D4A5F8) /* 181 */, + W64LIT(0xB287C38417998E47) /* 182 */, W64LIT(0xFE3EDC121BB31886) /* 183 */, + W64LIT(0xC7FE3CCC980CCBEF) /* 184 */, W64LIT(0xE46FB590189BFD03) /* 185 */, + W64LIT(0x3732FD469A4C57DC) /* 186 */, W64LIT(0x7EF700A07CF1AD65) /* 187 */, + W64LIT(0x59C64468A31D8859) /* 188 */, W64LIT(0x762FB0B4D45B61F6) /* 189 */, + W64LIT(0x155BAED099047718) /* 190 */, W64LIT(0x68755E4C3D50BAA6) /* 191 */, + W64LIT(0xE9214E7F22D8B4DF) /* 192 */, W64LIT(0x2ADDBF532EAC95F4) /* 193 */, + W64LIT(0x32AE3909B4BD0109) /* 194 */, W64LIT(0x834DF537B08E3450) /* 195 */, + W64LIT(0xFA209DA84220728D) /* 196 */, W64LIT(0x9E691D9B9EFE23F7) /* 197 */, + W64LIT(0x0446D288C4AE8D7F) /* 198 */, W64LIT(0x7B4CC524E169785B) /* 199 */, + W64LIT(0x21D87F0135CA1385) /* 200 */, W64LIT(0xCEBB400F137B8AA5) /* 201 */, + W64LIT(0x272E2B66580796BE) /* 202 */, W64LIT(0x3612264125C2B0DE) /* 203 */, + W64LIT(0x057702BDAD1EFBB2) /* 204 */, W64LIT(0xD4BABB8EACF84BE9) /* 205 */, + W64LIT(0x91583139641BC67B) /* 206 */, W64LIT(0x8BDC2DE08036E024) /* 207 */, + W64LIT(0x603C8156F49F68ED) /* 208 */, W64LIT(0xF7D236F7DBEF5111) /* 209 */, + W64LIT(0x9727C4598AD21E80) /* 210 */, W64LIT(0xA08A0896670A5FD7) /* 211 */, + W64LIT(0xCB4A8F4309EBA9CB) /* 212 */, W64LIT(0x81AF564B0F7036A1) /* 213 */, + W64LIT(0xC0B99AA778199ABD) /* 214 */, W64LIT(0x959F1EC83FC8E952) /* 215 */, + W64LIT(0x8C505077794A81B9) /* 216 */, W64LIT(0x3ACAAF8F056338F0) /* 217 */, + W64LIT(0x07B43F50627A6778) /* 218 */, W64LIT(0x4A44AB49F5ECCC77) /* 219 */, + W64LIT(0x3BC3D6E4B679EE98) /* 220 */, W64LIT(0x9CC0D4D1CF14108C) /* 221 */, + W64LIT(0x4406C00B206BC8A0) /* 222 */, W64LIT(0x82A18854C8D72D89) /* 223 */, + W64LIT(0x67E366B35C3C432C) /* 224 */, W64LIT(0xB923DD61102B37F2) /* 225 */, + W64LIT(0x56AB2779D884271D) /* 226 */, W64LIT(0xBE83E1B0FF1525AF) /* 227 */, + W64LIT(0xFB7C65D4217E49A9) /* 228 */, W64LIT(0x6BDBE0E76D48E7D4) /* 229 */, + W64LIT(0x08DF828745D9179E) /* 230 */, W64LIT(0x22EA6A9ADD53BD34) /* 231 */, + W64LIT(0xE36E141C5622200A) /* 232 */, W64LIT(0x7F805D1B8CB750EE) /* 233 */, + W64LIT(0xAFE5C7A59F58E837) /* 234 */, W64LIT(0xE27F996A4FB1C23C) /* 235 */, + W64LIT(0xD3867DFB0775F0D0) /* 236 */, W64LIT(0xD0E673DE6E88891A) /* 237 */, + W64LIT(0x123AEB9EAFB86C25) /* 238 */, W64LIT(0x30F1D5D5C145B895) /* 239 */, + W64LIT(0xBB434A2DEE7269E7) /* 240 */, W64LIT(0x78CB67ECF931FA38) /* 241 */, + W64LIT(0xF33B0372323BBF9C) /* 242 */, W64LIT(0x52D66336FB279C74) /* 243 */, + W64LIT(0x505F33AC0AFB4EAA) /* 244 */, W64LIT(0xE8A5CD99A2CCE187) /* 245 */, + W64LIT(0x534974801E2D30BB) /* 246 */, W64LIT(0x8D2D5711D5876D90) /* 247 */, + W64LIT(0x1F1A412891BC038E) /* 248 */, W64LIT(0xD6E2E71D82E56648) /* 249 */, + W64LIT(0x74036C3A497732B7) /* 250 */, W64LIT(0x89B67ED96361F5AB) /* 251 */, + W64LIT(0xFFED95D8F1EA02A2) /* 252 */, W64LIT(0xE72B3BD61464D43D) /* 253 */, + W64LIT(0xA6300F170BDC4820) /* 254 */, W64LIT(0xEBC18760ED78A77A) /* 255 */, + W64LIT(0xE6A6BE5A05A12138) /* 256 */, W64LIT(0xB5A122A5B4F87C98) /* 257 */, + W64LIT(0x563C6089140B6990) /* 258 */, W64LIT(0x4C46CB2E391F5DD5) /* 259 */, + W64LIT(0xD932ADDBC9B79434) /* 260 */, W64LIT(0x08EA70E42015AFF5) /* 261 */, + W64LIT(0xD765A6673E478CF1) /* 262 */, W64LIT(0xC4FB757EAB278D99) /* 263 */, + W64LIT(0xDF11C6862D6E0692) /* 264 */, W64LIT(0xDDEB84F10D7F3B16) /* 265 */, + W64LIT(0x6F2EF604A665EA04) /* 266 */, W64LIT(0x4A8E0F0FF0E0DFB3) /* 267 */, + W64LIT(0xA5EDEEF83DBCBA51) /* 268 */, W64LIT(0xFC4F0A2A0EA4371E) /* 269 */, + W64LIT(0xE83E1DA85CB38429) /* 270 */, W64LIT(0xDC8FF882BA1B1CE2) /* 271 */, + W64LIT(0xCD45505E8353E80D) /* 272 */, W64LIT(0x18D19A00D4DB0717) /* 273 */, + W64LIT(0x34A0CFEDA5F38101) /* 274 */, W64LIT(0x0BE77E518887CAF2) /* 275 */, + W64LIT(0x1E341438B3C45136) /* 276 */, W64LIT(0xE05797F49089CCF9) /* 277 */, + W64LIT(0xFFD23F9DF2591D14) /* 278 */, W64LIT(0x543DDA228595C5CD) /* 279 */, + W64LIT(0x661F81FD99052A33) /* 280 */, W64LIT(0x8736E641DB0F7B76) /* 281 */, + W64LIT(0x15227725418E5307) /* 282 */, W64LIT(0xE25F7F46162EB2FA) /* 283 */, + W64LIT(0x48A8B2126C13D9FE) /* 284 */, W64LIT(0xAFDC541792E76EEA) /* 285 */, + W64LIT(0x03D912BFC6D1898F) /* 286 */, W64LIT(0x31B1AAFA1B83F51B) /* 287 */, + W64LIT(0xF1AC2796E42AB7D9) /* 288 */, W64LIT(0x40A3A7D7FCD2EBAC) /* 289 */, + W64LIT(0x1056136D0AFBBCC5) /* 290 */, W64LIT(0x7889E1DD9A6D0C85) /* 291 */, + W64LIT(0xD33525782A7974AA) /* 292 */, W64LIT(0xA7E25D09078AC09B) /* 293 */, + W64LIT(0xBD4138B3EAC6EDD0) /* 294 */, W64LIT(0x920ABFBE71EB9E70) /* 295 */, + W64LIT(0xA2A5D0F54FC2625C) /* 296 */, W64LIT(0xC054E36B0B1290A3) /* 297 */, + W64LIT(0xF6DD59FF62FE932B) /* 298 */, W64LIT(0x3537354511A8AC7D) /* 299 */, + W64LIT(0xCA845E9172FADCD4) /* 300 */, W64LIT(0x84F82B60329D20DC) /* 301 */, + W64LIT(0x79C62CE1CD672F18) /* 302 */, W64LIT(0x8B09A2ADD124642C) /* 303 */, + W64LIT(0xD0C1E96A19D9E726) /* 304 */, W64LIT(0x5A786A9B4BA9500C) /* 305 */, + W64LIT(0x0E020336634C43F3) /* 306 */, W64LIT(0xC17B474AEB66D822) /* 307 */, + W64LIT(0x6A731AE3EC9BAAC2) /* 308 */, W64LIT(0x8226667AE0840258) /* 309 */, + W64LIT(0x67D4567691CAECA5) /* 310 */, W64LIT(0x1D94155C4875ADB5) /* 311 */, + W64LIT(0x6D00FD985B813FDF) /* 312 */, W64LIT(0x51286EFCB774CD06) /* 313 */, + W64LIT(0x5E8834471FA744AF) /* 314 */, W64LIT(0xF72CA0AEE761AE2E) /* 315 */, + W64LIT(0xBE40E4CDAEE8E09A) /* 316 */, W64LIT(0xE9970BBB5118F665) /* 317 */, + W64LIT(0x726E4BEB33DF1964) /* 318 */, W64LIT(0x703B000729199762) /* 319 */, + W64LIT(0x4631D816F5EF30A7) /* 320 */, W64LIT(0xB880B5B51504A6BE) /* 321 */, + W64LIT(0x641793C37ED84B6C) /* 322 */, W64LIT(0x7B21ED77F6E97D96) /* 323 */, + W64LIT(0x776306312EF96B73) /* 324 */, W64LIT(0xAE528948E86FF3F4) /* 325 */, + W64LIT(0x53DBD7F286A3F8F8) /* 326 */, W64LIT(0x16CADCE74CFC1063) /* 327 */, + W64LIT(0x005C19BDFA52C6DD) /* 328 */, W64LIT(0x68868F5D64D46AD3) /* 329 */, + W64LIT(0x3A9D512CCF1E186A) /* 330 */, W64LIT(0x367E62C2385660AE) /* 331 */, + W64LIT(0xE359E7EA77DCB1D7) /* 332 */, W64LIT(0x526C0773749ABE6E) /* 333 */, + W64LIT(0x735AE5F9D09F734B) /* 334 */, W64LIT(0x493FC7CC8A558BA8) /* 335 */, + W64LIT(0xB0B9C1533041AB45) /* 336 */, W64LIT(0x321958BA470A59BD) /* 337 */, + W64LIT(0x852DB00B5F46C393) /* 338 */, W64LIT(0x91209B2BD336B0E5) /* 339 */, + W64LIT(0x6E604F7D659EF19F) /* 340 */, W64LIT(0xB99A8AE2782CCB24) /* 341 */, + W64LIT(0xCCF52AB6C814C4C7) /* 342 */, W64LIT(0x4727D9AFBE11727B) /* 343 */, + W64LIT(0x7E950D0C0121B34D) /* 344 */, W64LIT(0x756F435670AD471F) /* 345 */, + W64LIT(0xF5ADD442615A6849) /* 346 */, W64LIT(0x4E87E09980B9957A) /* 347 */, + W64LIT(0x2ACFA1DF50AEE355) /* 348 */, W64LIT(0xD898263AFD2FD556) /* 349 */, + W64LIT(0xC8F4924DD80C8FD6) /* 350 */, W64LIT(0xCF99CA3D754A173A) /* 351 */, + W64LIT(0xFE477BACAF91BF3C) /* 352 */, W64LIT(0xED5371F6D690C12D) /* 353 */, + W64LIT(0x831A5C285E687094) /* 354 */, W64LIT(0xC5D3C90A3708A0A4) /* 355 */, + W64LIT(0x0F7F903717D06580) /* 356 */, W64LIT(0x19F9BB13B8FDF27F) /* 357 */, + W64LIT(0xB1BD6F1B4D502843) /* 358 */, W64LIT(0x1C761BA38FFF4012) /* 359 */, + W64LIT(0x0D1530C4E2E21F3B) /* 360 */, W64LIT(0x8943CE69A7372C8A) /* 361 */, + W64LIT(0xE5184E11FEB5CE66) /* 362 */, W64LIT(0x618BDB80BD736621) /* 363 */, + W64LIT(0x7D29BAD68B574D0B) /* 364 */, W64LIT(0x81BB613E25E6FE5B) /* 365 */, + W64LIT(0x071C9C10BC07913F) /* 366 */, W64LIT(0xC7BEEB7909AC2D97) /* 367 */, + W64LIT(0xC3E58D353BC5D757) /* 368 */, W64LIT(0xEB017892F38F61E8) /* 369 */, + W64LIT(0xD4EFFB9C9B1CC21A) /* 370 */, W64LIT(0x99727D26F494F7AB) /* 371 */, + W64LIT(0xA3E063A2956B3E03) /* 372 */, W64LIT(0x9D4A8B9A4AA09C30) /* 373 */, + W64LIT(0x3F6AB7D500090FB4) /* 374 */, W64LIT(0x9CC0F2A057268AC0) /* 375 */, + W64LIT(0x3DEE9D2DEDBF42D1) /* 376 */, W64LIT(0x330F49C87960A972) /* 377 */, + W64LIT(0xC6B2720287421B41) /* 378 */, W64LIT(0x0AC59EC07C00369C) /* 379 */, + W64LIT(0xEF4EAC49CB353425) /* 380 */, W64LIT(0xF450244EEF0129D8) /* 381 */, + W64LIT(0x8ACC46E5CAF4DEB6) /* 382 */, W64LIT(0x2FFEAB63989263F7) /* 383 */, + W64LIT(0x8F7CB9FE5D7A4578) /* 384 */, W64LIT(0x5BD8F7644E634635) /* 385 */, + W64LIT(0x427A7315BF2DC900) /* 386 */, W64LIT(0x17D0C4AA2125261C) /* 387 */, + W64LIT(0x3992486C93518E50) /* 388 */, W64LIT(0xB4CBFEE0A2D7D4C3) /* 389 */, + W64LIT(0x7C75D6202C5DDD8D) /* 390 */, W64LIT(0xDBC295D8E35B6C61) /* 391 */, + W64LIT(0x60B369D302032B19) /* 392 */, W64LIT(0xCE42685FDCE44132) /* 393 */, + W64LIT(0x06F3DDB9DDF65610) /* 394 */, W64LIT(0x8EA4D21DB5E148F0) /* 395 */, + W64LIT(0x20B0FCE62FCD496F) /* 396 */, W64LIT(0x2C1B912358B0EE31) /* 397 */, + W64LIT(0xB28317B818F5A308) /* 398 */, W64LIT(0xA89C1E189CA6D2CF) /* 399 */, + W64LIT(0x0C6B18576AAADBC8) /* 400 */, W64LIT(0xB65DEAA91299FAE3) /* 401 */, + W64LIT(0xFB2B794B7F1027E7) /* 402 */, W64LIT(0x04E4317F443B5BEB) /* 403 */, + W64LIT(0x4B852D325939D0A6) /* 404 */, W64LIT(0xD5AE6BEEFB207FFC) /* 405 */, + W64LIT(0x309682B281C7D374) /* 406 */, W64LIT(0xBAE309A194C3B475) /* 407 */, + W64LIT(0x8CC3F97B13B49F05) /* 408 */, W64LIT(0x98A9422FF8293967) /* 409 */, + W64LIT(0x244B16B01076FF7C) /* 410 */, W64LIT(0xF8BF571C663D67EE) /* 411 */, + W64LIT(0x1F0D6758EEE30DA1) /* 412 */, W64LIT(0xC9B611D97ADEB9B7) /* 413 */, + W64LIT(0xB7AFD5887B6C57A2) /* 414 */, W64LIT(0x6290AE846B984FE1) /* 415 */, + W64LIT(0x94DF4CDEACC1A5FD) /* 416 */, W64LIT(0x058A5BD1C5483AFF) /* 417 */, + W64LIT(0x63166CC142BA3C37) /* 418 */, W64LIT(0x8DB8526EB2F76F40) /* 419 */, + W64LIT(0xE10880036F0D6D4E) /* 420 */, W64LIT(0x9E0523C9971D311D) /* 421 */, + W64LIT(0x45EC2824CC7CD691) /* 422 */, W64LIT(0x575B8359E62382C9) /* 423 */, + W64LIT(0xFA9E400DC4889995) /* 424 */, W64LIT(0xD1823ECB45721568) /* 425 */, + W64LIT(0xDAFD983B8206082F) /* 426 */, W64LIT(0xAA7D29082386A8CB) /* 427 */, + W64LIT(0x269FCD4403B87588) /* 428 */, W64LIT(0x1B91F5F728BDD1E0) /* 429 */, + W64LIT(0xE4669F39040201F6) /* 430 */, W64LIT(0x7A1D7C218CF04ADE) /* 431 */, + W64LIT(0x65623C29D79CE5CE) /* 432 */, W64LIT(0x2368449096C00BB1) /* 433 */, + W64LIT(0xAB9BF1879DA503BA) /* 434 */, W64LIT(0xBC23ECB1A458058E) /* 435 */, + W64LIT(0x9A58DF01BB401ECC) /* 436 */, W64LIT(0xA070E868A85F143D) /* 437 */, + W64LIT(0x4FF188307DF2239E) /* 438 */, W64LIT(0x14D565B41A641183) /* 439 */, + W64LIT(0xEE13337452701602) /* 440 */, W64LIT(0x950E3DCF3F285E09) /* 441 */, + W64LIT(0x59930254B9C80953) /* 442 */, W64LIT(0x3BF299408930DA6D) /* 443 */, + W64LIT(0xA955943F53691387) /* 444 */, W64LIT(0xA15EDECAA9CB8784) /* 445 */, + W64LIT(0x29142127352BE9A0) /* 446 */, W64LIT(0x76F0371FFF4E7AFB) /* 447 */, + W64LIT(0x0239F450274F2228) /* 448 */, W64LIT(0xBB073AF01D5E868B) /* 449 */, + W64LIT(0xBFC80571C10E96C1) /* 450 */, W64LIT(0xD267088568222E23) /* 451 */, + W64LIT(0x9671A3D48E80B5B0) /* 452 */, W64LIT(0x55B5D38AE193BB81) /* 453 */, + W64LIT(0x693AE2D0A18B04B8) /* 454 */, W64LIT(0x5C48B4ECADD5335F) /* 455 */, + W64LIT(0xFD743B194916A1CA) /* 456 */, W64LIT(0x2577018134BE98C4) /* 457 */, + W64LIT(0xE77987E83C54A4AD) /* 458 */, W64LIT(0x28E11014DA33E1B9) /* 459 */, + W64LIT(0x270CC59E226AA213) /* 460 */, W64LIT(0x71495F756D1A5F60) /* 461 */, + W64LIT(0x9BE853FB60AFEF77) /* 462 */, W64LIT(0xADC786A7F7443DBF) /* 463 */, + W64LIT(0x0904456173B29A82) /* 464 */, W64LIT(0x58BC7A66C232BD5E) /* 465 */, + W64LIT(0xF306558C673AC8B2) /* 466 */, W64LIT(0x41F639C6B6C9772A) /* 467 */, + W64LIT(0x216DEFE99FDA35DA) /* 468 */, W64LIT(0x11640CC71C7BE615) /* 469 */, + W64LIT(0x93C43694565C5527) /* 470 */, W64LIT(0xEA038E6246777839) /* 471 */, + W64LIT(0xF9ABF3CE5A3E2469) /* 472 */, W64LIT(0x741E768D0FD312D2) /* 473 */, + W64LIT(0x0144B883CED652C6) /* 474 */, W64LIT(0xC20B5A5BA33F8552) /* 475 */, + W64LIT(0x1AE69633C3435A9D) /* 476 */, W64LIT(0x97A28CA4088CFDEC) /* 477 */, + W64LIT(0x8824A43C1E96F420) /* 478 */, W64LIT(0x37612FA66EEEA746) /* 479 */, + W64LIT(0x6B4CB165F9CF0E5A) /* 480 */, W64LIT(0x43AA1C06A0ABFB4A) /* 481 */, + W64LIT(0x7F4DC26FF162796B) /* 482 */, W64LIT(0x6CBACC8E54ED9B0F) /* 483 */, + W64LIT(0xA6B7FFEFD2BB253E) /* 484 */, W64LIT(0x2E25BC95B0A29D4F) /* 485 */, + W64LIT(0x86D6A58BDEF1388C) /* 486 */, W64LIT(0xDED74AC576B6F054) /* 487 */, + W64LIT(0x8030BDBC2B45805D) /* 488 */, W64LIT(0x3C81AF70E94D9289) /* 489 */, + W64LIT(0x3EFF6DDA9E3100DB) /* 490 */, W64LIT(0xB38DC39FDFCC8847) /* 491 */, + W64LIT(0x123885528D17B87E) /* 492 */, W64LIT(0xF2DA0ED240B1B642) /* 493 */, + W64LIT(0x44CEFADCD54BF9A9) /* 494 */, W64LIT(0x1312200E433C7EE6) /* 495 */, + W64LIT(0x9FFCC84F3A78C748) /* 496 */, W64LIT(0xF0CD1F72248576BB) /* 497 */, + W64LIT(0xEC6974053638CFE4) /* 498 */, W64LIT(0x2BA7B67C0CEC4E4C) /* 499 */, + W64LIT(0xAC2F4DF3E5CE32ED) /* 500 */, W64LIT(0xCB33D14326EA4C11) /* 501 */, + W64LIT(0xA4E9044CC77E58BC) /* 502 */, W64LIT(0x5F513293D934FCEF) /* 503 */, + W64LIT(0x5DC9645506E55444) /* 504 */, W64LIT(0x50DE418F317DE40A) /* 505 */, + W64LIT(0x388CB31A69DDE259) /* 506 */, W64LIT(0x2DB4A83455820A86) /* 507 */, + W64LIT(0x9010A91E84711AE9) /* 508 */, W64LIT(0x4DF7F0B7B1498371) /* 509 */, + W64LIT(0xD62A2EABC0977179) /* 510 */, W64LIT(0x22FAC097AA8D5C0E) /* 511 */, + W64LIT(0xF49FCC2FF1DAF39B) /* 512 */, W64LIT(0x487FD5C66FF29281) /* 513 */, + W64LIT(0xE8A30667FCDCA83F) /* 514 */, W64LIT(0x2C9B4BE3D2FCCE63) /* 515 */, + W64LIT(0xDA3FF74B93FBBBC2) /* 516 */, W64LIT(0x2FA165D2FE70BA66) /* 517 */, + W64LIT(0xA103E279970E93D4) /* 518 */, W64LIT(0xBECDEC77B0E45E71) /* 519 */, + W64LIT(0xCFB41E723985E497) /* 520 */, W64LIT(0xB70AAA025EF75017) /* 521 */, + W64LIT(0xD42309F03840B8E0) /* 522 */, W64LIT(0x8EFC1AD035898579) /* 523 */, + W64LIT(0x96C6920BE2B2ABC5) /* 524 */, W64LIT(0x66AF4163375A9172) /* 525 */, + W64LIT(0x2174ABDCCA7127FB) /* 526 */, W64LIT(0xB33CCEA64A72FF41) /* 527 */, + W64LIT(0xF04A4933083066A5) /* 528 */, W64LIT(0x8D970ACDD7289AF5) /* 529 */, + W64LIT(0x8F96E8E031C8C25E) /* 530 */, W64LIT(0xF3FEC02276875D47) /* 531 */, + W64LIT(0xEC7BF310056190DD) /* 532 */, W64LIT(0xF5ADB0AEBB0F1491) /* 533 */, + W64LIT(0x9B50F8850FD58892) /* 534 */, W64LIT(0x4975488358B74DE8) /* 535 */, + W64LIT(0xA3354FF691531C61) /* 536 */, W64LIT(0x0702BBE481D2C6EE) /* 537 */, + W64LIT(0x89FB24057DEDED98) /* 538 */, W64LIT(0xAC3075138596E902) /* 539 */, + W64LIT(0x1D2D3580172772ED) /* 540 */, W64LIT(0xEB738FC28E6BC30D) /* 541 */, + W64LIT(0x5854EF8F63044326) /* 542 */, W64LIT(0x9E5C52325ADD3BBE) /* 543 */, + W64LIT(0x90AA53CF325C4623) /* 544 */, W64LIT(0xC1D24D51349DD067) /* 545 */, + W64LIT(0x2051CFEEA69EA624) /* 546 */, W64LIT(0x13220F0A862E7E4F) /* 547 */, + W64LIT(0xCE39399404E04864) /* 548 */, W64LIT(0xD9C42CA47086FCB7) /* 549 */, + W64LIT(0x685AD2238A03E7CC) /* 550 */, W64LIT(0x066484B2AB2FF1DB) /* 551 */, + W64LIT(0xFE9D5D70EFBF79EC) /* 552 */, W64LIT(0x5B13B9DD9C481854) /* 553 */, + W64LIT(0x15F0D475ED1509AD) /* 554 */, W64LIT(0x0BEBCD060EC79851) /* 555 */, + W64LIT(0xD58C6791183AB7F8) /* 556 */, W64LIT(0xD1187C5052F3EEE4) /* 557 */, + W64LIT(0xC95D1192E54E82FF) /* 558 */, W64LIT(0x86EEA14CB9AC6CA2) /* 559 */, + W64LIT(0x3485BEB153677D5D) /* 560 */, W64LIT(0xDD191D781F8C492A) /* 561 */, + W64LIT(0xF60866BAA784EBF9) /* 562 */, W64LIT(0x518F643BA2D08C74) /* 563 */, + W64LIT(0x8852E956E1087C22) /* 564 */, W64LIT(0xA768CB8DC410AE8D) /* 565 */, + W64LIT(0x38047726BFEC8E1A) /* 566 */, W64LIT(0xA67738B4CD3B45AA) /* 567 */, + W64LIT(0xAD16691CEC0DDE19) /* 568 */, W64LIT(0xC6D4319380462E07) /* 569 */, + W64LIT(0xC5A5876D0BA61938) /* 570 */, W64LIT(0x16B9FA1FA58FD840) /* 571 */, + W64LIT(0x188AB1173CA74F18) /* 572 */, W64LIT(0xABDA2F98C99C021F) /* 573 */, + W64LIT(0x3E0580AB134AE816) /* 574 */, W64LIT(0x5F3B05B773645ABB) /* 575 */, + W64LIT(0x2501A2BE5575F2F6) /* 576 */, W64LIT(0x1B2F74004E7E8BA9) /* 577 */, + W64LIT(0x1CD7580371E8D953) /* 578 */, W64LIT(0x7F6ED89562764E30) /* 579 */, + W64LIT(0xB15926FF596F003D) /* 580 */, W64LIT(0x9F65293DA8C5D6B9) /* 581 */, + W64LIT(0x6ECEF04DD690F84C) /* 582 */, W64LIT(0x4782275FFF33AF88) /* 583 */, + W64LIT(0xE41433083F820801) /* 584 */, W64LIT(0xFD0DFE409A1AF9B5) /* 585 */, + W64LIT(0x4325A3342CDB396B) /* 586 */, W64LIT(0x8AE77E62B301B252) /* 587 */, + W64LIT(0xC36F9E9F6655615A) /* 588 */, W64LIT(0x85455A2D92D32C09) /* 589 */, + W64LIT(0xF2C7DEA949477485) /* 590 */, W64LIT(0x63CFB4C133A39EBA) /* 591 */, + W64LIT(0x83B040CC6EBC5462) /* 592 */, W64LIT(0x3B9454C8FDB326B0) /* 593 */, + W64LIT(0x56F56A9E87FFD78C) /* 594 */, W64LIT(0x2DC2940D99F42BC6) /* 595 */, + W64LIT(0x98F7DF096B096E2D) /* 596 */, W64LIT(0x19A6E01E3AD852BF) /* 597 */, + W64LIT(0x42A99CCBDBD4B40B) /* 598 */, W64LIT(0xA59998AF45E9C559) /* 599 */, + W64LIT(0x366295E807D93186) /* 600 */, W64LIT(0x6B48181BFAA1F773) /* 601 */, + W64LIT(0x1FEC57E2157A0A1D) /* 602 */, W64LIT(0x4667446AF6201AD5) /* 603 */, + W64LIT(0xE615EBCACFB0F075) /* 604 */, W64LIT(0xB8F31F4F68290778) /* 605 */, + W64LIT(0x22713ED6CE22D11E) /* 606 */, W64LIT(0x3057C1A72EC3C93B) /* 607 */, + W64LIT(0xCB46ACC37C3F1F2F) /* 608 */, W64LIT(0xDBB893FD02AAF50E) /* 609 */, + W64LIT(0x331FD92E600B9FCF) /* 610 */, W64LIT(0xA498F96148EA3AD6) /* 611 */, + W64LIT(0xA8D8426E8B6A83EA) /* 612 */, W64LIT(0xA089B274B7735CDC) /* 613 */, + W64LIT(0x87F6B3731E524A11) /* 614 */, W64LIT(0x118808E5CBC96749) /* 615 */, + W64LIT(0x9906E4C7B19BD394) /* 616 */, W64LIT(0xAFED7F7E9B24A20C) /* 617 */, + W64LIT(0x6509EADEEB3644A7) /* 618 */, W64LIT(0x6C1EF1D3E8EF0EDE) /* 619 */, + W64LIT(0xB9C97D43E9798FB4) /* 620 */, W64LIT(0xA2F2D784740C28A3) /* 621 */, + W64LIT(0x7B8496476197566F) /* 622 */, W64LIT(0x7A5BE3E6B65F069D) /* 623 */, + W64LIT(0xF96330ED78BE6F10) /* 624 */, W64LIT(0xEEE60DE77A076A15) /* 625 */, + W64LIT(0x2B4BEE4AA08B9BD0) /* 626 */, W64LIT(0x6A56A63EC7B8894E) /* 627 */, + W64LIT(0x02121359BA34FEF4) /* 628 */, W64LIT(0x4CBF99F8283703FC) /* 629 */, + W64LIT(0x398071350CAF30C8) /* 630 */, W64LIT(0xD0A77A89F017687A) /* 631 */, + W64LIT(0xF1C1A9EB9E423569) /* 632 */, W64LIT(0x8C7976282DEE8199) /* 633 */, + W64LIT(0x5D1737A5DD1F7ABD) /* 634 */, W64LIT(0x4F53433C09A9FA80) /* 635 */, + W64LIT(0xFA8B0C53DF7CA1D9) /* 636 */, W64LIT(0x3FD9DCBC886CCB77) /* 637 */, + W64LIT(0xC040917CA91B4720) /* 638 */, W64LIT(0x7DD00142F9D1DCDF) /* 639 */, + W64LIT(0x8476FC1D4F387B58) /* 640 */, W64LIT(0x23F8E7C5F3316503) /* 641 */, + W64LIT(0x032A2244E7E37339) /* 642 */, W64LIT(0x5C87A5D750F5A74B) /* 643 */, + W64LIT(0x082B4CC43698992E) /* 644 */, W64LIT(0xDF917BECB858F63C) /* 645 */, + W64LIT(0x3270B8FC5BF86DDA) /* 646 */, W64LIT(0x10AE72BB29B5DD76) /* 647 */, + W64LIT(0x576AC94E7700362B) /* 648 */, W64LIT(0x1AD112DAC61EFB8F) /* 649 */, + W64LIT(0x691BC30EC5FAA427) /* 650 */, W64LIT(0xFF246311CC327143) /* 651 */, + W64LIT(0x3142368E30E53206) /* 652 */, W64LIT(0x71380E31E02CA396) /* 653 */, + W64LIT(0x958D5C960AAD76F1) /* 654 */, W64LIT(0xF8D6F430C16DA536) /* 655 */, + W64LIT(0xC8FFD13F1BE7E1D2) /* 656 */, W64LIT(0x7578AE66004DDBE1) /* 657 */, + W64LIT(0x05833F01067BE646) /* 658 */, W64LIT(0xBB34B5AD3BFE586D) /* 659 */, + W64LIT(0x095F34C9A12B97F0) /* 660 */, W64LIT(0x247AB64525D60CA8) /* 661 */, + W64LIT(0xDCDBC6F3017477D1) /* 662 */, W64LIT(0x4A2E14D4DECAD24D) /* 663 */, + W64LIT(0xBDB5E6D9BE0A1EEB) /* 664 */, W64LIT(0x2A7E70F7794301AB) /* 665 */, + W64LIT(0xDEF42D8A270540FD) /* 666 */, W64LIT(0x01078EC0A34C22C1) /* 667 */, + W64LIT(0xE5DE511AF4C16387) /* 668 */, W64LIT(0x7EBB3A52BD9A330A) /* 669 */, + W64LIT(0x77697857AA7D6435) /* 670 */, W64LIT(0x004E831603AE4C32) /* 671 */, + W64LIT(0xE7A21020AD78E312) /* 672 */, W64LIT(0x9D41A70C6AB420F2) /* 673 */, + W64LIT(0x28E06C18EA1141E6) /* 674 */, W64LIT(0xD2B28CBD984F6B28) /* 675 */, + W64LIT(0x26B75F6C446E9D83) /* 676 */, W64LIT(0xBA47568C4D418D7F) /* 677 */, + W64LIT(0xD80BADBFE6183D8E) /* 678 */, W64LIT(0x0E206D7F5F166044) /* 679 */, + W64LIT(0xE258A43911CBCA3E) /* 680 */, W64LIT(0x723A1746B21DC0BC) /* 681 */, + W64LIT(0xC7CAA854F5D7CDD3) /* 682 */, W64LIT(0x7CAC32883D261D9C) /* 683 */, + W64LIT(0x7690C26423BA942C) /* 684 */, W64LIT(0x17E55524478042B8) /* 685 */, + W64LIT(0xE0BE477656A2389F) /* 686 */, W64LIT(0x4D289B5E67AB2DA0) /* 687 */, + W64LIT(0x44862B9C8FBBFD31) /* 688 */, W64LIT(0xB47CC8049D141365) /* 689 */, + W64LIT(0x822C1B362B91C793) /* 690 */, W64LIT(0x4EB14655FB13DFD8) /* 691 */, + W64LIT(0x1ECBBA0714E2A97B) /* 692 */, W64LIT(0x6143459D5CDE5F14) /* 693 */, + W64LIT(0x53A8FBF1D5F0AC89) /* 694 */, W64LIT(0x97EA04D81C5E5B00) /* 695 */, + W64LIT(0x622181A8D4FDB3F3) /* 696 */, W64LIT(0xE9BCD341572A1208) /* 697 */, + W64LIT(0x1411258643CCE58A) /* 698 */, W64LIT(0x9144C5FEA4C6E0A4) /* 699 */, + W64LIT(0x0D33D06565CF620F) /* 700 */, W64LIT(0x54A48D489F219CA1) /* 701 */, + W64LIT(0xC43E5EAC6D63C821) /* 702 */, W64LIT(0xA9728B3A72770DAF) /* 703 */, + W64LIT(0xD7934E7B20DF87EF) /* 704 */, W64LIT(0xE35503B61A3E86E5) /* 705 */, + W64LIT(0xCAE321FBC819D504) /* 706 */, W64LIT(0x129A50B3AC60BFA6) /* 707 */, + W64LIT(0xCD5E68EA7E9FB6C3) /* 708 */, W64LIT(0xB01C90199483B1C7) /* 709 */, + W64LIT(0x3DE93CD5C295376C) /* 710 */, W64LIT(0xAED52EDF2AB9AD13) /* 711 */, + W64LIT(0x2E60F512C0A07884) /* 712 */, W64LIT(0xBC3D86A3E36210C9) /* 713 */, + W64LIT(0x35269D9B163951CE) /* 714 */, W64LIT(0x0C7D6E2AD0CDB5FA) /* 715 */, + W64LIT(0x59E86297D87F5733) /* 716 */, W64LIT(0x298EF221898DB0E7) /* 717 */, + W64LIT(0x55000029D1A5AA7E) /* 718 */, W64LIT(0x8BC08AE1B5061B45) /* 719 */, + W64LIT(0xC2C31C2B6C92703A) /* 720 */, W64LIT(0x94CC596BAF25EF42) /* 721 */, + W64LIT(0x0A1D73DB22540456) /* 722 */, W64LIT(0x04B6A0F9D9C4179A) /* 723 */, + W64LIT(0xEFFDAFA2AE3D3C60) /* 724 */, W64LIT(0xF7C8075BB49496C4) /* 725 */, + W64LIT(0x9CC5C7141D1CD4E3) /* 726 */, W64LIT(0x78BD1638218E5534) /* 727 */, + W64LIT(0xB2F11568F850246A) /* 728 */, W64LIT(0xEDFABCFA9502BC29) /* 729 */, + W64LIT(0x796CE5F2DA23051B) /* 730 */, W64LIT(0xAAE128B0DC93537C) /* 731 */, + W64LIT(0x3A493DA0EE4B29AE) /* 732 */, W64LIT(0xB5DF6B2C416895D7) /* 733 */, + W64LIT(0xFCABBD25122D7F37) /* 734 */, W64LIT(0x70810B58105DC4B1) /* 735 */, + W64LIT(0xE10FDD37F7882A90) /* 736 */, W64LIT(0x524DCAB5518A3F5C) /* 737 */, + W64LIT(0x3C9E85878451255B) /* 738 */, W64LIT(0x4029828119BD34E2) /* 739 */, + W64LIT(0x74A05B6F5D3CECCB) /* 740 */, W64LIT(0xB610021542E13ECA) /* 741 */, + W64LIT(0x0FF979D12F59E2AC) /* 742 */, W64LIT(0x6037DA27E4F9CC50) /* 743 */, + W64LIT(0x5E92975A0DF1847D) /* 744 */, W64LIT(0xD66DE190D3E623FE) /* 745 */, + W64LIT(0x5032D6B87B568048) /* 746 */, W64LIT(0x9A36B7CE8235216E) /* 747 */, + W64LIT(0x80272A7A24F64B4A) /* 748 */, W64LIT(0x93EFED8B8C6916F7) /* 749 */, + W64LIT(0x37DDBFF44CCE1555) /* 750 */, W64LIT(0x4B95DB5D4B99BD25) /* 751 */, + W64LIT(0x92D3FDA169812FC0) /* 752 */, W64LIT(0xFB1A4A9A90660BB6) /* 753 */, + W64LIT(0x730C196946A4B9B2) /* 754 */, W64LIT(0x81E289AA7F49DA68) /* 755 */, + W64LIT(0x64669A0F83B1A05F) /* 756 */, W64LIT(0x27B3FF7D9644F48B) /* 757 */, + W64LIT(0xCC6B615C8DB675B3) /* 758 */, W64LIT(0x674F20B9BCEBBE95) /* 759 */, + W64LIT(0x6F31238275655982) /* 760 */, W64LIT(0x5AE488713E45CF05) /* 761 */, + W64LIT(0xBF619F9954C21157) /* 762 */, W64LIT(0xEABAC46040A8EAE9) /* 763 */, + W64LIT(0x454C6FE9F2C0C1CD) /* 764 */, W64LIT(0x419CF6496412691C) /* 765 */, + W64LIT(0xD3DC3BEF265B0F70) /* 766 */, W64LIT(0x6D0E60F5C3578A9E) /* 767 */, + W64LIT(0x5B0E608526323C55) /* 768 */, W64LIT(0x1A46C1A9FA1B59F5) /* 769 */, + W64LIT(0xA9E245A17C4C8FFA) /* 770 */, W64LIT(0x65CA5159DB2955D7) /* 771 */, + W64LIT(0x05DB0A76CE35AFC2) /* 772 */, W64LIT(0x81EAC77EA9113D45) /* 773 */, + W64LIT(0x528EF88AB6AC0A0D) /* 774 */, W64LIT(0xA09EA253597BE3FF) /* 775 */, + W64LIT(0x430DDFB3AC48CD56) /* 776 */, W64LIT(0xC4B3A67AF45CE46F) /* 777 */, + W64LIT(0x4ECECFD8FBE2D05E) /* 778 */, W64LIT(0x3EF56F10B39935F0) /* 779 */, + W64LIT(0x0B22D6829CD619C6) /* 780 */, W64LIT(0x17FD460A74DF2069) /* 781 */, + W64LIT(0x6CF8CC8E8510ED40) /* 782 */, W64LIT(0xD6C824BF3A6ECAA7) /* 783 */, + W64LIT(0x61243D581A817049) /* 784 */, W64LIT(0x048BACB6BBC163A2) /* 785 */, + W64LIT(0xD9A38AC27D44CC32) /* 786 */, W64LIT(0x7FDDFF5BAAF410AB) /* 787 */, + W64LIT(0xAD6D495AA804824B) /* 788 */, W64LIT(0xE1A6A74F2D8C9F94) /* 789 */, + W64LIT(0xD4F7851235DEE8E3) /* 790 */, W64LIT(0xFD4B7F886540D893) /* 791 */, + W64LIT(0x247C20042AA4BFDA) /* 792 */, W64LIT(0x096EA1C517D1327C) /* 793 */, + W64LIT(0xD56966B4361A6685) /* 794 */, W64LIT(0x277DA5C31221057D) /* 795 */, + W64LIT(0x94D59893A43ACFF7) /* 796 */, W64LIT(0x64F0C51CCDC02281) /* 797 */, + W64LIT(0x3D33BCC4FF6189DB) /* 798 */, W64LIT(0xE005CB184CE66AF1) /* 799 */, + W64LIT(0xFF5CCD1D1DB99BEA) /* 800 */, W64LIT(0xB0B854A7FE42980F) /* 801 */, + W64LIT(0x7BD46A6A718D4B9F) /* 802 */, W64LIT(0xD10FA8CC22A5FD8C) /* 803 */, + W64LIT(0xD31484952BE4BD31) /* 804 */, W64LIT(0xC7FA975FCB243847) /* 805 */, + W64LIT(0x4886ED1E5846C407) /* 806 */, W64LIT(0x28CDDB791EB70B04) /* 807 */, + W64LIT(0xC2B00BE2F573417F) /* 808 */, W64LIT(0x5C9590452180F877) /* 809 */, + W64LIT(0x7A6BDDFFF370EB00) /* 810 */, W64LIT(0xCE509E38D6D9D6A4) /* 811 */, + W64LIT(0xEBEB0F00647FA702) /* 812 */, W64LIT(0x1DCC06CF76606F06) /* 813 */, + W64LIT(0xE4D9F28BA286FF0A) /* 814 */, W64LIT(0xD85A305DC918C262) /* 815 */, + W64LIT(0x475B1D8732225F54) /* 816 */, W64LIT(0x2D4FB51668CCB5FE) /* 817 */, + W64LIT(0xA679B9D9D72BBA20) /* 818 */, W64LIT(0x53841C0D912D43A5) /* 819 */, + W64LIT(0x3B7EAA48BF12A4E8) /* 820 */, W64LIT(0x781E0E47F22F1DDF) /* 821 */, + W64LIT(0xEFF20CE60AB50973) /* 822 */, W64LIT(0x20D261D19DFFB742) /* 823 */, + W64LIT(0x16A12B03062A2E39) /* 824 */, W64LIT(0x1960EB2239650495) /* 825 */, + W64LIT(0x251C16FED50EB8B8) /* 826 */, W64LIT(0x9AC0C330F826016E) /* 827 */, + W64LIT(0xED152665953E7671) /* 828 */, W64LIT(0x02D63194A6369570) /* 829 */, + W64LIT(0x5074F08394B1C987) /* 830 */, W64LIT(0x70BA598C90B25CE1) /* 831 */, + W64LIT(0x794A15810B9742F6) /* 832 */, W64LIT(0x0D5925E9FCAF8C6C) /* 833 */, + W64LIT(0x3067716CD868744E) /* 834 */, W64LIT(0x910AB077E8D7731B) /* 835 */, + W64LIT(0x6A61BBDB5AC42F61) /* 836 */, W64LIT(0x93513EFBF0851567) /* 837 */, + W64LIT(0xF494724B9E83E9D5) /* 838 */, W64LIT(0xE887E1985C09648D) /* 839 */, + W64LIT(0x34B1D3C675370CFD) /* 840 */, W64LIT(0xDC35E433BC0D255D) /* 841 */, + W64LIT(0xD0AAB84234131BE0) /* 842 */, W64LIT(0x08042A50B48B7EAF) /* 843 */, + W64LIT(0x9997C4EE44A3AB35) /* 844 */, W64LIT(0x829A7B49201799D0) /* 845 */, + W64LIT(0x263B8307B7C54441) /* 846 */, W64LIT(0x752F95F4FD6A6CA6) /* 847 */, + W64LIT(0x927217402C08C6E5) /* 848 */, W64LIT(0x2A8AB754A795D9EE) /* 849 */, + W64LIT(0xA442F7552F72943D) /* 850 */, W64LIT(0x2C31334E19781208) /* 851 */, + W64LIT(0x4FA98D7CEAEE6291) /* 852 */, W64LIT(0x55C3862F665DB309) /* 853 */, + W64LIT(0xBD0610175D53B1F3) /* 854 */, W64LIT(0x46FE6CB840413F27) /* 855 */, + W64LIT(0x3FE03792DF0CFA59) /* 856 */, W64LIT(0xCFE700372EB85E8F) /* 857 */, + W64LIT(0xA7BE29E7ADBCE118) /* 858 */, W64LIT(0xE544EE5CDE8431DD) /* 859 */, + W64LIT(0x8A781B1B41F1873E) /* 860 */, W64LIT(0xA5C94C78A0D2F0E7) /* 861 */, + W64LIT(0x39412E2877B60728) /* 862 */, W64LIT(0xA1265EF3AFC9A62C) /* 863 */, + W64LIT(0xBCC2770C6A2506C5) /* 864 */, W64LIT(0x3AB66DD5DCE1CE12) /* 865 */, + W64LIT(0xE65499D04A675B37) /* 866 */, W64LIT(0x7D8F523481BFD216) /* 867 */, + W64LIT(0x0F6F64FCEC15F389) /* 868 */, W64LIT(0x74EFBE618B5B13C8) /* 869 */, + W64LIT(0xACDC82B714273E1D) /* 870 */, W64LIT(0xDD40BFE003199D17) /* 871 */, + W64LIT(0x37E99257E7E061F8) /* 872 */, W64LIT(0xFA52626904775AAA) /* 873 */, + W64LIT(0x8BBBF63A463D56F9) /* 874 */, W64LIT(0xF0013F1543A26E64) /* 875 */, + W64LIT(0xA8307E9F879EC898) /* 876 */, W64LIT(0xCC4C27A4150177CC) /* 877 */, + W64LIT(0x1B432F2CCA1D3348) /* 878 */, W64LIT(0xDE1D1F8F9F6FA013) /* 879 */, + W64LIT(0x606602A047A7DDD6) /* 880 */, W64LIT(0xD237AB64CC1CB2C7) /* 881 */, + W64LIT(0x9B938E7225FCD1D3) /* 882 */, W64LIT(0xEC4E03708E0FF476) /* 883 */, + W64LIT(0xFEB2FBDA3D03C12D) /* 884 */, W64LIT(0xAE0BCED2EE43889A) /* 885 */, + W64LIT(0x22CB8923EBFB4F43) /* 886 */, W64LIT(0x69360D013CF7396D) /* 887 */, + W64LIT(0x855E3602D2D4E022) /* 888 */, W64LIT(0x073805BAD01F784C) /* 889 */, + W64LIT(0x33E17A133852F546) /* 890 */, W64LIT(0xDF4874058AC7B638) /* 891 */, + W64LIT(0xBA92B29C678AA14A) /* 892 */, W64LIT(0x0CE89FC76CFAADCD) /* 893 */, + W64LIT(0x5F9D4E0908339E34) /* 894 */, W64LIT(0xF1AFE9291F5923B9) /* 895 */, + W64LIT(0x6E3480F60F4A265F) /* 896 */, W64LIT(0xEEBF3A2AB29B841C) /* 897 */, + W64LIT(0xE21938A88F91B4AD) /* 898 */, W64LIT(0x57DFEFF845C6D3C3) /* 899 */, + W64LIT(0x2F006B0BF62CAAF2) /* 900 */, W64LIT(0x62F479EF6F75EE78) /* 901 */, + W64LIT(0x11A55AD41C8916A9) /* 902 */, W64LIT(0xF229D29084FED453) /* 903 */, + W64LIT(0x42F1C27B16B000E6) /* 904 */, W64LIT(0x2B1F76749823C074) /* 905 */, + W64LIT(0x4B76ECA3C2745360) /* 906 */, W64LIT(0x8C98F463B91691BD) /* 907 */, + W64LIT(0x14BCC93CF1ADE66A) /* 908 */, W64LIT(0x8885213E6D458397) /* 909 */, + W64LIT(0x8E177DF0274D4711) /* 910 */, W64LIT(0xB49B73B5503F2951) /* 911 */, + W64LIT(0x10168168C3F96B6B) /* 912 */, W64LIT(0x0E3D963B63CAB0AE) /* 913 */, + W64LIT(0x8DFC4B5655A1DB14) /* 914 */, W64LIT(0xF789F1356E14DE5C) /* 915 */, + W64LIT(0x683E68AF4E51DAC1) /* 916 */, W64LIT(0xC9A84F9D8D4B0FD9) /* 917 */, + W64LIT(0x3691E03F52A0F9D1) /* 918 */, W64LIT(0x5ED86E46E1878E80) /* 919 */, + W64LIT(0x3C711A0E99D07150) /* 920 */, W64LIT(0x5A0865B20C4E9310) /* 921 */, + W64LIT(0x56FBFC1FE4F0682E) /* 922 */, W64LIT(0xEA8D5DE3105EDF9B) /* 923 */, + W64LIT(0x71ABFDB12379187A) /* 924 */, W64LIT(0x2EB99DE1BEE77B9C) /* 925 */, + W64LIT(0x21ECC0EA33CF4523) /* 926 */, W64LIT(0x59A4D7521805C7A1) /* 927 */, + W64LIT(0x3896F5EB56AE7C72) /* 928 */, W64LIT(0xAA638F3DB18F75DC) /* 929 */, + W64LIT(0x9F39358DABE9808E) /* 930 */, W64LIT(0xB7DEFA91C00B72AC) /* 931 */, + W64LIT(0x6B5541FD62492D92) /* 932 */, W64LIT(0x6DC6DEE8F92E4D5B) /* 933 */, + W64LIT(0x353F57ABC4BEEA7E) /* 934 */, W64LIT(0x735769D6DA5690CE) /* 935 */, + W64LIT(0x0A234AA642391484) /* 936 */, W64LIT(0xF6F9508028F80D9D) /* 937 */, + W64LIT(0xB8E319A27AB3F215) /* 938 */, W64LIT(0x31AD9C1151341A4D) /* 939 */, + W64LIT(0x773C22A57BEF5805) /* 940 */, W64LIT(0x45C7561A07968633) /* 941 */, + W64LIT(0xF913DA9E249DBE36) /* 942 */, W64LIT(0xDA652D9B78A64C68) /* 943 */, + W64LIT(0x4C27A97F3BC334EF) /* 944 */, W64LIT(0x76621220E66B17F4) /* 945 */, + W64LIT(0x967743899ACD7D0B) /* 946 */, W64LIT(0xF3EE5BCAE0ED6782) /* 947 */, + W64LIT(0x409F753600C879FC) /* 948 */, W64LIT(0x06D09A39B5926DB6) /* 949 */, + W64LIT(0x6F83AEB0317AC588) /* 950 */, W64LIT(0x01E6CA4A86381F21) /* 951 */, + W64LIT(0x66FF3462D19F3025) /* 952 */, W64LIT(0x72207C24DDFD3BFB) /* 953 */, + W64LIT(0x4AF6B6D3E2ECE2EB) /* 954 */, W64LIT(0x9C994DBEC7EA08DE) /* 955 */, + W64LIT(0x49ACE597B09A8BC4) /* 956 */, W64LIT(0xB38C4766CF0797BA) /* 957 */, + W64LIT(0x131B9373C57C2A75) /* 958 */, W64LIT(0xB1822CCE61931E58) /* 959 */, + W64LIT(0x9D7555B909BA1C0C) /* 960 */, W64LIT(0x127FAFDD937D11D2) /* 961 */, + W64LIT(0x29DA3BADC66D92E4) /* 962 */, W64LIT(0xA2C1D57154C2ECBC) /* 963 */, + W64LIT(0x58C5134D82F6FE24) /* 964 */, W64LIT(0x1C3AE3515B62274F) /* 965 */, + W64LIT(0xE907C82E01CB8126) /* 966 */, W64LIT(0xF8ED091913E37FCB) /* 967 */, + W64LIT(0x3249D8F9C80046C9) /* 968 */, W64LIT(0x80CF9BEDE388FB63) /* 969 */, + W64LIT(0x1881539A116CF19E) /* 970 */, W64LIT(0x5103F3F76BD52457) /* 971 */, + W64LIT(0x15B7E6F5AE47F7A8) /* 972 */, W64LIT(0xDBD7C6DED47E9CCF) /* 973 */, + W64LIT(0x44E55C410228BB1A) /* 974 */, W64LIT(0xB647D4255EDB4E99) /* 975 */, + W64LIT(0x5D11882BB8AAFC30) /* 976 */, W64LIT(0xF5098BBB29D3212A) /* 977 */, + W64LIT(0x8FB5EA14E90296B3) /* 978 */, W64LIT(0x677B942157DD025A) /* 979 */, + W64LIT(0xFB58E7C0A390ACB5) /* 980 */, W64LIT(0x89D3674C83BD4A01) /* 981 */, + W64LIT(0x9E2DA4DF4BF3B93B) /* 982 */, W64LIT(0xFCC41E328CAB4829) /* 983 */, + W64LIT(0x03F38C96BA582C52) /* 984 */, W64LIT(0xCAD1BDBD7FD85DB2) /* 985 */, + W64LIT(0xBBB442C16082AE83) /* 986 */, W64LIT(0xB95FE86BA5DA9AB0) /* 987 */, + W64LIT(0xB22E04673771A93F) /* 988 */, W64LIT(0x845358C9493152D8) /* 989 */, + W64LIT(0xBE2A488697B4541E) /* 990 */, W64LIT(0x95A2DC2DD38E6966) /* 991 */, + W64LIT(0xC02C11AC923C852B) /* 992 */, W64LIT(0x2388B1990DF2A87B) /* 993 */, + W64LIT(0x7C8008FA1B4F37BE) /* 994 */, W64LIT(0x1F70D0C84D54E503) /* 995 */, + W64LIT(0x5490ADEC7ECE57D4) /* 996 */, W64LIT(0x002B3C27D9063A3A) /* 997 */, + W64LIT(0x7EAEA3848030A2BF) /* 998 */, W64LIT(0xC602326DED2003C0) /* 999 */, + W64LIT(0x83A7287D69A94086) /* 1000 */, W64LIT(0xC57A5FCB30F57A8A) /* 1001 */, + W64LIT(0xB56844E479EBE779) /* 1002 */, W64LIT(0xA373B40F05DCBCE9) /* 1003 */, + W64LIT(0xD71A786E88570EE2) /* 1004 */, W64LIT(0x879CBACDBDE8F6A0) /* 1005 */, + W64LIT(0x976AD1BCC164A32F) /* 1006 */, W64LIT(0xAB21E25E9666D78B) /* 1007 */, + W64LIT(0x901063AAE5E5C33C) /* 1008 */, W64LIT(0x9818B34448698D90) /* 1009 */, + W64LIT(0xE36487AE3E1E8ABB) /* 1010 */, W64LIT(0xAFBDF931893BDCB4) /* 1011 */, + W64LIT(0x6345A0DC5FBBD519) /* 1012 */, W64LIT(0x8628FE269B9465CA) /* 1013 */, + W64LIT(0x1E5D01603F9C51EC) /* 1014 */, W64LIT(0x4DE44006A15049B7) /* 1015 */, + W64LIT(0xBF6C70E5F776CBB1) /* 1016 */, W64LIT(0x411218F2EF552BED) /* 1017 */, + W64LIT(0xCB0C0708705A36A3) /* 1018 */, W64LIT(0xE74D14754F986044) /* 1019 */, + W64LIT(0xCD56D9430EA8280E) /* 1020 */, W64LIT(0xC12591D7535F5065) /* 1021 */, + W64LIT(0xC83223F1720AEF96) /* 1022 */, W64LIT(0xC3A0396F7363A51F) /* 1023 */ +}; + +NAMESPACE_END + +#endif diff --git a/trdlocal.cpp b/trdlocal.cpp new file mode 100644 index 0000000..f810c14 --- /dev/null +++ b/trdlocal.cpp @@ -0,0 +1,66 @@ +// trdlocal.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "trdlocal.h" + +#ifdef THREADS_AVAILABLE + +NAMESPACE_BEGIN(CryptoPP) + +ThreadLocalStorage::Err::Err(const std::string& operation, int error) + : OS_Error(OTHER_ERROR, "ThreadLocalStorage: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error) +{ +} + +ThreadLocalStorage::ThreadLocalStorage() +{ +#ifdef HAS_WINTHREADS + m_index = TlsAlloc(); + if (m_index == TLS_OUT_OF_INDEXES) + throw Err("TlsAlloc", GetLastError()); +#else + int error = pthread_key_create(&m_index, NULL); + if (error) + throw Err("pthread_key_create", error); +#endif +} + +ThreadLocalStorage::~ThreadLocalStorage() +{ +#ifdef HAS_WINTHREADS + if (!TlsFree(m_index)) + throw Err("TlsFree", GetLastError()); +#else + int error = pthread_key_delete(m_index); + if (error) + throw Err("pthread_key_delete", error); +#endif +} + +void ThreadLocalStorage::SetValue(void *value) +{ +#ifdef HAS_WINTHREADS + if (!TlsSetValue(m_index, value)) + throw Err("TlsSetValue", GetLastError()); +#else + int error = pthread_setspecific(m_index, value); + if (error) + throw Err("pthread_key_getspecific", error); +#endif +} + +void *ThreadLocalStorage::GetValue() const +{ +#ifdef HAS_WINTHREADS + void *result = TlsGetValue(m_index); + if (!result && GetLastError() != NO_ERROR) + throw Err("TlsGetValue", GetLastError()); +#else + void *result = pthread_getspecific(m_index); +#endif + return result; +} + +NAMESPACE_END + +#endif // #ifdef THREADS_AVAILABLE diff --git a/trdlocal.h b/trdlocal.h new file mode 100644 index 0000000..f07b793 --- /dev/null +++ b/trdlocal.h @@ -0,0 +1,45 @@ +#ifndef CRYPTOPP_TRDLOCAL_H +#define CRYPTOPP_TRDLOCAL_H + +#include "config.h" + +#ifdef THREADS_AVAILABLE + +#include "misc.h" + +#ifdef HAS_WINTHREADS +#include <windows.h> +typedef DWORD ThreadLocalIndexType; +#else +#include <pthread.h> +typedef pthread_key_t ThreadLocalIndexType; +#endif + +NAMESPACE_BEGIN(CryptoPP) + +//! thread local storage +class ThreadLocalStorage : public NotCopyable +{ +public: + //! exception thrown by ThreadLocalStorage class + class Err : public OS_Error + { + public: + Err(const std::string& operation, int error); + }; + + ThreadLocalStorage(); + ~ThreadLocalStorage(); + + void SetValue(void *value); + void *GetValue() const; + +private: + ThreadLocalIndexType m_index; +}; + +NAMESPACE_END + +#endif // #ifdef THREADS_AVAILABLE + +#endif diff --git a/trunhash.h b/trunhash.h new file mode 100644 index 0000000..66d600f --- /dev/null +++ b/trunhash.h @@ -0,0 +1,46 @@ +#ifndef CRYPTOPP_TRUNHASH_H +#define CRYPTOPP_TRUNHASH_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +class NullHash : public HashTransformation +{ +public: + void Update(const byte *input, unsigned int length) {} + unsigned int DigestSize() const {return 0;} + void TruncatedFinal(byte *digest, unsigned int digestSize) {} + bool TruncatedVerify(const byte *digest, unsigned int digestLength) {return true;} +}; + +//! construct new HashModule with smaller DigestSize() from existing one +template <class T> +class TruncatedHashTemplate : public HashTransformation +{ +public: + TruncatedHashTemplate(T hm, unsigned int digestSize) + : m_hm(hm), m_digestSize(digestSize) {} + TruncatedHashTemplate(const byte *key, unsigned int keyLength, unsigned int digestSize) + : m_hm(key, keyLength), m_digestSize(digestSize) {} + TruncatedHashTemplate(unsigned int digestSize) + : m_digestSize(digestSize) {} + + void Update(const byte *input, unsigned int length) + {m_hm.Update(input, length);} + unsigned int DigestSize() const {return m_digestSize;} + void TruncatedFinal(byte *digest, unsigned int digestSize) + {m_hm.TruncatedFinal(digest, digestSize);} + bool TruncatedVerify(const byte *digest, unsigned int digestLength) + {return m_hm.TruncatedVerify(digest, digestLength);} + +private: + T m_hm; + unsigned int m_digestSize; +}; + +typedef TruncatedHashTemplate<HashTransformation &> TruncatedHashModule; + +NAMESPACE_END + +#endif diff --git a/twofish.cpp b/twofish.cpp new file mode 100644 index 0000000..2371002 --- /dev/null +++ b/twofish.cpp @@ -0,0 +1,168 @@ +// twofish.cpp - modified by Wei Dai from Matthew Skala's twofish.c +// The original code and all modifications are in the public domain. + +#include "pch.h" +#include "twofish.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +// compute (c * x^4) mod (x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1) +// over GF(256) +static inline unsigned int Mod(unsigned int c) +{ + static const unsigned int modulus = 0x14d; + unsigned int c2 = (c<<1) ^ ((c & 0x80) ? modulus : 0); + unsigned int c1 = c2 ^ (c>>1) ^ ((c & 1) ? (modulus>>1) : 0); + return c | (c1 << 8) | (c2 << 16) | (c1 << 24); +} + +// compute RS(12,8) code with the above polynomial as generator +// this is equivalent to multiplying by the RS matrix +static word32 ReedSolomon(word32 high, word32 low) +{ + for (unsigned int i=0; i<8; i++) + { + high = Mod(high>>24) ^ (high<<8) ^ (low>>24); + low <<= 8; + } + return high; +} + +inline word32 Twofish::Base::h0(word32 x, const word32 *key, unsigned int kLen) +{ + x = x | (x<<8) | (x<<16) | (x<<24); + switch(kLen) + { +#define Q(a, b, c, d, t) q[a][GETBYTE(t,0)] ^ (q[b][GETBYTE(t,1)] << 8) ^ (q[c][GETBYTE(t,2)] << 16) ^ (q[d][GETBYTE(t,3)] << 24) + case 4: x = Q(1, 0, 0, 1, x) ^ key[6]; + case 3: x = Q(1, 1, 0, 0, x) ^ key[4]; + case 2: x = Q(0, 1, 0, 1, x) ^ key[2]; + x = Q(0, 0, 1, 1, x) ^ key[0]; + } + return x; +} + +inline word32 Twofish::Base::h(word32 x, const word32 *key, unsigned int kLen) +{ + x = h0(x, key, kLen); + return mds[0][GETBYTE(x,0)] ^ mds[1][GETBYTE(x,1)] ^ mds[2][GETBYTE(x,2)] ^ mds[3][GETBYTE(x,3)]; +} + +void Twofish::Base::UncheckedSetKey(CipherDir dir, const byte *userKey, unsigned int keylength) +{ + AssertValidKeyLength(keylength); + + unsigned int len = (keylength <= 16 ? 2 : (keylength <= 24 ? 3 : 4)); + SecBlock<word32> key(len*2); + GetUserKey(LITTLE_ENDIAN_ORDER, key.begin(), len*2, userKey, keylength); + + unsigned int i; + for (i=0; i<40; i+=2) + { + word32 a = h(i, key, len); + word32 b = rotlFixed(h(i+1, key+1, len), 8); + m_k[i] = a+b; + m_k[i+1] = rotlFixed(a+2*b, 9); + } + + SecBlock<word32> svec(2*len); + for (i=0; i<len; i++) + svec[2*(len-i-1)] = ReedSolomon(key[2*i+1], key[2*i]); + for (i=0; i<256; i++) + { + word32 t = h0(i, svec, len); + m_s[0][i] = mds[0][GETBYTE(t, 0)]; + m_s[1][i] = mds[1][GETBYTE(t, 1)]; + m_s[2][i] = mds[2][GETBYTE(t, 2)]; + m_s[3][i] = mds[3][GETBYTE(t, 3)]; + } +} + +#define G1(x) (m_s[0][GETBYTE(x,0)] ^ m_s[1][GETBYTE(x,1)] ^ m_s[2][GETBYTE(x,2)] ^ m_s[3][GETBYTE(x,3)]) +#define G2(x) (m_s[0][GETBYTE(x,3)] ^ m_s[1][GETBYTE(x,0)] ^ m_s[2][GETBYTE(x,1)] ^ m_s[3][GETBYTE(x,2)]) + +#define ENCROUND(n, a, b, c, d) \ + x = G1 (a); y = G2 (b); \ + x += y; y += x + k[2 * (n) + 1]; \ + (c) ^= x + k[2 * (n)]; \ + (c) = rotrFixed(c, 1); \ + (d) = rotlFixed(d, 1) ^ y + +#define ENCCYCLE(n) \ + ENCROUND (2 * (n), a, b, c, d); \ + ENCROUND (2 * (n) + 1, c, d, a, b) + +#define DECROUND(n, a, b, c, d) \ + x = G1 (a); y = G2 (b); \ + x += y; y += x; \ + (d) ^= y + k[2 * (n) + 1]; \ + (d) = rotrFixed(d, 1); \ + (c) = rotlFixed(c, 1); \ + (c) ^= (x + k[2 * (n)]) + +#define DECCYCLE(n) \ + DECROUND (2 * (n) + 1, c, d, a, b); \ + DECROUND (2 * (n), a, b, c, d) + +typedef BlockGetAndPut<word32, LittleEndian> Block; + +void Twofish::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 x, y, a, b, c, d; + + Block::Get(inBlock)(a)(b)(c)(d); + + a ^= m_k[0]; + b ^= m_k[1]; + c ^= m_k[2]; + d ^= m_k[3]; + + const word32 *k = m_k+8; + ENCCYCLE (0); + ENCCYCLE (1); + ENCCYCLE (2); + ENCCYCLE (3); + ENCCYCLE (4); + ENCCYCLE (5); + ENCCYCLE (6); + ENCCYCLE (7); + + c ^= m_k[4]; + d ^= m_k[5]; + a ^= m_k[6]; + b ^= m_k[7]; + + Block::Put(xorBlock, outBlock)(c)(d)(a)(b); +} + +void Twofish::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 x, y, a, b, c, d; + + Block::Get(inBlock)(c)(d)(a)(b); + + c ^= m_k[4]; + d ^= m_k[5]; + a ^= m_k[6]; + b ^= m_k[7]; + + const word32 *k = m_k+8; + DECCYCLE (7); + DECCYCLE (6); + DECCYCLE (5); + DECCYCLE (4); + DECCYCLE (3); + DECCYCLE (2); + DECCYCLE (1); + DECCYCLE (0); + + a ^= m_k[0]; + b ^= m_k[1]; + c ^= m_k[2]; + d ^= m_k[3]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +NAMESPACE_END diff --git a/twofish.h b/twofish.h new file mode 100644 index 0000000..820a438 --- /dev/null +++ b/twofish.h @@ -0,0 +1,58 @@ +#ifndef CRYPTOPP_TWOFISH_H +#define CRYPTOPP_TWOFISH_H + +/** \file +*/ + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct Twofish_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 0, 32>, FixedRounds<16> +{ + static const char *StaticAlgorithmName() {return "Twofish";} +}; + +/// <a href="http://www.weidai.com/scan-mirror/cs.html#Twofish">Twofish</a> +class Twofish : public Twofish_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate<Twofish_Info> + { + public: + void UncheckedSetKey(CipherDir direction, const byte *userKey, unsigned int length); + + protected: + static word32 h0(word32 x, const word32 *key, unsigned int kLen); + static word32 h(word32 x, const word32 *key, unsigned int kLen); + + static const byte q[2][256]; + static const word32 mds[4][256]; + + FixedSizeSecBlock<word32, 40> m_k; + FixedSizeSecBlock<word32[256], 4> m_s; + }; + + class Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherTemplate<ENCRYPTION, Enc> Encryption; + typedef BlockCipherTemplate<DECRYPTION, Dec> Decryption; +}; + +typedef Twofish::Encryption TwofishEncryption; +typedef Twofish::Decryption TwofishDecryption; + +NAMESPACE_END + +#endif diff --git a/twofishv.dat b/twofishv.dat new file mode 100644 index 0000000..54fbc37 --- /dev/null +++ b/twofishv.dat @@ -0,0 +1,9 @@ +00000000000000000000000000000000 00000000000000000000000000000000 9F589F5CF6122C32B6BFEC2F2AE8C35A +00000000000000000000000000000000 9F589F5CF6122C32B6BFEC2F2AE8C35A D491DB16E7B1C39E86CB086B789F5419 +9F589F5CF6122C32B6BFEC2F2AE8C35A D491DB16E7B1C39E86CB086B789F5419 019F9809DE1711858FAAC3A3BA20FBC3 +D491DB16E7B1C39E86CB086B789F5419 019F9809DE1711858FAAC3A3BA20FBC3 6363977DE839486297E661C6C9D668EB +000000000000000000000000000000000000000000000000 00000000000000000000000000000000 EFA71F788965BD4453F860178FC19101 +EFA71F788965BD4453F860178FC191010000000000000000 88B2B2706B105E36B446BB6D731A1E88 39DA69D6BA4997D585B6DC073CA341B2 +88B2B2706B105E36B446BB6D731A1E88EFA71F788965BD44 39DA69D6BA4997D585B6DC073CA341B2 182B02D81497EA45F9DAACDC29193A65 +0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000 57FF739D4DC92C1BD7FC01700CC8216F +D43BB7556EA32E46F2A282B7D45B4E0D57FF739D4DC92C1BD7FC01700CC8216F 90AFE91BB288544F2C32DC239B2635E6 6CB4561C40BF0A9705931CB6D408E7FA diff --git a/usage.dat b/usage.dat new file mode 100644 index 0000000..201aece --- /dev/null +++ b/usage.dat @@ -0,0 +1,66 @@ +Test Driver for Crypto++(TM) Library, a C++ Class Library of Cryptographic Schemes + +- To generate an RSA key + cryptest g + +- To encrypt and decrypt a string using RSA + cryptest r + +- To sign a file using RSA + cryptest rs privatekeyfile messagefile signaturefile + +- To verify a signature of a file using RSA + cryptest rv publickeyfile messagefile signaturefile + +- To calculate MD5, SHA, and RIPEMD-160 message digests + cryptest m file + +- To encrypt and decrypt a string using DES-EDE in CBC mode + cryptest t + +- To encrypt or decrypt a file + cryptest e|d input output + +- To secret share a file (shares will be named file.000, file.001, etc) + cryptest ss <threshold> <number-of-shares> file + +- To reconstruct a secret-shared file + cryptest sr file share1 share2 [....] + (number of shares given must be equal to threshold) + +- To information disperse a file (shares will be named file.000, file.001, etc) + cryptest id <threshold> <number-of-shares> file + +- To reconstruct an information-dispersed file + cryptest ir file share1 share2 [....] + (number of shares given must be equal to threshold) + +- To gzip a file + cryptest z <compression-level> input output + +- To gunzip a file + cryptest u input output + +- To base64 encode a file + cryptest e64 input output + +- To base64 decode a file + cryptest d64 input output + +- To hex encode a file + cryptest e16 input output + +- To hex decode a file + cryptest d16 input output + +- To forward a TCP connection + cryptest ft source-port destination-host destination-port + +- To run the FIPS-140-2 sample application + cryptest fips + +- To run validation tests + cryptest v + +- To run benchmarks + cryptest b [time for each benchmark in seconds] diff --git a/validat1.cpp b/validat1.cpp new file mode 100644 index 0000000..88c5b52 --- /dev/null +++ b/validat1.cpp @@ -0,0 +1,1250 @@ +// validat1.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "files.h" +#include "hex.h" +#include "modes.h" +#include "cbcmac.h" +#include "dmac.h" +#include "idea.h" +#include "des.h" +#include "rc2.h" +#include "arc4.h" +#include "rc5.h" +#include "blowfish.h" +#include "diamond.h" +#include "wake.h" +#include "3way.h" +#include "safer.h" +#include "gost.h" +#include "shark.h" +#include "cast.h" +#include "square.h" +#include "seal.h" +#include "rc6.h" +#include "mars.h" +#include "rijndael.h" +#include "twofish.h" +#include "serpent.h" +#include "skipjack.h" +#include "osrng.h" +#include "zdeflate.h" + +#include <stdlib.h> +#include <time.h> +#include <memory> +#include <iostream> +#include <iomanip> + +#include "validate.h" + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +bool ValidateAll(bool thorough) +{ + bool pass=TestSettings(); + pass=TestOS_RNG() && pass; + + pass=ValidateCRC32() && pass; + pass=ValidateAdler32() && pass; + pass=ValidateMD2() && pass; + pass=ValidateMD5() && pass; + pass=ValidateSHA() && pass; + pass=ValidateSHA2() && pass; + pass=ValidateHAVAL() && pass; + pass=ValidateTiger() && pass; + pass=ValidateRIPEMD() && pass; + pass=ValidatePanama() && pass; + + pass=ValidateMD5MAC() && pass; + pass=ValidateHMAC() && pass; + pass=ValidateXMACC() && pass; + + pass=ValidatePBKDF() && pass; + + pass=ValidateDES() && pass; + pass=ValidateCipherModes() && pass; + pass=ValidateIDEA() && pass; + pass=ValidateSAFER() && pass; + pass=ValidateRC2() && pass; + pass=ValidateARC4() && pass; + pass=ValidateRC5() && pass; + pass=ValidateBlowfish() && pass; + pass=ValidateDiamond2() && pass; + pass=ValidateThreeWay() && pass; + pass=ValidateGOST() && pass; + pass=ValidateSHARK() && pass; + pass=ValidateCAST() && pass; + pass=ValidateSquare() && pass; + pass=ValidateSKIPJACK() && pass; + pass=ValidateSEAL() && pass; + pass=ValidateRC6() && pass; + pass=ValidateMARS() && pass; + pass=ValidateRijndael() && pass; + pass=ValidateTwofish() && pass; + pass=ValidateSerpent() && pass; + + pass=ValidateBBS() && pass; + pass=ValidateDH() && pass; + pass=ValidateMQV() && pass; + pass=ValidateRSA() && pass; + pass=ValidateElGamal() && pass; + pass=ValidateDLIES() && pass; + pass=ValidateNR() && pass; + pass=ValidateDSA(thorough) && pass; + pass=ValidateLUC() && pass; + pass=ValidateLUC_DH() && pass; + pass=ValidateLUC_DL() && pass; + pass=ValidateXTR_DH() && pass; + pass=ValidateRabin() && pass; + pass=ValidateRW() && pass; +// pass=ValidateBlumGoldwasser() && pass; + pass=ValidateECP() && pass; + pass=ValidateEC2N() && pass; + pass=ValidateECDSA() && pass; + pass=ValidateESIGN() && pass; + + if (pass) + cout << "\nAll tests passed!\n"; + else + cout << "\nOops! Not all tests passed.\n"; + + return pass; +} + +bool TestSettings() +{ + bool pass = true; + + cout << "\nTesting Settings...\n\n"; + + if (*(word32 *)"\x01\x02\x03\x04" == 0x04030201L) + { +#ifdef IS_LITTLE_ENDIAN + cout << "passed: "; +#else + cout << "FAILED: "; + pass = false; +#endif + cout << "Your machine is little endian.\n"; + } + else if (*(word32 *)"\x01\x02\x03\x04" == 0x01020304L) + { +#ifndef IS_LITTLE_ENDIAN + cout << "passed: "; +#else + cout << "FAILED: "; + pass = false; +#endif + cout << "Your machine is big endian.\n"; + } + else + { + cout << "FAILED: Your machine is neither big endian nor little endian.\n"; + pass = false; + } + + if (sizeof(byte) == 1) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "sizeof(byte) == " << sizeof(byte) << endl; + + if (sizeof(word16) == 2) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "sizeof(word16) == " << sizeof(word16) << endl; + + if (sizeof(word32) == 4) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "sizeof(word32) == " << sizeof(word32) << endl; + +#ifdef WORD64_AVAILABLE + if (sizeof(word64) == 8) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "sizeof(word64) == " << sizeof(word64) << endl; +#else + if (sizeof(dword) >= 8) + { + cout << "FAILED: sizeof(dword) >= 8, but WORD64_AVAILABLE not defined" << endl; + pass = false; + } + else + cout << "passed: word64 not available" << endl; +#endif + + if (sizeof(dword) == 2*sizeof(word)) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "sizeof(word) == " << sizeof(word) << ", sizeof(dword) == " << sizeof(dword) << endl; + + dword test = (dword(1)<<WORD_BITS) + 2; + if (HIGH_WORD(test) == 1 && LOW_WORD(test) == 2) + cout << "passed: "; + else + { + cout << "FAILED: "; + pass = false; + } + cout << "HIGH_WORD() and LOW_WORD() macros\n"; + + if (!pass) + { + cout << "Some critical setting in config.h is in error. Please fix it and recompile." << endl; + abort(); + } + return pass; +} + +bool TestOS_RNG() +{ + bool pass = true; + +#ifdef BLOCKING_RNG_AVAILABLE + { + cout << "\nTesting operating system provided blocking random number generator...\n\n"; + + BlockingRng rng; + ArraySink *sink; + RandomNumberSource test(rng, 100000, false, new Deflator(sink=new ArraySink(NULL,0))); + unsigned long total=0, length=0; + time_t t = time(NULL), t1 = 0; + + // check that it doesn't take too long to generate a reasonable amount of randomness + while (total < 16 && (t1 < 10 || total*8 > t1)) + { + test.Pump(1); + total += 1; + t1 = time(NULL) - t; + } + + if (total < 16) + { + cout << "FAILED:"; + pass = false; + } + else + cout << "passed:"; + cout << " it took " << t1 << " seconds to generate " << total << " bytes" << endl; + + if (t1 < 2) + { + // that was fast, are we really blocking? + // first exhaust the extropy reserve + t = time(NULL); + while (time(NULL) - t < 2) + { + test.Pump(1); + total += 1; + } + + // if it generates too many bytes in a certain amount of time, + // something's probably wrong + t = time(NULL); + while (time(NULL) - t < 2) + { + test.Pump(1); + total += 1; + length += 1; + } + if (length > 1024) + { + cout << "FAILED:"; + pass = false; + } + else + cout << "passed:"; + cout << " it generated " << length << " bytes in " << time(NULL) - t << " seconds" << endl; + } + + test.AttachedTransformation()->MessageEnd(); + + if (sink->TotalPutLength() < total) + { + cout << "FAILED:"; + pass = false; + } + else + cout << "passed:"; + cout << " " << total << " generated bytes compressed to " << sink->TotalPutLength() << " bytes by DEFLATE" << endl; + } +#else + cout << "\nNo operating system provided blocking random number generator, skipping test." << endl; +#endif + +#ifdef NONBLOCKING_RNG_AVAILABLE + { + cout << "\nTesting operating system provided nonblocking random number generator...\n\n"; + + NonblockingRng rng; + ArraySink *sink; + RandomNumberSource test(rng, 100000, true, new Deflator(sink=new ArraySink(NULL, 0))); + + if (sink->TotalPutLength() < 100000) + { + cout << "FAILED:"; + pass = false; + } + else + cout << "passed:"; + cout << " 100000 generated bytes compressed to " << sink->TotalPutLength() << " bytes by DEFLATE" << endl; + } +#else + cout << "\nNo operating system provided nonblocking random number generator, skipping test." << endl; +#endif + + return pass; +} + +// VC50 workaround +typedef auto_ptr<BlockTransformation> apbt; + +class CipherFactory +{ +public: + virtual unsigned int BlockSize() const =0; + virtual unsigned int KeyLength() const =0; + + virtual apbt NewEncryption(const byte *key) const =0; + virtual apbt NewDecryption(const byte *key) const =0; +}; + +template <class E, class D> class FixedRoundsCipherFactory : public CipherFactory +{ +public: + FixedRoundsCipherFactory(unsigned int keylen=0) : m_keylen(keylen?keylen:E::DEFAULT_KEYLENGTH) {} + unsigned int BlockSize() const {return E::BLOCKSIZE;} + unsigned int KeyLength() const {return m_keylen;} + + apbt NewEncryption(const byte *key) const + {return apbt(new E(key, m_keylen));} + apbt NewDecryption(const byte *key) const + {return apbt(new D(key, m_keylen));} + + unsigned int m_keylen; +}; + +template <class E, class D> class VariableRoundsCipherFactory : public CipherFactory +{ +public: + VariableRoundsCipherFactory(unsigned int keylen=0, unsigned int rounds=0) + : m_keylen(keylen ? keylen : E::DEFAULT_KEYLENGTH), m_rounds(rounds ? rounds : E::DEFAULT_ROUNDS) {} + unsigned int BlockSize() const {return E::BLOCKSIZE;} + unsigned int KeyLength() const {return m_keylen;} + + apbt NewEncryption(const byte *key) const + {return apbt(new E(key, m_keylen, m_rounds));} + apbt NewDecryption(const byte *key) const + {return apbt(new D(key, m_keylen, m_rounds));} + + unsigned int m_keylen, m_rounds; +}; + +bool BlockTransformationTest(const CipherFactory &cg, BufferedTransformation &valdata, unsigned int tuples = 0xffff) +{ + HexEncoder output(new FileSink(cout)); + SecByteBlock plain(cg.BlockSize()), cipher(cg.BlockSize()), out(cg.BlockSize()), outplain(cg.BlockSize()); + SecByteBlock key(cg.KeyLength()); + bool pass=true, fail; + + while (valdata.MaxRetrievable() && tuples--) + { + valdata.Get(key, cg.KeyLength()); + valdata.Get(plain, cg.BlockSize()); + valdata.Get(cipher, cg.BlockSize()); + + apbt transE = cg.NewEncryption(key); + transE->ProcessBlock(plain, out); + fail = memcmp(out, cipher, cg.BlockSize()) != 0; + + apbt transD = cg.NewDecryption(key); + transD->ProcessBlock(out, outplain); + fail=fail || memcmp(outplain, plain, cg.BlockSize()); + + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + output.Put(key, cg.KeyLength()); + cout << " "; + output.Put(outplain, cg.BlockSize()); + cout << " "; + output.Put(out, cg.BlockSize()); + cout << endl; + } + return pass; +} + +class FilterTester : public Unflushable<Sink> +{ +public: + FilterTester(const byte *validOutput, unsigned int outputLen) + : validOutput(validOutput), outputLen(outputLen), counter(0), fail(false) {} + void PutByte(byte inByte) + { + if (counter >= outputLen || validOutput[counter] != inByte) + { + fail = true; + assert(false); + } + counter++; + } + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) + { + while (length--) + FilterTester::PutByte(*inString++); + + if (messageEnd) + if (counter != outputLen) + { + fail = true; + assert(false); + } + + return 0; + } + bool GetResult() + { + return !fail; + } + + const byte *validOutput; + unsigned int outputLen, counter; + bool fail; +}; + +bool TestFilter(BufferedTransformation &bt, const byte *in, unsigned int inLen, const byte *out, unsigned int outLen) +{ + FilterTester *ft; + bt.Attach(ft = new FilterTester(out, outLen)); + + while (inLen) + { + unsigned int randomLen = GlobalRNG().GenerateWord32(0, inLen); + bt.Put(in, randomLen); + in += randomLen; + inLen -= randomLen; + } + bt.MessageEnd(); + return ft->GetResult(); +} + +bool ValidateDES() +{ + cout << "\nDES validation suite running...\n\n"; + + FileSource valdata("descert.dat", true, new HexDecoder); + bool pass = BlockTransformationTest(FixedRoundsCipherFactory<DESEncryption, DESDecryption>(), valdata); + + cout << "\nTesting EDE2, EDE3, and XEX3 variants...\n\n"; + + FileSource valdata1("3desval.dat", true, new HexDecoder); + pass = BlockTransformationTest(FixedRoundsCipherFactory<DES_EDE2_Encryption, DES_EDE2_Decryption>(), valdata1, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<DES_EDE3_Encryption, DES_EDE3_Decryption>(), valdata1, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<DES_XEX3_Encryption, DES_XEX3_Decryption>(), valdata1, 1) && pass; + + return pass; +} + +bool TestModeIV(SymmetricCipher &e, SymmetricCipher &d) +{ + SecByteBlock lastIV; + StreamTransformationFilter filter(e, new StreamTransformationFilter(d)); + byte plaintext[20480]; + + for (unsigned int i=1; i<sizeof(plaintext); i*=2) + { + SecByteBlock iv(e.IVSize()); + e.GetNextIV(iv); + + if (iv == lastIV) + return false; + else + lastIV = iv; + + e.Resynchronize(iv); + d.Resynchronize(iv); + + unsigned int length = STDMAX(GlobalRNG().GenerateWord32(0, i), (word32)e.MinLastBlockSize()); + GlobalRNG().GenerateBlock(plaintext, length); + + if (!TestFilter(filter, plaintext, length, plaintext, length)) + return false; + } + + return true; +} + +bool ValidateCipherModes() +{ + cout << "\nTesting DES modes...\n\n"; + const byte key[] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + const byte iv[] = {0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef}; + const byte plain[] = { // "Now is the time for all " without tailing 0 + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20}; + DESEncryption desE(key); + DESDecryption desD(key); + bool pass=true, fail; + + { + // from FIPS 81 + const byte encrypted[] = { + 0x3f, 0xa4, 0x0e, 0x8a, 0x98, 0x4d, 0x48, 0x15, + 0x6a, 0x27, 0x17, 0x87, 0xab, 0x88, 0x83, 0xf9, + 0x89, 0x3d, 0x51, 0xec, 0x4b, 0x56, 0x3b, 0x53}; + + ECB_Mode_ExternalCipher::Encryption modeE(desE); + fail = !TestFilter(StreamTransformationFilter(modeE, NULL, StreamTransformationFilter::NO_PADDING).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "ECB encryption" << endl; + + ECB_Mode_ExternalCipher::Decryption modeD(desD); + fail = !TestFilter(StreamTransformationFilter(modeD, NULL, StreamTransformationFilter::NO_PADDING).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "ECB decryption" << endl; + } + { + // from FIPS 81 + const byte encrypted[] = { + 0xE5, 0xC7, 0xCD, 0xDE, 0x87, 0x2B, 0xF2, 0x7C, + 0x43, 0xE9, 0x34, 0x00, 0x8C, 0x38, 0x9C, 0x0F, + 0x68, 0x37, 0x88, 0x49, 0x9A, 0x7C, 0x05, 0xF6}; + + CBC_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE, NULL, StreamTransformationFilter::NO_PADDING).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with no padding" << endl; + + CBC_Mode_ExternalCipher::Decryption modeD(desD, iv); + fail = !TestFilter(StreamTransformationFilter(modeD, NULL, StreamTransformationFilter::NO_PADDING).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with no padding" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC mode IV generation" << endl; + } + { + // generated with Crypto++, matches FIPS 81 + // but has extra 8 bytes as result of padding + const byte encrypted[] = { + 0xE5, 0xC7, 0xCD, 0xDE, 0x87, 0x2B, 0xF2, 0x7C, + 0x43, 0xE9, 0x34, 0x00, 0x8C, 0x38, 0x9C, 0x0F, + 0x68, 0x37, 0x88, 0x49, 0x9A, 0x7C, 0x05, 0xF6, + 0x62, 0xC1, 0x6A, 0x27, 0xE4, 0xFC, 0xF2, 0x77}; + + CBC_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with PKCS #7 padding" << endl; + + CBC_Mode_ExternalCipher::Decryption modeD(desD, iv); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with PKCS #7 padding" << endl; + } + { + // generated with Crypto++, matches FIPS 81 + // but has extra 8 bytes as result of padding + const byte encrypted[] = { + 0xE5, 0xC7, 0xCD, 0xDE, 0x87, 0x2B, 0xF2, 0x7C, + 0x43, 0xE9, 0x34, 0x00, 0x8C, 0x38, 0x9C, 0x0F, + 0x68, 0x37, 0x88, 0x49, 0x9A, 0x7C, 0x05, 0xF6, + 0x57, 0x25, 0x0C, 0x94, 0x83, 0xD5, 0x01, 0x79}; + + CBC_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE, NULL, StreamTransformationFilter::ONE_AND_ZEROS_PADDING).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with one-and-zeros padding" << endl; + + CBC_Mode_ExternalCipher::Decryption modeD(desD, iv); + fail = !TestFilter(StreamTransformationFilter(modeD, NULL, StreamTransformationFilter::ONE_AND_ZEROS_PADDING).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with one-and-zeros padding" << endl; + } + { + const byte plain[] = {'a', 0, 0, 0, 0, 0, 0, 0}; + // generated with Crypto++ + const byte encrypted[] = { + 0x9B, 0x47, 0x57, 0x59, 0xD6, 0x9C, 0xF6, 0xD0}; + + CBC_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE, NULL, StreamTransformationFilter::ZEROS_PADDING).Ref(), + plain, 1, encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with zeros padding" << endl; + + CBC_Mode_ExternalCipher::Decryption modeD(desD, iv); + fail = !TestFilter(StreamTransformationFilter(modeD, NULL, StreamTransformationFilter::ZEROS_PADDING).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with zeros padding" << endl; + } + { + // generated with Crypto++, matches FIPS 81 + // but with last two blocks swapped as result of CTS + const byte encrypted[] = { + 0xE5, 0xC7, 0xCD, 0xDE, 0x87, 0x2B, 0xF2, 0x7C, + 0x68, 0x37, 0x88, 0x49, 0x9A, 0x7C, 0x05, 0xF6, + 0x43, 0xE9, 0x34, 0x00, 0x8C, 0x38, 0x9C, 0x0F}; + + CBC_CTS_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with ciphertext stealing (CTS)" << endl; + + CBC_CTS_Mode_ExternalCipher::Decryption modeD(desD, iv); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with ciphertext stealing (CTS)" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC CTS IV generation" << endl; + } + { + // generated with Crypto++ + const byte decryptionIV[] = {0x4D, 0xD0, 0xAC, 0x8F, 0x47, 0xCF, 0x79, 0xCE}; + const byte encrypted[] = {0x12, 0x34, 0x56}; + + byte stolenIV[8]; + + CBC_CTS_Mode_ExternalCipher::Encryption modeE(desE, iv); + modeE.SetStolenIV(stolenIV); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, 3, encrypted, sizeof(encrypted)); + fail = memcmp(stolenIV, decryptionIV, 8) != 0 || fail; + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC encryption with ciphertext and IV stealing" << endl; + + CBC_CTS_Mode_ExternalCipher::Decryption modeD(desD, stolenIV); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, 3); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC decryption with ciphertext and IV stealing" << endl; + } + { + const byte encrypted[] = { // from FIPS 81 + 0xF3,0x09,0x62,0x49,0xC7,0xF4,0x6E,0x51, + 0xA6,0x9E,0x83,0x9B,0x1A,0x92,0xF7,0x84, + 0x03,0x46,0x71,0x33,0x89,0x8E,0xA6,0x22}; + + CFB_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB encryption" << endl; + + CFB_Mode_ExternalCipher::Decryption modeD(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB decryption" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB mode IV generation" << endl; + } + { + const byte plain[] = { // "Now is the." without tailing 0 + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,0x68,0x65}; + const byte encrypted[] = { // from FIPS 81 + 0xf3,0x1f,0xda,0x07,0x01,0x14,0x62,0xee,0x18,0x7f}; + + CFB_Mode_ExternalCipher::Encryption modeE(desE, iv, 1); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB (8-bit feedback) encryption" << endl; + + CFB_Mode_ExternalCipher::Decryption modeD(desE, iv, 1); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB (8-bit feedback) decryption" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CFB (8-bit feedback) IV generation" << endl; + } + { + const byte encrypted[] = { // from Eric Young's libdes + 0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51, + 0x35,0xf2,0x4a,0x24,0x2e,0xeb,0x3d,0x3f, + 0x3d,0x6d,0x5b,0xe3,0x25,0x5a,0xf8,0xc3}; + + OFB_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "OFB encryption" << endl; + + OFB_Mode_ExternalCipher::Decryption modeD(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "OFB decryption" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "OFB IV generation" << endl; + } + { + const byte encrypted[] = { // generated with Crypto++ + 0xF3, 0x09, 0x62, 0x49, 0xC7, 0xF4, 0x6E, 0x51, + 0x16, 0x3A, 0x8C, 0xA0, 0xFF, 0xC9, 0x4C, 0x27, + 0xFA, 0x2F, 0x80, 0xF4, 0x80, 0xB8, 0x6F, 0x75}; + + CTR_Mode_ExternalCipher::Encryption modeE(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeE).Ref(), + plain, sizeof(plain), encrypted, sizeof(encrypted)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "Counter Mode encryption" << endl; + + CTR_Mode_ExternalCipher::Decryption modeD(desE, iv); + fail = !TestFilter(StreamTransformationFilter(modeD).Ref(), + encrypted, sizeof(encrypted), plain, sizeof(plain)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "Counter Mode decryption" << endl; + + fail = !TestModeIV(modeE, modeD); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "Counter Mode IV generation" << endl; + } + { + const byte plain[] = { // "7654321 Now is the time for " + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20}; + const byte mac1[] = { // from FIPS 113 + 0xf1, 0xd3, 0x0f, 0x68, 0x49, 0x31, 0x2c, 0xa4}; + const byte mac2[] = { // generated with Crypto++ + 0x35, 0x80, 0xC5, 0xC4, 0x6B, 0x81, 0x24, 0xE2}; + + CBC_MAC<DES> cbcmac(key); + HashFilter cbcmacFilter(cbcmac); + fail = !TestFilter(cbcmacFilter, plain, sizeof(plain), mac1, sizeof(mac1)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "CBC MAC" << endl; + + DMAC<DES> dmac(key); + HashFilter dmacFilter(dmac); + fail = !TestFilter(dmacFilter, plain, sizeof(plain), mac2, sizeof(mac2)); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed ") << "DMAC" << endl; + } + + return pass; +} + +bool ValidateIDEA() +{ + cout << "\nIDEA validation suite running...\n\n"; + + FileSource valdata("ideaval.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<IDEAEncryption, IDEADecryption>(), valdata); +} + +bool ValidateSAFER() +{ + cout << "\nSAFER validation suite running...\n\n"; + + FileSource valdata("saferval.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(VariableRoundsCipherFactory<SAFER_K_Encryption, SAFER_K_Decryption>(8,6), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory<SAFER_K_Encryption, SAFER_K_Decryption>(16,12), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory<SAFER_SK_Encryption, SAFER_SK_Decryption>(8,6), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory<SAFER_SK_Encryption, SAFER_SK_Decryption>(16,10), valdata, 4) && pass; + return pass; +} + +bool ValidateRC2() +{ + cout << "\nRC2 validation suite running...\n\n"; + + FileSource valdata("rc2val.dat", true, new HexDecoder); + HexEncoder output(new FileSink(cout)); + SecByteBlock plain(RC2Encryption::BLOCKSIZE), cipher(RC2Encryption::BLOCKSIZE), out(RC2Encryption::BLOCKSIZE), outplain(RC2Encryption::BLOCKSIZE); + SecByteBlock key(128); + bool pass=true, fail; + + while (valdata.MaxRetrievable()) + { + byte keyLen, effectiveLen; + + valdata.Get(keyLen); + valdata.Get(effectiveLen); + valdata.Get(key, keyLen); + valdata.Get(plain, RC2Encryption::BLOCKSIZE); + valdata.Get(cipher, RC2Encryption::BLOCKSIZE); + + apbt transE(new RC2Encryption(key, keyLen, effectiveLen)); + transE->ProcessBlock(plain, out); + fail = memcmp(out, cipher, RC2Encryption::BLOCKSIZE) != 0; + + apbt transD(new RC2Decryption(key, keyLen, effectiveLen)); + transD->ProcessBlock(out, outplain); + fail=fail || memcmp(outplain, plain, RC2Encryption::BLOCKSIZE); + + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + output.Put(key, keyLen); + cout << " "; + output.Put(outplain, RC2Encryption::BLOCKSIZE); + cout << " "; + output.Put(out, RC2Encryption::BLOCKSIZE); + cout << endl; + } + return pass; +} + +bool ValidateARC4() +{ + unsigned char Key0[] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef }; + unsigned char Input0[]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + unsigned char Output0[] = {0x75,0xb7,0x87,0x80,0x99,0xe0,0xc5,0x96}; + + unsigned char Key1[]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + unsigned char Input1[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output1[]={0x74,0x94,0xc2,0xe7,0x10,0x4b,0x08,0x79}; + + unsigned char Key2[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Input2[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output2[]={0xde,0x18,0x89,0x41,0xa3,0x37,0x5d,0x3a}; + + unsigned char Key3[]={0xef,0x01,0x23,0x45}; + unsigned char Input3[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output3[]={0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,0xbd,0x61}; + + unsigned char Key4[]={ 0x01,0x23,0x45,0x67,0x89,0xab, 0xcd,0xef }; + unsigned char Input4[] = + {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01}; + unsigned char Output4[]= { + 0x75,0x95,0xc3,0xe6,0x11,0x4a,0x09,0x78,0x0c,0x4a,0xd4, + 0x52,0x33,0x8e,0x1f,0xfd,0x9a,0x1b,0xe9,0x49,0x8f, + 0x81,0x3d,0x76,0x53,0x34,0x49,0xb6,0x77,0x8d,0xca, + 0xd8,0xc7,0x8a,0x8d,0x2b,0xa9,0xac,0x66,0x08,0x5d, + 0x0e,0x53,0xd5,0x9c,0x26,0xc2,0xd1,0xc4,0x90,0xc1, + 0xeb,0xbe,0x0c,0xe6,0x6d,0x1b,0x6b,0x1b,0x13,0xb6, + 0xb9,0x19,0xb8,0x47,0xc2,0x5a,0x91,0x44,0x7a,0x95, + 0xe7,0x5e,0x4e,0xf1,0x67,0x79,0xcd,0xe8,0xbf,0x0a, + 0x95,0x85,0x0e,0x32,0xaf,0x96,0x89,0x44,0x4f,0xd3, + 0x77,0x10,0x8f,0x98,0xfd,0xcb,0xd4,0xe7,0x26,0x56, + 0x75,0x00,0x99,0x0b,0xcc,0x7e,0x0c,0xa3,0xc4,0xaa, + 0xa3,0x04,0xa3,0x87,0xd2,0x0f,0x3b,0x8f,0xbb,0xcd, + 0x42,0xa1,0xbd,0x31,0x1d,0x7a,0x43,0x03,0xdd,0xa5, + 0xab,0x07,0x88,0x96,0xae,0x80,0xc1,0x8b,0x0a,0xf6, + 0x6d,0xff,0x31,0x96,0x16,0xeb,0x78,0x4e,0x49,0x5a, + 0xd2,0xce,0x90,0xd7,0xf7,0x72,0xa8,0x17,0x47,0xb6, + 0x5f,0x62,0x09,0x3b,0x1e,0x0d,0xb9,0xe5,0xba,0x53, + 0x2f,0xaf,0xec,0x47,0x50,0x83,0x23,0xe6,0x71,0x32, + 0x7d,0xf9,0x44,0x44,0x32,0xcb,0x73,0x67,0xce,0xc8, + 0x2f,0x5d,0x44,0xc0,0xd0,0x0b,0x67,0xd6,0x50,0xa0, + 0x75,0xcd,0x4b,0x70,0xde,0xdd,0x77,0xeb,0x9b,0x10, + 0x23,0x1b,0x6b,0x5b,0x74,0x13,0x47,0x39,0x6d,0x62, + 0x89,0x74,0x21,0xd4,0x3d,0xf9,0xb4,0x2e,0x44,0x6e, + 0x35,0x8e,0x9c,0x11,0xa9,0xb2,0x18,0x4e,0xcb,0xef, + 0x0c,0xd8,0xe7,0xa8,0x77,0xef,0x96,0x8f,0x13,0x90, + 0xec,0x9b,0x3d,0x35,0xa5,0x58,0x5c,0xb0,0x09,0x29, + 0x0e,0x2f,0xcd,0xe7,0xb5,0xec,0x66,0xd9,0x08,0x4b, + 0xe4,0x40,0x55,0xa6,0x19,0xd9,0xdd,0x7f,0xc3,0x16, + 0x6f,0x94,0x87,0xf7,0xcb,0x27,0x29,0x12,0x42,0x64, + 0x45,0x99,0x85,0x14,0xc1,0x5d,0x53,0xa1,0x8c,0x86, + 0x4c,0xe3,0xa2,0xb7,0x55,0x57,0x93,0x98,0x81,0x26, + 0x52,0x0e,0xac,0xf2,0xe3,0x06,0x6e,0x23,0x0c,0x91, + 0xbe,0xe4,0xdd,0x53,0x04,0xf5,0xfd,0x04,0x05,0xb3, + 0x5b,0xd9,0x9c,0x73,0x13,0x5d,0x3d,0x9b,0xc3,0x35, + 0xee,0x04,0x9e,0xf6,0x9b,0x38,0x67,0xbf,0x2d,0x7b, + 0xd1,0xea,0xa5,0x95,0xd8,0xbf,0xc0,0x06,0x6f,0xf8, + 0xd3,0x15,0x09,0xeb,0x0c,0x6c,0xaa,0x00,0x6c,0x80, + 0x7a,0x62,0x3e,0xf8,0x4c,0x3d,0x33,0xc1,0x95,0xd2, + 0x3e,0xe3,0x20,0xc4,0x0d,0xe0,0x55,0x81,0x57,0xc8, + 0x22,0xd4,0xb8,0xc5,0x69,0xd8,0x49,0xae,0xd5,0x9d, + 0x4e,0x0f,0xd7,0xf3,0x79,0x58,0x6b,0x4b,0x7f,0xf6, + 0x84,0xed,0x6a,0x18,0x9f,0x74,0x86,0xd4,0x9b,0x9c, + 0x4b,0xad,0x9b,0xa2,0x4b,0x96,0xab,0xf9,0x24,0x37, + 0x2c,0x8a,0x8f,0xff,0xb1,0x0d,0x55,0x35,0x49,0x00, + 0xa7,0x7a,0x3d,0xb5,0xf2,0x05,0xe1,0xb9,0x9f,0xcd, + 0x86,0x60,0x86,0x3a,0x15,0x9a,0xd4,0xab,0xe4,0x0f, + 0xa4,0x89,0x34,0x16,0x3d,0xdd,0xe5,0x42,0xa6,0x58, + 0x55,0x40,0xfd,0x68,0x3c,0xbf,0xd8,0xc0,0x0f,0x12, + 0x12,0x9a,0x28,0x4d,0xea,0xcc,0x4c,0xde,0xfe,0x58, + 0xbe,0x71,0x37,0x54,0x1c,0x04,0x71,0x26,0xc8,0xd4, + 0x9e,0x27,0x55,0xab,0x18,0x1a,0xb7,0xe9,0x40,0xb0, + 0xc0}; + + // VC60 workaround: auto_ptr lacks reset() + member_ptr<ARC4> arc4; + bool pass=true, fail; + int i; + + cout << "\nARC4 validation suite running...\n\n"; + + arc4.reset(new ARC4(Key0, sizeof(Key0))); + arc4->ProcessString(Input0, sizeof(Input0)); + fail = memcmp(Input0, Output0, sizeof(Input0)) != 0; + cout << (fail ? "FAILED" : "passed") << " Test 0" << endl; + pass = pass && !fail; + + arc4.reset(new ARC4(Key1, sizeof(Key1))); + arc4->ProcessString(Key1, Input1, sizeof(Key1)); + fail = memcmp(Output1, Key1, sizeof(Key1)) != 0; + cout << (fail ? "FAILED" : "passed") << " Test 1" << endl; + pass = pass && !fail; + + arc4.reset(new ARC4(Key2, sizeof(Key2))); + for (i=0, fail=false; i<sizeof(Input2); i++) + if (arc4->ProcessByte(Input2[i]) != Output2[i]) + fail = true; + cout << (fail ? "FAILED" : "passed") << " Test 2" << endl; + pass = pass && !fail; + + arc4.reset(new ARC4(Key3, sizeof(Key3))); + for (i=0, fail=false; i<sizeof(Input3); i++) + if (arc4->ProcessByte(Input3[i]) != Output3[i]) + fail = true; + cout << (fail ? "FAILED" : "passed") << " Test 3" << endl; + pass = pass && !fail; + + arc4.reset(new ARC4(Key4, sizeof(Key4))); + for (i=0, fail=false; i<sizeof(Input4); i++) + if (arc4->ProcessByte(Input4[i]) != Output4[i]) + fail = true; + cout << (fail ? "FAILED" : "passed") << " Test 4" << endl; + pass = pass && !fail; + + return pass; +} + +bool ValidateRC5() +{ + cout << "\nRC5 validation suite running...\n\n"; + + FileSource valdata("rc5val.dat", true, new HexDecoder); + return BlockTransformationTest(VariableRoundsCipherFactory<RC5Encryption, RC5Decryption>(16, 12), valdata); +} + +bool ValidateRC6() +{ + cout << "\nRC6 validation suite running...\n\n"; + + FileSource valdata("rc6val.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RC6Encryption, RC6Decryption>(16), valdata, 2) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RC6Encryption, RC6Decryption>(24), valdata, 2) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RC6Encryption, RC6Decryption>(32), valdata, 2) && pass; + return pass; +} + +bool ValidateMARS() +{ + cout << "\nMARS validation suite running...\n\n"; + + FileSource valdata("marsval.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(FixedRoundsCipherFactory<MARSEncryption, MARSDecryption>(16), valdata, 4) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<MARSEncryption, MARSDecryption>(24), valdata, 3) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<MARSEncryption, MARSDecryption>(32), valdata, 2) && pass; + return pass; +} + +bool ValidateRijndael() +{ + cout << "\nRijndael validation suite running...\n\n"; + + FileSource valdata("rijndael.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RijndaelEncryption, RijndaelDecryption>(16), valdata, 4) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RijndaelEncryption, RijndaelDecryption>(24), valdata, 3) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<RijndaelEncryption, RijndaelDecryption>(32), valdata, 2) && pass; + return pass; +} + +bool ValidateTwofish() +{ + cout << "\nTwofish validation suite running...\n\n"; + + FileSource valdata("twofishv.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(FixedRoundsCipherFactory<TwofishEncryption, TwofishDecryption>(16), valdata, 4) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<TwofishEncryption, TwofishDecryption>(24), valdata, 3) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<TwofishEncryption, TwofishDecryption>(32), valdata, 2) && pass; + return pass; +} + +bool ValidateSerpent() +{ + cout << "\nSerpent validation suite running...\n\n"; + + FileSource valdata("serpentv.dat", true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(FixedRoundsCipherFactory<SerpentEncryption, SerpentDecryption>(16), valdata, 4) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<SerpentEncryption, SerpentDecryption>(24), valdata, 3) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<SerpentEncryption, SerpentDecryption>(32), valdata, 2) && pass; + return pass; +} + +bool ValidateBlowfish() +{ + cout << "\nBlowfish validation suite running...\n\n"; + + HexEncoder output(new FileSink(cout)); + char *key[]={"abcdefghijklmnopqrstuvwxyz", "Who is John Galt?"}; + byte *plain[]={(byte *)"BLOWFISH", (byte *)"\xfe\xdc\xba\x98\x76\x54\x32\x10"}; + byte *cipher[]={(byte *)"\x32\x4e\xd0\xfe\xf4\x13\xa2\x03", (byte *)"\xcc\x91\x73\x2b\x80\x22\xf6\x84"}; + byte out[8], outplain[8]; + bool pass=true, fail; + + for (int i=0; i<2; i++) + { + ECB_Mode<Blowfish>::Encryption enc((byte *)key[i], strlen(key[i])); + enc.ProcessData(out, plain[i], 8); + fail = memcmp(out, cipher[i], 8) != 0; + + ECB_Mode<Blowfish>::Decryption dec((byte *)key[i], strlen(key[i])); + dec.ProcessData(outplain, cipher[i], 8); + fail = fail || memcmp(outplain, plain[i], 8); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << '\"' << key[i] << '\"'; + for (int j=0; j<(signed int)(30-strlen(key[i])); j++) + cout << ' '; + output.Put(outplain, 8); + cout << " "; + output.Put(out, 8); + cout << endl; + } + return pass; +} + +bool ValidateDiamond2() +{ + cout << "\nDiamond2 validation suite running...\n\n"; + + FileSource valdata("diamond.dat", true, new HexDecoder); + HexEncoder output(new FileSink(cout)); + byte key[32], plain[16], cipher[16], out[16], outplain[16]; + byte blocksize, rounds, keysize; + bool pass=true, fail; + member_ptr<BlockTransformation> diamond; // VC60 workaround: auto_ptr lacks reset + + while (valdata.MaxRetrievable() >= 1) + { + valdata.Get(blocksize); + valdata.Get(rounds); + valdata.Get(keysize); + valdata.Get(key, keysize); + valdata.Get(plain, blocksize); + valdata.Get(cipher, blocksize); + + if (blocksize==16) + diamond.reset(new Diamond2Encryption(key, keysize, rounds)); + else + diamond.reset(new Diamond2LiteEncryption(key, keysize, rounds)); + + diamond->ProcessBlock(plain, out); + fail=memcmp(out, cipher, blocksize) != 0; + + if (blocksize==16) + diamond.reset(new Diamond2Decryption(key, keysize, rounds)); + else + diamond.reset(new Diamond2LiteDecryption(key, keysize, rounds)); + + diamond->ProcessBlock(out, outplain); + fail=fail || memcmp(outplain, plain, blocksize); + + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + output.Put(key, keysize); + cout << "\n "; + output.Put(outplain, blocksize); + cout << " "; + output.Put(out, blocksize); + cout << endl; + } + return pass; +} + +bool ValidateThreeWay() +{ + cout << "\n3-WAY validation suite running...\n\n"; + + FileSource valdata("3wayval.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<ThreeWayEncryption, ThreeWayDecryption>(), valdata); +} + +bool ValidateGOST() +{ + cout << "\nGOST validation suite running...\n\n"; + + FileSource valdata("gostval.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<GOSTEncryption, GOSTDecryption>(), valdata); +} + +bool ValidateSHARK() +{ + cout << "\nSHARK validation suite running...\n\n"; + +#ifdef WORD64_AVAILABLE + FileSource valdata("sharkval.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<SHARKEncryption, SHARKDecryption>(), valdata); +#else + cout << "word64 not available, skipping SHARK validation." << endl; + return true; +#endif +} + +bool ValidateCAST() +{ + bool pass = true; + + cout << "\nCAST-128 validation suite running...\n\n"; + + FileSource val128("cast128v.dat", true, new HexDecoder); + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST128Encryption, CAST128Decryption>(16), val128, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST128Encryption, CAST128Decryption>(10), val128, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST128Encryption, CAST128Decryption>(5), val128, 1) && pass; + + cout << "\nCAST-256 validation suite running...\n\n"; + + FileSource val256("cast256v.dat", true, new HexDecoder); + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST256Encryption, CAST256Decryption>(16), val256, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST256Encryption, CAST256Decryption>(24), val256, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory<CAST256Encryption, CAST256Decryption>(32), val256, 1) && pass; + + return pass; +} + +bool ValidateSquare() +{ + cout << "\nSquare validation suite running...\n\n"; + + FileSource valdata("squareva.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<SquareEncryption, SquareDecryption>(), valdata); +} + +bool ValidateSKIPJACK() +{ + cout << "\nSKIPJACK validation suite running...\n\n"; + + FileSource valdata("skipjack.dat", true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory<SKIPJACKEncryption, SKIPJACKDecryption>(), valdata); +} + +bool ValidateSEAL() +{ + byte input[] = {0x37,0xa0,0x05,0x95,0x9b,0x84,0xc4,0x9c,0xa4,0xbe,0x1e,0x05,0x06,0x73,0x53,0x0f,0x5f,0xb0,0x97,0xfd,0xf6,0xa1,0x3f,0xbd,0x6c,0x2c,0xde,0xcd,0x81,0xfd,0xee,0x7c}; + byte output[32]; + byte key[] = {0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0}; + byte iv[] = {0x01, 0x35, 0x77, 0xaf}; + + cout << "\nSEAL validation suite running...\n\n"; + + SEAL<>::Encryption seal(key); + seal.Resynchronize(iv); + unsigned int size = sizeof(input); + bool pass = true; + + memset(output, 1, size); + seal.ProcessString(output, input, size); + for (unsigned int i=0; i<size; i++) + if (output[i] != 0) + pass = false; + + seal.Seek(1); + output[1] = seal.ProcessByte(output[1]); + seal.ProcessString(output+2, size-2); + pass = pass && memcmp(output+1, input+1, size-1) == 0; + + cout << (pass ? "passed" : "FAILED") << endl; + return pass; +} diff --git a/validat2.cpp b/validat2.cpp new file mode 100644 index 0000000..783f7be --- /dev/null +++ b/validat2.cpp @@ -0,0 +1,740 @@ +// validat2.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "blumshub.h" +#include "rsa.h" +#include "md2.h" +#include "elgamal.h" +#include "nr.h" +#include "dsa.h" +#include "dh.h" +#include "mqv.h" +#include "luc.h" +#include "xtrcrypt.h" +#include "rabin.h" +#include "rw.h" +#include "eccrypto.h" +#include "ecp.h" +#include "ec2n.h" +#include "asn.h" +#include "rng.h" +#include "files.h" +#include "hex.h" +#include "oids.h" +#include "esign.h" +#include "osrng.h" + +#include <iostream> +#include <iomanip> + +#include "validate.h" + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +class FixedRNG : public RandomNumberGenerator +{ +public: + FixedRNG(BufferedTransformation &source) : m_source(source) {} + + byte GenerateByte() + { + byte b; + m_source.Get(b); + return b; + } + +private: + BufferedTransformation &m_source; +}; + +bool ValidateBBS() +{ + cout << "\nBlumBlumShub validation suite running...\n\n"; + + Integer p("212004934506826557583707108431463840565872545889679278744389317666981496005411448865750399674653351"); + Integer q("100677295735404212434355574418077394581488455772477016953458064183204108039226017738610663984508231"); + Integer seed("63239752671357255800299643604761065219897634268887145610573595874544114193025997412441121667211431"); + BlumBlumShub bbs(p, q, seed); + bool pass = true, fail; + int j; + + const byte output1[] = { + 0x49,0xEA,0x2C,0xFD,0xB0,0x10,0x64,0xA0,0xBB,0xB9, + 0x2A,0xF1,0x01,0xDA,0xC1,0x8A,0x94,0xF7,0xB7,0xCE}; + const byte output2[] = { + 0x74,0x45,0x48,0xAE,0xAC,0xB7,0x0E,0xDF,0xAF,0xD7, + 0xD5,0x0E,0x8E,0x29,0x83,0x75,0x6B,0x27,0x46,0xA1}; + + byte buf[20]; + + bbs.GenerateBlock(buf, 20); + fail = memcmp(output1, buf, 20) != 0; + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + for (j=0;j<20;j++) + cout << setw(2) << setfill('0') << hex << (int)buf[j]; + cout << endl; + + bbs.Seek(10); + bbs.GenerateBlock(buf, 10); + fail = memcmp(output1+10, buf, 10) != 0; + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + for (j=0;j<10;j++) + cout << setw(2) << setfill('0') << hex << (int)buf[j]; + cout << endl; + + bbs.Seek(1234567); + bbs.GenerateBlock(buf, 20); + fail = memcmp(output2, buf, 20) != 0; + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + for (j=0;j<20;j++) + cout << setw(2) << setfill('0') << hex << (int)buf[j]; + cout << endl; + + return pass; +} + +bool SignatureValidate(PK_Signer &priv, PK_Verifier &pub, bool thorough = false) +{ + bool pass = true, fail; + + fail = !pub.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2) || !priv.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "signature key validation\n"; + + const byte *message = (byte *)"test message"; + const int messageLen = 12; + byte buffer[512]; + + memset(buffer, 0, sizeof(buffer)); + priv.SignMessage(GlobalRNG(), message, messageLen, buffer); + fail = !pub.VerifyMessage(message, messageLen, buffer); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "signature and verification\n"; + + ++buffer[0]; + fail = pub.VerifyMessage(message, messageLen, buffer); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "checking invalid signature" << endl; + + return pass; +} + +bool CryptoSystemValidate(PK_Decryptor &priv, PK_Encryptor &pub, bool thorough = false) +{ + bool pass = true, fail; + + fail = !pub.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2) || !priv.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "cryptosystem key validation\n"; + + const byte *message = (byte *)"test message"; + const int messageLen = 12; + SecByteBlock ciphertext(priv.CiphertextLength(messageLen)); + SecByteBlock plaintext(priv.MaxPlaintextLength(ciphertext.size())); + + pub.Encrypt(GlobalRNG(), message, messageLen, ciphertext); + fail = priv.Decrypt(ciphertext, priv.CiphertextLength(messageLen), plaintext) != DecodingResult(messageLen); + fail = fail || memcmp(message, plaintext, messageLen); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "encryption and decryption\n"; + + return pass; +} + +bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d) +{ + if (d.GetCryptoParameters().Validate(GlobalRNG(), 3)) + cout << "passed simple key agreement domain parameters validation" << endl; + else + { + cout << "FAILED simple key agreement domain parameters invalid" << endl; + return false; + } + + SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength()); + SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength()); + SecByteBlock val1(d.AgreedValueLength()), val2(d.AgreedValueLength()); + + d.GenerateKeyPair(GlobalRNG(), priv1, pub1); + d.GenerateKeyPair(GlobalRNG(), priv2, pub2); + + memset(val1.begin(), 0x10, val1.size()); + memset(val2.begin(), 0x11, val2.size()); + + if (!(d.Agree(val1, priv1, pub2) && d.Agree(val2, priv2, pub1))) + { + cout << "FAILED simple key agreement failed" << endl; + return false; + } + + if (memcmp(val1.begin(), val2.begin(), d.AgreedValueLength())) + { + cout << "FAILED simple agreed values not equal" << endl; + return false; + } + + cout << "passed simple key agreement" << endl; + return true; +} + +bool AuthenticatedKeyAgreementValidate(AuthenticatedKeyAgreementDomain &d) +{ + if (d.GetCryptoParameters().Validate(GlobalRNG(), 3)) + cout << "passed authenticated key agreement domain parameters validation" << endl; + else + { + cout << "FAILED authenticated key agreement domain parameters invalid" << endl; + return false; + } + + SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength()); + SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength()); + SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength()); + SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength()); + SecByteBlock val1(d.AgreedValueLength()), val2(d.AgreedValueLength()); + + d.GenerateStaticKeyPair(GlobalRNG(), spriv1, spub1); + d.GenerateStaticKeyPair(GlobalRNG(), spriv2, spub2); + d.GenerateEphemeralKeyPair(GlobalRNG(), epriv1, epub1); + d.GenerateEphemeralKeyPair(GlobalRNG(), epriv2, epub2); + + memset(val1.begin(), 0x10, val1.size()); + memset(val2.begin(), 0x11, val2.size()); + + if (!(d.Agree(val1, spriv1, epriv1, spub2, epub2) && d.Agree(val2, spriv2, epriv2, spub1, epub1))) + { + cout << "FAILED authenticated key agreement failed" << endl; + return false; + } + + if (memcmp(val1.begin(), val2.begin(), d.AgreedValueLength())) + { + cout << "FAILED authenticated agreed values not equal" << endl; + return false; + } + + cout << "passed authenticated key agreement" << endl; + return true; +} + +bool ValidateRSA() +{ + cout << "\nRSA validation suite running...\n\n"; + + byte out[100], outPlain[100]; + bool pass = true, fail; + + { + char *plain = "Everyone gets Friday off."; + byte *signature = (byte *) + "\x05\xfa\x6a\x81\x2f\xc7\xdf\x8b\xf4\xf2\x54\x25\x09\xe0\x3e\x84" + "\x6e\x11\xb9\xc6\x20\xbe\x20\x09\xef\xb4\x40\xef\xbc\xc6\x69\x21" + "\x69\x94\xac\x04\xf3\x41\xb5\x7d\x05\x20\x2d\x42\x8f\xb2\xa2\x7b" + "\x5c\x77\xdf\xd9\xb1\x5b\xfc\x3d\x55\x93\x53\x50\x34\x10\xc1\xe1"; + + FileSource keys("rsa512a.dat", true, new HexDecoder); + RSASSA_PKCS1v15_MD2_Signer rsaPriv(keys); + RSASSA_PKCS1v15_MD2_Verifier rsaPub(rsaPriv); + + rsaPriv.SignMessage(GlobalRNG(), (byte *)plain, strlen(plain), out); + fail = memcmp(signature, out, 64) != 0; + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "signature check against test vector\n"; + + fail = !rsaPub.VerifyMessage((byte *)plain, strlen(plain), out); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "verification check against test vector\n"; + + out[10]++; + fail = rsaPub.VerifyMessage((byte *)plain, strlen(plain), out); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "invalid signature verification\n"; + } + { + FileSource keys("rsa1024.dat", true, new HexDecoder); + RSAES_PKCS1v15_Decryptor rsaPriv(keys); + RSAES_PKCS1v15_Encryptor rsaPub(rsaPriv); + + pass = CryptoSystemValidate(rsaPriv, rsaPub) && pass; + } + { + byte *plain = (byte *) + "\x54\x85\x9b\x34\x2c\x49\xea\x2a"; + byte *encrypted = (byte *) + "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a" + "\x8b\x40\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4" + "\x17\x53\x03\x29\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52" + "\x62\x51"; + byte *oaepSeed = (byte *) + "\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2" + "\xf0\x6c\xb5\x8f"; + ByteQueue bq; + bq.Put(oaepSeed, 20); + FixedRNG rng(bq); + + FileSource privFile("rsa400pv.dat", true, new HexDecoder); + FileSource pubFile("rsa400pb.dat", true, new HexDecoder); + RSAES_OAEP_SHA_Decryptor rsaPriv; + rsaPriv.AccessKey().BERDecodeKey(privFile); + RSAES_OAEP_SHA_Encryptor rsaPub(pubFile); + + memset(out, 0, 50); + memset(outPlain, 0, 8); + rsaPub.Encrypt(rng, plain, 8, out); + DecodingResult result = rsaPriv.FixedLengthDecrypt(encrypted, outPlain); + fail = !result.isValidCoding || (result.messageLength!=8) || memcmp(out, encrypted, 50) || memcmp(plain, outPlain, 8); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "PKCS 2.0 encryption and decryption\n"; + } + + return pass; +} + +bool ValidateDH() +{ + cout << "\nDH validation suite running...\n\n"; + + FileSource f("dh1024.dat", true, new HexDecoder()); + DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateMQV() +{ + cout << "\nMQV validation suite running...\n\n"; + + FileSource f("mqv1024.dat", true, new HexDecoder()); + MQV mqv(f); + return AuthenticatedKeyAgreementValidate(mqv); +} + +bool ValidateLUC_DH() +{ + cout << "\nLUC-DH validation suite running...\n\n"; + + FileSource f("lucd512.dat", true, new HexDecoder()); + LUC_DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateXTR_DH() +{ + cout << "\nXTR-DH validation suite running...\n\n"; + + FileSource f("xtrdh171.dat", true, new HexDecoder()); + XTR_DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateElGamal() +{ + cout << "\nElGamal validation suite running...\n\n"; + bool pass = true; + { + FileSource fc("elgc1024.dat", true, new HexDecoder); + ElGamalDecryptor privC(fc); + ElGamalEncryptor pubC(privC); + privC.AccessKey().Precompute(); + ByteQueue queue; + privC.AccessKey().SavePrecomputation(queue); + privC.AccessKey().LoadPrecomputation(queue); + + pass = CryptoSystemValidate(privC, pubC) && pass; + } + return pass; +} + +bool ValidateDLIES() +{ + cout << "\nDLIES validation suite running...\n\n"; + bool pass = true; + { + FileSource fc("dlie1024.dat", true, new HexDecoder); + DLIES<>::Decryptor privC(fc); + DLIES<>::Encryptor pubC(privC); + pass = CryptoSystemValidate(privC, pubC) && pass; + } + { + cout << "Generating new encryption key..." << endl; + DLIES<>::GroupParameters gp; + gp.GenerateRandomWithKeySize(GlobalRNG(), 128); + DLIES<>::Decryptor decryptor; + decryptor.AccessKey().GenerateRandom(GlobalRNG(), gp); + DLIES<>::Encryptor encryptor(decryptor); + + pass = CryptoSystemValidate(decryptor, encryptor) && pass; + } + return pass; +} + +bool ValidateNR() +{ + cout << "\nNR validation suite running...\n\n"; + bool pass = true; + { + FileSource f("nr2048.dat", true, new HexDecoder); + NR<SHA>::Signer privS(f); + privS.AccessKey().Precompute(); + NR<SHA>::Verifier pubS(privS); + + pass = SignatureValidate(privS, pubS) && pass; + } + { + cout << "Generating new signature key..." << endl; + NR<SHA>::Signer privS(GlobalRNG(), 256); + NR<SHA>::Verifier pubS(privS); + + pass = SignatureValidate(privS, pubS) && pass; + } + return pass; +} + +bool ValidateDSA(bool thorough) +{ + cout << "\nDSA validation suite running...\n\n"; + + bool pass = true, fail; + { + FileSource fs("dsa512.dat", true, new HexDecoder()); + GDSA<SHA>::Signer priv(fs); + priv.AccessKey().Precompute(16); + GDSA<SHA>::Verifier pub(priv); + + byte seed[]={0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b, 0xa8, 0xb6, 0x21, + 0x1b, 0x40, 0x62, 0xba, 0x32, 0x24, 0xe0, 0x42, 0x7d, 0xd3}; + Integer k("358dad57 1462710f 50e254cf 1a376b2b deaadfbfh"); + Integer h("a9993e36 4706816a ba3e2571 7850c26c 9cd0d89dh"); + byte sig[]={0x8b, 0xac, 0x1a, 0xb6, 0x64, 0x10, 0x43, 0x5c, 0xb7, 0x18, + 0x1f, 0x95, 0xb1, 0x6a, 0xb9, 0x7c, 0x92, 0xb3, 0x41, 0xc0, + 0x41, 0xe2, 0x34, 0x5f, 0x1f, 0x56, 0xdf, 0x24, 0x58, 0xf4, + 0x26, 0xd1, 0x55, 0xb4, 0xba, 0x2d, 0xb6, 0xdc, 0xd8, 0xc8}; + Integer r(sig, 20); + Integer s(sig+20, 20); + + Integer pGen, qGen, rOut, sOut; + int c; + + fail = !DSA::GeneratePrimes(seed, 160, c, pGen, 512, qGen); + fail = fail || (pGen != pub.GetKey().GetGroupParameters().GetModulus()) || (qGen != pub.GetKey().GetGroupParameters().GetSubgroupOrder()); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "prime generation test\n"; + + priv.GetDigestSignatureScheme().RawSign(k, h, rOut, sOut); + fail = (rOut != r) || (sOut != s); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "signature check against test vector\n"; + + fail = !pub.VerifyMessage((byte *)"abc", 3, sig); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "verification check against test vector\n"; + + fail = pub.VerifyMessage((byte *)"xyz", 3, sig); + pass = pass && !fail; + } + FileSource fs1("dsa1024.dat", true, new HexDecoder()); + DSA::Signer priv(fs1); + DSA::Verifier pub(priv); + FileSource fs2("dsa1024b.dat", true, new HexDecoder()); + DSA::Verifier pub1(fs2); + assert(pub.GetKey() == pub1.GetKey()); + pass = SignatureValidate(priv, pub, thorough) && pass; + return pass; +} + +bool ValidateLUC() +{ + cout << "\nLUC validation suite running...\n\n"; + bool pass=true; + + { + FileSource f("luc1024.dat", true, new HexDecoder); + LUCSSA_PKCS1v15_SHA_Signer priv(f); + LUCSSA_PKCS1v15_SHA_Verifier pub(priv); + pass = SignatureValidate(priv, pub) && pass; + } + { + LUCES_OAEP_SHA_Decryptor priv(GlobalRNG(), 512); + LUCES_OAEP_SHA_Encryptor pub(priv); + pass = CryptoSystemValidate(priv, pub) && pass; + } + return pass; +} + +bool ValidateLUC_DL() +{ + cout << "\nLUC-HMP validation suite running...\n\n"; + + FileSource f("lucs512.dat", true, new HexDecoder); + LUC_HMP<SHA>::Signer privS(f); + LUC_HMP<SHA>::Verifier pubS(privS); + bool pass = SignatureValidate(privS, pubS); + + cout << "\nLUC-IES validation suite running...\n\n"; + + FileSource fc("lucc512.dat", true, new HexDecoder); + LUC_IES<>::Decryptor privC(fc); + LUC_IES<>::Encryptor pubC(privC); + pass = CryptoSystemValidate(privC, pubC) && pass; + + return pass; +} + +bool ValidateRabin() +{ + cout << "\nRabin validation suite running...\n\n"; + bool pass=true; + + { + FileSource f("rabi1024.dat", true, new HexDecoder); + RabinPSSR<SHA>::Signer priv(f); + RabinPSSR<SHA>::Verifier pub(priv); + pass = SignatureValidate(priv, pub) && pass; + } + { + RabinES<OAEP<SHA> >::Decryptor priv(GlobalRNG(), 512); + RabinES<OAEP<SHA> >::Encryptor pub(priv); + pass = CryptoSystemValidate(priv, pub) && pass; + } + return pass; +} + +bool ValidateRW() +{ + cout << "\nRW validation suite running...\n\n"; + + FileSource f("rw1024.dat", true, new HexDecoder); + RWSSA<SHA>::Signer priv(f); + RWSSA<SHA>::Verifier pub(priv); + + return SignatureValidate(priv, pub); +} + +/* +bool ValidateBlumGoldwasser() +{ + cout << "\nBlumGoldwasser validation suite running...\n\n"; + + FileSource f("blum512.dat", true, new HexDecoder); + BlumGoldwasserPrivateKey priv(f); + BlumGoldwasserPublicKey pub(priv); + + return CryptoSystemValidate(priv, pub); +} +*/ + +bool ValidateECP() +{ + cout << "\nECP validation suite running...\n\n"; + + ECIES<ECP>::Decryptor cpriv(GlobalRNG(), ASN1::secp192r1()); + ECIES<ECP>::Encryptor cpub(cpriv); + ByteQueue bq; + cpriv.GetKey().DEREncode(bq); + cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + cpub.GetKey().DEREncode(bq); + ECDSA<ECP, SHA>::Signer spriv(bq); + ECDSA<ECP, SHA>::Verifier spub(bq); + ECDH<ECP>::Domain ecdhc(ASN1::secp192r1()); + ECMQV<ECP>::Domain ecmqvc(ASN1::secp192r1()); + + spriv.AccessKey().Precompute(); + ByteQueue queue; + spriv.AccessKey().SavePrecomputation(queue); + spriv.AccessKey().LoadPrecomputation(queue); + + bool pass = SignatureValidate(spriv, spub); + cpub.AccessKey().Precompute(); + cpriv.AccessKey().Precompute(); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + cout << "Turning on point compression..." << endl; + cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true); + cpub.AccessKey().AccessGroupParameters().SetPointCompression(true); + ecdhc.AccessGroupParameters().SetPointCompression(true); + ecmqvc.AccessGroupParameters().SetPointCompression(true); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + cout << "Testing SEC 2 recommended curves..." << endl; + OID oid; + while (!(oid = DL_GroupParameters_EC<ECP>::GetNextRecommendedParametersOID(oid)).m_values.empty()) + { + DL_GroupParameters_EC<ECP> params(oid); + bool fail = !params.Validate(GlobalRNG(), 2); + cout << (fail ? "FAILED" : "passed") << " " << dec << params.GetCurve().GetField().MaxElementBitLength() << " bits" << endl; + pass = pass && !fail; + } + + return pass; +} + +bool ValidateEC2N() +{ + cout << "\nEC2N validation suite running...\n\n"; + + ECIES<EC2N>::Decryptor cpriv(GlobalRNG(), ASN1::sect193r1()); + ECIES<EC2N>::Encryptor cpub(cpriv); + ByteQueue bq; + cpriv.DEREncode(bq); + cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + cpub.DEREncode(bq); + ECDSA<EC2N, SHA>::Signer spriv(bq); + ECDSA<EC2N, SHA>::Verifier spub(bq); + ECDH<EC2N>::Domain ecdhc(ASN1::sect193r1()); + ECMQV<EC2N>::Domain ecmqvc(ASN1::sect193r1()); + + spriv.AccessKey().Precompute(); + ByteQueue queue; + spriv.AccessKey().SavePrecomputation(queue); + spriv.AccessKey().LoadPrecomputation(queue); + + bool pass = SignatureValidate(spriv, spub); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + cout << "Turning on point compression..." << endl; + cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true); + cpub.AccessKey().AccessGroupParameters().SetPointCompression(true); + ecdhc.AccessGroupParameters().SetPointCompression(true); + ecmqvc.AccessGroupParameters().SetPointCompression(true); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + +#if 0 // TODO: turn this back on when I make EC2N faster for pentanomial basis + cout << "Testing SEC 2 recommended curves..." << endl; + OID oid; + while (!(oid = ECParameters<EC2N>::GetNextRecommendedParametersOID(oid)).m_values.empty()) + { + ECParameters<EC2N> params(oid); + bool fail = !params.ValidateParameters(GlobalRNG()); + cout << (fail ? "FAILED" : "passed") << " " << params.GetCurve().GetField().MaxElementBitLength() << " bits" << endl; + pass = pass && !fail; + } +#endif + + return pass; +} + +bool ValidateECDSA() +{ + cout << "\nECDSA validation suite running...\n\n"; + + // from Sample Test Vectors for P1363 + GF2NT gf2n(191, 9, 0); + byte a[]="\x28\x66\x53\x7B\x67\x67\x52\x63\x6A\x68\xF5\x65\x54\xE1\x26\x40\x27\x6B\x64\x9E\xF7\x52\x62\x67"; + byte b[]="\x2E\x45\xEF\x57\x1F\x00\x78\x6F\x67\xB0\x08\x1B\x94\x95\xA3\xD9\x54\x62\xF5\xDE\x0A\xA1\x85\xEC"; + EC2N ec(gf2n, PolynomialMod2(a,24), PolynomialMod2(b,24)); + + EC2N::Point P; + ec.DecodePoint(P, (byte *)"\x04\x36\xB3\xDA\xF8\xA2\x32\x06\xF9\xC4\xF2\x99\xD7\xB2\x1A\x9C\x36\x91\x37\xF2\xC8\x4A\xE1\xAA\x0D" + "\x76\x5B\xE7\x34\x33\xB3\xF9\x5E\x33\x29\x32\xE7\x0E\xA2\x45\xCA\x24\x18\xEA\x0E\xF9\x80\x18\xFB", ec.EncodedPointSize()); + Integer n("40000000000000000000000004a20e90c39067c893bbb9a5H"); + Integer d("340562e1dda332f9d2aec168249b5696ee39d0ed4d03760fH"); + EC2N::Point Q(ec.Multiply(d, P)); + ECDSA<EC2N, SHA>::Signer priv(ec, P, n, d); + ECDSA<EC2N, SHA>::Verifier pub(priv); + + Integer h("A9993E364706816ABA3E25717850C26C9CD0D89DH"); + Integer k("3eeace72b4919d991738d521879f787cb590aff8189d2b69H"); + byte sig[]="\x03\x8e\x5a\x11\xfb\x55\xe4\xc6\x54\x71\xdc\xd4\x99\x84\x52\xb1\xe0\x2d\x8a\xf7\x09\x9b\xb9\x30" + "\x0c\x9a\x08\xc3\x44\x68\xc2\x44\xb4\xe5\xd6\xb2\x1b\x3c\x68\x36\x28\x07\x41\x60\x20\x32\x8b\x6e"; + Integer r(sig, 24); + Integer s(sig+24, 24); + + Integer rOut, sOut; + bool fail, pass=true; + + priv.GetDigestSignatureScheme().RawSign(k, h, rOut, sOut); + fail = (rOut != r) || (sOut != s); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "signature check against test vector\n"; + + fail = !pub.VerifyMessage((byte *)"abc", 3, sig); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "verification check against test vector\n"; + + fail = pub.VerifyMessage((byte *)"xyz", 3, sig); + pass = pass && !fail; + + pass = SignatureValidate(priv, pub) && pass; + + return pass; +} + +bool ValidateESIGN() +{ + cout << "\nESIGN validation suite running...\n\n"; + + bool pass = true, fail; + + const char *plain = "test"; + const byte *signature = (byte *) + "\xA3\xE3\x20\x65\xDE\xDA\xE7\xEC\x05\xC1\xBF\xCD\x25\x79\x7D\x99\xCD\xD5\x73\x9D\x9D\xF3\xA4\xAA\x9A\xA4\x5A\xC8\x23\x3D\x0D\x37\xFE\xBC\x76\x3F\xF1\x84\xF6\x59" + "\x14\x91\x4F\x0C\x34\x1B\xAE\x9A\x5C\x2E\x2E\x38\x08\x78\x77\xCB\xDC\x3C\x7E\xA0\x34\x44\x5B\x0F\x67\xD9\x35\x2A\x79\x47\x1A\x52\x37\x71\xDB\x12\x67\xC1\xB6\xC6" + "\x66\x73\xB3\x40\x2E\xD6\xF2\x1A\x84\x0A\xB6\x7B\x0F\xEB\x8B\x88\xAB\x33\xDD\xE4\x83\x21\x90\x63\x2D\x51\x2A\xB1\x6F\xAB\xA7\x5C\xFD\x77\x99\xF2\xE1\xEF\x67\x1A" + "\x74\x02\x37\x0E\xED\x0A\x06\xAD\xF4\x15\x65\xB8\xE1\xD1\x45\xAE\x39\x19\xB4\xFF\x5D\xF1\x45\x7B\xE0\xFE\x72\xED\x11\x92\x8F\x61\x41\x4F\x02\x00\xF2\x76\x6F\x7C" + "\x79\xA2\xE5\x52\x20\x5D\x97\x5E\xFE\x39\xAE\x21\x10\xFB\x35\xF4\x80\x81\x41\x13\xDD\xE8\x5F\xCA\x1E\x4F\xF8\x9B\xB2\x68\xFB\x28"; + + FileSource keys("esig1536.dat", true, new HexDecoder); + ESIGN<SHA>::Signer signer(keys); + ESIGN<SHA>::Verifier verifier(signer); + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + + fail = !verifier.VerifyMessage((byte *)plain, strlen(plain), signature); + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + cout << "verification check against test vector\n"; + + cout << "Generating signature key from seed..." << endl; + InvertibleESIGNFunction priv; + priv.GenerateRandom(GlobalRNG(), MakeParameters("Seed", ConstByteArrayParameter((const byte *)"test", 4))("KeySize", 3*512)); + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + + return pass; +} diff --git a/validat3.cpp b/validat3.cpp new file mode 100644 index 0000000..aa7aae1 --- /dev/null +++ b/validat3.cpp @@ -0,0 +1,638 @@ +// validat3.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "validate.h" + +#include "smartptr.h" +#include "crc.h" +#include "adler32.h" +#include "md2.h" +#include "md4.h" +#include "md5.h" +#include "sha.h" +#include "tiger.h" +#include "ripemd.h" +#include "haval.h" +#include "panama.h" + +#include "md5mac.h" +#include "hmac.h" +#include "xormac.h" + +#include "integer.h" +#include "pwdbased.h" +#include "filters.h" +#include "hex.h" +#include "files.h" + +#include <iostream> +#include <iomanip> + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +struct HashTestTuple +{ + HashTestTuple(const char *input, const char *output, unsigned int repeatTimes=1) + : input((byte *)input), output((byte *)output), inputLen(strlen(input)), repeatTimes(repeatTimes) {} + + HashTestTuple(const char *input, unsigned int inputLen, const char *output, unsigned int repeatTimes) + : input((byte *)input), output((byte *)output), inputLen(inputLen), repeatTimes(repeatTimes) {} + + const byte *input, *output; + unsigned int inputLen, repeatTimes; +}; + +bool HashModuleTest(HashTransformation &md, const HashTestTuple *testSet, unsigned int testSetSize) +{ + bool pass=true, fail; + SecByteBlock digest(md.DigestSize()); + + for (unsigned int i=0; i<testSetSize; i++) + { + unsigned j; + + for (j=0; j<testSet[i].repeatTimes; j++) + md.Update(testSet[i].input, testSet[i].inputLen); + md.Final(digest); + fail = memcmp(digest, testSet[i].output, md.DigestSize()) != 0; + pass = pass && !fail; + + cout << (fail ? "FAILED " : "passed "); + for (j=0; j<md.DigestSize(); j++) + cout << setw(2) << setfill('0') << hex << (int)digest[j]; + cout << " \"" << (char *)testSet[i].input << '\"'; + if (testSet[i].repeatTimes != 1) + cout << " repeated " << dec << testSet[i].repeatTimes << " times"; + cout << endl; + } + + return pass; +} + +bool ValidateCRC32() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\x00\x00\x00\x00"), + HashTestTuple("a", "\x43\xbe\xb7\xe8"), + HashTestTuple("abc", "\xc2\x41\x24\x35"), + HashTestTuple("message digest", "\x7f\x9d\x15\x20"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xbd\x50\x27\x4c"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xd2\xe6\xc2\x1f"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x72\x4a\xa9\x7c"), + HashTestTuple("123456789", "\x26\x39\xf4\xcb") + }; + + CRC32 crc; + + cout << "\nCRC-32 validation suite running...\n\n"; + return HashModuleTest(crc, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateAdler32() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\x00\x00\x00\x01"), + HashTestTuple("a", "\x00\x62\x00\x62"), + HashTestTuple("abc", "\x02\x4d\x01\x27"), + HashTestTuple("message digest", "\x29\x75\x05\x86"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\x90\x86\x0b\x20"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\x8a\xdb\x15\x0c"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\x15\xd8\x70\xf9", 15625) + }; + + Adler32 md; + + cout << "\nAdler-32 validation suite running...\n\n"; + return HashModuleTest(md, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateMD2() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\x83\x50\xe5\xa3\xe2\x4c\x15\x3d\xf2\x27\x5c\x9f\x80\x69\x27\x73"), + HashTestTuple("a", "\x32\xec\x01\xec\x4a\x6d\xac\x72\xc0\xab\x96\xfb\x34\xc0\xb5\xd1"), + HashTestTuple("abc", "\xda\x85\x3b\x0d\x3f\x88\xd9\x9b\x30\x28\x3a\x69\xe6\xde\xd6\xbb"), + HashTestTuple("message digest", "\xab\x4f\x49\x6b\xfb\x2a\x53\x0b\x21\x9f\xf3\x30\x31\xfe\x06\xb0"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\x4e\x8d\xdf\xf3\x65\x02\x92\xab\x5a\x41\x08\xc3\xaa\x47\x94\x0b"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xda\x33\xde\xf2\xa4\x2d\xf1\x39\x75\x35\x28\x46\xc3\x03\x38\xcd"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\xd5\x97\x6f\x79\xd8\x3d\x3a\x0d\xc9\x80\x6c\x3c\x66\xf3\xef\xd8") + }; + + MD2 md2; + + cout << "\nMD2 validation suite running...\n\n"; + return HashModuleTest(md2, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateMD4() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0"), + HashTestTuple("a", "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24"), + HashTestTuple("abc", "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d"), + HashTestTuple("message digest", "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d\xa9"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05\x36") + }; + + MD4 md4; + + cout << "\nMD4 validation suite running...\n\n"; + return HashModuleTest(md4, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateMD5() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e"), + HashTestTuple("a", "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8\x31\xc3\x99\xe2\x69\x77\x26\x61"), + HashTestTuple("abc", "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"), + HashTestTuple("message digest", "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55\xac\x49\xda\x2e\x21\x07\xb6\x7a") + }; + + MD5 md5; + + cout << "\nMD5 validation suite running...\n\n"; + return HashModuleTest(md5, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateSHA() +{ + HashTestTuple testSet[] = + { + HashTestTuple("abc", "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F", 15625) + }; + + SHA sha; + + cout << "\nSHA validation suite running...\n\n"; + return HashModuleTest(sha, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateSHA2() +{ + HashTestTuple testSet256[] = + { + HashTestTuple("abc", "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1"), + }; + + HashTestTuple testSet384[] = + { + HashTestTuple("abc", "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7"), + HashTestTuple("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "\x09\x33\x0c\x33\xf7\x11\x47\xe8\x3d\x19\x2f\xc7\x82\xcd\x1b\x47\x53\x11\x1b\x17\x3b\x3b\x05\xd2\x2f\xa0\x80\x86\xe3\xb0\xf7\x12\xfc\xc7\xc7\x1a\x55\x7e\x2d\xb9\x66\xc3\xe9\xfa\x91\x74\x60\x39"), + }; + + HashTestTuple testSet512[] = + { + HashTestTuple("abc", "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f"), + HashTestTuple("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14\x3f\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88\x90\x18\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4\xb5\x43\x3a\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b\x87\x4b\xe9\x09"), + }; + + bool pass = true; + + cout << "\nSHA-256 validation suite running...\n\n"; + SHA256 sha256; + pass = HashModuleTest(sha256, testSet256, sizeof(testSet256)/sizeof(testSet256[0])) && pass; + + cout << "\nSHA-384 validation suite running...\n\n"; + SHA384 sha384; + pass = HashModuleTest(sha384, testSet384, sizeof(testSet384)/sizeof(testSet384[0])) && pass; + + cout << "\nSHA-512 validation suite running...\n\n"; + SHA512 sha512; + pass = HashModuleTest(sha512, testSet512, sizeof(testSet512)/sizeof(testSet512[0])) && pass; + + return pass; +} + +bool ValidateTiger() +{ + cout << "\nTiger validation suite running...\n\n"; + +#ifdef WORD64_AVAILABLE + HashTestTuple testSet[] = + { + HashTestTuple("", "\x32\x93\xac\x63\x0c\x13\xf0\x24\x5f\x92\xbb\xb1\x76\x6e\x16\x16\x7a\x4e\x58\x49\x2d\xde\x73\xf3"), + HashTestTuple("abc", "\x2a\xab\x14\x84\xe8\xc1\x58\xf2\xbf\xb8\xc5\xff\x41\xb5\x7a\x52\x51\x29\x13\x1c\x95\x7b\x5f\x93"), + HashTestTuple("Tiger", "\xdd\x00\x23\x07\x99\xf5\x00\x9f\xec\x6d\xeb\xc8\x38\xbb\x6a\x27\xdf\x2b\x9d\x6f\x11\x0c\x79\x37"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "\xf7\x1c\x85\x83\x90\x2a\xfb\x87\x9e\xdf\xe6\x10\xf8\x2c\x0d\x47\x86\xa3\xa5\x34\x50\x44\x86\xb5"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789", "\x48\xce\xeb\x63\x08\xb8\x7d\x46\xe9\x5d\x65\x61\x12\xcd\xf1\x8d\x97\x91\x5f\x97\x65\x65\x89\x57"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham", "\x8a\x86\x68\x29\x04\x0a\x41\x0c\x72\x9a\xd2\x3f\x5a\xda\x71\x16\x03\xb3\xcd\xd3\x57\xe4\xc1\x5e"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.", "\xce\x55\xa6\xaf\xd5\x91\xf5\xeb\xac\x54\x7f\xf8\x4f\x89\x22\x7f\x93\x31\xda\xb0\xb6\x11\xc8\x89"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.", "\x63\x1a\xbd\xd1\x03\xeb\x9a\x3d\x24\x5b\x6d\xfd\x4d\x77\xb2\x57\xfc\x74\x39\x50\x1d\x15\x68\xdd"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "\xc5\x40\x34\xe5\xb4\x3e\xb8\x00\x58\x48\xa7\xe0\xae\x6a\xac\x76\xe4\xff\x59\x0a\xe7\x15\xfd\x25") + }; + + Tiger tiger; + + return HashModuleTest(tiger, testSet, sizeof(testSet)/sizeof(testSet[0])); +#else + cout << "word64 not available, skipping Tiger validation." << endl; + return true; +#endif +} + +bool ValidateRIPEMD() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31"), + HashTestTuple("a", "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe"), + HashTestTuple("abc", "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc"), + HashTestTuple("message digest", "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb\xd3\x32\x3c\xab\x82\xbf\x63\x32\x6b\xfb"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\x52\x78\x32\x43\xc1\x69\x7b\xdb\xe1\x6d\x37\xf9\x7f\x68\xf0\x83\x25\xdc\x15\x28", 15625) + }; + + RIPEMD160 md; + + cout << "\nRIPEMD-160 validation suite running...\n\n"; + return HashModuleTest(md, testSet, sizeof(testSet)/sizeof(testSet[0])); +} + +bool ValidateHAVAL() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\xC6\x8F\x39\x91\x3F\x90\x1F\x3D\xDF\x44\xC7\x07\x35\x7A\x7D\x70"), + HashTestTuple("a", "\x4D\xA0\x8F\x51\x4A\x72\x75\xDB\xC4\xCE\xCE\x4A\x34\x73\x85\x98\x39\x83\xA8\x30"), + HashTestTuple("HAVAL", "\x0C\x13\x96\xD7\x77\x26\x89\xC4\x67\x73\xF3\xDA\xAC\xA4\xEF\xA9\x82\xAD\xBF\xB2\xF1\x46\x7E\xEA"), + HashTestTuple("0123456789", "\xBE\xBD\x78\x16\xF0\x9B\xAE\xEC\xF8\x90\x3B\x1B\x9B\xC6\x72\xD9\xFA\x42\x8E\x46\x2B\xA6\x99\xF8\x14\x84\x15\x29"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xC9\xC7\xD8\xAF\xA1\x59\xFD\x9E\x96\x5C\xB8\x3F\xF5\xEE\x6F\x58\xAE\xDA\x35\x2C\x0E\xFF\x00\x55\x48\x15\x3A\x61\x55\x1C\x38\xEE"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xB4\x5C\xB6\xE6\x2F\x2B\x13\x20\xE4\xF8\xF1\xB0\xB2\x73\xD4\x5A\xDD\x47\xC3\x21\xFD\x23\x99\x9D\xCF\x40\x3A\xC3\x76\x36\xD9\x63") + }; + + bool pass=true; + + cout << "\nHAVAL validation suite running...\n\n"; + { + HAVAL3 md(16); + pass = HashModuleTest(md, testSet+0, 1) && pass; + } + { + HAVAL3 md(20); + pass = HashModuleTest(md, testSet+1, 1) && pass; + } + { + HAVAL4 md(24); + pass = HashModuleTest(md, testSet+2, 1) && pass; + } + { + HAVAL4 md(28); + pass = HashModuleTest(md, testSet+3, 1) && pass; + } + { + HAVAL5 md(32); + pass = HashModuleTest(md, testSet+4, 1) && pass; + } + { + HAVAL5 md(32); + pass = HashModuleTest(md, testSet+5, 1) && pass; + } + + return pass; +} + +bool ValidatePanama() +{ + bool pass=true; + + // the first two test vectors are from the reference implementation + // the rest were generated by Crypto++ + HashTestTuple testSet1[] = + { + HashTestTuple("", "\xaa\x0c\xc9\x54\xd7\x57\xd7\xac\x77\x79\xca\x33\x42\x33\x4c\xa4\x71\xab\xd4\x7d\x59\x52\xac\x91\xed\x83\x7e\xcd\x5b\x16\x92\x2b"), + HashTestTuple("The quick brown fox jumps over the lazy dog", "\x5f\x5c\xa3\x55\xb9\x0a\xc6\x22\xb0\xaa\x7e\x65\x4e\xf5\xf2\x7e\x9e\x75\x11\x14\x15\xb4\x8b\x8a\xfe\x3a\xdd\x1c\x6b\x89\xcb\xa1"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\xaf\x9c\x66\xfb\x60\x58\xe2\x23\x2a\x5d\xfb\xa0\x63\xee\x14\xb0\xf8\x6f\x0e\x33\x4e\x16\x58\x12\x55\x94\x35\x46\x4d\xd9\xbb\x60", 15625) + }; + HashTestTuple testSet2[] = + { + HashTestTuple("", "\xe8\x1a\xa0\x45\x23\x53\x2d\xd7\x26\x7e\x5c\x5b\xc3\xba\x0e\x28\x98\x37\xa6\x2b\xa0\x32\x35\x03\x51\x98\x0e\x96\x0a\x84\xb0\xaf"), + HashTestTuple("The quick brown fox jumps over the lazy dog", "\x8f\xa7\xda\xdc\xe0\x11\x0f\x97\x9a\x0b\x79\x5e\x76\xb2\xc2\x56\x28\xd8\xbd\xa8\x87\x47\x75\x81\x49\xc4\x2e\x3b\xc1\x3f\x85\xbc"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\xcb\x34\xf0\x93\x7e\x8d\x87\x0d\x3b\xd7\xff\x63\x11\x76\x5f\x2c\x22\x9a\x6c\x21\x54\xe4\xdb\x11\x95\x38\xdb\x51\x59\x43\x7c\xab", 15625) + }; + + cout << "\nPanama Hash Function (little endian) validation suite running...\n\n"; + PanamaHash<LittleEndian> panamaLE; + pass = HashModuleTest(panamaLE, testSet1, sizeof(testSet1)/sizeof(testSet1[0])) && pass; + + cout << "\nPanama Hash Function (big endian) validation suite running...\n\n"; + PanamaHash<BigEndian> panamaBE; + pass = HashModuleTest(panamaBE, testSet2, sizeof(testSet2)/sizeof(testSet2[0])) && pass; + + // these were generated by Crypto++ + unsigned char Key0[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f}; + unsigned char Input0l[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f}; + unsigned char Output0l[] = { + 0xF0,0x7F,0x5F,0xF2,0xCC,0xD0,0x1A,0x0A, + 0x7D,0x44,0xAC,0xD6,0xD2,0x39,0xC2,0xAF, + 0x0D,0xA1,0xFF,0x35,0x27,0x5B,0xAF,0x5D, + 0xFA,0x6E,0x09,0x41,0x1B,0x79,0xD8,0xB9}; + unsigned char Input0b[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f}; + unsigned char Output0b[] = { + 0xE1,0x2E,0x2F,0x6B,0xA4,0x1A,0xE8,0x32, + 0xD8,0x88,0xDA,0x9F,0xA6,0x86,0x3B,0xC3, + 0x7C,0x0E,0x99,0x6F,0x19,0x0A,0x17,0x11, + 0x33,0x03,0x22,0xD3,0x7B,0xD9,0x8C,0xA4}; + + // VC60 workaround: auto_ptr lacks reset() + member_ptr<StreamTransformation> cipher; + bool fail; + + cout << "\nPanama Cipher (little endian) validation suite running...\n\n"; + + cipher.reset(new PanamaCipher<LittleEndian>::Encryption(Key0, 64)); + cipher->ProcessString(Input0l, sizeof(Input0l)); + fail = memcmp(Input0l, Output0l, sizeof(Input0l)) != 0; + cout << (fail ? "FAILED" : "passed") << " Test 0" << endl; + pass = pass && !fail; + + cout << "\nPanama Cipher (big endian) validation suite running...\n\n"; + + cipher.reset(new PanamaCipher<BigEndian>::Encryption(Key0, 64)); + cipher->ProcessString(Input0b, sizeof(Input0b)); + fail = memcmp(Input0b, Output0b, sizeof(Input0b)) != 0; + cout << (fail ? "FAILED" : "passed") << " Test 0" << endl; + pass = pass && !fail; + + return pass; +} + +bool ValidateMD5MAC() +{ + const byte keys[2][MD5MAC::KEYLENGTH]={ + {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}, + {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10}}; + + const char *TestVals[7]={ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}; + + const byte output[2][7][MD5MAC::DIGESTSIZE]={ + {{0x1f,0x1e,0xf2,0x37,0x5c,0xc0,0xe0,0x84,0x4f,0x98,0xe7,0xe8,0x11,0xa3,0x4d,0xa8}, + {0x7a,0x76,0xee,0x64,0xca,0x71,0xef,0x23,0x7e,0x26,0x29,0xed,0x94,0x52,0x73,0x65}, + {0xe8,0x01,0x3c,0x11,0xf7,0x20,0x9d,0x13,0x28,0xc0,0xca,0xa0,0x4f,0xd0,0x12,0xa6}, + {0xc8,0x95,0x53,0x4f,0x22,0xa1,0x74,0xbc,0x3e,0x6a,0x25,0xa2,0xb2,0xef,0xd6,0x30}, + {0x91,0x72,0x86,0x7e,0xb6,0x00,0x17,0x88,0x4c,0x6f,0xa8,0xcc,0x88,0xeb,0xe7,0xc9}, + {0x3b,0xd0,0xe1,0x1d,0x5e,0x09,0x4c,0xb7,0x1e,0x35,0x44,0xac,0xa9,0xb8,0xbf,0xa2}, + {0x93,0x37,0x16,0x64,0x44,0xcc,0x95,0x35,0xb7,0xd5,0xb8,0x0f,0x91,0xe5,0x29,0xcb}}, + {{0x2f,0x6e,0x73,0x13,0xbf,0xbb,0xbf,0xcc,0x3a,0x2d,0xde,0x26,0x8b,0x59,0xcc,0x4d}, + {0x69,0xf6,0xca,0xff,0x40,0x25,0x36,0xd1,0x7a,0xe1,0x38,0x03,0x2c,0x0c,0x5f,0xfd}, + {0x56,0xd3,0x2b,0x6c,0x34,0x76,0x65,0xd9,0x74,0xd6,0xf7,0x5c,0x3f,0xc6,0xf0,0x40}, + {0xb8,0x02,0xb2,0x15,0x4e,0x59,0x8b,0x6f,0x87,0x60,0x56,0xc7,0x85,0x46,0x2c,0x0b}, + {0x5a,0xde,0xf4,0xbf,0xf8,0x04,0xbe,0x08,0x58,0x7e,0x94,0x41,0xcf,0x6d,0xbd,0x57}, + {0x18,0xe3,0x49,0xa5,0x24,0x44,0xb3,0x0e,0x5e,0xba,0x5a,0xdd,0xdc,0xd9,0xf1,0x8d}, + {0xf2,0xb9,0x06,0xa5,0xb8,0x4b,0x9b,0x4b,0xbe,0x95,0xed,0x32,0x56,0x4e,0xe7,0xeb}}}; + + byte digest[MD5MAC::DIGESTSIZE]; + bool pass=true, fail; + + cout << "\nMD5MAC validation suite running...\n"; + + for (int k=0; k<2; k++) + { + MD5MAC mac(keys[k]); + cout << "\nKEY: "; + for (int j=0;j<MD5MAC::KEYLENGTH;j++) + cout << setw(2) << setfill('0') << hex << (int)keys[k][j]; + cout << endl << endl; + for (int i=0;i<7;i++) + { + mac.Update((byte *)TestVals[i], strlen(TestVals[i])); + mac.Final(digest); + fail = memcmp(digest, output[k][i], MD5MAC::DIGESTSIZE) + || !mac.VerifyDigest(output[k][i], (byte *)TestVals[i], strlen(TestVals[i])); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed "); + for (int j=0;j<MD5MAC::DIGESTSIZE;j++) + cout << setw(2) << setfill('0') << hex << (int)digest[j]; + cout << " \"" << TestVals[i] << '\"' << endl; + } + } + + return pass; +} + +bool ValidateHMAC() +{ + typedef HMAC<MD5> HMAC_MD5; + + const char* keys[]= + { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "Jefe", + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + }; + + HashTestTuple testSet[] = + { + HashTestTuple("Hi There", "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d"), + HashTestTuple("what do ya want for nothing?", "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"), + HashTestTuple("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", + "\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6"), + HashTestTuple("Test Using Larger Than Block-Size Key - Hash Key First", "\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f\x0b\x62\xe6\xce\x61\xb9\xd0\xcd") + }; + + bool pass=true; + + cout << "\nHMAC/MD5 validation suite running...\n"; + + for (int k=0; k<4; k++) + { + HMAC_MD5 mac((byte *)keys[k], strlen(keys[k])); + cout << "\nKEY: "; + for (int j=0; keys[k][j] != 0; j++) + cout << setw(2) << setfill('0') << hex << (int)(byte)keys[k][j]; + cout << endl; + + pass = HashModuleTest(mac, testSet+k, 1) && pass; + } + + return pass; +} + +bool ValidateXMACC() +{ + typedef XMACC<MD5> XMACC_MD5; + + const byte keys[2][XMACC_MD5::KEYLENGTH]={ + {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb}, + {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98}}; + + const word32 counters[2]={0xccddeeff, 0x76543210}; + + const char *TestVals[7]={ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}; + + const byte output[2][7][XMACC_MD5::DIGESTSIZE]={ + {{0xcc,0xdd,0xef,0x00,0xfa,0x89,0x54,0x92,0x86,0x32,0xda,0x2a,0x3f,0x29,0xc5,0x52,0xa0,0x0d,0x05,0x13}, + {0xcc,0xdd,0xef,0x01,0xae,0xdb,0x8b,0x7b,0x69,0x71,0xc7,0x91,0x71,0x48,0x9d,0x18,0xe7,0xdf,0x9d,0x5a}, + {0xcc,0xdd,0xef,0x02,0x5e,0x01,0x2e,0x2e,0x4b,0xc3,0x83,0x62,0xc2,0xf4,0xe6,0x18,0x1c,0x44,0xaf,0xca}, + {0xcc,0xdd,0xef,0x03,0x3e,0xa9,0xf1,0xe0,0x97,0x91,0xf8,0xe2,0xbe,0xe0,0xdf,0xf3,0x41,0x03,0xb3,0x5a}, + {0xcc,0xdd,0xef,0x04,0x2e,0x6a,0x8d,0xb9,0x72,0xe3,0xce,0x9f,0xf4,0x28,0x45,0xe7,0xbc,0x80,0xa9,0xc7}, + {0xcc,0xdd,0xef,0x05,0x1a,0xd5,0x40,0x78,0xfb,0x16,0x37,0xfc,0x7a,0x1d,0xce,0xb4,0x77,0x10,0xb2,0xa0}, + {0xcc,0xdd,0xef,0x06,0x13,0x2f,0x11,0x47,0xd7,0x1b,0xb5,0x52,0x36,0x51,0x26,0xb0,0x96,0xd7,0x60,0x81}}, + {{0x76,0x54,0x32,0x11,0xe9,0xcb,0x74,0x32,0x07,0x93,0xfe,0x01,0xdd,0x27,0xdb,0xde,0x6b,0x77,0xa4,0x56}, + {0x76,0x54,0x32,0x12,0xcd,0x55,0x87,0x5c,0xc0,0x35,0x85,0x99,0x44,0x02,0xa5,0x0b,0x8c,0xe7,0x2c,0x68}, + {0x76,0x54,0x32,0x13,0xac,0xfd,0x87,0x50,0xc3,0x8f,0xcd,0x58,0xaa,0xa5,0x7e,0x7a,0x25,0x63,0x26,0xd1}, + {0x76,0x54,0x32,0x14,0xe3,0x30,0xf5,0xdd,0x27,0x2b,0x76,0x22,0x7f,0xaa,0x90,0x73,0x6a,0x48,0xdb,0x00}, + {0x76,0x54,0x32,0x15,0xfc,0x57,0x00,0x20,0x7c,0x9d,0xf6,0x30,0x6f,0xbd,0x46,0x3e,0xfb,0x8a,0x2c,0x60}, + {0x76,0x54,0x32,0x16,0xfb,0x0f,0xd3,0xdf,0x4c,0x4b,0xc3,0x05,0x9d,0x63,0x1e,0xba,0x25,0x2b,0xbe,0x35}, + {0x76,0x54,0x32,0x17,0xc6,0xfe,0xe6,0x5f,0xb1,0x35,0x8a,0xf5,0x32,0x7a,0x80,0xbd,0xb8,0x72,0xee,0xae}}}; + + byte digest[XMACC_MD5::DIGESTSIZE]; + bool pass=true, fail; + + cout << "\nXMACC/MD5 validation suite running...\n"; + + for (int k=0; k<2; k++) + { + XMACC_MD5 mac(keys[k], counters[k]); + cout << "\nKEY: "; + for (int j=0;j<XMACC_MD5::KEYLENGTH;j++) + cout << setw(2) << setfill('0') << hex << (int)keys[k][j]; + cout << " COUNTER: 0x" << hex << counters[k] << endl << endl; + for (int i=0;i<7;i++) + { + mac.Update((byte *)TestVals[i], strlen(TestVals[i])); + mac.Final(digest); + fail = memcmp(digest, output[k][i], XMACC_MD5::DIGESTSIZE) + || !mac.VerifyDigest(output[k][i], (byte *)TestVals[i], strlen(TestVals[i])); + pass = pass && !fail; + cout << (fail ? "FAILED " : "passed "); + for (int j=0;j<XMACC_MD5::DIGESTSIZE;j++) + cout << setw(2) << setfill('0') << hex << (int)digest[j]; + cout << " \"" << TestVals[i] << '\"' << endl; + } + } + + return pass; +} + +struct PBKDF_TestTuple +{ + byte purpose; + unsigned int iterations; + const char *hexPassword, *hexSalt, *hexDerivedKey; +}; + +bool TestPBKDF(PasswordBasedKeyDerivationFunction &pbkdf, const PBKDF_TestTuple *testSet, unsigned int testSetSize) +{ + bool pass = true; + + for (unsigned int i=0; i<testSetSize; i++) + { + const PBKDF_TestTuple &tuple = testSet[i]; + + string password, salt, derivedKey; + StringSource(tuple.hexPassword, true, new HexDecoder(new StringSink(password))); + StringSource(tuple.hexSalt, true, new HexDecoder(new StringSink(salt))); + StringSource(tuple.hexDerivedKey, true, new HexDecoder(new StringSink(derivedKey))); + + SecByteBlock derived(derivedKey.size()); + pbkdf.GeneralDeriveKey(derived, derived.size(), tuple.purpose, (byte *)password.data(), password.size(), (byte *)salt.data(), salt.size(), tuple.iterations); + bool fail = memcmp(derived, derivedKey.data(), derived.size()) != 0; + pass = pass && !fail; + + HexEncoder enc(new FileSink(cout)); + cout << (fail ? "FAILED " : "passed "); + enc.Put(tuple.purpose); + cout << " " << tuple.iterations; + cout << " " << tuple.hexPassword << " " << tuple.hexSalt << " "; + enc.Put(derived, derived.size()); + cout << endl; + } + + return pass; +} + +bool ValidatePBKDF() +{ + bool pass = true; + + { + // from OpenSSL PKCS#12 Program FAQ v1.77, at http://www.drh-consultancy.demon.co.uk/test.txt + PBKDF_TestTuple testSet[] = + { + {1, 1, "0073006D006500670000", "0A58CF64530D823F", "8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3"}, + {2, 1, "0073006D006500670000", "0A58CF64530D823F", "79993DFE048D3B76"}, + {1, 1, "0073006D006500670000", "642B99AB44FB4B1F", "F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966"}, + {2, 1, "0073006D006500670000", "642B99AB44FB4B1F", "C0A38D64A79BEA1D"}, + {3, 1, "0073006D006500670000", "3D83C0E4546AC140", "8D967D88F6CAA9D714800AB3D48051D63F73A312"}, + {1, 1000, "007100750065006500670000", "05DEC959ACFF72F7", "ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4"}, + {2, 1000, "007100750065006500670000", "05DEC959ACFF72F7", "11DEDAD7758D4860"}, + {1, 1000, "007100750065006500670000", "1682C0FC5B3F7EC5", "483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F"}, + {2, 1000, "007100750065006500670000", "1682C0FC5B3F7EC5", "9D461D1B00355C50"}, + {3, 1000, "007100750065006500670000", "263216FCC2FAB31C", "5EC4C7A80DF652294C3925B6489A7AB857C83476"} + }; + + PKCS12_PBKDF<SHA1> pbkdf; + + cout << "\nPKCS #12 PBKDF validation suite running...\n\n"; + pass = TestPBKDF(pbkdf, testSet, sizeof(testSet)/sizeof(testSet[0])) && pass; + } + + { + // from draft-ietf-smime-password-03.txt, at http://www.imc.org/draft-ietf-smime-password + PBKDF_TestTuple testSet[] = + { + {0, 5, "70617373776f7264", "1234567878563412", "D1DAA78615F287E6"}, + {0, 500, "416C6C206E2D656E746974696573206D75737420636F6D6D756E69636174652077697468206F74686572206E2d656E74697469657320766961206E2D3120656E746974656568656568656573", "1234567878563412","6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"} + }; + + PKCS5_PBKDF2_HMAC<SHA1> pbkdf; + + cout << "\nPKCS #5 PBKDF2 validation suite running...\n\n"; + pass = TestPBKDF(pbkdf, testSet, sizeof(testSet)/sizeof(testSet[0])) && pass; + } + + return pass; +} diff --git a/validate.h b/validate.h new file mode 100644 index 0000000..7c2a1d7 --- /dev/null +++ b/validate.h @@ -0,0 +1,74 @@ +#ifndef CRYPTOPP_VALIDATE_H +#define CRYPTOPP_VALIDATE_H + +#include "cryptlib.h" +#include "randpool.h" + +bool ValidateAll(bool thorough); +bool TestSettings(); +bool TestOS_RNG(); + +bool ValidateCRC32(); +bool ValidateAdler32(); +bool ValidateMD2(); +bool ValidateMD4(); +bool ValidateMD5(); +bool ValidateSHA(); +bool ValidateSHA2(); +bool ValidateHAVAL(); +bool ValidateTiger(); +bool ValidateRIPEMD(); +bool ValidatePanama(); + +bool ValidateMD5MAC(); +bool ValidateHMAC(); +bool ValidateXMACC(); + +bool ValidateCipherModes(); +bool ValidatePBKDF(); + +bool ValidateDES(); +bool ValidateIDEA(); +bool ValidateSAFER(); +bool ValidateRC2(); +bool ValidateARC4(); + +bool ValidateRC5(); +bool ValidateBlowfish(); +bool ValidateDiamond2(); +bool ValidateThreeWay(); +bool ValidateGOST(); +bool ValidateSHARK(); +bool ValidateSEAL(); +bool ValidateCAST(); +bool ValidateSquare(); +bool ValidateSKIPJACK(); +bool ValidateRC6(); +bool ValidateMARS(); +bool ValidateRijndael(); +bool ValidateTwofish(); +bool ValidateSerpent(); + +bool ValidateBBS(); +bool ValidateDH(); +bool ValidateMQV(); +bool ValidateRSA(); +bool ValidateElGamal(); +bool ValidateDLIES(); +bool ValidateNR(); +bool ValidateDSA(bool thorough); +bool ValidateLUC(); +bool ValidateLUC_DL(); +bool ValidateLUC_DH(); +bool ValidateXTR_DH(); +bool ValidateRabin(); +bool ValidateRW(); +//bool ValidateBlumGoldwasser(); +bool ValidateECP(); +bool ValidateEC2N(); +bool ValidateECDSA(); +bool ValidateESIGN(); + +CryptoPP::RandomPool & GlobalRNG(); + +#endif diff --git a/wait.cpp b/wait.cpp new file mode 100644 index 0000000..f7a0e36 --- /dev/null +++ b/wait.cpp @@ -0,0 +1,110 @@ +// wait.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "wait.h" +#include "misc.h" + +#ifdef SOCKETS_AVAILABLE + +#ifdef USE_BERKELEY_STYLE_SOCKETS +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +WaitObjectContainer::WaitObjectContainer() +{ + Clear(); +} + +void WaitObjectContainer::Clear() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + m_handles.clear(); +#else + m_maxFd = 0; + FD_ZERO(&m_readfds); + FD_ZERO(&m_writefds); +#endif + m_noWait = false; +} + +#ifdef USE_WINDOWS_STYLE_SOCKETS + +void WaitObjectContainer::AddHandle(HANDLE handle) +{ + m_handles.push_back(handle); +} + +bool WaitObjectContainer::Wait(unsigned long milliseconds) +{ + if (m_noWait || m_handles.empty()) + return true; + + DWORD result = ::WaitForMultipleObjects(m_handles.size(), &m_handles[0], FALSE, milliseconds); + + if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size()) + return true; + else if (result == WAIT_TIMEOUT) + return false; + else + throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError())); +} + +#else + +void WaitObjectContainer::AddReadFd(int fd) +{ + FD_SET(fd, &m_readfds); + m_maxFd = STDMAX(m_maxFd, fd); +} + +void WaitObjectContainer::AddWriteFd(int fd) +{ + FD_SET(fd, &m_writefds); + m_maxFd = STDMAX(m_maxFd, fd); +} + +bool WaitObjectContainer::Wait(unsigned long milliseconds) +{ + if (m_noWait || m_maxFd == 0) + return true; + + timeval tv, *timeout; + + if (milliseconds == INFINITE_TIME) + timeout = NULL; + else + { + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = (milliseconds % 1000) * 1000; + timeout = &tv; + } + + int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout); + + if (result > 0) + return true; + else if (result == 0) + return false; + else + throw Err("WaitObjectContainer: select failed with error " + errno); +} + +#endif + +// ******************************************************** + +bool Waitable::Wait(unsigned long milliseconds) +{ + WaitObjectContainer container; + GetWaitObjects(container); + return container.Wait(milliseconds); +} + +NAMESPACE_END + +#endif @@ -0,0 +1,57 @@ +#ifndef CRYPTOPP_WAIT_H +#define CRYPTOPP_WAIT_H + +#include "config.h" + +#ifdef SOCKETS_AVAILABLE + +#include "cryptlib.h" +#include <vector> + +#ifdef USE_WINDOWS_STYLE_SOCKETS +#include <windows.h> +#else +#include <sys/types.h> +#endif + +NAMESPACE_BEGIN(CryptoPP) + +//! container of wait objects +class WaitObjectContainer +{ +public: + //! exception thrown by WaitObjectContainer + class Err : public Exception + { + public: + Err(const std::string& s) : Exception(IO_ERROR, s) {} + }; + + WaitObjectContainer(); + + void Clear(); + void SetNoWait() {m_noWait = true;} + bool Wait(unsigned long milliseconds); + +#ifdef USE_WINDOWS_STYLE_SOCKETS + void AddHandle(HANDLE handle); +#else + void AddReadFd(int fd); + void AddWriteFd(int fd); +#endif + +private: +#ifdef USE_WINDOWS_STYLE_SOCKETS + std::vector<HANDLE> m_handles; +#else + fd_set m_readfds, m_writefds; + int m_maxFd; +#endif + bool m_noWait; +}; + +NAMESPACE_END + +#endif + +#endif diff --git a/wake.cpp b/wake.cpp new file mode 100644 index 0000000..3fc0b2f --- /dev/null +++ b/wake.cpp @@ -0,0 +1,122 @@ +// wake.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "wake.h" + +#include "strciphr.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +void WAKE_TestInstantiations() +{ + WAKE_CFB<>::Encryption x1; + WAKE_CFB<>::Decryption x3; + WAKE_OFB<>::Encryption x2; + WAKE_OFB<>::Decryption x4; +} + +inline word32 WAKE_Base::M(word32 x, word32 y) +{ + word32 w = x+y; + return (w>>8) ^ t[(byte)w]; +} + +void WAKE_Base::GenKey(word32 k0, word32 k1, word32 k2, word32 k3) +{ + long x, z; + int p ; + static long tt[10]= { + 0x726a8f3bL, // table + 0xe69a3b5cL, + 0xd3c71fe5L, + 0xab3c73d2L, + 0x4d3a8eb3L, + 0x0396d6e8L, + 0x3d4c2f7aL, + 0x9ee27cf3L, } ; + t[0] = k0; + t[1] = k1; + t[2] = k2; + t[3] = k3; + for (p=4 ; p<256 ; p++) + { + x=t[p-4]+t[p-1] ; // fill t + t[p]= (x>>3) ^ tt[byte(x&7)] ; + } + + for (p=0 ; p<23 ; p++) + t[p]+=t[p+89] ; // mix first entries + x=t[33] ; z=t[59] | 0x01000001L ; + z=z&0xff7fffffL ; + for (p=0 ; p<256 ; p++) { //change top byte to + x=(x&0xff7fffffL)+z ; // a permutation etc + t[p]=(t[p] & 0x00ffffffL) ^ x ; } + + t[256]=t[0] ; + byte y=byte(x); + for (p=0 ; p<256 ; p++) { // further change perm. + t[p]=t[y=byte(t[p^y]^y)] ; // and other digits + t[y]=t[p+1] ; } +} + +template <class B> +void WAKE_Policy<B>::CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length) +{ + word32 k0, k1, k2, k3; + BlockGetAndPut<word32, BigEndian, false>::Get(key)(r3)(r4)(r5)(r6)(k0)(k1)(k2)(k3); + GenKey(k0, k1, k2, k3); +} + +// CFB +template <class B> +void WAKE_Policy<B>::Iterate(byte *output, const byte *input, CipherDir dir, unsigned int iterationCount) +{ + RegisterOutput<B> registerOutput(output, input, dir); + + while (iterationCount--) + { + r3 = M(r3, ConditionalByteReverse(B::ToEnum(), r6)); + r4 = M(r4, r3); + r5 = M(r5, r4); + r6 = M(r6, r5); + registerOutput(r6); + } +} + +// OFB +template <class B> +void WAKE_Policy<B>::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + KeystreamOutput<B> keystreamOperation(operation, output, input); + + while (iterationCount--) + { + keystreamOperation(r6); + r3 = M(r3, r6); + r4 = M(r4, r3); + r5 = M(r5, r4); + r6 = M(r6, r5); + } +} +/* +template <class B> +void WAKE_ROFB_Policy<B>::Iterate(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + KeystreamOutput<B> keystreamOperation(operation, output, input); + + while (iterationCount--) + { + keystreamOperation(r6); + r3 = M(r3, r6); + r4 = M(r4, r3); + r5 = M(r5, r4); + r6 = M(r6, r5); + } +} +*/ +template class WAKE_Policy<BigEndian>; +template class WAKE_Policy<LittleEndian>; +//template class WAKE_ROFB_Policy<BigEndian>; +//template class WAKE_ROFB_Policy<LittleEndian>; + +NAMESPACE_END @@ -0,0 +1,76 @@ +#ifndef CRYPTOPP_WAKE_H +#define CRYPTOPP_WAKE_H + +#include "seckey.h" +#include "secblock.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class B = BigEndian> +struct WAKE_Info : public FixedKeyLength<32> +{ + static const char *StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "WAKE-CFB-LE" : "WAKE-CFB-BE";} +}; + +class WAKE_Base +{ +protected: + word32 M(word32 x, word32 y); + void GenKey(word32 k0, word32 k1, word32 k2, word32 k3); + + word32 t[257]; + word32 r3, r4, r5, r6; +}; + +template <class B = BigEndian> +class WAKE_Policy : public WAKE_Info<B> + , public CFB_CipherConcretePolicy<word32, 1> + , public AdditiveCipherConcretePolicy<word32, 1, 64> + , protected WAKE_Base +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, unsigned int length); + // CFB + byte * GetRegisterBegin() {return (byte *)&r6;} + void Iterate(byte *output, const byte *input, CipherDir dir, unsigned int iterationCount); + // OFB + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); + bool IsRandomAccess() const {return false;} +}; + +//! <a href="http://www.weidai.com/scan-mirror/cs.html#WAKE-CFB-BE">WAKE-CFB-BE</a> +template <class B = BigEndian> +struct WAKE_CFB : public WAKE_Info<B>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<WAKE_Policy<B>, CFB_EncryptionTemplate<> > > Encryption; + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<WAKE_Policy<B>, CFB_DecryptionTemplate<> > > Decryption; +}; + +//! WAKE-OFB +template <class B = BigEndian> +struct WAKE_OFB : public WAKE_Info<B>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinalTemplate<ConcretePolicyHolder<WAKE_Policy<B>, AdditiveCipherTemplate<> > > Encryption; + typedef Encryption Decryption; +}; + +/* +template <class B = BigEndian> +class WAKE_ROFB_Policy : public WAKE_Policy<B> +{ +protected: + void Iterate(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); +}; + +template <class B = BigEndian> +struct WAKE_ROFB : public WAKE_Info<B> +{ + typedef SymmetricCipherTemplate<ConcretePolicyHolder<AdditiveCipherTemplate<>, WAKE_ROFB_Policy<B> > > Encryption; + typedef Encryption Decryption; +}; +*/ + +NAMESPACE_END + +#endif diff --git a/winpipes.cpp b/winpipes.cpp new file mode 100644 index 0000000..a195d17 --- /dev/null +++ b/winpipes.cpp @@ -0,0 +1,202 @@ +// winpipes.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "winpipes.h" + +#ifdef WINDOWS_PIPES_AVAILABLE + +#include "wait.h" + +NAMESPACE_BEGIN(CryptoPP) + +WindowsHandle::WindowsHandle(HANDLE h, bool own) + : m_h(h), m_own(own) +{ +} + +WindowsHandle::~WindowsHandle() +{ + if (m_own) + { + try + { + CloseHandle(); + } + catch (...) + { + } + } +} + +bool WindowsHandle::HandleValid() const +{ + return m_h && m_h != INVALID_HANDLE_VALUE; +} + +void WindowsHandle::AttachHandle(HANDLE h, bool own) +{ + if (m_own) + CloseHandle(); + + m_h = h; + m_own = own; + HandleChanged(); +} + +HANDLE WindowsHandle::DetachHandle() +{ + HANDLE h = m_h; + m_h = INVALID_HANDLE_VALUE; + HandleChanged(); + return h; +} + +void WindowsHandle::CloseHandle() +{ + if (m_h != INVALID_HANDLE_VALUE) + { + ::CloseHandle(m_h); + m_h = INVALID_HANDLE_VALUE; + HandleChanged(); + } +} + +// ******************************************************** + +void WindowsPipe::HandleError(const char *operation) const +{ + DWORD err = GetLastError(); + throw Err(GetHandle(), operation, err); +} + +WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error) + : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error) + , m_h(s) +{ +} + +// ************************************************************* + +WindowsPipeReceiver::WindowsPipeReceiver() + : m_resultPending(false), m_eofReceived(false) +{ + m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); + CheckAndHandleError("CreateEvent", m_event.HandleValid()); + memset(&m_overlapped, 0, sizeof(m_overlapped)); + m_overlapped.hEvent = m_event; +} + +void WindowsPipeReceiver::Receive(byte* buf, unsigned int bufLen) +{ + assert(!m_resultPending && !m_eofReceived); + + HANDLE h = GetHandle(); + if (ReadFile(h, buf, bufLen, &m_lastResult, &m_overlapped)) + { + if (m_lastResult == 0) + m_eofReceived = true; + } + else + { + switch (GetLastError()) + { + default: + CheckAndHandleError("ReadFile", false); + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: + m_lastResult = 0; + m_eofReceived = true; + break; + case ERROR_IO_PENDING: + m_resultPending = true; + } + } +} + +void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container) +{ + if (m_resultPending) + container.AddHandle(m_event); + else if (!m_eofReceived) + container.SetNoWait(); +} + +unsigned int WindowsPipeReceiver::GetReceiveResult() +{ + if (m_resultPending) + { + HANDLE h = GetHandle(); + if (GetOverlappedResult(h, &m_overlapped, &m_lastResult, false)) + { + if (m_lastResult == 0) + m_eofReceived = true; + } + else + { + switch (GetLastError()) + { + default: + CheckAndHandleError("GetOverlappedResult", false); + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: + m_lastResult = 0; + m_eofReceived = true; + } + } + m_resultPending = false; + } + return m_lastResult; +} + +// ************************************************************* + +WindowsPipeSender::WindowsPipeSender() + : m_resultPending(false), m_lastResult(0) +{ + m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); + CheckAndHandleError("CreateEvent", m_event.HandleValid()); + memset(&m_overlapped, 0, sizeof(m_overlapped)); + m_overlapped.hEvent = m_event; +} + +void WindowsPipeSender::Send(const byte* buf, unsigned int bufLen) +{ + DWORD written = 0; + HANDLE h = GetHandle(); + if (WriteFile(h, buf, bufLen, &written, &m_overlapped)) + { + m_resultPending = false; + m_lastResult = written; + } + else + { + if (GetLastError() != ERROR_IO_PENDING) + CheckAndHandleError("WriteFile", false); + + m_resultPending = true; + } +} + +void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container) +{ + if (m_resultPending) + container.AddHandle(m_event); + else + container.SetNoWait(); +} + +unsigned int WindowsPipeSender::GetSendResult() +{ + if (m_resultPending) + { + HANDLE h = GetHandle(); + BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, false); + CheckAndHandleError("GetOverlappedResult", result); + m_resultPending = false; + } + return m_lastResult; +} + +NAMESPACE_END + +#endif diff --git a/winpipes.h b/winpipes.h new file mode 100644 index 0000000..3260e19 --- /dev/null +++ b/winpipes.h @@ -0,0 +1,141 @@ +#ifndef CRYPTOPP_WINPIPES_H +#define CRYPTOPP_WINPIPES_H + +#include "config.h" + +#ifdef WINDOWS_PIPES_AVAILABLE + +#include "network.h" +#include "queue.h" +#include <windows.h> + +NAMESPACE_BEGIN(CryptoPP) + +//! Windows Handle +class WindowsHandle +{ +public: + WindowsHandle(HANDLE h = INVALID_HANDLE_VALUE, bool own=false); + WindowsHandle(const WindowsHandle &h) : m_h(h.m_h), m_own(false) {} + virtual ~WindowsHandle(); + + bool GetOwnership() const {return m_own;} + void SetOwnership(bool own) {m_own = own;} + + operator HANDLE() {return m_h;} + HANDLE GetHandle() const {return m_h;} + bool HandleValid() const; + void AttachHandle(HANDLE h, bool own=false); + HANDLE DetachHandle(); + void CloseHandle(); + +protected: + virtual void HandleChanged() {} + + HANDLE m_h; + bool m_own; +}; + +//! Windows Pipe +class WindowsPipe +{ +public: + class Err : public OS_Error + { + public: + Err(HANDLE h, const std::string& operation, int error); + HANDLE GetHandle() const {return m_h;} + + private: + HANDLE m_h; + }; + +protected: + virtual HANDLE GetHandle() const =0; + virtual void HandleError(const char *operation) const; + void CheckAndHandleError(const char *operation, BOOL result) const + {assert(result==TRUE || result==FALSE); if (!result) HandleError(operation);} +}; + +//! . +class WindowsPipeReceiver : public WindowsPipe, public NetworkReceiver +{ +public: + WindowsPipeReceiver(); + + bool MustWaitForResult() {return true;} + void Receive(byte* buf, unsigned int bufLen); + unsigned int GetReceiveResult(); + bool EofReceived() const {return m_eofReceived;} + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container); + +private: + WindowsHandle m_event; + OVERLAPPED m_overlapped; + bool m_resultPending; + DWORD m_lastResult; + bool m_eofReceived; +}; + +//! . +class WindowsPipeSender : public WindowsPipe, public NetworkSender +{ +public: + WindowsPipeSender(); + + bool MustWaitForResult() {return true;} + void Send(const byte* buf, unsigned int bufLen); + unsigned int GetSendResult(); + void SendEof() {} + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container); + +private: + WindowsHandle m_event; + OVERLAPPED m_overlapped; + bool m_resultPending; + DWORD m_lastResult; +}; + +//! Windows Pipe Source +class WindowsPipeSource : public WindowsHandle, public NetworkSource, public WindowsPipeReceiver +{ +public: + WindowsPipeSource(HANDLE h=INVALID_HANDLE_VALUE, bool pumpAll=false, BufferedTransformation *attachment=NULL) + : WindowsHandle(h), NetworkSource(attachment) + { + if (pumpAll) + PumpAll(); + } + + NetworkSource::GetMaxWaitObjectCount; + NetworkSource::GetWaitObjects; + +private: + HANDLE GetHandle() const {return WindowsHandle::GetHandle();} + NetworkReceiver & AccessReceiver() {return *this;} +}; + +//! Windows Pipe Sink +class WindowsPipeSink : public WindowsHandle, public NetworkSink, public WindowsPipeSender +{ +public: + WindowsPipeSink(HANDLE h=INVALID_HANDLE_VALUE, unsigned int maxBufferSize=0, bool autoFlush=false) + : WindowsHandle(h), NetworkSink(maxBufferSize, autoFlush) {} + + NetworkSink::GetMaxWaitObjectCount; + NetworkSink::GetWaitObjects; + +private: + HANDLE GetHandle() const {return WindowsHandle::GetHandle();} + NetworkSender & AccessSender() {return *this;} +}; + +NAMESPACE_END + +#endif + +#endif @@ -0,0 +1,103 @@ +#ifndef CRYPTOPP_WORDS_H +#define CRYPTOPP_WORDS_H + +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +inline unsigned int CountWords(const word *X, unsigned int N) +{ + while (N && X[N-1]==0) + N--; + return N; +} + +inline void SetWords(word *r, word a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] = a; +} + +inline void CopyWords(word *r, const word *a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] = a[i]; +} + +inline void XorWords(word *r, const word *a, const word *b, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] = a[i] ^ b[i]; +} + +inline void XorWords(word *r, const word *a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] ^= a[i]; +} + +inline void AndWords(word *r, const word *a, const word *b, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] = a[i] & b[i]; +} + +inline void AndWords(word *r, const word *a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] &= a[i]; +} + +inline word ShiftWordsLeftByBits(word *r, unsigned int n, unsigned int shiftBits) +{ + assert (shiftBits<WORD_BITS); + word u, carry=0; + if (shiftBits) + for (unsigned int i=0; i<n; i++) + { + u = r[i]; + r[i] = (u << shiftBits) | carry; + carry = u >> (WORD_BITS-shiftBits); + } + return carry; +} + +inline word ShiftWordsRightByBits(word *r, unsigned int n, unsigned int shiftBits) +{ + assert (shiftBits<WORD_BITS); + word u, carry=0; + if (shiftBits) + for (int i=n-1; i>=0; i--) + { + u = r[i]; + r[i] = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + } + return carry; +} + +inline void ShiftWordsLeftByWords(word *r, unsigned int n, unsigned int shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (unsigned int i=n-1; i>=shiftWords; i--) + r[i] = r[i-shiftWords]; + SetWords(r, 0, shiftWords); + } +} + +inline void ShiftWordsRightByWords(word *r, unsigned int n, unsigned int shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (unsigned int i=0; i+shiftWords<n; i++) + r[i] = r[i+shiftWords]; + SetWords(r+n-shiftWords, 0, shiftWords); + } +} + +NAMESPACE_END + +#endif diff --git a/xormac.h b/xormac.h new file mode 100644 index 0000000..0877362 --- /dev/null +++ b/xormac.h @@ -0,0 +1,170 @@ +// xormac.h - written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_XORMAC_H +#define CRYPTOPP_XORMAC_H + +#include "iterhash.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +template <class T> struct DigestSizeSubtract4Workaround {enum {RESULT = T::DIGESTSIZE-4};}; // VC60 workaround + +template <class T> +class XMACC_Base : public FixedKeyLength<DigestSizeSubtract4Workaround<T>::RESULT, SimpleKeyingInterface::INTERNALLY_GENERATED_IV>, + public IteratedHash<typename T::HashWordType, typename T::ByteOrderClass, T::BLOCKSIZE, MessageAuthenticationCode> +{ +public: + static std::string StaticAlgorithmName() {return std::string("XMAC(") + T::StaticAlgorithmName() + ")";} + enum {DIGESTSIZE = 4+T::DIGESTSIZE}; + typedef typename T::HashWordType HashWordType; + + XMACC_Base() : IteratedHash<HashWordType, CPP_TYPENAME T::ByteOrderClass, T::BLOCKSIZE, MessageAuthenticationCode>(T::DIGESTSIZE) {} + + void CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Resynchronize(const byte *IV) + { + GetWord(false, BIG_ENDIAN_ORDER, m_counter, IV); + Restart(); + } + unsigned int IVSize() const + {return 4;} + void GetNextIV(byte *IV) + { + if (m_counter == 0xffffffff) + throw NotImplemented("XMACC: must have a valid counter to get next IV"); + PutWord(false, BIG_ENDIAN_ORDER, IV, m_counter+1); + } + + word32 CurrentCounter() const {return m_counter;} + + void TruncatedFinal(byte *mac, unsigned int size); + bool TruncatedVerify(const byte *mac, unsigned int length); + unsigned int DigestSize() const {return DIGESTSIZE;} // need to override this + +private: + void Init(); + static void WriteWord32(byte *output, word32 value); + static void XorDigest(HashWordType *digest, const HashWordType *buffer); + void vTransform(const HashWordType *data); + + FixedSizeSecBlock<byte, DigestSizeSubtract4Workaround<T>::RESULT> m_key; + enum {BUFFER_SIZE = ((T::DIGESTSIZE) / sizeof(HashWordType))}; // VC60 workaround + FixedSizeSecBlock<HashWordType, BUFFER_SIZE> m_buffer; + word32 m_counter, m_index; +}; + +//! <a href="http://www.weidai.com/scan-mirror/mac.html#XMAC">XMAC</a> +/*! If you need to generate MACs with XMACC (instead of just verifying them), + you must save the counter before destroying an XMACC object + and reinitialize it the next time you create an XMACC with the same key. + Start counter at 0 when using a key for the first time. */ +template <class T> +class XMACC : public MessageAuthenticationCodeTemplate<XMACC_Base<T> > +{ +public: + XMACC() {} + XMACC(const byte *key, word32 counter = 0xffffffff) + {SetKey(key, KEYLENGTH, MakeParameters(Name::XMACC_Counter(), counter));} +}; + +template <class T> void XMACC_Base<T>::CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + ThrowIfInvalidKeyLength(length); + m_counter = 0xffffffff; + const byte *iv = NULL; + if (params.GetValue(Name::IV(), iv)) + GetWord(false, BIG_ENDIAN_ORDER, m_counter, iv); + else + params.GetValue(Name::XMACC_Counter(), m_counter); + memcpy(m_key, key, KEYLENGTH); + Init(); +} + +template <class T> void XMACC_Base<T>::Init() +{ + m_index = 0x80000000; + memset(m_digest, 0, T::DIGESTSIZE); +} + +template <class T> inline void XMACC_Base<T>::WriteWord32(byte *output, word32 value) +{ + output[0] = byte(value >> 24); + output[1] = byte(value >> 16); + output[2] = byte(value >> 8); + output[3] = byte(value); +} + +template <class T> inline void XMACC_Base<T>::XorDigest(HashWordType *digest, const HashWordType *buffer) +{ + for (unsigned i=0; i<(T::DIGESTSIZE/sizeof(HashWordType)); i++) + digest[i] ^= buffer[i]; +} + +template <class T> void XMACC_Base<T>::vTransform(const HashWordType *input) +{ + memcpy(m_buffer, m_key, KEYLENGTH); + WriteWord32((byte *)m_buffer.begin()+KEYLENGTH, ++m_index); + T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE); + T::Transform(m_buffer, input); + XorDigest(m_digest, m_buffer); +} + +template <class T> void XMACC_Base<T>::TruncatedFinal(byte *mac, unsigned int size) +{ + ThrowIfInvalidTruncatedSize(size); + if (size < 4) + throw InvalidArgument("XMACC: truncating the MAC to less than 4 bytes will cause it to be unverifiable"); + if (m_counter == 0xffffffff) + throw InvalidArgument("XMACC: the counter must be initialized to a valid value for MAC generation"); + + PadLastBlock(BLOCKSIZE - 2*sizeof(HashWordType)); + CorrectEndianess(m_data, m_data, BLOCKSIZE - 2*sizeof(HashWordType)); + m_data[m_data.size()-2] = ByteReverse(GetBitCountHi()); // byteReverse for backwards compatibility + m_data[m_data.size()-1] = ByteReverse(GetBitCountLo()); + vTransform(m_data); + + memcpy(m_buffer, m_key, KEYLENGTH); + WriteWord32((byte *)m_buffer.begin()+KEYLENGTH, 0); + memset(m_data, 0, BLOCKSIZE-4); + WriteWord32((byte *)m_data.begin()+BLOCKSIZE-4, ++m_counter); + T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE); + T::CorrectEndianess(m_data, m_data, BLOCKSIZE); + T::Transform(m_buffer, m_data); + XorDigest(m_digest, m_buffer); + + WriteWord32(mac, m_counter); + T::CorrectEndianess(m_digest, m_digest, T::DIGESTSIZE); + memcpy(mac+4, m_digest, size-4); + + Restart(); // reinit for next use +} + +template <class T> bool XMACC_Base<T>::TruncatedVerify(const byte *mac, unsigned int size) +{ + assert(4 <= size && size <= DIGESTSIZE); + + PadLastBlock(BLOCKSIZE - 2*sizeof(HashWordType)); + CorrectEndianess(m_data, m_data, BLOCKSIZE - 2*sizeof(HashWordType)); + m_data[m_data.size()-2] = ByteReverse(GetBitCountHi()); // byteReverse for backwards compatibility + m_data[m_data.size()-1] = ByteReverse(GetBitCountLo()); + vTransform(m_data); + + memcpy(m_buffer, m_key, KEYLENGTH); + WriteWord32((byte *)m_buffer.begin()+KEYLENGTH, 0); + memset(m_data, 0, BLOCKSIZE-4); + memcpy((byte *)m_data.begin()+BLOCKSIZE-4, mac, 4); + T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE); + T::CorrectEndianess(m_data, m_data, BLOCKSIZE); + T::Transform(m_buffer, m_data); + XorDigest(m_digest, m_buffer); + + T::CorrectEndianess(m_digest, m_digest, T::DIGESTSIZE); + bool macValid = (memcmp(mac+4, m_digest, size-4) == 0); + Restart(); // reinit for next use + return macValid; +} + +NAMESPACE_END + +#endif @@ -0,0 +1,101 @@ +// cryptlib.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "xtr.h" +#include "nbtheory.h" + +#include "algebra.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +GFP2Element & GFP2Element::Zero() +{ + static GFP2Element zero; + return zero; +} + +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits) +{ + assert(qbits > 9); // no primes exist for pbits = 10, qbits = 9 + assert(pbits > qbits); + + const Integer minQ = Integer::Power2(qbits - 1); + const Integer maxQ = Integer::Power2(qbits) - 1; + const Integer minP = Integer::Power2(pbits - 1); + const Integer maxP = Integer::Power2(pbits) - 1; + + Integer r1, r2; + do + { + bool qFound = q.Randomize(rng, minQ, maxQ, Integer::PRIME, 7, 12); + assert(qFound); + bool solutionsExist = SolveModularQuadraticEquation(r1, r2, 1, -1, 1, q); + assert(solutionsExist); + } while (!p.Randomize(rng, minP, maxP, Integer::PRIME, CRT(rng.GenerateBit()?r1:r2, q, 2, 3), 3*q)); + assert(((p.Squared() - p + 1) % q).IsZero()); + + GFP2_ONB<ModularArithmetic> gfp2(p); + GFP2Element three = gfp2.ConvertIn(3), t; + + while (true) + { + g.c1.Randomize(rng, Integer::Zero(), p-1); + g.c2.Randomize(rng, Integer::Zero(), p-1); + t = XTR_Exponentiate(g, p+1, p); + if (t.c1 == t.c2) + continue; + g = XTR_Exponentiate(g, (p.Squared()-p+1)/q, p); + if (g != three) + break; + } + assert(XTR_Exponentiate(g, q, p) == three); +} + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p) +{ + unsigned int bitCount = e.BitCount(); + if (bitCount == 0) + return GFP2Element(-3, -3); + + // find the lowest bit of e that is 1 + unsigned int lowest1bit; + for (lowest1bit=0; e.GetBit(lowest1bit) == 0; lowest1bit++) {} + + GFP2_ONB<MontgomeryRepresentation> gfp2(p); + GFP2Element c = gfp2.ConvertIn(b); + GFP2Element cp = gfp2.PthPower(c); + GFP2Element S[5] = {gfp2.ConvertIn(3), c, gfp2.SpecialOperation1(c)}; + + // do all exponents bits except the lowest zeros starting from the top + unsigned int i; + for (i = e.BitCount() - 1; i>lowest1bit; i--) + { + if (e.GetBit(i)) + { + gfp2.RaiseToPthPower(S[0]); + gfp2.Accumulate(S[0], gfp2.SpecialOperation2(S[2], c, S[1])); + S[1] = gfp2.SpecialOperation1(S[1]); + S[2] = gfp2.SpecialOperation1(S[2]); + S[0].swap(S[1]); + } + else + { + gfp2.RaiseToPthPower(S[2]); + gfp2.Accumulate(S[2], gfp2.SpecialOperation2(S[0], cp, S[1])); + S[1] = gfp2.SpecialOperation1(S[1]); + S[0] = gfp2.SpecialOperation1(S[0]); + S[2].swap(S[1]); + } + } + + // now do the lowest zeros + while (i--) + S[1] = gfp2.SpecialOperation1(S[1]); + + return gfp2.ConvertOut(S[1]); +} + +template class AbstractRing<GFP2Element>; +template class AbstractGroup<GFP2Element>; + +NAMESPACE_END @@ -0,0 +1,215 @@ +#ifndef CRYPTOPP_XTR_H +#define CRYPTOPP_XTR_H + +/** \file + "The XTR public key system" by Arjen K. Lenstra and Eric R. Verheul +*/ + +#include "modarith.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! an element of GF(p^2) +class GFP2Element +{ +public: + GFP2Element() {} + GFP2Element(const Integer &c1, const Integer &c2) : c1(c1), c2(c2) {} + GFP2Element(const byte *encodedElement, unsigned int size) + : c1(encodedElement, size/2), c2(encodedElement+size/2, size/2) {} + + void Encode(byte *encodedElement, unsigned int size) + { + c1.Encode(encodedElement, size/2); + c2.Encode(encodedElement+size/2, size/2); + } + + bool operator==(const GFP2Element &rhs) const {return c1 == rhs.c1 && c2 == rhs.c2;} + bool operator!=(const GFP2Element &rhs) const {return !operator==(rhs);} + + void swap(GFP2Element &a) + { + c1.swap(a.c1); + c2.swap(a.c2); + } + + static GFP2Element & Zero(); + + Integer c1, c2; +}; + +//! GF(p^2), optimal normal basis +template <class F> +class GFP2_ONB : public AbstractRing<GFP2Element> +{ +public: + typedef F BaseField; + + GFP2_ONB(const Integer &p) : modp(p) + { + if (p%3 != 2) + throw InvalidArgument("GFP2_ONB: modulus must be equivalent to 2 mod 3"); + } + + const Integer& GetModulus() const {return modp.GetModulus();} + + GFP2Element ConvertIn(const Integer &a) const + { + t = modp.Inverse(modp.ConvertIn(a)); + return GFP2Element(t, t); + } + + GFP2Element ConvertIn(const GFP2Element &a) const + {return GFP2Element(modp.ConvertIn(a.c1), modp.ConvertIn(a.c2));} + + GFP2Element ConvertOut(const GFP2Element &a) const + {return GFP2Element(modp.ConvertOut(a.c1), modp.ConvertOut(a.c2));} + + bool Equal(const GFP2Element &a, const GFP2Element &b) const + { + return modp.Equal(a.c1, b.c1) && modp.Equal(a.c2, b.c2); + } + + const Element& Identity() const + { + return GFP2Element::Zero(); + } + + const Element& Add(const Element &a, const Element &b) const + { + result.c1 = modp.Add(a.c1, b.c1); + result.c2 = modp.Add(a.c2, b.c2); + return result; + } + + const Element& Inverse(const Element &a) const + { + result.c1 = modp.Inverse(a.c1); + result.c2 = modp.Inverse(a.c2); + return result; + } + + const Element& Double(const Element &a) const + { + result.c1 = modp.Double(a.c1); + result.c2 = modp.Double(a.c2); + return result; + } + + const Element& Subtract(const Element &a, const Element &b) const + { + result.c1 = modp.Subtract(a.c1, b.c1); + result.c2 = modp.Subtract(a.c2, b.c2); + return result; + } + + Element& Accumulate(Element &a, const Element &b) const + { + modp.Accumulate(a.c1, b.c1); + modp.Accumulate(a.c2, b.c2); + return a; + } + + Element& Reduce(Element &a, const Element &b) const + { + modp.Reduce(a.c1, b.c1); + modp.Reduce(a.c2, b.c2); + return a; + } + + bool IsUnit(const Element &a) const + { + return a.c1.NotZero() || a.c2.NotZero(); + } + + const Element& MultiplicativeIdentity() const + { + result.c1 = result.c2 = modp.Inverse(modp.MultiplicativeIdentity()); + return result; + } + + const Element& Multiply(const Element &a, const Element &b) const + { + t = modp.Add(a.c1, a.c2); + t = modp.Multiply(t, modp.Add(b.c1, b.c2)); + result.c1 = modp.Multiply(a.c1, b.c1); + result.c2 = modp.Multiply(a.c2, b.c2); + result.c1.swap(result.c2); + modp.Reduce(t, result.c1); + modp.Reduce(t, result.c2); + modp.Reduce(result.c1, t); + modp.Reduce(result.c2, t); + return result; + } + + const Element& MultiplicativeInverse(const Element &a) const + { + return result = Exponentiate(a, modp.GetModulus()-2); + } + + const Element& Square(const Element &a) const + { + const Integer &ac1 = (&a == &result) ? (t = a.c1) : a.c1; + result.c1 = modp.Multiply(modp.Subtract(modp.Subtract(a.c2, a.c1), a.c1), a.c2); + result.c2 = modp.Multiply(modp.Subtract(modp.Subtract(ac1, a.c2), a.c2), ac1); + return result; + } + + Element Exponentiate(const Element &a, const Integer &e) const + { + Integer edivp, emodp; + Integer::Divide(emodp, edivp, e, modp.GetModulus()); + Element b = PthPower(a); + return AbstractRing<GFP2Element>::CascadeExponentiate(a, emodp, b, edivp); + } + + const Element & PthPower(const Element &a) const + { + result = a; + result.c1.swap(result.c2); + return result; + } + + void RaiseToPthPower(Element &a) const + { + a.c1.swap(a.c2); + } + + // a^2 - 2a^p + const Element & SpecialOperation1(const Element &a) const + { + assert(&a != &result); + result = Square(a); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c2, a.c1); + modp.Reduce(result.c2, a.c1); + return result; + } + + // x * z - y * z^p + const Element & SpecialOperation2(const Element &x, const Element &y, const Element &z) const + { + assert(&x != &result && &y != &result && &z != &result); + t = modp.Add(x.c2, y.c2); + result.c1 = modp.Multiply(z.c1, modp.Subtract(y.c1, t)); + modp.Accumulate(result.c1, modp.Multiply(z.c2, modp.Subtract(t, x.c1))); + t = modp.Add(x.c1, y.c1); + result.c2 = modp.Multiply(z.c2, modp.Subtract(y.c2, t)); + modp.Accumulate(result.c2, modp.Multiply(z.c1, modp.Subtract(t, x.c2))); + return result; + } + +protected: + BaseField modp; + mutable GFP2Element result; + mutable Integer t; +}; + +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits); + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p); + +NAMESPACE_END + +#endif diff --git a/xtrcrypt.cpp b/xtrcrypt.cpp new file mode 100644 index 0000000..20e78e7 --- /dev/null +++ b/xtrcrypt.cpp @@ -0,0 +1,108 @@ +// xtrcrypt.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "xtrcrypt.h" +#include "nbtheory.h" +#include "asn.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +XTR_DH::XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g) + : m_p(p), m_q(q), m_g(g) +{ +} + +XTR_DH::XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits) +{ + XTR_FindPrimesAndGenerator(rng, m_p, m_q, m_g, pbits, qbits); +} + +XTR_DH::XTR_DH(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_g.c1.BERDecode(seq); + m_g.c2.BERDecode(seq); + seq.MessageEnd(); +} + +void XTR_DH::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_g.c1.DEREncode(seq); + m_g.c2.DEREncode(seq); + seq.MessageEnd(); +} + +bool XTR_DH::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_p > Integer::One() && m_p.IsOdd(); + pass = pass && m_q > Integer::One() && m_q.IsOdd(); + GFP2Element three = GFP2_ONB<ModularArithmetic>(m_p).ConvertIn(3); + pass = pass && !(m_g.c1.IsNegative() || m_g.c2.IsNegative() || m_g.c1 >= m_p || m_g.c2 >= m_p || m_g == three); + if (level >= 1) + pass = pass && ((m_p.Squared()-m_p+1)%m_q).IsZero(); + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + pass = pass && XTR_Exponentiate(m_g, (m_p.Squared()-m_p+1)/m_q, m_p) != three; + pass = pass && XTR_Exponentiate(m_g, m_q, m_p) == three; + } + return pass; +} + +bool XTR_DH::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; +} + +void XTR_DH::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupGenerator) + ; +} + +void XTR_DH::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const +{ + Integer x(rng, Integer::Zero(), m_q-1); + x.Encode(privateKey, PrivateKeyLength()); +} + +void XTR_DH::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const +{ + Integer x(privateKey, PrivateKeyLength()); + GFP2Element y = XTR_Exponentiate(m_g, x, m_p); + y.Encode(publicKey, PublicKeyLength()); +} + +bool XTR_DH::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const +{ + GFP2Element w(otherPublicKey, PublicKeyLength()); + if (validateOtherPublicKey) + { + GFP2_ONB<ModularArithmetic> gfp2(m_p); + GFP2Element three = gfp2.ConvertIn(3); + if (w.c1.IsNegative() || w.c2.IsNegative() || w.c1 >= m_p || w.c2 >= m_p || w == three) + return false; + if (XTR_Exponentiate(w, m_q, m_p) != three) + return false; + } + Integer s(privateKey, PrivateKeyLength()); + GFP2Element z = XTR_Exponentiate(w, s, m_p); + z.Encode(agreedValue, AgreedValueLength()); + return true; +} + +NAMESPACE_END diff --git a/xtrcrypt.h b/xtrcrypt.h new file mode 100644 index 0000000..6aee127 --- /dev/null +++ b/xtrcrypt.h @@ -0,0 +1,54 @@ +#ifndef CRYPTOPP_XTRCRYPT_H +#define CRYPTOPP_XTRCRYPT_H + +/** \file + "The XTR public key system" by Arjen K. Lenstra and Eric R. Verheul +*/ + +#include "xtr.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! XTR-DH with key validation + +class XTR_DH : public SimpleKeyAgreementDomain, public CryptoParameters +{ + typedef XTR_DH ThisClass; + +public: + XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g); + XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits); + XTR_DH(BufferedTransformation &domainParams); + + void DEREncode(BufferedTransformation &domainParams) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + CryptoParameters & AccessCryptoParameters() {return *this;} + unsigned int AgreedValueLength() const {return 2*m_p.ByteCount();} + unsigned int PrivateKeyLength() const {return m_q.ByteCount();} + unsigned int PublicKeyLength() const {return 2*m_p.ByteCount();} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + + const Integer &GetModulus() const {return m_p;} + const Integer &GetSubgroupOrder() const {return m_q;} + const GFP2Element &GetSubgroupGenerator() const {return m_g;} + + void SetModulus(const Integer &p) {m_p = p;} + void SetSubgroupOrder(const Integer &q) {m_q = q;} + void SetSubgroupGenerator(const GFP2Element &g) {m_g = g;} + +private: + unsigned int ExponentBitLength() const; + + Integer m_p, m_q; + GFP2Element m_g; +}; + +NAMESPACE_END + +#endif diff --git a/xtrdh171.dat b/xtrdh171.dat new file mode 100644 index 0000000..c75ff48 --- /dev/null +++ b/xtrdh171.dat @@ -0,0 +1,3 @@ +305F02160559DCD66A95A57249A15BAD6B431BF2CD58615B901D02153365CFA0D3B1B6577B2DB243 +DDE45EDB91C18B0F5F0216032F4EBA0911B3D0B14F6F1292A74DFFD4A8FCF22C1802160211CB3EDA +809FA0FF8C3A8AE691EC4C95A06A3395CF diff --git a/xtrdh342.dat b/xtrdh342.dat new file mode 100644 index 0000000..ce67aaa --- /dev/null +++ b/xtrdh342.dat @@ -0,0 +1,5 @@ +3081A6022B28E3FED51D3D861D962B0A16A92ACDB380ADAFB478CA555004C3AF387F853F9DE9921C +7DCB40098D25C757021D03094844F135A3A50049A848C3FC02412FCBED6040FB1BDE99A4D93E3B02 +2B13F411960B85F9B031A247E072046892B1EE6C95A47242A839F8E24B96B88F37B4BDA2C6D253BC +0AAF29F1022B0D2AFE639D324E558B2B312E435E03957769D745C881D259DDFD2F48F9C08F82ECCF +F4E7ADD47C705896D0 diff --git a/zdeflate.cpp b/zdeflate.cpp new file mode 100644 index 0000000..98dcad3 --- /dev/null +++ b/zdeflate.cpp @@ -0,0 +1,736 @@ +// zdeflate.cpp - written and placed in the public domain by Wei Dai + +// Many of the algorithms and tables used here came from the deflate implementation +// by Jean-loup Gailly, which was included in Crypto++ 4.0 and earlier. I completely +// rewrote it in order to fix a bug that I could not figure out. This code +// is less clever, but hopefully more understandable and maintainable. + +#include "pch.h" +#include "zdeflate.h" +#include <functional> + +NAMESPACE_BEGIN(CryptoPP) + +using namespace std; + +LowFirstBitWriter::LowFirstBitWriter(BufferedTransformation *attachment) + : Filter(attachment), m_counting(false), m_buffer(0), m_bitsBuffered(0), m_bytesBuffered(0) +{ +} + +void LowFirstBitWriter::StartCounting() +{ + assert(!m_counting); + m_counting = true; + m_bitCount = 0; +} + +unsigned long LowFirstBitWriter::FinishCounting() +{ + assert(m_counting); + m_counting = false; + return m_bitCount; +} + +void LowFirstBitWriter::PutBits(unsigned long value, unsigned int length) +{ + if (m_counting) + m_bitCount += length; + else + { + m_buffer |= value << m_bitsBuffered; + m_bitsBuffered += length; + assert(m_bitsBuffered <= sizeof(unsigned long)*8); + while (m_bitsBuffered >= 8) + { + m_outputBuffer[m_bytesBuffered++] = (byte)m_buffer; + if (m_bytesBuffered == m_outputBuffer.size()) + { + AttachedTransformation()->PutModifiable(m_outputBuffer, m_bytesBuffered); + m_bytesBuffered = 0; + } + m_buffer >>= 8; + m_bitsBuffered -= 8; + } + } +} + +void LowFirstBitWriter::FlushBitBuffer() +{ + if (m_counting) + m_bitCount += 8*(m_bitsBuffered > 0); + else + { + if (m_bytesBuffered > 0) + { + AttachedTransformation()->PutModifiable(m_outputBuffer, m_bytesBuffered); + m_bytesBuffered = 0; + } + if (m_bitsBuffered > 0) + { + AttachedTransformation()->Put((byte)m_buffer); + m_buffer = 0; + m_bitsBuffered = 0; + } + } +} + +void LowFirstBitWriter::ClearBitBuffer() +{ + m_buffer = 0; + m_bytesBuffered = 0; + m_bitsBuffered = 0; +} + +HuffmanEncoder::HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes) +{ + Initialize(codeBits, nCodes); +} + +struct HuffmanNode +{ + unsigned int symbol; + union {unsigned int parent, depth, freq;}; +}; + +struct FreqLessThan +{ + inline bool operator()(unsigned int lhs, const HuffmanNode &rhs) {return lhs < rhs.freq;} + inline bool operator()(const HuffmanNode &lhs, const HuffmanNode &rhs) const {return lhs.freq < rhs.freq;} +}; + +void HuffmanEncoder::GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, unsigned int nCodes) +{ + assert(nCodes > 0); + assert(nCodes <= (unsigned int)(1 << maxCodeBits)); + + unsigned int i; + SecBlockWithHint<HuffmanNode, 2*286> tree(nCodes); + for (i=0; i<nCodes; i++) + { + tree[i].symbol = i; + tree[i].freq = codeCounts[i]; + } + sort(tree.begin(), tree.end(), FreqLessThan()); + unsigned int treeBegin = upper_bound(tree.begin(), tree.end(), 0, FreqLessThan()) - tree.begin(); + if (treeBegin == nCodes) + { // special case for no codes + fill(codeBits, codeBits+nCodes, 0); + return; + } + tree.resize(nCodes + nCodes - treeBegin - 1); + + unsigned int leastLeaf = treeBegin, leastInterior = nCodes; + for (i=nCodes; i<tree.size(); i++) + { + unsigned int least; + least = (leastLeaf == nCodes || (leastInterior < i && tree[leastInterior].freq < tree[leastLeaf].freq)) ? leastInterior++ : leastLeaf++; + tree[i].freq = tree[least].freq; + tree[least].parent = i; + least = (leastLeaf == nCodes || (leastInterior < i && tree[leastInterior].freq < tree[leastLeaf].freq)) ? leastInterior++ : leastLeaf++; + tree[i].freq += tree[least].freq; + tree[least].parent = i; + } + + tree[tree.size()-1].depth = 0; + if (tree.size() >= 2) + for (i=tree.size()-2; i>=nCodes; i--) + tree[i].depth = tree[tree[i].parent].depth + 1; + unsigned int sum = 0; + SecBlockWithHint<unsigned int, 15+1> blCount(maxCodeBits+1); + fill(blCount.begin(), blCount.end(), 0); + for (i=treeBegin; i<nCodes; i++) + { + unsigned int depth = STDMIN(maxCodeBits, tree[tree[i].parent].depth + 1); + blCount[depth]++; + sum += 1 << (maxCodeBits - depth); + } + + unsigned int overflow = sum > (unsigned int)(1 << maxCodeBits) ? sum - (1 << maxCodeBits) : 0; + + while (overflow--) + { + unsigned int bits = maxCodeBits-1; + while (blCount[bits] == 0) + bits--; + blCount[bits]--; + blCount[bits+1] += 2; + assert(blCount[maxCodeBits] > 0); + blCount[maxCodeBits]--; + } + + for (i=0; i<treeBegin; i++) + codeBits[tree[i].symbol] = 0; + unsigned int bits = maxCodeBits; + for (i=treeBegin; i<nCodes; i++) + { + while (blCount[bits] == 0) + bits--; + codeBits[tree[i].symbol] = bits; + blCount[bits]--; + } + assert(blCount[bits] == 0); +} + +void HuffmanEncoder::Initialize(const unsigned int *codeBits, unsigned int nCodes) +{ + assert(nCodes > 0); + unsigned int maxCodeBits = *max_element(codeBits, codeBits+nCodes); + if (maxCodeBits == 0) + return; // assume this object won't be used + + SecBlockWithHint<unsigned int, 15+1> blCount(maxCodeBits+1); + fill(blCount.begin(), blCount.end(), 0); + unsigned int i; + for (i=0; i<nCodes; i++) + blCount[codeBits[i]]++; + + code_t code = 0; + SecBlockWithHint<code_t, 15+1> nextCode(maxCodeBits+1); + nextCode[1] = 0; + for (i=2; i<=maxCodeBits; i++) + { + code = (code + blCount[i-1]) << 1; + nextCode[i] = code; + } + assert(maxCodeBits == 1 || code == (1 << maxCodeBits) - blCount[maxCodeBits]); + + m_valueToCode.resize(nCodes); + for (i=0; i<nCodes; i++) + { + unsigned int len = m_valueToCode[i].len = codeBits[i]; + if (len != 0) + m_valueToCode[i].code = BitReverse(nextCode[len]++) >> (8*sizeof(code_t)-len); + } +} + +inline void HuffmanEncoder::Encode(LowFirstBitWriter &writer, value_t value) const +{ + assert(m_valueToCode[value].len > 0); + writer.PutBits(m_valueToCode[value].code, m_valueToCode[value].len); +} + +Deflator::Deflator(BufferedTransformation *attachment, int deflateLevel, int log2WindowSize) + : LowFirstBitWriter(attachment) +{ + InitializeStaticEncoders(); + IsolatedInitialize(MakeParameters("DeflateLevel", deflateLevel)("Log2WindowSize", log2WindowSize)); +} + +Deflator::Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment) + : LowFirstBitWriter(attachment) +{ + InitializeStaticEncoders(); + IsolatedInitialize(parameters); +} + +void Deflator::InitializeStaticEncoders() +{ + unsigned int codeLengths[288]; + fill(codeLengths + 0, codeLengths + 144, 8); + fill(codeLengths + 144, codeLengths + 256, 9); + fill(codeLengths + 256, codeLengths + 280, 7); + fill(codeLengths + 280, codeLengths + 288, 8); + m_staticLiteralEncoder.Initialize(codeLengths, 288); + fill(codeLengths + 0, codeLengths + 32, 5); + m_staticDistanceEncoder.Initialize(codeLengths, 32); +} + +void Deflator::IsolatedInitialize(const NameValuePairs ¶meters) +{ + int log2WindowSize = parameters.GetIntValueWithDefault("Log2WindowSize", DEFAULT_LOG2_WINDOW_SIZE); + + if (!(MIN_LOG2_WINDOW_SIZE <= log2WindowSize && log2WindowSize <= MAX_LOG2_WINDOW_SIZE)) + throw InvalidArgument("Deflator: " + IntToString(log2WindowSize) + " is an invalid window size"); + + m_log2WindowSize = log2WindowSize; + DSIZE = 1 << m_log2WindowSize; + DMASK = DSIZE - 1; + HSIZE = 1 << m_log2WindowSize; + HMASK = HSIZE - 1; + m_byteBuffer.New(2*DSIZE); + m_head.New(HSIZE); + m_prev.New(DSIZE); + m_matchBuffer.New(DSIZE/2); + + SetDeflateLevel(parameters.GetIntValueWithDefault("DeflateLevel", DEFAULT_DEFLATE_LEVEL)); + Reset(true); +} + +void Deflator::Reset(bool forceReset) +{ + if (forceReset) + ClearBitBuffer(); + else + assert(m_bitsBuffered == 0); + + m_headerWritten = false; + m_matchAvailable = false; + m_dictionaryEnd = 0; + m_stringStart = 0; + m_lookahead = 0; + m_minLookahead = MAX_MATCH; + m_previousMatch = 0; + m_previousLength = 0; + m_matchBufferEnd = 0; + m_blockStart = 0; + m_blockLength = 0; + + // m_prev will be initialized automaticly in InsertString + fill(m_head.begin(), m_head.end(), 0); + + fill(m_literalCounts.begin(), m_literalCounts.end(), 0); + fill(m_distanceCounts.begin(), m_distanceCounts.end(), 0); +} + +void Deflator::SetDeflateLevel(int deflateLevel) +{ + if (!(MIN_DEFLATE_LEVEL <= deflateLevel && deflateLevel <= MAX_DEFLATE_LEVEL)) + throw InvalidArgument("Deflator: " + IntToString(deflateLevel) + " is an invalid deflate level"); + + unsigned int configurationTable[10][4] = { + /* good lazy nice chain */ + /* 0 */ {0, 0, 0, 0}, /* store only */ + /* 1 */ {4, 3, 8, 4}, /* maximum speed, no lazy matches */ + /* 2 */ {4, 3, 16, 8}, + /* 3 */ {4, 3, 32, 32}, + /* 4 */ {4, 4, 16, 16}, /* lazy matches */ + /* 5 */ {8, 16, 32, 32}, + /* 6 */ {8, 16, 128, 128}, + /* 7 */ {8, 32, 128, 256}, + /* 8 */ {32, 128, 258, 1024}, + /* 9 */ {32, 258, 258, 4096}}; /* maximum compression */ + + GOOD_MATCH = configurationTable[deflateLevel][0]; + MAX_LAZYLENGTH = configurationTable[deflateLevel][1]; + MAX_CHAIN_LENGTH = configurationTable[deflateLevel][3]; + + m_deflateLevel = deflateLevel; +} + +unsigned int Deflator::FillWindow(const byte *str, unsigned int length) +{ + unsigned int accepted = STDMIN(length, 2*DSIZE-(m_stringStart+m_lookahead)); + + if (m_stringStart >= 2*DSIZE - MAX_MATCH) + { + if (m_blockStart < DSIZE) + EndBlock(false); + + memcpy(m_byteBuffer, m_byteBuffer + DSIZE, DSIZE); + + m_dictionaryEnd = m_dictionaryEnd < DSIZE ? 0 : m_dictionaryEnd-DSIZE; + assert(m_stringStart >= DSIZE); + m_stringStart -= DSIZE; + assert(m_previousMatch >= DSIZE || m_previousLength < MIN_MATCH); + m_previousMatch -= DSIZE; + assert(m_blockStart >= DSIZE); + m_blockStart -= DSIZE; + + unsigned int i; + + for (i=0; i<HSIZE; i++) + m_head[i] = SaturatingSubtract(m_head[i], DSIZE); + + for (i=0; i<DSIZE; i++) + m_prev[i] = SaturatingSubtract(m_prev[i], DSIZE); + + accepted = STDMIN(accepted + DSIZE, length); + } + assert(accepted > 0); + + memcpy(m_byteBuffer + m_stringStart + m_lookahead, str, accepted); + m_lookahead += accepted; + return accepted; +} + +inline unsigned int Deflator::ComputeHash(const byte *str) const +{ + assert(str+3 <= m_byteBuffer + m_stringStart + m_lookahead); + return ((str[0] << 10) ^ (str[1] << 5) ^ str[2]) & HMASK; +} + +unsigned int Deflator::LongestMatch(unsigned int &bestMatch) const +{ + assert(m_previousLength < MAX_MATCH); + + bestMatch = 0; + unsigned int bestLength = STDMAX(m_previousLength, (unsigned int)MIN_MATCH-1); + if (m_lookahead <= bestLength) + return 0; + + const byte *scan = m_byteBuffer + m_stringStart, *scanEnd = scan + STDMIN((unsigned int)MAX_MATCH, m_lookahead); + unsigned int limit = m_stringStart > (DSIZE-MAX_MATCH) ? m_stringStart - (DSIZE-MAX_MATCH) : 0; + unsigned int current = m_head[ComputeHash(scan)]; + + unsigned int chainLength = MAX_CHAIN_LENGTH; + if (m_previousLength >= GOOD_MATCH) + chainLength >>= 2; + + while (current > limit && --chainLength > 0) + { + const byte *match = m_byteBuffer + current; + assert(scan + bestLength < m_byteBuffer + m_stringStart + m_lookahead); + if (scan[bestLength-1] == match[bestLength-1] && scan[bestLength] == match[bestLength] && scan[0] == match[0] && scan[1] == match[1]) + { + assert(scan[2] == match[2]); + unsigned int len = std::mismatch(scan+3, scanEnd, match+3).first - scan; + assert(len != bestLength); + if (len > bestLength) + { + bestLength = len; + bestMatch = current; + if (len == (scanEnd - scan)) + break; + } + } + current = m_prev[current & DMASK]; + } + return (bestMatch > 0) ? bestLength : 0; +} + +inline void Deflator::InsertString(unsigned int start) +{ + unsigned int hash = ComputeHash(m_byteBuffer + start); + m_prev[start & DMASK] = m_head[hash]; + m_head[hash] = start; +} + +void Deflator::ProcessBuffer() +{ + if (!m_headerWritten) + { + WritePrestreamHeader(); + m_headerWritten = true; + } + + if (m_deflateLevel == 0) + { + while (m_lookahead > 0) + { + LiteralByte(m_byteBuffer[m_stringStart++]); + m_lookahead--; + } + return; + } + + while (m_lookahead > m_minLookahead) + { + while (m_dictionaryEnd < m_stringStart && m_dictionaryEnd+3 <= m_stringStart+m_lookahead) + InsertString(m_dictionaryEnd++); + + if (m_matchAvailable) + { + unsigned int matchPosition, matchLength; + bool usePreviousMatch; + if (m_previousLength >= MAX_LAZYLENGTH) + usePreviousMatch = true; + else + { + matchLength = LongestMatch(matchPosition); + usePreviousMatch = (m_previousLength > 0 && matchLength == 0); + } + if (usePreviousMatch) + { + MatchFound(m_stringStart-1-m_previousMatch, m_previousLength); + m_stringStart += m_previousLength-1; + m_lookahead -= m_previousLength-1; + m_matchAvailable = false; + m_previousLength = 0; + } + else + { + m_previousLength = matchLength; + m_previousMatch = matchPosition; + LiteralByte(m_byteBuffer[m_stringStart-1]); + m_stringStart++; + m_lookahead--; + } + } + else + { + m_previousLength = LongestMatch(m_previousMatch); + m_matchAvailable = true; + m_stringStart++; + m_lookahead--; + } + } + assert(m_stringStart - (m_blockStart+m_blockLength) <= 1); + if (m_minLookahead == 0 && m_matchAvailable) + { + LiteralByte(m_byteBuffer[m_stringStart-1]); + m_matchAvailable = false; + } +} + +unsigned int Deflator::Put2(const byte *str, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Deflator"); + + unsigned int accepted = 0; + while (accepted < length) + { + unsigned int newAccepted = FillWindow(str+accepted, length-accepted); + ProcessBuffer(); + // call ProcessUncompressedData() after WritePrestreamHeader() + ProcessUncompressedData(str+accepted, newAccepted); + accepted += newAccepted; + } + assert(accepted == length); + + if (messageEnd) + { + m_minLookahead = 0; + ProcessBuffer(); + EndBlock(true); + FlushBitBuffer(); + WritePoststreamTail(); + Reset(); + } + + Output(0, NULL, 0, messageEnd, blocking); + return 0; +} + +bool Deflator::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Deflator"); + + m_minLookahead = 0; + ProcessBuffer(); + m_minLookahead = MAX_MATCH; + EndBlock(false); + if (hardFlush) + EncodeBlock(false, STORED); + return false; +} + +void Deflator::LiteralByte(byte b) +{ + m_matchBuffer[m_matchBufferEnd++].literalCode = b; + m_literalCounts[b]++; + + if (m_blockStart+(++m_blockLength) == m_byteBuffer.size() || m_matchBufferEnd == m_matchBuffer.size()) + EndBlock(false); +} + +void Deflator::MatchFound(unsigned int distance, unsigned int length) +{ + static const unsigned int lengthCodes[] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, + 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, + 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285}; + static const unsigned int lengthBases[] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; + static const unsigned int distanceBases[30] = + {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; + + EncodedMatch &m = m_matchBuffer[m_matchBufferEnd++]; + unsigned int lengthCode = lengthCodes[length-3]; + m.literalCode = lengthCode; + m.literalExtra = length - lengthBases[lengthCode-257]; + unsigned int distanceCode = upper_bound(distanceBases, distanceBases+30, distance) - distanceBases - 1; + m.distanceCode = distanceCode; + m.distanceExtra = distance - distanceBases[distanceCode]; + + m_literalCounts[lengthCode]++; + m_distanceCounts[distanceCode]++; + + if (m_blockStart+(m_blockLength+=length) == m_byteBuffer.size() || m_matchBufferEnd == m_matchBuffer.size()) + EndBlock(false); +} + +inline unsigned int CodeLengthEncode(const unsigned int *begin, + const unsigned int *end, + const unsigned int *& p, + unsigned int &extraBits, + unsigned int &extraBitsLength) +{ + unsigned int v = *p; + if ((end-p) >= 3) + { + const unsigned int *oldp = p; + if (v==0 && p[1]==0 && p[2]==0) + { + for (p=p+3; p!=end && *p==0 && p!=oldp+138; p++) {} + unsigned int repeat = p - oldp; + if (repeat <= 10) + { + extraBits = repeat-3; + extraBitsLength = 3; + return 17; + } + else + { + extraBits = repeat-11; + extraBitsLength = 7; + return 18; + } + } + else if (p!=begin && v==p[-1] && v==p[1] && v==p[2]) + { + for (p=p+3; p!=end && *p==v && p!=oldp+6; p++) {} + unsigned int repeat = p - oldp; + extraBits = repeat-3; + extraBitsLength = 2; + return 16; + } + } + p++; + extraBits = 0; + extraBitsLength = 0; + return v; +} + +void Deflator::EncodeBlock(bool eof, unsigned int blockType) +{ + PutBits(eof, 1); + PutBits(blockType, 2); + + if (blockType == STORED) + { + assert(m_blockStart + m_blockLength <= m_byteBuffer.size()); + FlushBitBuffer(); + AttachedTransformation()->PutWord16(m_blockLength, LITTLE_ENDIAN_ORDER); + AttachedTransformation()->PutWord16(~m_blockLength, LITTLE_ENDIAN_ORDER); + AttachedTransformation()->Put(m_byteBuffer + m_blockStart, m_blockLength); + } + else + { + if (blockType == DYNAMIC) + { +#if defined(_MSC_VER) && !defined(__MWERKS__) + // VC60 workaround: built-in reverse_iterator has two template parameters, Dinkumware only has one + typedef reverse_bidirectional_iterator<unsigned int *, unsigned int> RevIt; +#else + typedef reverse_iterator<unsigned int *> RevIt; +#endif + + FixedSizeSecBlock<unsigned int, 286> literalCodeLengths; + FixedSizeSecBlock<unsigned int, 30> distanceCodeLengths; + + m_literalCounts[256] = 1; + HuffmanEncoder::GenerateCodeLengths(literalCodeLengths, 15, m_literalCounts, 286); + m_dynamicLiteralEncoder.Initialize(literalCodeLengths, 286); + unsigned int hlit = find_if(RevIt(literalCodeLengths.end()), RevIt(literalCodeLengths.begin()+257), bind2nd(not_equal_to<unsigned int>(), 0)).base() - (literalCodeLengths.begin()+257); + + HuffmanEncoder::GenerateCodeLengths(distanceCodeLengths, 15, m_distanceCounts, 30); + m_dynamicDistanceEncoder.Initialize(distanceCodeLengths, 30); + unsigned int hdist = find_if(RevIt(distanceCodeLengths.end()), RevIt(distanceCodeLengths.begin()+1), bind2nd(not_equal_to<unsigned int>(), 0)).base() - (distanceCodeLengths.begin()+1); + + SecBlockWithHint<unsigned int, 286+30> combinedLengths(hlit+257+hdist+1); + memcpy(combinedLengths, literalCodeLengths, (hlit+257)*sizeof(unsigned int)); + memcpy(combinedLengths+hlit+257, distanceCodeLengths, (hdist+1)*sizeof(unsigned int)); + + FixedSizeSecBlock<unsigned int, 19> codeLengthCodeCounts, codeLengthCodeLengths; + fill(codeLengthCodeCounts.begin(), codeLengthCodeCounts.end(), 0); + const unsigned int *p = combinedLengths.begin(), *begin = combinedLengths.begin(), *end = combinedLengths.end(); + while (p != end) + { + unsigned int code, extraBits, extraBitsLength; + code = CodeLengthEncode(begin, end, p, extraBits, extraBitsLength); + codeLengthCodeCounts[code]++; + } + HuffmanEncoder::GenerateCodeLengths(codeLengthCodeLengths, 7, codeLengthCodeCounts, 19); + HuffmanEncoder codeLengthEncoder(codeLengthCodeLengths, 19); + static const unsigned int border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + unsigned int hclen = 19; + while (hclen > 4 && codeLengthCodeLengths[border[hclen-1]] == 0) + hclen--; + hclen -= 4; + + PutBits(hlit, 5); + PutBits(hdist, 5); + PutBits(hclen, 4); + + for (unsigned int i=0; i<hclen+4; i++) + PutBits(codeLengthCodeLengths[border[i]], 3); + + p = combinedLengths.begin(); + while (p != end) + { + unsigned int code, extraBits, extraBitsLength; + code = CodeLengthEncode(begin, end, p, extraBits, extraBitsLength); + codeLengthEncoder.Encode(*this, code); + PutBits(extraBits, extraBitsLength); + } + } + + static const unsigned int lengthExtraBits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const unsigned int distanceExtraBits[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + const HuffmanEncoder &literalEncoder = (blockType == STATIC) ? m_staticLiteralEncoder : m_dynamicLiteralEncoder; + const HuffmanEncoder &distanceEncoder = (blockType == STATIC) ? m_staticDistanceEncoder : m_dynamicDistanceEncoder; + + for (unsigned int i=0; i<m_matchBufferEnd; i++) + { + unsigned int literalCode = m_matchBuffer[i].literalCode; + literalEncoder.Encode(*this, literalCode); + if (literalCode >= 257) + { + assert(literalCode <= 285); + PutBits(m_matchBuffer[i].literalExtra, lengthExtraBits[literalCode-257]); + unsigned int distanceCode = m_matchBuffer[i].distanceCode; + distanceEncoder.Encode(*this, distanceCode); + PutBits(m_matchBuffer[i].distanceExtra, distanceExtraBits[distanceCode]); + } + } + literalEncoder.Encode(*this, 256); // end of block + } +} + +void Deflator::EndBlock(bool eof) +{ + if (m_matchBufferEnd == 0 && !eof) + return; + + if (m_deflateLevel == 0) + EncodeBlock(eof, STORED); + else if (m_blockLength < 128) + EncodeBlock(eof, STATIC); + else + { + unsigned int storedLen = 8*(m_blockLength+4) + RoundUpToMultipleOf(m_bitsBuffered+3, 8U)-m_bitsBuffered; + StartCounting(); + EncodeBlock(eof, STATIC); + unsigned int staticLen = FinishCounting(); + StartCounting(); + EncodeBlock(eof, DYNAMIC); + unsigned int dynamicLen = FinishCounting(); + + if (storedLen <= staticLen && storedLen <= dynamicLen) + EncodeBlock(eof, STORED); + else if (staticLen <= dynamicLen) + EncodeBlock(eof, STATIC); + else + EncodeBlock(eof, DYNAMIC); + } + + m_matchBufferEnd = 0; + m_blockStart += m_blockLength; + m_blockLength = 0; + fill(m_literalCounts.begin(), m_literalCounts.end(), 0); + fill(m_distanceCounts.begin(), m_distanceCounts.end(), 0); +} + +NAMESPACE_END diff --git a/zdeflate.h b/zdeflate.h new file mode 100644 index 0000000..60970d0 --- /dev/null +++ b/zdeflate.h @@ -0,0 +1,117 @@ +#ifndef CRYPTOPP_ZDEFLATE_H +#define CRYPTOPP_ZDEFLATE_H + +#include "filters.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class LowFirstBitWriter : public Filter +{ +public: + LowFirstBitWriter(BufferedTransformation *attachment); + void PutBits(unsigned long value, unsigned int length); + void FlushBitBuffer(); + void ClearBitBuffer(); + + void StartCounting(); + unsigned long FinishCounting(); + +protected: + bool m_counting; + unsigned long m_bitCount; + unsigned long m_buffer; + unsigned int m_bitsBuffered, m_bytesBuffered; + FixedSizeSecBlock<byte, 256> m_outputBuffer; +}; + +//! Huffman Encoder +class HuffmanEncoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + + HuffmanEncoder() {} + HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes); + void Initialize(const unsigned int *codeBits, unsigned int nCodes); + + static void GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, unsigned int nCodes); + + void Encode(LowFirstBitWriter &writer, value_t value) const; + + struct Code + { + unsigned int code; + unsigned int len; + }; + + SecBlock<Code> m_valueToCode; +}; + +//! DEFLATE (RFC 1951) compressor + +class Deflator : public LowFirstBitWriter +{ +public: + enum {MIN_DEFLATE_LEVEL = 0, DEFAULT_DEFLATE_LEVEL = 6, MAX_DEFLATE_LEVEL = 9}; + enum {MIN_LOG2_WINDOW_SIZE = 9, DEFAULT_LOG2_WINDOW_SIZE = 15, MAX_LOG2_WINDOW_SIZE = 15}; + Deflator(BufferedTransformation *attachment=NULL, int deflateLevel=DEFAULT_DEFLATE_LEVEL, int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE); + //! possible parameter names: Log2WindowSize, DeflateLevel + Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULL); + + //! this function can be used to set the deflate level in the middle of compression + void SetDeflateLevel(int deflateLevel); + int GetDeflateLevel() const {return m_deflateLevel;} + int GetLog2WindowSize() const {return m_log2WindowSize;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +private: + virtual void WritePrestreamHeader() {} + virtual void ProcessUncompressedData(const byte *string, unsigned int length) {} + virtual void WritePoststreamTail() {} + + enum {STORED = 0, STATIC = 1, DYNAMIC = 2}; + enum {MIN_MATCH = 3, MAX_MATCH = 258}; + + void InitializeStaticEncoders(); + void Reset(bool forceReset = false); + unsigned int FillWindow(const byte *str, unsigned int length); + unsigned int ComputeHash(const byte *str) const; + unsigned int LongestMatch(unsigned int &bestMatch) const; + void InsertString(unsigned int start); + void ProcessBuffer(); + + void LiteralByte(byte b); + void MatchFound(unsigned int distance, unsigned int length); + void EncodeBlock(bool eof, unsigned int blockType); + void EndBlock(bool eof); + + struct EncodedMatch + { + unsigned literalCode : 9; + unsigned literalExtra : 5; + unsigned distanceCode : 5; + unsigned distanceExtra : 13; + }; + + int m_deflateLevel, m_log2WindowSize; + unsigned int DSIZE, DMASK, HSIZE, HMASK, GOOD_MATCH, MAX_LAZYLENGTH, MAX_CHAIN_LENGTH; + bool m_headerWritten, m_matchAvailable; + unsigned int m_dictionaryEnd, m_stringStart, m_lookahead, m_minLookahead, m_previousMatch, m_previousLength; + HuffmanEncoder m_staticLiteralEncoder, m_staticDistanceEncoder, m_dynamicLiteralEncoder, m_dynamicDistanceEncoder; + SecByteBlock m_byteBuffer; + SecBlock<word16> m_head, m_prev; + FixedSizeSecBlock<unsigned int, 286> m_literalCounts; + FixedSizeSecBlock<unsigned int, 30> m_distanceCounts; + SecBlock<EncodedMatch> m_matchBuffer; + unsigned int m_matchBufferEnd, m_blockStart, m_blockLength; +}; + +NAMESPACE_END + +#endif diff --git a/zinflate.cpp b/zinflate.cpp new file mode 100644 index 0000000..fccbf83 --- /dev/null +++ b/zinflate.cpp @@ -0,0 +1,581 @@ +// zinflate.cpp - written and placed in the public domain by Wei Dai + +// This is a complete reimplementation of the DEFLATE decompression algorithm. +// It should not be affected by any security vulnerabilities in the zlib +// compression library. In particular it is not affected by the double free bug +// (http://www.kb.cert.org/vuls/id/368819). + +#include "pch.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct CodeLessThan +{ + inline bool operator()(const CryptoPP::HuffmanDecoder::code_t lhs, const CryptoPP::HuffmanDecoder::CodeInfo &rhs) + {return lhs < rhs.code;} +}; + +inline bool LowFirstBitReader::FillBuffer(unsigned int length) +{ + while (m_bitsBuffered < length) + { + byte b; + if (!m_store.Get(b)) + return false; + m_buffer |= (unsigned long)b << m_bitsBuffered; + m_bitsBuffered += 8; + } + assert(m_bitsBuffered <= sizeof(unsigned long)*8); + return true; +} + +inline unsigned long LowFirstBitReader::PeekBits(unsigned int length) +{ + bool result = FillBuffer(length); + assert(result); + return m_buffer & (((unsigned long)1 << length) - 1); +} + +inline void LowFirstBitReader::SkipBits(unsigned int length) +{ + assert(m_bitsBuffered >= length); + m_buffer >>= length; + m_bitsBuffered -= length; +} + +inline unsigned long LowFirstBitReader::GetBits(unsigned int length) +{ + unsigned long result = PeekBits(length); + SkipBits(length); + return result; +} + +inline HuffmanDecoder::code_t HuffmanDecoder::NormalizeCode(HuffmanDecoder::code_t code, unsigned int codeBits) +{ + return code << (MAX_CODE_BITS - codeBits); +} + +void HuffmanDecoder::Initialize(const unsigned int *codeBits, unsigned int nCodes) +{ + // the Huffman codes are represented in 3 ways in this code: + // + // 1. most significant code bit (i.e. top of code tree) in the least significant bit position + // 2. most significant code bit (i.e. top of code tree) in the most significant bit position + // 3. most significant code bit (i.e. top of code tree) in n-th least significant bit position, + // where n is the maximum code length for this code tree + // + // (1) is the way the codes come in from the deflate stream + // (2) is used to sort codes so they can be binary searched + // (3) is used in this function to compute codes from code lengths + // + // a code in representation (2) is called "normalized" here + // The BitReverse() function is used to convert between (1) and (2) + // The NormalizeCode() function is used to convert from (3) to (2) + + if (nCodes == 0) + throw Err("null code"); + + m_maxCodeBits = *std::max_element(codeBits, codeBits+nCodes); + + if (m_maxCodeBits > MAX_CODE_BITS) + throw Err("code length exceeds maximum"); + + if (m_maxCodeBits == 0) + throw Err("null code"); + + // count number of codes of each length + SecBlockWithHint<unsigned int, 15+1> blCount(m_maxCodeBits+1); + std::fill(blCount.begin(), blCount.end(), 0); + unsigned int i; + for (i=0; i<nCodes; i++) + blCount[codeBits[i]]++; + + // compute the starting code of each length + code_t code = 0; + SecBlockWithHint<code_t, 15+1> nextCode(m_maxCodeBits+1); + nextCode[1] = 0; + for (i=2; i<=m_maxCodeBits; i++) + { + // compute this while checking for overflow: code = (code + blCount[i-1]) << 1 + if (code > code + blCount[i-1]) + throw Err("codes oversubscribed"); + code += blCount[i-1]; + if (code > (code << 1)) + throw Err("codes oversubscribed"); + code <<= 1; + nextCode[i] = code; + } + + if (code > (1 << m_maxCodeBits) - blCount[m_maxCodeBits]) + throw Err("codes oversubscribed"); + else if (m_maxCodeBits != 1 && code < (1 << m_maxCodeBits) - blCount[m_maxCodeBits]) + throw Err("codes incomplete"); + + // compute a vector of <code, length, value> triples sorted by code + m_codeToValue.resize(nCodes - blCount[0]); + unsigned int j=0; + for (i=0; i<nCodes; i++) + { + unsigned int len = codeBits[i]; + if (len != 0) + { + code = NormalizeCode(nextCode[len]++, len); + m_codeToValue[j].code = code; + m_codeToValue[j].len = len; + m_codeToValue[j].value = i; + j++; + } + } + std::sort(m_codeToValue.begin(), m_codeToValue.end()); + + // initialize the decoding cache + m_cacheBits = STDMIN(9U, m_maxCodeBits); + m_cacheMask = (1 << m_cacheBits) - 1; + m_normalizedCacheMask = NormalizeCode(m_cacheMask, m_cacheBits); + assert(m_normalizedCacheMask == BitReverse(m_cacheMask)); + + if (m_cache.size() != 1 << m_cacheBits) + m_cache.resize(1 << m_cacheBits); + + for (i=0; i<m_cache.size(); i++) + m_cache[i].type = 0; +} + +void HuffmanDecoder::FillCacheEntry(LookupEntry &entry, code_t normalizedCode) const +{ + normalizedCode &= m_normalizedCacheMask; + const CodeInfo &codeInfo = *(std::upper_bound(m_codeToValue.begin(), m_codeToValue.end(), normalizedCode, CodeLessThan())-1); + if (codeInfo.len <= m_cacheBits) + { + entry.type = 1; + entry.value = codeInfo.value; + entry.len = codeInfo.len; + } + else + { + entry.begin = &codeInfo; + const CodeInfo *last = & *(std::upper_bound(m_codeToValue.begin(), m_codeToValue.end(), normalizedCode + ~m_normalizedCacheMask, CodeLessThan())-1); + if (codeInfo.len == last->len) + { + entry.type = 2; + entry.len = codeInfo.len; + } + else + { + entry.type = 3; + entry.end = last+1; + } + } +} + +inline unsigned int HuffmanDecoder::Decode(code_t code, /* out */ value_t &value) const +{ + assert(m_codeToValue.size() > 0); + LookupEntry &entry = m_cache[code & m_cacheMask]; + + code_t normalizedCode; + if (entry.type != 1) + normalizedCode = BitReverse(code); + + if (entry.type == 0) + FillCacheEntry(entry, normalizedCode); + + if (entry.type == 1) + { + value = entry.value; + return entry.len; + } + else + { + const CodeInfo &codeInfo = (entry.type == 2) + ? entry.begin[(normalizedCode << m_cacheBits) >> (MAX_CODE_BITS - (entry.len - m_cacheBits))] + : *(std::upper_bound(entry.begin, entry.end, normalizedCode, CodeLessThan())-1); + value = codeInfo.value; + return codeInfo.len; + } +} + +bool HuffmanDecoder::Decode(LowFirstBitReader &reader, value_t &value) const +{ + reader.FillBuffer(m_maxCodeBits); + unsigned int codeBits = Decode(reader.PeekBuffer(), value); + if (codeBits > reader.BitsBuffered()) + return false; + reader.SkipBits(codeBits); + return true; +} + +// ************************************************************* + +Inflator::Inflator(BufferedTransformation *attachment, bool repeat, int propagation) + : AutoSignaling<Filter>(attachment, propagation) + , m_state(PRE_STREAM), m_repeat(repeat) + , m_decodersInitializedWithFixedCodes(false), m_reader(m_inQueue) +{ +} + +void Inflator::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_state = PRE_STREAM; + parameters.GetValue("Repeat", m_repeat); + m_inQueue.Clear(); + m_reader.SkipBits(m_reader.BitsBuffered()); +} + +inline void Inflator::OutputByte(byte b) +{ + m_window[m_current++] = b; + if (m_current == m_window.size()) + { + ProcessDecompressedData(m_window + m_lastFlush, m_window.size() - m_lastFlush); + m_lastFlush = 0; + m_current = 0; + } + if (m_maxDistance < m_window.size()) + m_maxDistance++; +} + +void Inflator::OutputString(const byte *string, unsigned int length) +{ + while (length--) + OutputByte(*string++); +} + +void Inflator::OutputPast(unsigned int length, unsigned int distance) +{ + if (distance > m_maxDistance) + throw BadBlockErr(); + unsigned int start; + if (m_current > distance) + start = m_current - distance; + else + start = m_current + m_window.size() - distance; + + if (start + length > m_window.size()) + { + for (; start < m_window.size(); start++, length--) + OutputByte(m_window[start]); + start = 0; + } + + if (start + length > m_current || m_current + length >= m_window.size()) + { + while (length--) + OutputByte(m_window[start++]); + } + else + { + memcpy(m_window + m_current, m_window + start, length); + m_current += length; + m_maxDistance = STDMIN((unsigned int)m_window.size(), m_maxDistance + length); + } +} + +unsigned int Inflator::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Inflator"); + + LazyPutter lp(m_inQueue, inString, length); + ProcessInput(messageEnd != 0); + + if (messageEnd) + if (!(m_state == PRE_STREAM || m_state == AFTER_END)) + throw UnexpectedEndErr(); + + Output(0, NULL, 0, messageEnd, blocking); + return 0; +} + +bool Inflator::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Inflator"); + + if (hardFlush) + ProcessInput(true); + FlushOutput(); + + return false; +} + +void Inflator::ProcessInput(bool flush) +{ + while (true) + { + if (m_inQueue.IsEmpty()) + return; + + switch (m_state) + { + case PRE_STREAM: + if (!flush && m_inQueue.CurrentSize() < MaxPrestreamHeaderSize()) + return; + ProcessPrestreamHeader(); + m_state = WAIT_HEADER; + m_maxDistance = 0; + m_current = 0; + m_lastFlush = 0; + m_window.New(1 << GetLog2WindowSize()); + break; + case WAIT_HEADER: + { + // maximum number of bytes before actual compressed data starts + const unsigned int MAX_HEADER_SIZE = BitsToBytes(3+5+5+4+19*7+286*15+19*15); + if (m_inQueue.CurrentSize() < (flush ? 1 : MAX_HEADER_SIZE)) + return; + DecodeHeader(); + break; + } + case DECODING_BODY: + if (!DecodeBody()) + return; + break; + case POST_STREAM: + if (!flush && m_inQueue.CurrentSize() < MaxPoststreamTailSize()) + return; + ProcessPoststreamTail(); + m_state = m_repeat ? PRE_STREAM : AFTER_END; + Output(0, NULL, 0, GetAutoSignalPropagation(), true); // TODO: non-blocking + break; + case AFTER_END: + m_inQueue.TransferTo(*AttachedTransformation()); + return; + } + } +} + +void Inflator::DecodeHeader() +{ + if (!m_reader.FillBuffer(3)) + throw UnexpectedEndErr(); + m_eof = m_reader.GetBits(1) != 0; + m_blockType = (byte)m_reader.GetBits(2); + switch (m_blockType) + { + case 0: // stored + { + m_reader.SkipBits(m_reader.BitsBuffered() % 8); + if (!m_reader.FillBuffer(32)) + throw UnexpectedEndErr(); + m_storedLen = (word16)m_reader.GetBits(16); + word16 nlen = (word16)m_reader.GetBits(16); + if (nlen != (word16)~m_storedLen) + throw BadBlockErr(); + break; + } + case 1: // fixed codes + if (!m_decodersInitializedWithFixedCodes) + { + unsigned int codeLengths[288]; + std::fill(codeLengths + 0, codeLengths + 144, 8); + std::fill(codeLengths + 144, codeLengths + 256, 9); + std::fill(codeLengths + 256, codeLengths + 280, 7); + std::fill(codeLengths + 280, codeLengths + 288, 8); + m_literalDecoder.Initialize(codeLengths, 288); + std::fill(codeLengths + 0, codeLengths + 32, 5); + m_distanceDecoder.Initialize(codeLengths, 32); + m_decodersInitializedWithFixedCodes = true; + } + m_nextDecode = LITERAL; + break; + case 2: // dynamic codes + { + m_decodersInitializedWithFixedCodes = false; + if (!m_reader.FillBuffer(5+5+4)) + throw UnexpectedEndErr(); + unsigned int hlit = m_reader.GetBits(5); + unsigned int hdist = m_reader.GetBits(5); + unsigned int hclen = m_reader.GetBits(4); + + FixedSizeSecBlock<unsigned int, 286+32> codeLengths; + unsigned int i; + static const unsigned int border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + std::fill(codeLengths.begin(), codeLengths+19, 0); + for (i=0; i<hclen+4; i++) + codeLengths[border[i]] = m_reader.GetBits(3); + + try + { + HuffmanDecoder codeLengthDecoder(codeLengths, 19); + for (i = 0; i < hlit+257+hdist+1; ) + { + unsigned int k, count, repeater; + bool result = codeLengthDecoder.Decode(m_reader, k); + if (!result) + throw UnexpectedEndErr(); + if (k <= 15) + { + count = 1; + repeater = k; + } + else switch (k) + { + case 16: + if (!m_reader.FillBuffer(2)) + throw UnexpectedEndErr(); + count = 3 + m_reader.GetBits(2); + if (i == 0) + throw BadBlockErr(); + repeater = codeLengths[i-1]; + break; + case 17: + if (!m_reader.FillBuffer(3)) + throw UnexpectedEndErr(); + count = 3 + m_reader.GetBits(3); + repeater = 0; + break; + case 18: + if (!m_reader.FillBuffer(7)) + throw UnexpectedEndErr(); + count = 11 + m_reader.GetBits(7); + repeater = 0; + break; + } + if (i + count > hlit+257+hdist+1) + throw BadBlockErr(); + std::fill(codeLengths + i, codeLengths + i + count, repeater); + i += count; + } + m_literalDecoder.Initialize(codeLengths, hlit+257); + if (hdist == 0 && codeLengths[hlit+257] == 0) + { + if (hlit != 0) // a single zero distance code length means all literals + throw BadBlockErr(); + } + else + m_distanceDecoder.Initialize(codeLengths+hlit+257, hdist+1); + m_nextDecode = LITERAL; + } + catch (HuffmanDecoder::Err &) + { + throw BadBlockErr(); + } + break; + } + default: + throw BadBlockErr(); // reserved block type + } + m_state = DECODING_BODY; +} + +bool Inflator::DecodeBody() +{ + bool blockEnd = false; + switch (m_blockType) + { + case 0: // stored + assert(m_reader.BitsBuffered() == 0); + while (!m_inQueue.IsEmpty() && !blockEnd) + { + unsigned int size; + const byte *block = m_inQueue.Spy(size); + size = STDMIN(size, (unsigned int)m_storedLen); + OutputString(block, size); + m_inQueue.Skip(size); + m_storedLen -= size; + if (m_storedLen == 0) + blockEnd = true; + } + break; + case 1: // fixed codes + case 2: // dynamic codes + static const unsigned int lengthStarts[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const unsigned int lengthExtraBits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const unsigned int distanceStarts[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const unsigned int distanceExtraBits[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + switch (m_nextDecode) + { + while (true) + { + case LITERAL: + if (!m_literalDecoder.Decode(m_reader, m_literal)) + { + m_nextDecode = LITERAL; + break; + } + if (m_literal < 256) + OutputByte((byte)m_literal); + else if (m_literal == 256) // end of block + { + blockEnd = true; + break; + } + else + { + if (m_literal > 285) + throw BadBlockErr(); + unsigned int bits; + case LENGTH_BITS: + bits = lengthExtraBits[m_literal-257]; + if (!m_reader.FillBuffer(bits)) + { + m_nextDecode = LENGTH_BITS; + break; + } + m_literal = m_reader.GetBits(bits) + lengthStarts[m_literal-257]; + case DISTANCE: + if (!m_distanceDecoder.Decode(m_reader, m_distance)) + { + m_nextDecode = DISTANCE; + break; + } + case DISTANCE_BITS: + bits = distanceExtraBits[m_distance]; + if (!m_reader.FillBuffer(bits)) + { + m_nextDecode = DISTANCE_BITS; + break; + } + m_distance = m_reader.GetBits(bits) + distanceStarts[m_distance]; + OutputPast(m_literal, m_distance); + } + } + } + } + if (blockEnd) + { + if (m_eof) + { + FlushOutput(); + m_reader.SkipBits(m_reader.BitsBuffered()%8); + if (m_reader.BitsBuffered()) + { + // undo too much lookahead + SecBlockWithHint<byte, 4> buffer(m_reader.BitsBuffered() / 8); + for (unsigned int i=0; i<buffer.size(); i++) + buffer[i] = (byte)m_reader.GetBits(8); + m_inQueue.Unget(buffer, buffer.size()); + } + m_state = POST_STREAM; + } + else + m_state = WAIT_HEADER; + } + return blockEnd; +} + +void Inflator::FlushOutput() +{ + if (m_state != PRE_STREAM) + { + assert(m_current >= m_lastFlush); + ProcessDecompressedData(m_window + m_lastFlush, m_current - m_lastFlush); + m_lastFlush = m_current; + } +} + +NAMESPACE_END diff --git a/zinflate.h b/zinflate.h new file mode 100644 index 0000000..b3172c8 --- /dev/null +++ b/zinflate.h @@ -0,0 +1,143 @@ +#ifndef CRYPTOPP_ZINFLATE_H +#define CRYPTOPP_ZINFLATE_H + +#include "filters.h" +#include <vector> + +NAMESPACE_BEGIN(CryptoPP) + +//! . +class LowFirstBitReader +{ +public: + LowFirstBitReader(BufferedTransformation &store) + : m_store(store), m_buffer(0), m_bitsBuffered(0) {} + unsigned long BitsLeft() const {return m_store.MaxRetrievable() * 8 + m_bitsBuffered;} + unsigned int BitsBuffered() const {return m_bitsBuffered;} + unsigned long PeekBuffer() const {return m_buffer;} + bool FillBuffer(unsigned int length); + unsigned long PeekBits(unsigned int length); + void SkipBits(unsigned int length); + unsigned long GetBits(unsigned int length); + +private: + BufferedTransformation &m_store; + unsigned long m_buffer; + unsigned int m_bitsBuffered; +}; + +struct CodeLessThan; + +//! Huffman Decoder +class HuffmanDecoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + enum {MAX_CODE_BITS = sizeof(code_t)*8}; + + class Err : public Exception {public: Err(const std::string &what) : Exception(INVALID_DATA_FORMAT, "HuffmanDecoder: " + what) {}}; + + HuffmanDecoder() {} + HuffmanDecoder(const unsigned int *codeBitLengths, unsigned int nCodes) {Initialize(codeBitLengths, nCodes);} + + void Initialize(const unsigned int *codeBitLengths, unsigned int nCodes); + unsigned int Decode(code_t code, /* out */ value_t &value) const; + bool Decode(LowFirstBitReader &reader, value_t &value) const; + +private: + friend struct CodeLessThan; + + struct CodeInfo + { + CodeInfo(code_t code=0, unsigned int len=0, value_t value=0) : code(code), len(len), value(value) {} + inline bool operator<(const CodeInfo &rhs) const {return code < rhs.code;} + code_t code; + unsigned int len; + value_t value; + }; + + struct LookupEntry + { + unsigned int type; + union + { + value_t value; + const CodeInfo *begin; + }; + union + { + unsigned int len; + const CodeInfo *end; + }; + }; + + static code_t NormalizeCode(code_t code, unsigned int codeBits); + void FillCacheEntry(LookupEntry &entry, code_t normalizedCode) const; + + unsigned int m_maxCodeBits, m_cacheBits, m_cacheMask, m_normalizedCacheMask; + std::vector<CodeInfo, AllocatorWithCleanup<CodeInfo> > m_codeToValue; + mutable std::vector<LookupEntry, AllocatorWithCleanup<LookupEntry> > m_cache; +}; + +//! DEFLATE (RFC 1951) decompressor + +class Inflator : public AutoSignaling<Filter> +{ +public: + class Err : public Exception + { + public: + Err(ErrorType e, const std::string &s) + : Exception(e, s) {} + }; + class UnexpectedEndErr : public Err {public: UnexpectedEndErr() : Err(INVALID_DATA_FORMAT, "Inflator: unexpected end of compressed block") {}}; + class BadBlockErr : public Err {public: BadBlockErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in compressed block") {}}; + + /*! \param repeat decompress multiple compressed streams in series + \param autoSignalPropagation 0 to turn off MessageEnd signal + */ + Inflator(BufferedTransformation *attachment = NULL, bool repeat = false, int autoSignalPropagation = -1); + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + + virtual unsigned int GetLog2WindowSize() const {return 15;} + +protected: + ByteQueue m_inQueue; + +private: + virtual unsigned int MaxPrestreamHeaderSize() const {return 0;} + virtual void ProcessPrestreamHeader() {} + virtual void ProcessDecompressedData(const byte *string, unsigned int length) + {AttachedTransformation()->Put(string, length);} + virtual unsigned int MaxPoststreamTailSize() const {return 0;} + virtual void ProcessPoststreamTail() {} + + void ProcessInput(bool flush); + void DecodeHeader(); + bool DecodeBody(); + void FlushOutput(); + void OutputByte(byte b); + void OutputString(const byte *string, unsigned int length); + void OutputPast(unsigned int length, unsigned int distance); + + enum State {PRE_STREAM, WAIT_HEADER, DECODING_BODY, POST_STREAM, AFTER_END}; + State m_state; + bool m_repeat, m_eof, m_decodersInitializedWithFixedCodes; + byte m_blockType; + word16 m_storedLen; + enum NextDecode {LITERAL, LENGTH_BITS, DISTANCE, DISTANCE_BITS}; + NextDecode m_nextDecode; + unsigned int m_literal, m_distance; // for LENGTH_BITS or DISTANCE_BITS + HuffmanDecoder m_literalDecoder, m_distanceDecoder; + LowFirstBitReader m_reader; + SecByteBlock m_window; + unsigned int m_maxDistance, m_current, m_lastFlush; +}; + +NAMESPACE_END + +#endif diff --git a/zlib.cpp b/zlib.cpp new file mode 100644 index 0000000..6195965 --- /dev/null +++ b/zlib.cpp @@ -0,0 +1,90 @@ +// zlib.cpp - written and placed in the public domain by Wei Dai + +// "zlib" is the name of a well known C language compression library +// (http://www.zlib.org) and also the name of a compression format +// (RFC 1950) that the library implements. This file is part of a +// complete reimplementation of the zlib compression format. + +#include "pch.h" +#include "zlib.h" +#include "zdeflate.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const byte DEFLATE_METHOD = 8; +static const byte FDICT_FLAG = 1 << 5; + +// ************************************************************* + +void ZlibCompressor::WritePrestreamHeader() +{ + m_adler32.Restart(); + byte cmf = DEFLATE_METHOD | ((GetLog2WindowSize()-8) << 4); + byte flags = GetCompressionLevel() << 6; + AttachedTransformation()->PutWord16(RoundUpToMultipleOf(cmf*256+flags, 31)); +} + +void ZlibCompressor::ProcessUncompressedData(const byte *inString, unsigned int length) +{ + m_adler32.Update(inString, length); +} + +void ZlibCompressor::WritePoststreamTail() +{ + FixedSizeSecBlock<byte, 4> adler32; + m_adler32.Final(adler32); + AttachedTransformation()->Put(adler32, 4); +} + +unsigned int ZlibCompressor::GetCompressionLevel() const +{ + static const unsigned int deflateToCompressionLevel[] = {0, 1, 1, 1, 2, 2, 2, 2, 2, 3}; + return deflateToCompressionLevel[GetDeflateLevel()]; +} + +// ************************************************************* + +ZlibDecompressor::ZlibDecompressor(BufferedTransformation *attachment, bool repeat, int propagation) + : Inflator(attachment, repeat, propagation) +{ +} + +void ZlibDecompressor::ProcessPrestreamHeader() +{ + m_adler32.Restart(); + + byte cmf; + byte flags; + + if (!m_inQueue.Get(cmf) || !m_inQueue.Get(flags)) + throw HeaderErr(); + + if ((cmf*256+flags) % 31 != 0) + throw HeaderErr(); // if you hit this exception, you're probably trying to decompress invalid data + + if ((cmf & 0xf) != DEFLATE_METHOD) + throw UnsupportedAlgorithm(); + + if (flags & FDICT_FLAG) + throw UnsupportedPresetDictionary(); + + m_log2WindowSize = 8 + (cmf >> 4); +} + +void ZlibDecompressor::ProcessDecompressedData(const byte *inString, unsigned int length) +{ + AttachedTransformation()->Put(inString, length); + m_adler32.Update(inString, length); +} + +void ZlibDecompressor::ProcessPoststreamTail() +{ + FixedSizeSecBlock<byte, 4> adler32; + if (m_inQueue.Get(adler32, 4) != 4) + throw Adler32Err(); + if (!m_adler32.Verify(adler32)) + throw Adler32Err(); +} + +NAMESPACE_END @@ -0,0 +1,58 @@ +#ifndef CRYPTOPP_ZLIB_H +#define CRYPTOPP_ZLIB_H + +#include "adler32.h" +#include "zdeflate.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ZLIB Compressor (RFC 1950) +class ZlibCompressor : public Deflator +{ +public: + ZlibCompressor(BufferedTransformation *attachment=NULL, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE) + : Deflator(attachment, deflateLevel, log2WindowSize) {} + ZlibCompressor(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULL) + : Deflator(parameters, attachment) {} + + unsigned int GetCompressionLevel() const; + +private: + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, unsigned int length); + void WritePoststreamTail(); + + Adler32 m_adler32; +}; + +/// ZLIB Decompressor (RFC 1950) +class ZlibDecompressor : public Inflator +{ +public: + typedef Inflator::Err Err; + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: header decoding error") {}}; + class Adler32Err : public Err {public: Adler32Err() : Err(DATA_INTEGRITY_CHECK_FAILED, "ZlibDecompressor: ADLER32 check error") {}}; + class UnsupportedAlgorithm : public Err {public: UnsupportedAlgorithm() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported algorithm") {}}; + class UnsupportedPresetDictionary : public Err {public: UnsupportedPresetDictionary() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported preset dictionary") {}}; + + /*! \param repeat decompress multiple compressed streams in series + \param autoSignalPropagation 0 to turn off MessageEnd signal + */ + ZlibDecompressor(BufferedTransformation *attachment = NULL, bool repeat = false, int autoSignalPropagation = -1); + unsigned int GetLog2WindowSize() const {return m_log2WindowSize;} + +private: + unsigned int MaxPrestreamHeaderSize() const {return 2;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, unsigned int length); + unsigned int MaxPoststreamTailSize() const {return 4;} + void ProcessPoststreamTail(); + + unsigned int m_log2WindowSize; + Adler32 m_adler32; +}; + +NAMESPACE_END + +#endif |