diff --git a/stepmania/src/CryptManager.cpp b/stepmania/src/CryptManager.cpp index 46870afa2f..d561ec0732 100644 --- a/stepmania/src/CryptManager.cpp +++ b/stepmania/src/CryptManager.cpp @@ -3,11 +3,27 @@ #include "RageUtil.h" #include "RageLog.h" #include "PrefsManager.h" -#include "RageFile.h" -#include "crypto/CryptRSA.h" -#include "crypto/CryptRand.h" -#include "crypto/CryptMD5.h" +// crypt headers +#include "CryptHelpers.h" +#include "crypto51/sha.h" +#include "crypto51/channels.h" +#include "crypto51/hex.h" +#include "crypto51/rsa.h" +#include "crypto51/md5.h" +#include "crypto51/osrng.h" +#include + +using namespace CryptoPP; +using namespace std; + +#ifdef WIN32 + #ifdef DEBUG + #pragma comment(lib, "crypto51\\Release\\cryptlib.lib") + #else + #pragma comment(lib, "crypto51\\Debug\\cryptlib.lib") + #endif +#endif static const CString PRIVATE_KEY_PATH = "Data/private.key.rsa"; static const CString PUBLIC_KEY_PATH = "Data/public.key.rsa"; @@ -17,17 +33,19 @@ CryptManager* CRYPTMAN = NULL; // global and accessable from anywhere in our pro CryptManager::CryptManager() { - if( !PREFSMAN->m_bSignProfileData ) - return; - // // generate keys if none are available // - if( !DoesFileExist(PRIVATE_KEY_PATH) || !DoesFileExist(PUBLIC_KEY_PATH) ) + /* This is crashing in crypto51/integer.cpp CryptoPP::RecursiveInverseModPower2 + * in Linux. -glenn */ + if( PREFSMAN->m_bSignProfileData ) { - LOG->Warn( "Keys missing. Generating new keys" ); - GenerateRSAKey( KEY_LENGTH, PRIVATE_KEY_PATH, PUBLIC_KEY_PATH, "aoksdjaksd" ); - FlushDirCache(); + if( !DoesFileExist(PRIVATE_KEY_PATH) || !DoesFileExist(PUBLIC_KEY_PATH) ) + { + LOG->Warn( "Keys missing. Generating new keys" ); + GenerateRSAKey( KEY_LENGTH, PRIVATE_KEY_PATH, PUBLIC_KEY_PATH, "aoksdjaksd" ); + FlushDirCache(); + } } } @@ -40,119 +58,80 @@ void CryptManager::GenerateRSAKey( unsigned int keyLength, CString privFilename, { ASSERT( PREFSMAN->m_bSignProfileData ); - // Does the RNG need to be inited and seeded every time? - random_init(); - random_add_noise( seed ); + AutoSeededRandomPool rng; - RSAKey key; - key.Generate( keyLength ); + RSAES_OAEP_SHA_Decryptor priv(rng, keyLength); + RageFileSink privFile(privFilename); + priv.DEREncode(privFile); + privFile.MessageEnd(); - RageFile out; - - CString sPublic; - key.PublicBlob( sPublic ); - if( !out.Open( pubFilename, RageFile::WRITE ) ) - RageException::Throw( "Error opening %s: %s", pubFilename.c_str(), out.GetError().c_str() ); - out.Write( sPublic ); - out.Close(); - - CString sPrivate; - key.PrivateBlob( sPrivate ); - if( !out.Open( privFilename, RageFile::WRITE ) ) - RageException::Throw( "Error opening %s: %s", privFilename.c_str(), out.GetError().c_str() ); - out.Write( sPrivate ); - out.Close(); + RSAES_OAEP_SHA_Encryptor pub(priv); + RageFileSink pubFile(pubFilename); + pub.DEREncode(pubFile); + pubFile.MessageEnd(); } -void CryptManager::SignFileToFile( CString sPath, CString sSignatureFilename ) +void CryptManager::SignFileToFile( CString sPath, CString sSignatureFile ) { - if( sSignatureFilename == "" ) - sSignatureFilename = sPath + SIGNATURE_APPEND; - - LOG->Trace("SignFile(%s)", sPath.c_str()); ASSERT( PREFSMAN->m_bSignProfileData ); - if( !IsAFile(PRIVATE_KEY_PATH) ) + CString sPrivFilename = PRIVATE_KEY_PATH; + CString sMessageFilename = sPath;; + if( sSignatureFile.empty() ) + sSignatureFile = sPath + SIGNATURE_APPEND; + + if( !IsAFile(sPrivFilename) ) return; - if( !IsAFile(sPath) ) + if( !IsAFile(sMessageFilename) ) return; - const CString sig = Sign( sPath ); + // CAREFUL: These classes can throw all kinds of exceptions. Should this + // be wrapped in a try catch? - RageFile out; - if( !out.Open( sSignatureFilename, RageFile::WRITE ) ) - RageException::Throw( "Error opening %s: %s", sSignatureFilename.c_str(), out.GetError().c_str() ); - out.Write( sig ); + RageFileSource privFile(sPrivFilename, true); + RSASSA_PKCS1v15_SHA_Signer priv(privFile); + AutoSeededRandomPool rng; + RageFileSource f(sMessageFilename, true, new SignerFilter(rng, priv, new RageFileSink(sSignatureFile))); } -bool CryptManager::VerifyFileWithFile( CString sPath, CString sSignatureFilename ) -{ - if( !IsAFile(sPath) ) - return false; - - if( sSignatureFilename == "" ) - sSignatureFilename = sPath + SIGNATURE_APPEND; - - LOG->Trace("VerifyFile(%s)", sPath.c_str()); - ASSERT( PREFSMAN->m_bSignProfileData ); - - if( !IsAFile(PUBLIC_KEY_PATH) ) - return false; - - if( !IsAFile(sSignatureFilename) ) - return false; - - CString sig; - { - RageFile in; - if( !in.Open( sSignatureFilename, RageFile::READ ) ) - RageException::Throw( "Error opening %s: %s", sSignatureFilename.c_str(), in.GetError().c_str() ); - in.Read( sig ); - } - - return Verify( sPath, sig ); -} - -CString CryptManager::Sign( CString sPath ) +bool CryptManager::VerifyFileWithFile( CString sPath, CString sSignatureFile ) { ASSERT( PREFSMAN->m_bSignProfileData ); - if( !IsAFile(PRIVATE_KEY_PATH) ) - return ""; + CString sPubFilename = PUBLIC_KEY_PATH; + CString sMessageFilename = sPath;; + if( sSignatureFile.empty() ) + sSignatureFile = sPath + SIGNATURE_APPEND; - if( !IsAFile(sPath) ) - return ""; + if( !IsAFile(sPubFilename) ) + return false; - CString data; - { - RageFile in; - if( !in.Open( sPath, RageFile::READ ) ) - RageException::Throw( "Error opening %s: %s", sPath.c_str(), in.GetError().c_str() ); - in.Read( data ); - } + if( !IsAFile(sSignatureFile) ) + return false; - RSAKey key; - { - RageFile keyfile; - if( !keyfile.Open( PRIVATE_KEY_PATH ) ) - RageException::Throw( "Error opening %s: %s", PRIVATE_KEY_PATH.c_str(), keyfile.GetError().c_str() ); - CString private_blob; - keyfile.Read( private_blob ); - key.LoadFromPrivateBlob( private_blob ); - } + // CAREFUL: These classes can throw all kinds of exceptions. Should this + // be wrapped in a try catch? - CString sig; - key.Sign( data, sig ); + /* XXX: This is opening sPubFilename for RageFile::WRITE instead of READ. */ + RageFileSource pubFile(sPubFilename, true); + RSASSA_PKCS1v15_SHA_Verifier pub(pubFile); - return sig; + RageFileSource signatureFile(sSignatureFile, true); + 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()); + RageFileSource f(sMessageFilename, true, verifierFilter); + + return verifierFilter->GetLastResult(); } bool CryptManager::Verify( CString sPath, CString sSignature ) { - if( !IsAFile(sPath) ) - return false; - ASSERT( PREFSMAN->m_bSignProfileData ); CString sPubFilename = PUBLIC_KEY_PATH; @@ -161,61 +140,43 @@ bool CryptManager::Verify( CString sPath, CString sSignature ) if( !IsAFile(sPubFilename) ) return false; - CString data; - { - RageFile in; - if( !in.Open( sPath, RageFile::READ ) ) - RageException::Throw( "Error opening %s: %s", sPath.c_str(), in.GetError().c_str() ); - in.Read( data ); - } + // CAREFUL: These classes can throw all kinds of exceptions. Should this + // be wrapped in a try catch? - RSAKey key; - { - RageFile keyfile; - if( !keyfile.Open( PRIVATE_KEY_PATH ) ) - RageException::Throw( "Error opening %s: %s", PRIVATE_KEY_PATH.c_str(), keyfile.GetError().c_str() ); - CString private_blob; - keyfile.Read( private_blob ); - key.LoadFromPrivateBlob( private_blob ); - } + RageFileSource pubFile(sPubFilename, true); + RSASSA_PKCS1v15_SHA_Verifier pub(pubFile); - return key.Verify( data, sSignature ); + StringSource signatureFile(sSignature, true); + 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()); + RageFileSource f(sMessageFilename, true, verifierFilter); + + return verifierFilter->GetLastResult(); } -CString BinaryToHex( const unsigned char *string, int iNumBytes ) -{ - CString s; - for( int i=0; im_bSignProfileData ); - RageFile file; - if( !file.Open( fn, RageFile::READ ) ) - { - LOG->Warn( "GetMD5: Failed to open file '%s'", fn.c_str() ); - return ""; - } + MD5 md5; + HashFilter md5Filter(md5); - MD5Init(&md5c); - while( !file.AtEOF() && file.GetError().empty() ) - { - iBytesRead = file.Read( buffer, sizeof(buffer) ); - MD5Update(&md5c, buffer, iBytesRead); - } - MD5Final(digest, &md5c); + auto_ptr channelSwitch(new ChannelSwitch); + channelSwitch->AddDefaultRoute(md5Filter); + RageFileSource(fn, true, channelSwitch.release()); - return BinaryToHex( digest, sizeof(digest) ); + HexEncoder encoder(new RageFileSink("temp.txt"), false); + cout << "\nMD5: "; + md5Filter.TransferTo(encoder); + + ASSERT(0); + return ""; } CString CryptManager::GetPublicKeyFileName() diff --git a/stepmania/src/crypto51/Debug/cryptlib.lib b/stepmania/src/crypto51/Debug/cryptlib.lib new file mode 100644 index 0000000000..df5df2dcf6 Binary files /dev/null and b/stepmania/src/crypto51/Debug/cryptlib.lib differ diff --git a/stepmania/src/crypto51/GNUmakefile b/stepmania/src/crypto51/GNUmakefile new file mode 100644 index 0000000000..e509eb5ff9 --- /dev/null +++ b/stepmania/src/crypto51/GNUmakefile @@ -0,0 +1,76 @@ +# 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. +# Note that you must define NDEBUG for your own application if you define it for Crypto++. +# Also, make sure you run the validation tests and test your own program thoroughly +# after turning on -O2. The GCC optimizer may have bugs that cause it to generate incorrect code. +# 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) +AR = libtool +ARFLAGS = -static -o +CXXFLAGS += -D__pic__ +IS_GCC2 = $(shell c++ -v 2>&1 | grep -c gcc-932) +ifeq ($(IS_GCC2),1) +CXXFLAGS += -fno-coalesce-templates -fno-coalesce-static-vtables +CXX = c++ +LDLIBS += -lstdc++ +LDFLAGS += -flat_namespace -undefined suppress -m +endif +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 = test.o +#TESTOBJS = bench.o test.o validat1.o validat2.o validat3.o adhoc.o datatest.o regtest.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) + +adhoc.cpp: adhoc.cpp.proto +ifeq ($(wildcard adhoc.cpp),) + cp adhoc.cpp.proto adhoc.cpp +else + touch adhoc.cpp +endif + +.SUFFIXES: .cpp + +.cpp.o: + $(CXX) $(CXXFLAGS) -c $< diff --git a/stepmania/src/crypto51/License.txt b/stepmania/src/crypto51/License.txt new file mode 100644 index 0000000000..2a8ec4e487 --- /dev/null +++ b/stepmania/src/crypto51/License.txt @@ -0,0 +1,67 @@ +Compilation Copyright (c) 1995-2003 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, +and their use is subject to additional licenses included in these files. + +mars.cpp - Copyright 1998 Brian Gladman. + +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 +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/stepmania/src/crypto51/Readme.txt b/stepmania/src/crypto51/Readme.txt new file mode 100644 index 0000000000..d9ca490d9f --- /dev/null +++ b/stepmania/src/crypto51/Readme.txt @@ -0,0 +1,255 @@ +Crypto++: a C++ Class Library of Cryptographic Primitives +Version 5.1 3/20/2003 + +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, 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 should check the compiler options to make sure +that the library and your application are using the same C++ run-time +libraries and calling conventions. + +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 through inline comments in header files, which are +processed through Doxygen to produce an HTML reference manual. You can find +a link to the manual from http://www.cryptopp.com. Also at that site is +the Crypto++ FAQ, which you should browse through before attempting to +use this library, because it will likely answer many of questions that +may come up. + +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 +cryptopp@weidai.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 Serpent, HAVAL and IDEA to use public domain code + - implemented SSE2 optimizations for Integer operations + - fixed a bug in HMAC::TruncatedFinal() + - fixed SKIPJACK byte ordering following NIST clarification dated 5/9/02 + +5.01 (special FIPS 140-2 release, in development) + - added known answer test for X9.17 RNG in FIPS 140 power-up self test + - is being evaluated for FIPS 140-2 compliance + +5.1 - added PSS padding and changed PSSR to track IEEE P1363a draft standard + - added blinding for RSA and Rabin to defend against timing attacks + on decryption operations + - changed signing and decryption APIs to support the above + - changed WaitObjectContainer to allow waiting for more than 64 + objects at a time on Win32 platforms + - fixed a bug in CBC and ECB modes with processing non-aligned data + - fixed standard conformance bugs in DLIES (DHAES mode) and RW/EMSA2 + signature scheme (these fixes are not backwards compatible) + - fixed a number of compiler warnings, minor bugs, and portability problems + - removed Sapphire diff --git a/stepmania/src/crypto51/Release/cryptlib.lib b/stepmania/src/crypto51/Release/cryptlib.lib new file mode 100644 index 0000000000..d7be5bbb1f Binary files /dev/null and b/stepmania/src/crypto51/Release/cryptlib.lib differ diff --git a/stepmania/src/crypto51/algebra.cpp b/stepmania/src/crypto51/algebra.cpp new file mode 100644 index 0000000000..222109aa28 --- /dev/null +++ b/stepmania/src/crypto51/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 + +NAMESPACE_BEGIN(CryptoPP) + +template const T& AbstractGroup::Double(const Element &a) const +{ + return Add(a, a); +} + +template const T& AbstractGroup::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 T& AbstractGroup::Accumulate(Element &a, const Element &b) const +{ + return a = Add(a, b); +} + +template T& AbstractGroup::Reduce(Element &a, const Element &b) const +{ + return a = Subtract(a, b); +} + +template const T& AbstractRing::Square(const Element &a) const +{ + return Multiply(a, a); +} + +template const T& AbstractRing::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 const T& AbstractEuclideanDomain::Mod(const Element &a, const Element &b) const +{ + Element q; + DivisionAlgorithm(result, q, a, b); + return result; +} + +template const T& AbstractEuclideanDomain::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 const typename QuotientRing::Element& QuotientRing::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 T AbstractGroup::ScalarMultiply(const Element &base, const Integer &exponent) const +{ + Element result; + SimultaneousMultiply(&result, base, &exponent, 1); + return result; +} + +template T AbstractGroup::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< 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=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< Element GeneralCascadeMultiplication(const AbstractGroup &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 +void AbstractGroup::SimultaneousMultiply(T *results, const T &base, const Integer *expBegin, unsigned int expCount) const +{ + std::vector > buckets(expCount); + std::vector exponents; + exponents.reserve(expCount); + unsigned int i; + + for (i=0; iNotNegative()); + 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 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 T AbstractRing::Exponentiate(const Element &base, const Integer &exponent) const +{ + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; +} + +template T AbstractRing::CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const +{ + return MultiplicativeGroup().AbstractGroup::CascadeScalarMultiply(x, e1, y, e2); +} + +template Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end) +{ + return GeneralCascadeMultiplication(ring.MultiplicativeGroup(), begin, end); +} + +template +void AbstractRing::SimultaneousExponentiate(T *results, const T &base, const Integer *exponents, unsigned int expCount) const +{ + MultiplicativeGroup().AbstractGroup::SimultaneousMultiply(results, base, exponents, expCount); +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/algebra.h b/stepmania/src/crypto51/algebra.h new file mode 100644 index 0000000000..bb36e59bd8 --- /dev/null +++ b/stepmania/src/crypto51/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 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 AbstractRing : public AbstractGroup +{ +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& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup + { + public: + const AbstractRing& 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 *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +//! Base and Exponent +template +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {} + bool operator<(const BaseAndExponent &rhs) const {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template + Element GeneralCascadeMultiplication(const AbstractGroup &group, Iterator begin, Iterator end); +template + Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end); + +// ******************************************************** + +//! Abstract Euclidean Domain +template class AbstractEuclideanDomain : public AbstractRing +{ +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 EuclideanDomainOf : public AbstractEuclideanDomain +{ +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 QuotientRing : public AbstractRing +{ +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/stepmania/src/crypto51/algparam.cpp b/stepmania/src/crypto51/algparam.cpp new file mode 100644 index 0000000000..1f49db6f9c --- /dev/null +++ b/stepmania/src/crypto51/algparam.cpp @@ -0,0 +1,10 @@ +// algparam.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +bool (*AssignIntToInteger)(const std::type_info &valueType, void *pInteger, const void *pInt) = NULL; + +NAMESPACE_END diff --git a/stepmania/src/crypto51/algparam.h b/stepmania/src/crypto51/algparam.h new file mode 100644 index 0000000000..999998d88f --- /dev/null +++ b/stepmania/src/crypto51/algparam.h @@ -0,0 +1,325 @@ +#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 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 GetValueHelperClass +{ +public: + GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst) + : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) + { + if (strcmp(m_name, "ValueNames") == 0) + { + m_found = m_getValueNames = true; + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType); + if (searchFirst) + searchFirst->GetVoidValue(m_name, valueType, pValue); + if (typeid(T) != typeid(BASE)) + pObject->BASE::GetVoidValue(m_name, valueType, pValue); + ((*reinterpret_cast(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';'; + } + + if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType); + *reinterpret_cast(pValue) = pObject; + m_found = true; + return; + } + + if (!m_found && searchFirst) + m_found = searchFirst->GetVoidValue(m_name, valueType, pValue); + + if (!m_found && typeid(T) != typeid(BASE)) + m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue); + } + + operator bool() const {return m_found;} + + template + GetValueHelperClass & operator()(const char *name, const R & (T::*pm)() const) + { + if (m_getValueNames) + (*reinterpret_cast(m_pValue) += name) += ";"; + if (!m_found && strcmp(name, m_name) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType); + *reinterpret_cast(m_pValue) = (m_pObject->*pm)(); + m_found = true; + } + return *this; + } + + GetValueHelperClass &Assignable() + { + if (m_getValueNames) + ((*reinterpret_cast(m_pValue) += "ThisObject:") += typeid(T).name()) += ';'; + if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); + *reinterpret_cast(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 +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL, BASE *dummy=NULL) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +// ******************************************************** + +template +R Hack_DefaultValueFromConstReferenceType(const R &) +{ + return R(); +} + +template +bool Hack_GetValueIntoConstReference(const NameValuePairs &source, const char *name, const R &value) +{ + return source.GetValue(name, const_cast(value)); +} + +template +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 + 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(*(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 + 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(*(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(*(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 +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source, BASE *dummy=NULL) +{ + return AssignFromHelperClass(pObject, source); +} + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +// ******************************************************** + +// This should allow the linker to discard Integer code if not needed. +extern bool (*AssignIntToInteger)(const std::type_info &valueType, void *pInteger, const void *pInt); + +const std::type_info & IntegerTypeId(); + +template +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 + AlgorithmParameters, R> operator()(const char *name, const R &value) const + { + return AlgorithmParameters, 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(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 (!(AssignIntToInteger != NULL && typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value))) + { + ThrowIfTypeMismatch(name, typeid(T), valueType); + *reinterpret_cast(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 +AlgorithmParameters MakeParameters(const char *name, const T &value) +{ + return AlgorithmParameters(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/stepmania/src/crypto51/argnames.h b/stepmania/src/crypto51/argnames.h new file mode 100644 index 0000000000..ed227eedc2 --- /dev/null +++ b/stepmania/src/crypto51/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 diff --git a/stepmania/src/crypto51/asn.cpp b/stepmania/src/crypto51/asn.cpp new file mode 100644 index 0000000000..262a430406 --- /dev/null +++ b/stepmania/src/crypto51/asn.cpp @@ -0,0 +1,556 @@ +// asn.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "asn.h" + +#include +#include + +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 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(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(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 diff --git a/stepmania/src/crypto51/asn.h b/stepmania/src/crypto51/asn.h new file mode 100644 index 0000000000..b3fba6acee --- /dev/null +++ b/stepmania/src/crypto51/asn.h @@ -0,0 +1,346 @@ +#ifndef CRYPTOPP_ASN_H +#define CRYPTOPP_ASN_H + +#include "filters.h" +#include "queue.h" +#include + +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 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 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 ASNOptional : public member_ptr +{ +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 + //! decode subjectPublicKey part of subjectPublicKeyInfo, or privateKey part of privateKeyInfo, without the BIT STRING or OCTET STRING header + virtual void BERDecodeKey(BufferedTransformation &bt) {assert(false);} + virtual void BERDecodeKey2(BufferedTransformation &bt, bool parametersPresent, unsigned int size) + {BERDecodeKey(bt);} + //! encode subjectPublicKey part of subjectPublicKeyInfo, or privateKey part of privateKeyInfo, without the BIT STRING or OCTET STRING header + virtual void DEREncodeKey(BufferedTransformation &bt) const =0; +}; + +//! encodes/decodes subjectPublicKeyInfo +class X509PublicKey : virtual public ASN1Key, public PublicKey +{ +public: + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; +}; + +//! encodes/decodes privateKeyInfo +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 +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)-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::max conflicts with MFC max macro +// CW41 workaround: std::numeric_limits::max causes a template error +template +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 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/stepmania/src/crypto51/basecode.cpp b/stepmania/src/crypto51/basecode.cpp new file mode 100644 index 0000000000..1e81ece478 --- /dev/null +++ b/stepmania/src/crypto51/basecode.cpp @@ -0,0 +1,228 @@ +// basecode.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "basecode.h" +#include "fltrimpl.h" +#include + +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); + + { + unsigned int b = begin[m_inputPosition++], bitsLeftInSource = 8; + while (true) + { + assert(m_bitPos < m_bitsPerChar); + unsigned int bitsLeftInTarget = m_bitsPerChar-m_bitPos; + m_outBuf[m_bytePos] |= b >> (8-bitsLeftInTarget); + if (bitsLeftInSource >= bitsLeftInTarget) + { + m_bitPos = 0; + ++m_bytePos; + bitsLeftInSource -= bitsLeftInTarget; + if (bitsLeftInSource == 0) + break; + b <<= bitsLeftInTarget; + b &= 0xff; + } + else + { + m_bitPos += bitsLeftInSource; + break; + } + } + } + + assert(m_bytePos <= m_outputBlockSize); + if (m_bytePos == m_outputBlockSize) + { + int i; + for (i=0; i 0) + ++m_bytePos; + + int i; + for (i=0; i 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_NO_MESSAGE_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 +{ +public: + BaseN_Encoder(BufferedTransformation *attachment=NULL) + : Unflushable(attachment) {} + + BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULL, int padding=-1) + : Unflushable(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 +{ +public: + BaseN_Decoder(BufferedTransformation *attachment=NULL) + : Unflushable(attachment) {} + + BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULL) + : Unflushable(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 +{ +public: + Grouper(BufferedTransformation *attachment=NULL) + : Bufferless(attachment) {} + + Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULL) + : Bufferless(attachment) + { + IsolatedInitialize(MakeParameters("GroupSize", groupSize) + ("Separator", ConstByteArrayParameter(separator)) + ("Terminator", ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + unsigned int Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking); + +private: + SecByteBlock m_separator, m_terminator; + unsigned int m_groupSize, m_counter; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/channels.cpp b/stepmania/src/crypto51/channels.cpp new file mode 100644 index 0000000000..d13bcf429a --- /dev/null +++ b/stepmania/src/crypto51/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 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 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(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 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/stepmania/src/crypto51/channels.h b/stepmania/src/crypto51/channels.h new file mode 100644 index 0000000000..4b12ce6877 --- /dev/null +++ b/stepmania/src/crypto51/channels.h @@ -0,0 +1,91 @@ +#ifndef CRYPTOPP_CHANNELS_H +#define CRYPTOPP_CHANNELS_H + +#include "simple.h" +#include "smartptr.h" +#include +#include + +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 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 RouteList; + typedef std::list 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 +{ +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 Route; + typedef std::multimap RouteMap; + RouteMap m_routeMap; + + typedef std::pair > DefaultRoute; + typedef std::list DefaultRouteList; + DefaultRouteList m_defaultRoutes; + + friend class ChannelRouteIterator; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/config.h b/stepmania/src/crypto51/config.h new file mode 100644 index 0000000000..f27910c4eb --- /dev/null +++ b/stepmania/src/crypto51/config.h @@ -0,0 +1,247 @@ +#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(__BIG_ENDIAN__) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || 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__) || defined(__MACH__) +# 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 +#if defined(_MSC_VER) && (_MSC_VER < 1300) +#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(__unix__) || defined(__MACH__) +#define CRYPTOPP_UNIX_AVAILABLE +#endif + +#if defined(WORD64_AVAILABLE) && (defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE) || defined(macintosh)) +# define HIGHRES_TIMER_AVAILABLE +#endif + +#ifdef CRYPTOPP_UNIX_AVAILABLE +# 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 + +#ifdef CRYPTOPP_UNIX_AVAILABLE +# define NONBLOCKING_RNG_AVAILABLE +# define BLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# define HAS_PTHREADS +# define THREADS_AVAILABLE +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# define HAS_WINTHREADS +# define THREADS_AVAILABLE +#endif + +#endif // NO_OS_DEPENDENCE + +#endif diff --git a/stepmania/src/crypto51/cryptest.dsp b/stepmania/src/crypto51/cryptest.dsp new file mode 100644 index 0000000000..f926f35d98 --- /dev/null +++ b/stepmania/src/crypto51/cryptest.dsp @@ -0,0 +1,388 @@ +# Microsoft Developer Studio Project File - Name="cryptest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 60000 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cryptest - Win32 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 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!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 "cryptest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cryptest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(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 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=echo This configuration is used to build a static binary for FIPS 140 evaluation by a testing laboratory. echo Crypto++ users should not build this configuration directly. +# End Special Build Tool + +!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 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=echo This configuration is used to build a static binary for FIPS 140 evaluation by a testing laboratory. echo Crypto++ users should not build this configuration directly. +# End Special Build Tool + +!ELSEIF "$(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 /MD /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 /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /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 + +!ENDIF + +# Begin Target + +# Name "cryptest - Win32 FIPS 140 Release" +# Name "cryptest - Win32 FIPS 140 Debug" +# Name "cryptest - Win32 Release" +# Name "cryptest - Win32 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 ".cpp;.h" +# Begin Source File + +SOURCE=.\bench.h +# End Source File +# Begin Source File + +SOURCE=.\factory.h +# End Source File +# Begin Source File + +SOURCE=.\test.cpp +# End Source File +# Begin Source File + +SOURCE=.\validate.h +# End Source File +# End Group +# End Target +# End Project diff --git a/stepmania/src/crypto51/cryptest.dsw b/stepmania/src/crypto51/cryptest.dsw new file mode 100644 index 0000000000..bce8473e35 --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/cryptlib.cpp b/stepmania/src/crypto51/cryptlib.cpp new file mode 100644 index 0000000000..e3fe2d5f9d --- /dev/null +++ b/stepmania/src/crypto51/cryptlib.cpp @@ -0,0 +1,687 @@ +// 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 + +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 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 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 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 + { + // VC60 complains if this function is missing + EncryptionFilter(const EncryptionFilter &x) : Unflushable(NULL), m_rng(x.m_rng), m_encryptor(x.m_encryptor) {} + + EncryptionFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment) + : Unflushable(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(RandomNumberGenerator &rng, BufferedTransformation *attachment) const +{ + struct DecryptionFilter : public Unflushable + { + // VC60 complains if this function is missing + DecryptionFilter(const DecryptionFilter &x) : Unflushable(NULL), m_rng(x.m_rng), m_decryptor(x.m_decryptor) {} + + DecryptionFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment) + : Unflushable(attachment), m_rng(rng), 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(m_rng, 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; + } + + RandomNumberGenerator &m_rng; + const PK_Decryptor &m_decryptor; + SecByteBlock m_plaintext; + DecodingResult m_result; + }; + + return new DecryptionFilter(rng, *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(RandomNumberGenerator &rng, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const +{ + if (cipherTextLength != FixedCiphertextLength()) + return DecodingResult(); + + return FixedLengthDecrypt(rng, cipherText, plainText); +} + +unsigned int PK_Signer::Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const +{ + std::auto_ptr m(messageAccumulator); + return SignAndRestart(rng, *m, signature, false); +} + +unsigned int PK_Signer::SignMessage(RandomNumberGenerator &rng, const byte *message, unsigned int messageLen, byte *signature) const +{ + std::auto_ptr m(NewSignatureAccumulator(rng)); + m->Update(message, messageLen); + return SignAndRestart(rng, *m, signature, false); +} + +unsigned int PK_Signer::SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, unsigned int recoverableMessageLength, + const byte *nonrecoverableMessage, unsigned int nonrecoverableMessageLength, byte *signature) const +{ + std::auto_ptr m(NewSignatureAccumulator(rng)); + InputRecoverableMessage(*m, recoverableMessage, recoverableMessageLength); + m->Update(nonrecoverableMessage, nonrecoverableMessageLength); + return SignAndRestart(rng, *m, signature, false); +} + +bool PK_Verifier::Verify(PK_MessageAccumulator *messageAccumulator) const +{ + std::auto_ptr m(messageAccumulator); + return VerifyAndRestart(*m); +} + +bool PK_Verifier::VerifyMessage(const byte *message, unsigned int messageLen, const byte *signature, unsigned int signatureLength) const +{ + std::auto_ptr m(NewVerificationAccumulator()); + InputSignature(*m, signature, signatureLength); + m->Update(message, messageLen); + return VerifyAndRestart(*m); +} + +DecodingResult PK_Verifier::Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const +{ + std::auto_ptr m(messageAccumulator); + return RecoverAndRestart(recoveredMessage, *m); +} + +DecodingResult PK_Verifier::RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, unsigned int nonrecoverableMessageLength, + const byte *signature, unsigned int signatureLength) const +{ + std::auto_ptr m(NewVerificationAccumulator()); + InputSignature(*m, signature, signatureLength); + m->Update(nonrecoverableMessage, nonrecoverableMessageLength); + return RecoverAndRestart(recoveredMessage, *m); +} + +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/stepmania/src/crypto51/cryptlib.dsp b/stepmania/src/crypto51/cryptlib.dsp new file mode 100644 index 0000000000..e9f7c8731c --- /dev/null +++ b/stepmania/src/crypto51/cryptlib.dsp @@ -0,0 +1,746 @@ +# Microsoft Developer Studio Project File - Name="cryptlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 60000 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=cryptlib - Win32 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 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!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 "cryptlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "cryptlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(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" + +!ELSEIF "$(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 /MD /W3 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /YX"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 /MDd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PRECOMPILED_HEADERS" /YX"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 + +!ENDIF + +# Begin Target + +# Name "cryptlib - Win32 FIPS 140 Release" +# Name "cryptlib - Win32 FIPS 140 Debug" +# Name "cryptlib - Win32 Release" +# Name "cryptlib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter ".cpp" +# Begin Source File + +SOURCE=.\algebra.cpp +# End Source File +# Begin Source File + +SOURCE=.\algparam.cpp +# End Source File +# Begin Source File + +SOURCE=.\asn.cpp +# End Source File +# Begin Source File + +SOURCE=.\basecode.cpp +# End Source File +# Begin Source File + +SOURCE=.\channels.cpp +# End Source File +# Begin Source File + +SOURCE=.\cryptlib.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=.\eprecomp.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=.\hex.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=.\md5.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=.\mqueue.cpp +# End Source File +# Begin Source File + +SOURCE=.\nbtheory.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=.\pkcspad.cpp +# End Source File +# Begin Source File + +SOURCE=.\polynomi.cpp +# End Source File +# Begin Source File + +SOURCE=.\pssr.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=.\randpool.cpp +# End Source File +# Begin Source File + +SOURCE=.\rsa.cpp +# End Source File +# Begin Source File + +SOURCE=.\sha.cpp +# End Source File +# Begin Source File + +SOURCE=.\strciphr.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=.\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/stepmania/src/crypto51/cryptlib.h b/stepmania/src/crypto51/cryptlib.h new file mode 100644 index 0000000000..27783971cf --- /dev/null +++ b/stepmania/src/crypto51/cryptlib.h @@ -0,0 +1,1564 @@ +// 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 Crypto++TM Library 5.1 Reference Manual +
+
Abstract Base Classes
+ cryptlib.h +
Symmetric Ciphers
+ SymmetricCipherDocumentation +
Hash Functions
+ HAVAL, MD2, MD4, MD5, PanamaHash, RIPEMD160, SHA, SHA256, SHA384, SHA512, Tiger +
Non-Cryptographic Checksums
+ CRC32, Adler32 +
Message Authentication Codes
+ #MD5MAC, XMACC, HMAC, CBC_MAC, DMAC, PanamaMAC +
Random Number Generators
+ NullRNG(), LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG +
Public Key Cryptosystems
+ DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES +
Public Key Signature Schemes
+ DSA, GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RabinSS, RWSS, ESIGN +
Key Agreement
+ #DH, DH2, #MQV, ECDH, ECMQV, XTR_DH +
Algebraic Structures
+ Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, + ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, + GF2NP, GF256, GF2_32, EC2N, ECP +
Secret Sharing and Information Dispersal
+ SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery +
Compression
+ Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor +
Input Source Classes
+ StringSource, FileSource, SocketSource, WindowsPipeSource, RandomNumberSource +
Output Sink Classes
+ StringSinkTemplate, ArraySink, FileSink, SocketSink, WindowsPipeSink +
Filter Wrappers
+ StreamTransformationFilter, HashFilter, HashVerificationFilter, SignerFilter, SignatureVerificationFilter +
Binary to Text Encoders and Decoders
+ HexEncoder, HexDecoder, Base64Encoder, Base64Decoder +
Wrappers for OS features
+ Timer, Socket, WindowsHandle, ThreadLocalStorage +
FIPS 140 related
+ fips140.h +
+ +

This reference manual is a work in progress. Some classes are still lacking detailed descriptions. +

Click here to download a zip archive containing this manual. +

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 +#include +#include +#include +#include + +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 +struct EnumToType +{ + static ENUM_TYPE ToEnum() {return (ENUM_TYPE)VALUE;} +}; + +enum ByteOrder {LITTLE_ENDIAN_ORDER = 0, BIG_ENDIAN_ORDER = 1}; +typedef EnumToType LittleEndian; +typedef EnumToType 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_errorType(errorType), 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 + 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 + 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 + 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 + 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 + 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;} + + //! returns how input should be aligned for optimal performance + virtual unsigned int OptimalDataAlignment() 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 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 BlockCipher; +typedef SimpleKeyedTransformation SymmetricCipher; +typedef SimpleKeyedTransformation 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 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 which can be written into by the caller, and then used as input to Put() + /*! \param size is requested size (as a hint) for input, and size of the returned space for output */ + /*! \note The purpose of this method is to help avoid doing extra memory allocations. */ + 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(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 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(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(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(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(RandomNumberGenerator &rng, 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(RandomNumberGenerator &rng, 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(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const =0; + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const; +}; + +//! interface for public-key signers and verifiers + +/*! This class provides an interface common to signers and verifiers + for querying scheme properties. +*/ +class PK_SignatureScheme +{ +public: + //! invalid key exception, may be thrown by any function in this class if the private or public key has a length that can't be used + class InvalidKeyLength : public Exception + { + public: + InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {} + }; + + //! key too short exception, may be thrown by any function in this class if the private or public key is too short to sign or verify anything + class KeyTooShort : public InvalidKeyLength + { + public: + KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {} + }; + + virtual ~PK_SignatureScheme() {} + + //! signature length if it only depends on the key, otherwise 0 + virtual unsigned int SignatureLength() const =0; + + //! maximum signature length produced for a given length of recoverable message part + virtual unsigned int MaxSignatureLength(unsigned int recoverablePartLength = 0) const {return SignatureLength();} + + //! length of longest message that can be recovered, or 0 if this signature scheme does not support message recovery + virtual unsigned int MaxRecoverableLength() const =0; + + //! length of longest message that can be recovered from a signature of given length, or 0 if this signature scheme does not support message recovery + virtual unsigned int MaxRecoverableLengthFromSignatureLength(unsigned int signatureLength) const =0; + + //! requires a random number generator to sign + /*! if this returns false, NullRNG() can be passed to functions that take RandomNumberGenerator & */ + virtual bool IsProbabilistic() const =0; + + //! whether or not a non-recoverable message part can be signed + virtual bool AllowNonrecoverablePart() const =0; + + //! if this function returns true, during verification you must input the signature before the message, otherwise you can input it at anytime */ + virtual bool SignatureUpfront() const {return false;} + + //! whether you must input the recoverable part before the non-recoverable part during signing + virtual bool RecoverablePartFirst() const =0; +}; + +//! interface for accumulating messages to be signed or verified +/*! Only Update() should be called + on this class. No other functions inherited from HashTransformation should be called. +*/ +class PK_MessageAccumulator : public HashTransformation +{ +public: + //! should not be called on PK_MessageAccumulator + unsigned int DigestSize() const + {throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");} + //! should not be called on PK_MessageAccumulator + void TruncatedFinal(byte *digest, unsigned int digestSize) + {throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called");} +}; + +//! interface for public-key signers + +class PK_Signer : virtual public PK_SignatureScheme, public PrivateKeyAlgorithm +{ +public: + //! create a new HashTransformation to accumulate the message to be signed + virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng = NullRNG()) const =0; + + virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, unsigned int recoverableMessageLength) const =0; + + //! sign and delete messageAccumulator (even in case of exception thrown) + /*! \pre size of signature == MaxSignatureLength() + \return actual signature length + */ + virtual unsigned int Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const; + + //! sign and restart messageAccumulator + /*! \pre size of signature == MaxSignatureLength() + \return actual signature length + */ + virtual unsigned int SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0; + + //! sign a message + /*! \pre size of signature == MaxSignatureLength() + \return actual signature length + */ + virtual unsigned int SignMessage(RandomNumberGenerator &rng, const byte *message, unsigned int messageLen, byte *signature) const; + + //! sign a recoverable message + /*! \pre size of signature == MaxSignatureLength(recoverableMessageLength) + \return actual signature length + */ + virtual unsigned int SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, unsigned int recoverableMessageLength, + const byte *nonrecoverableMessage, unsigned int nonrecoverableMessageLength, byte *signature) const; +}; + +//! interface for public-key signature verifiers +/*! The Recover* functions throw NotImplemented if the signature scheme does not support + message recovery. + The Verify* functions throw InvalidDataFormat if the scheme does support message + recovery and the signature contains a non-empty recoverable message part. The + Recovery* functions should be used in that case. +*/ +class PK_Verifier : virtual public PK_SignatureScheme, public PublicKeyAlgorithm +{ +public: + //! create a new HashTransformation to accumulate the message to be verified + virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0; + + //! input signature into a message accumulator + virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, unsigned int signatureLength) const =0; + + //! check whether messageAccumulator contains a valid signature and message, and delete messageAccumulator (even in case of exception thrown) + virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const; + + //! check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator + virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0; + + //! check whether input signature is a valid signature for input message + virtual bool VerifyMessage(const byte *message, unsigned int messageLen, + const byte *signature, unsigned int signatureLength) const; + + //! recover a message from its signature + /*! \pre size of recoveredMessage == MaxRecoverableLengthFromSignatureLength(signatureLength) + */ + virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const; + + //! recover a message from its signature + /*! \pre size of recoveredMessage == MaxRecoverableLengthFromSignatureLength(signatureLength) + */ + virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0; + + //! recover a message from its signature + /*! \pre size of recoveredMessage == MaxRecoverableLengthFromSignatureLength(signatureLength) + */ + virtual DecodingResult RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, unsigned int nonrecoverableMessageLength, + const byte *signature, unsigned int signatureLength) const; +}; + +//! 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/stepmania/src/crypto51/default.h b/stepmania/src/crypto51/default.h new file mode 100644 index 0000000000..ce3739ddfc --- /dev/null +++ b/stepmania/src/crypto51/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 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::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::Decryption m_cipher; + member_ptr 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 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 m_mac; + HashVerifier *m_hashVerifier; + bool m_throwException; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/des.cpp b/stepmania/src/crypto51/des.cpp new file mode 100644 index 0000000000..b3a58e5059 --- /dev/null +++ b/stepmania/src/crypto51/des.cpp @@ -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 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 diff --git a/stepmania/src/crypto51/des.h b/stepmania/src/crypto51/des.h new file mode 100644 index 0000000000..65b4d33b42 --- /dev/null +++ b/stepmania/src/crypto51/des.h @@ -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";} +}; + +/// DES +/*! 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 + { + 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 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; + typedef BlockCipherTemplate Decryption; +}; + +struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + static const char *StaticAlgorithmName() {return "DES-EDE2";} +}; + +/// DES-EDE2 +class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate + { + 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; + typedef BlockCipherTemplate Decryption; +}; + +struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + static const char *StaticAlgorithmName() {return "DES-EDE3";} +}; + +/// DES-EDE3 +class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate + { + 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; + typedef BlockCipherTemplate Decryption; +}; + +struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + static const char *StaticAlgorithmName() {return "DES-XEX3";} +}; + +/// DES-XEX3, AKA DESX +class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation +{ + class Base : public BlockCipherBaseTemplate + { + public: + void UncheckedSetKey(CipherDir dir, const byte *key, unsigned int length); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_x1, m_x3; + DES::Encryption m_des; + }; + +public: + typedef BlockCipherTemplate Encryption; + typedef BlockCipherTemplate 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/stepmania/src/crypto51/descert.dat b/stepmania/src/crypto51/descert.dat new file mode 100644 index 0000000000..5d3ddc7d38 --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/dessp.cpp b/stepmania/src/crypto51/dessp.cpp new file mode 100644 index 0000000000..1f7a9510c1 --- /dev/null +++ b/stepmania/src/crypto51/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 diff --git a/stepmania/src/crypto51/eprecomp.cpp b/stepmania/src/crypto51/eprecomp.cpp new file mode 100644 index 0000000000..f9878b9043 --- /dev/null +++ b/stepmania/src/crypto51/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 void DL_FixedBasePrecomputationImpl::SetBase(const DL_GroupPrecomputation &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 void DL_FixedBasePrecomputationImpl::Precompute(const DL_GroupPrecomputation &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 void DL_FixedBasePrecomputationImpl::Load(const DL_GroupPrecomputation &group, BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(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 void DL_FixedBasePrecomputationImpl::Save(const DL_GroupPrecomputation &group, BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned(seq, 1); // version + m_exponentBase.DEREncode(seq); + for (unsigned i=0; i void DL_FixedBasePrecomputationImpl::PrepareCascade(const DL_GroupPrecomputation &i_group, std::vector > &eb, const Integer &exponent) const +{ + const AbstractGroup &group = i_group.GetGroup(); + + Integer r, q, e = exponent; + bool fastNegate = group.InversionIsFast() && m_windowSize > 1; + unsigned int i; + + for (i=0; i+1(group.Inverse(m_bases[i]), m_exponentBase - r)); + } + else + eb.push_back(BaseAndExponent(m_bases[i], r)); + } + eb.push_back(BaseAndExponent(m_bases[i], e)); +} + +template T DL_FixedBasePrecomputationImpl::Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const +{ + std::vector > eb; // array of segments of the exponent and precalculated bases + eb.reserve(m_bases.size()); + PrepareCascade(group, eb, exponent); + return group.ConvertOut(GeneralCascadeMultiplication(group.GetGroup(), eb.begin(), eb.end())); +} + +template T + DL_FixedBasePrecomputationImpl::CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, + const DL_FixedBasePrecomputation &i_pc2, const Integer &exponent2) const +{ + std::vector > eb; // array of segments of the exponent and precalculated bases + const DL_FixedBasePrecomputationImpl &pc2 = static_cast &>(i_pc2); + eb.reserve(m_bases.size() + pc2.m_bases.size()); + PrepareCascade(group, eb, exponent); + pc2.PrepareCascade(group, eb, exponent2); + return group.ConvertOut(GeneralCascadeMultiplication(group.GetGroup(), eb.begin(), eb.end())); +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/eprecomp.h b/stepmania/src/crypto51/eprecomp.h new file mode 100644 index 0000000000..ae38c9c7bc --- /dev/null +++ b/stepmania/src/crypto51/eprecomp.h @@ -0,0 +1,69 @@ +#ifndef CRYPTOPP_EPRECOMP_H +#define CRYPTOPP_EPRECOMP_H + +#include "integer.h" +#include "algebra.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +template +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 & GetGroup() const =0; + virtual Element BERDecodeElement(BufferedTransformation &bt) const =0; + virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0; +}; + +template +class DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual bool IsInitialized() const =0; + virtual void SetBase(const DL_GroupPrecomputation &group, const Element &base) =0; + virtual const Element & GetBase(const DL_GroupPrecomputation &group) const =0; + virtual void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) =0; + virtual void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) =0; + virtual void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const =0; + virtual Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const =0; + virtual Element CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const =0; +}; + +template +class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + // DL_FixedBasePrecomputation + bool IsInitialized() const + {return !m_bases.empty();} + void SetBase(const DL_GroupPrecomputation &group, const Element &base); + const Element & GetBase(const DL_GroupPrecomputation &group) const + {return group.NeedConversions() ? m_base : m_bases[0];} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage); + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation); + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const; + Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Element CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const; + +private: + void PrepareCascade(const DL_GroupPrecomputation &group, std::vector > &eb, const Integer &exponent) const; + + Element m_base; + unsigned int m_windowSize; + Integer m_exponentBase; // what base to represent the exponent in + std::vector m_bases; // precalculated bases +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/files.cpp b/stepmania/src/crypto51/files.cpp new file mode 100644 index 0000000000..2b42010ac8 --- /dev/null +++ b/stepmania/src/crypto51/files.cpp @@ -0,0 +1,186 @@ +// 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::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; + + if (begin == 0 && end == 1) + { + int result = m_stream->peek(); + if (result == EOF) // GCC workaround: 2.95.2 doesn't have char_traits::eof() + return 0; + else + { + unsigned int blockedBytes = target.ChannelPut(channel, byte(result), blocking); + begin += 1-blockedBytes; + return blockedBytes; + } + } + + // 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(this)->TransferTo2(target, copyMax, channel, blocking); + begin += copyMax; + if (blockedBytes) + { + const_cast(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 diff --git a/stepmania/src/crypto51/files.h b/stepmania/src/crypto51/files.h new file mode 100644 index 0000000000..2c0c52d9db --- /dev/null +++ b/stepmania/src/crypto51/files.h @@ -0,0 +1,95 @@ +#ifndef CRYPTOPP_FILES_H +#define CRYPTOPP_FILES_H + +#include "cryptlib.h" +#include "filters.h" + +#include +#include + +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 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 +{ +public: + typedef FileStore::Err Err; + typedef FileStore::OpenErr OpenErr; + typedef FileStore::ReadErr ReadErr; + + FileSource(BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment) {} + FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputStreamPointer", &in));} + FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULL, bool binary=true) + : SourceTemplate(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/stepmania/src/crypto51/filters.cpp b/stepmania/src/crypto51/filters.cpp new file mode 100644 index 0000000000..64c2a37dca --- /dev/null +++ b/stepmania/src/crypto51/filters.cpp @@ -0,0 +1,897 @@ +// 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 +#include + +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(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) +{ + if (m_transparent) + { + 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_NO_MESSAGE_END; + } + return 0; +} + +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) +{ + if (m_filter.get()) + m_filter->Attach(new OutputProxy(*this, false)); +} + +bool ProxyFilter::IsolatedFlush(bool hardFlush, bool blocking) +{ + return m_filter.get() ? m_filter->Flush(hardFlush, -1, blocking) : false; +} + +void ProxyFilter::SetFilter(Filter *filter) +{ + m_filter.reset(filter); + if (filter) + { + OutputProxy *proxy; + std::auto_ptr temp(proxy = new OutputProxy(*this, false)); + m_filter->TransferAllTo(*proxy); + m_filter->Attach(temp.release()); + } +} + +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(), 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(); + assert(size != 0); // TODO: handle recoverable signature scheme + 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.SignatureUpfront()) + m_verifier.InputSignature(*m_messageAccumulator, inString, m_verifier.SignatureLength()); + 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.SignatureUpfront()); + } +} + +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_verifier.InputSignature(*m_messageAccumulator, m_signature, m_signature.size()); + m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator); + } + else + { + m_verifier.InputSignature(*m_messageAccumulator, inString, length); + m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator); + 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 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 +{ +public: + MeterFilter(BufferedTransformation *attachment=NULL, bool transparent=true) + : Bufferless(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(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, private FilterPutSpaceHelper +{ +public: + HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULL, bool putMessage=false) + : Bufferless(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 +{ +public: + SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULL, bool putMessage=false) + : Unflushable(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 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 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 +{ +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 +{ +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); + + bool IsolatedFlush(bool hardFlush, bool blocking); + + void SetFilter(Filter *filter); + void NextPutMultiple(const byte *s, unsigned int len); + +protected: + member_ptr m_filter; +}; + +//! 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(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULL) + : SimpleProxyFilter(decryptor.CreateDecryptionFilter(rng), attachment) {} +}; + +//! Append input to a string object +template +class StringSinkTemplate : public Bufferless +{ +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) + { + if (length > 0) + { + typename T::size_type size = m_output->size(); + if (length < size && size + length > m_output->capacity()) + m_output->reserve(2*size); + 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 StringSink; + +//! Copy input to a memory buffer +class ArraySink : public Bufferless +{ +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 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 +{ +public: + Source(BufferedTransformation *attachment) + : InputRejecting(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 SourceTemplate : public Source +{ +public: + SourceTemplate(BufferedTransformation *attachment) + : Source(attachment) {} + SourceTemplate(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 +{ +public: + StringSource(BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment) {} + StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + StringSource(const byte *string, unsigned int length, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + +#ifdef __MWERKS__ // CW60 workaround + StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULL) +#else + template StringSource(const T &string, bool pumpAll, BufferedTransformation *attachment = NULL) +#endif + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} +}; + +//! . +class RandomNumberSource : public SourceTemplate +{ +public: + RandomNumberSource(RandomNumberGenerator &rng, unsigned int length, bool pumpAll, BufferedTransformation *attachment = NULL) + : SourceTemplate(attachment, RandomNumberStore(rng, length)) {if (pumpAll) PumpAll();} +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/fips140.cpp b/stepmania/src/crypto51/fips140.cpp new file mode 100644 index 0000000000..7781956a2e --- /dev/null +++ b/stepmania/src/crypto51/fips140.cpp @@ -0,0 +1,79 @@ +// 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 +} + +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + EncryptionPairwiseConsistencyTest(encryptor, decryptor); +#endif +} + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + SignaturePairwiseConsistencyTest(signer, verifier); +#endif +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/fips140.h b/stepmania/src/crypto51/fips140.h new file mode 100644 index 0000000000..76353ed5b1 --- /dev/null +++ b/stepmania/src/crypto51/fips140.h @@ -0,0 +1,47 @@ +#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); + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/fltrimpl.h b/stepmania/src/crypto51/fltrimpl.h new file mode 100644 index 0000000000..a35e68b0a6 --- /dev/null +++ b/stepmania/src/crypto51/fltrimpl.h @@ -0,0 +1,42 @@ +#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 (messageEnd && 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/stepmania/src/crypto51/hex.cpp b/stepmania/src/crypto51/hex.cpp new file mode 100644 index 0000000000..fb6537948d --- /dev/null +++ b/stepmania/src/crypto51/hex.cpp @@ -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 diff --git a/stepmania/src/crypto51/hex.h b/stepmania/src/crypto51/hex.h new file mode 100644 index 0000000000..85cdaa8ae6 --- /dev/null +++ b/stepmania/src/crypto51/hex.h @@ -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 &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters("Uppercase", uppercase)("GroupSize", outputGroupSize)("Separator", ConstByteArrayParameter(separator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +//! Decode base 16 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 diff --git a/stepmania/src/crypto51/integer.cpp b/stepmania/src/crypto51/integer.cpp new file mode 100644 index 0000000000..e18507fd33 --- /dev/null +++ b/stepmania/src/crypto51/integer.cpp @@ -0,0 +1,4004 @@ +// 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 + +#ifdef SSE2_INTRINSICS_AVAILABLE +#include +#endif + +#include "algebra.cpp" +#include "eprecomp.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +bool FunctionAssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt) +{ + if (valueType != typeid(Integer)) + return false; + *reinterpret_cast(pInteger) = *reinterpret_cast(pInt); + return true; +} + +static int DummyAssignIntToInteger = (AssignIntToInteger = FunctionAssignIntToInteger, 0); + +#ifdef SSE2_INTRINSICS_AVAILABLE +template +AllocatorBase::pointer AlignedAllocator::allocate(size_type n, const void *) +{ + if (n < 4) + return new T[n]; + else + return (T *)_mm_malloc(sizeof(T)*n, 16); + +} + +template +void AlignedAllocator::deallocate(void *p, size_type n) +{ + memset(p, 0, n*sizeof(T)); + if (n < 4) + delete [] p; + else + _mm_free(p); +} + +template class AlignedAllocator; +#endif + +#define MAKE_DWORD(lowWord, highWord) ((dword(highWord)< 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>= 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: +#ifndef __pic__ // -fpic uses up a register, leaving too few for the asm code + 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); +#endif + 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 + +#ifndef __pic__ +__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; +} +#endif // __pic__ + +// 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 +void DoRecursiveMultiply(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL); + +template +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

(R, T, A, B, N, NULL); // VC60 workaround: needs this NULL +} + +template +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

(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

(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + P::Subtract(R0, A0, A1, N2); + P::Subtract(R1, B1, B0, N2); + RecursiveMultiply

(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply

(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply

(R0, T2, A0, B0, N2); + RecursiveMultiply

(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 +void DoRecursiveSquare(word *R, word *T, const word *A, unsigned int N, const P *dummy=NULL); + +template +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

(R, T, A, N, NULL); // VC60 workaround: needs this NULL +} + +template +void DoRecursiveSquare(word *R, word *T, const word *A, unsigned int N, const P *dummy) +{ + const unsigned int N2 = N/2; + + RecursiveSquare

(R0, T2, A0, N2); + RecursiveSquare

(R2, T2, A1, N2); + RecursiveMultiply

(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 +void DoRecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, unsigned int N, const P *dummy=NULL); + +template +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

(R, T, A, B, N, NULL); +} + +template +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

(R, T, A0, B0, N2); + RecursiveMultiplyBottom

(T0, T1, A1, B0, N2); + P::Add(R1, R1, T0, N2); + RecursiveMultiplyBottom

(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 +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

(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

(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + P::Subtract(R0, A0, A1, N2); + P::Subtract(R1, B1, B0, N2); + RecursiveMultiply

(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply

(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply

(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(R, T, A, B, N); + else +#endif + RecursiveMultiply(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(R, T, A, N); + else +#endif + RecursiveSquare(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(R, T, A, B, N); + else +#endif + RecursiveMultiplyBottom(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(R, T, L, A, B, N); + else +#endif + RecursiveMultiplyTop(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=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]= 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(value)); +} + +Integer::Integer(Sign s, word high, word low) + : reg(2), sign(s) +{ + reg[0] = low; + reg[1] = high; +} + +bool Integer::IsConvertableToLong() const +{ + if (ByteCount() > sizeof(long)) + return false; + + unsigned long value = reg[0]; + value += SafeLeftShift(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(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 +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::length() not defined in GCC 3.2 + unsigned int length; + for (length = 0; str[length] != 0; length++) {} +#else + unsigned int length = std::char_traits::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= '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 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 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::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 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 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 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().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 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::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::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; + +NAMESPACE_END diff --git a/stepmania/src/crypto51/integer.h b/stepmania/src/crypto51/integer.h new file mode 100644 index 0000000000..fcf3ebefff --- /dev/null +++ b/stepmania/src/crypto51/integer.h @@ -0,0 +1,439 @@ +#ifndef CRYPTOPP_INTEGER_H +#define CRYPTOPP_INTEGER_H + +/** \file */ + +#include "cryptlib.h" +#include "secblock.h" + +#include +#include + +#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 +# if defined(_mm_free) +# define SSE2_INTRINSICS_AVAILABLE +# endif +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef SSE2_INTRINSICS_AVAILABLE + template + class AlignedAllocator : public AllocatorBase + { + 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 > 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 Sign {POSITIVE=0, NEGATIVE=1}; + + //! + 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 two words + Integer(Sign s, word highWord, word lowWord); + + //! 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); + + 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/stepmania/src/crypto51/iterhash.cpp b/stepmania/src/crypto51/iterhash.cpp new file mode 100644 index 0000000000..00cc12bcd4 --- /dev/null +++ b/stepmania/src/crypto51/iterhash.cpp @@ -0,0 +1,122 @@ +// 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 +IteratedHashBase::IteratedHashBase(unsigned int blockSize, unsigned int digestSize) + : m_data(blockSize/sizeof(T)), m_digest(digestSize/sizeof(T)) + , m_countHi(0), m_countLo(0) +{ +} + +template void IteratedHashBase::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 = ModPowerOf2(tmp, blockSize); + + if (num != 0) // process left over data + { + 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; + } + } + + // now process the input data in blocks of blockSize bytes and save the leftovers to m_data + if (len >= blockSize) + { + if (input == (byte *)m_data.begin()) + { + assert(len == blockSize); + HashBlock(m_data); + return; + } + else if (IsAligned(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 byte * IteratedHashBase::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 unsigned int IteratedHashBase::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 void IteratedHashBase::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 void IteratedHashBase::Restart() +{ + m_countLo = m_countHi = 0; + Init(); +} + +#ifdef WORD64_AVAILABLE +template class IteratedHashBase; +template class IteratedHashBase; +#endif + +template class IteratedHashBase; +template class IteratedHashBase; + +NAMESPACE_END diff --git a/stepmania/src/crypto51/iterhash.h b/stepmania/src/crypto51/iterhash.h new file mode 100644 index 0000000000..7945cec6b3 --- /dev/null +++ b/stepmania/src/crypto51/iterhash.h @@ -0,0 +1,121 @@ +#ifndef CRYPTOPP_ITERHASH_H +#define CRYPTOPP_ITERHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +template +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();} + unsigned int OptimalDataAlignment() const {return sizeof(T);} + 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 m_data; // Data buffer + SecBlock m_digest; // Message digest + +private: + T m_countLo, m_countHi; +}; + +//! . +template +class IteratedHashBase2 : public IteratedHashBase +{ +public: + IteratedHashBase2(unsigned int blockSize, unsigned int digestSize) + : IteratedHashBase(blockSize, digestSize) {} + + typedef B ByteOrderClass; + typedef typename IteratedHashBase::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 IteratedHash : public IteratedHashBase2 +{ +public: + enum {BLOCKSIZE = S}; + +private: + CRYPTOPP_COMPILE_ASSERT((BLOCKSIZE & (BLOCKSIZE - 1)) == 0); // blockSize is a power of 2 + +protected: + IteratedHash(unsigned int digestSize) : IteratedHashBase2(BLOCKSIZE, digestSize) {} + unsigned int BlockSize() const {return BLOCKSIZE;} +}; + +template +class IteratedHashWithStaticTransform : public IteratedHash +{ +protected: + IteratedHashWithStaticTransform(unsigned int digestSize) : IteratedHash(digestSize) {} + void vTransform(const T *data) {M::Transform(m_digest, data);} + std::string AlgorithmName() const {return M::StaticAlgorithmName();} +}; + +// ************************************************************* + +template void IteratedHashBase2::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 void IteratedHashBase2::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/stepmania/src/crypto51/md5.cpp b/stepmania/src/crypto51/md5.cpp new file mode 100644 index 0000000000..7bd4f38530 --- /dev/null +++ b/stepmania/src/crypto51/md5.cpp @@ -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 diff --git a/stepmania/src/crypto51/md5.h b/stepmania/src/crypto51/md5.h new file mode 100644 index 0000000000..2e8850f9ce --- /dev/null +++ b/stepmania/src/crypto51/md5.h @@ -0,0 +1,24 @@ +#ifndef CRYPTOPP_MD5_H +#define CRYPTOPP_MD5_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! MD5 +/*! 128 Bit Hash */ +class MD5 : public IteratedHashWithStaticTransform +{ +public: + enum {DIGESTSIZE = 16}; + MD5() : IteratedHashWithStaticTransform(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/stepmania/src/crypto51/mdc.h b/stepmania/src/crypto51/mdc.h new file mode 100644 index 0000000000..8c76aafd21 --- /dev/null +++ b/stepmania/src/crypto51/mdc.h @@ -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 +struct MDC_Info : public FixedBlockSize, public FixedKeyLength +{ + static std::string StaticAlgorithmName() {return std::string("MDC/")+T::StaticAlgorithmName();} +}; + +//! MDC +/*! a construction by Peter Gutmann to turn an iterated hash function into a PRF */ +template +class MDC : public MDC_Info +{ + class Enc : public BlockCipherBaseTemplate > + { + 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::KEYLENGTH, AllocatorWithCleanup > m_key; + mutable FixedSizeSecBlock::BLOCKSIZE, AllocatorWithCleanup > m_buffer; + }; + +public: + //! use BlockCipher interface + typedef BlockCipherTemplate Encryption; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/misc.cpp b/stepmania/src/crypto51/misc.cpp new file mode 100644 index 0000000000..c193b3f3ed --- /dev/null +++ b/stepmania/src/crypto51/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; i0; 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 diff --git a/stepmania/src/crypto51/misc.h b/stepmania/src/crypto51/misc.h new file mode 100644 index 0000000000..1e341e2594 --- /dev/null +++ b/stepmania/src/crypto51/misc.h @@ -0,0 +1,688 @@ +#ifndef CRYPTOPP_MISC_H +#define CRYPTOPP_MISC_H + +#include "config.h" +#include "cryptlib.h" +#include +#include // CodeWarrior doesn't have memory.h +#include +#include + +#ifdef INTEL_INTRINSICS +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** compile-time assertion *************** + +template +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 TwoBases : public BASE1, public BASE2 +{ +}; + +template +class ThreeBases : public BASE1, public BASE2, public BASE3 +{ +}; + +template +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 inline const _Tp& STDMIN(const _Tp& __a, const _Tp& __b) +{ + return __b < __a ? __b : __a; +} + +template 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 +inline bool IsPowerOf2(T n) +{ + return n > 0 && (n & (n-1)) == 0; +} + +template +inline T2 ModPowerOf2(T1 a, T2 b) +{ + assert(IsPowerOf2(b)); + return T2(a) & (b-1); +} + +template +inline T RoundDownToMultipleOf(T n, T m) +{ + return n - (IsPowerOf2(m) ? ModPowerOf2(n, m) : (n%m)); +} + +template +inline T RoundUpToMultipleOf(T n, T m) +{ + return RoundDownToMultipleOf(n+m-1, m); +} + +template +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 +inline bool IsAligned(const void *p, T *dummy=NULL) // VC60 workaround +{ + return IsAlignedOn(p, GetAlignment()); +} + +#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 // can't use 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 +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 +inline CipherDir GetCipherDir(const T &obj) +{ + return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; +} + +// ************** rotate functions *************** + +template inline T rotlFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x<>(sizeof(T)*8-y)); +} + +template inline T rotrFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +template inline T rotlVariable(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x<>(sizeof(T)*8-y)); +} + +template inline T rotrVariable(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +template inline T rotlMod(T x, unsigned int y) +{ + y %= sizeof(T)*8; + return (x<>(sizeof(T)*8-y)); +} + +template 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 x, unsigned int y) +{ + assert(y < 32); + return y ? _lrotl(x, y) : x; +} + +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? _lrotr(x, y) : x; +} + +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + assert(y < 32); + return _lrotl(x, y); +} + +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + assert(y < 32); + return _lrotr(x, y); +} + +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + return _lrotl(x, y); +} + +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + return _lrotr(x, y); +} + +#endif // #ifdef INTEL_INTRINSICS + +#ifdef PPC_INTRINSICS + +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? __rlwinm(x,y,0,31) : x; +} + +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + assert(y < 32); + return y ? __rlwinm(x,32-y,0,31) : x; +} + +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + assert(y < 32); + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + assert(y < 32); + return (__rlwnm(x,32-y,0,31)); +} + +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,32-y,0,31)); +} + +#endif // #ifdef PPC_INTRINSICS + +// ************** endian reversal *************** + +template +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 +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 +inline T ConditionalByteReverse(ByteOrder order, T value) +{ + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +template +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 +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 +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 +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 +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + if (assumeAligned) + { + assert(IsAligned(block)); + return ConditionalByteReverse(order, *reinterpret_cast(block)); + } + else + return UnalignedGetWord(order, block); +} + +template +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) +{ + result = GetWord(assumeAligned, order, block); +} + +template +inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULL) +{ + if (assumeAligned) + { + assert(IsAligned(block)); + if (xorBlock) + *reinterpret_cast(block) = ConditionalByteReverse(order, value) ^ *reinterpret_cast(xorBlock); + else + *reinterpret_cast(block) = ConditionalByteReverse(order, value); + } + else + UnalignedPutWord(order, block, value, xorBlock); +} + +template +class GetBlock +{ +public: + GetBlock(const void *block) + : m_block((const byte *)block) {} + + template + inline GetBlock & operator()(U &x) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +template +class PutBlock +{ +public: + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + template + inline PutBlock & 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 +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between expression-statements and declarations + static inline GetBlock Get(const void *block) {return GetBlock(block);} + typedef PutBlock Put; +}; + +template +std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) +{ + if (!NativeByteOrderIs(order)) + value = ByteReverse(value); + + return std::string((char *)&value, sizeof(value)); +} + +template +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 struct SafeShifter; + +template<> struct SafeShifter +{ + template + static inline T RightShift(T value, unsigned int bits) + { + return 0; + } + + template + static inline T LeftShift(T value, unsigned int bits) + { + return 0; + } +}; + +template<> struct SafeShifter +{ + template + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + template + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +template +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +template +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + +NAMESPACE_END + +#endif // MISC_H diff --git a/stepmania/src/crypto51/modarith.h b/stepmania/src/crypto51/modarith.h new file mode 100644 index 0000000000..b97b1060e7 --- /dev/null +++ b/stepmania/src/crypto51/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 +{ +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::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing::SimultaneousExponentiate(results, base, exponents, exponentsCount);} + +private: + Integer u; + mutable SecAlignedWordBlock workspace; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/modes.cpp b/stepmania/src/crypto51/modes.cpp new file mode 100644 index 0000000000..70c23234f2 --- /dev/null +++ b/stepmania/src/crypto51/modes.cpp @@ -0,0 +1,266 @@ +// 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::Encryption m0; + CFB_Mode::Decryption m1; + OFB_Mode::Encryption m2; + CTR_Mode::Encryption m3; + ECB_Mode::Encryption m4; + CBC_Mode::Encryption m5; +} + +// explicit instantiations for Darwin gcc-932.1 +template class CFB_CipherTemplate >; +template class CFB_EncryptionTemplate<>; +template class CFB_DecryptionTemplate<>; +template class AdditiveCipherTemplate<>; +template class CFB_CipherTemplate >; +template class CFB_EncryptionTemplate >; +template class CFB_DecryptionTemplate >; +template class AdditiveCipherTemplate >; +template class AdditiveCipherTemplate >; + +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; i--) + { + unsigned int sum = m_register[i] + byte(iterationCount) + carry; + m_counterArray[i] = (byte) sum; + carry = sum >> 8; + iterationCount >>= 8; + } +} + +static inline void IncrementCounterByOne(byte *inout, unsigned int s) +{ + for (int i=s-1, carry=1; i>=0 && carry; i--) + carry = !++inout[i]; +} + +static inline void IncrementCounterByOne(byte *output, const byte *input, unsigned int s) +{ + for (int i=s-1, carry=1; i>=0; i--) + carry = !(output[i] = input[i]+carry) && carry; +} + +inline void CTR_ModePolicy::ProcessMultipleBlocks(byte *output, const byte *input, unsigned int n) +{ + unsigned int s = BlockSize(), j = 0; + for (unsigned int i=1; iProcessAndXorMultipleBlocks(m_counterArray, input, output, n); + IncrementCounterByOne(m_counterArray, m_counterArray + s*(n-1), s); +} + +void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + unsigned int maxBlocks = m_cipher->OptimalNumberOfParallelBlocks(); + if (maxBlocks == 1) + { + unsigned int sizeIncrement = BlockSize(); + while (iterationCount) + { + m_cipher->ProcessAndXorBlock(m_counterArray, input, output); + IncrementCounterByOne(m_counterArray, sizeIncrement); + output += sizeIncrement; + input += sizeIncrement; + iterationCount -= 1; + } + } + else + { + unsigned int sizeIncrement = maxBlocks * 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 inputAlignmentOk = !RequireAlignedInput() || IsAlignedOn(inString, alignment); + + if (IsAlignedOn(outString, alignment)) + { + if (inputAlignmentOk) + ProcessBlocks(outString, inString, length / s); + else + { + memcpy(outString, inString, length); + ProcessBlocks(outString, outString, length / s); + } + } + else + { + while (length) + { + if (inputAlignmentOk) + ProcessBlocks(m_buffer, inString, 1); + else + { + memcpy(m_buffer, inString, s); + ProcessBlocks(m_buffer, m_buffer, 1); + } + memcpy(outString, m_buffer, s); + inString += s; + outString += 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 diff --git a/stepmania/src/crypto51/modes.h b/stepmania/src/crypto51/modes.h new file mode 100644 index 0000000000..46e8dd26d0 --- /dev/null +++ b/stepmania/src/crypto51/modes.h @@ -0,0 +1,370 @@ +#ifndef CRYPTOPP_MODES_H +#define CRYPTOPP_MODES_H + +/*! \file +*/ + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "strciphr.h" +#include "argnames.h" +#include "algparam.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 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 +{ +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 +{ + 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 +{ + 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;} + + inline void ProcessMultipleBlocks(byte *output, const byte *input, unsigned int n); + + 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;} + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length); + +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); + } + + 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 +{ +public: + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length); +}; + +//! . +template +class CipherModeFinalTemplate_CipherHolder : public ObjectHolder, 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 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 +struct CFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > Decryption; +}; + +//! CFB mode, external cipher +struct CFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > Decryption; +}; + +//! OFB mode +template +struct OFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +//! OFB mode, external cipher +struct OFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +//! CTR mode +template +struct CTR_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +//! CTR mode, external cipher +struct CTR_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +//! ECB mode +template +struct ECB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +//! ECB mode, external cipher +struct ECB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef Encryption Decryption; +}; + +//! CBC mode +template +struct CBC_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +//! CBC mode, external cipher +struct CBC_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +//! CBC mode with ciphertext stealing +template +struct CBC_CTS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +//! CBC mode with ciphertext stealing, external cipher +struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher 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 CTR_Mode_ExternalCipher::Encryption CounterMode; +#endif + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/mqueue.cpp b/stepmania/src/crypto51/mqueue.cpp new file mode 100644 index 0000000000..2bac976c8f --- /dev/null +++ b/stepmania/src/crypto51/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::const_iterator it = m_lengths.begin(); + unsigned int i; + for (i=0; i 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/stepmania/src/crypto51/mqueue.h b/stepmania/src/crypto51/mqueue.h new file mode 100644 index 0000000000..edc701a75e --- /dev/null +++ b/stepmania/src/crypto51/mqueue.h @@ -0,0 +1,98 @@ +#ifndef CRYPTOPP_MQUEUE_H +#define CRYPTOPP_MQUEUE_H + +#include "queue.h" +#include "filters.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +//! Message Queue +class MessageQueue : public AutoSignaling +{ +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 m_lengths, m_messageCounts; +}; + + +//! A filter that checks messages on two channels for equality +class EqualityComparisonFilter : public Unflushable > +{ +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 >(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 diff --git a/stepmania/src/crypto51/nbtheory.cpp b/stepmania/src/crypto51/nbtheory.cpp new file mode 100644 index 0000000000..852beb5712 --- /dev/null +++ b/stepmania/src/crypto51/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 +#include + +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= bound); + + unsigned int i; + for (i = 0; primeTable[i]3 && b>1 && b3 && b>1 && b>a; + + Integer z = a_exp_b_mod_c(b, m, n); + if (z==1 || z==nminus1) + return true; + for (unsigned j=1; j3); + + Integer b; + for (unsigned int i=0; i2); + + 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= 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, 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 &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 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 &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>= 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>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/stepmania/src/crypto51/nbtheory.h b/stepmania/src/crypto51/nbtheory.h new file mode 100644 index 0000000000..685dc41a11 --- /dev/null +++ b/stepmania/src/crypto51/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, 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/stepmania/src/crypto51/oaep.cpp b/stepmania/src/crypto51/oaep.cpp new file mode 100644 index 0000000000..8913631bc5 --- /dev/null +++ b/stepmania/src/crypto51/oaep.cpp @@ -0,0 +1,107 @@ +// oaep.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "oaep.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +// ******************************************************** + +ANONYMOUS_NAMESPACE_BEGIN + template + struct PHashComputation + { + PHashComputation() {H().CalculateDigest(pHash, P, PLen);} + byte pHash[H::DIGESTSIZE]; + }; + + template + const byte *PHash() + { + static PHashComputation pHash; + return pHash.pHash; + } +NAMESPACE_END + +template +unsigned int OAEP::MaxUnpaddedLength(unsigned int paddedLength) const +{ + return paddedLength/8 > 1+2*H::DIGESTSIZE ? paddedLength/8-1-2*H::DIGESTSIZE : 0; +} + +template +void OAEP::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(), hLen); + memset(maskedDB+hLen, 0, dbLen-hLen-inputLength-1); + maskedDB[dbLen-inputLength-1] = 0x01; + memcpy(maskedDB+dbLen-inputLength, input, inputLength); + + rng.GenerateBlock(maskedSeed, seedLen); + H h; + MGF mgf; + mgf.GenerateAndMask(h, maskedDB, dbLen, maskedSeed, seedLen); + mgf.GenerateAndMask(h, maskedSeed, seedLen, maskedDB, dbLen); +} + +template +DecodingResult OAEP::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; + + H h; + MGF mgf; + mgf.GenerateAndMask(h, maskedSeed, seedLen, maskedDB, dbLen); + mgf.GenerateAndMask(h, 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(), 0)) != M) || invalid; + invalid = (memcmp(maskedDB, PHash(), hLen) != 0) || invalid; + + if (invalid) + return DecodingResult(); + + M++; + memcpy(output, M, maskedDB+dbLen-M); + return DecodingResult(maskedDB+dbLen-M); +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/oaep.h b/stepmania/src/crypto51/oaep.h new file mode 100644 index 0000000000..c242698a2b --- /dev/null +++ b/stepmania/src/crypto51/oaep.h @@ -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 + +/// EME-OAEP, for use with RSAES +template +class OAEP : public PK_EncryptionMessageEncodingMethod, public EncryptionStandard +{ +public: + static std::string StaticAlgorithmName() {return std::string("OAEP-") + MGF::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + typedef OAEP EncryptionMessageEncodingMethod; + + 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 diff --git a/stepmania/src/crypto51/oids.h b/stepmania/src/crypto51/oids.h new file mode 100644 index 0000000000..fe00a9cb15 --- /dev/null +++ b/stepmania/src/crypto51/oids.h @@ -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/stepmania/src/crypto51/osrng.cpp b/stepmania/src/crypto51/osrng.cpp new file mode 100644 index 0000000000..57f92e7709 --- /dev/null +++ b/stepmania/src/crypto51/osrng.cpp @@ -0,0 +1,172 @@ +// 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 +#include +#endif + +#ifdef CRYPTOPP_UNIX_AVAILABLE +#include +#include +#include +#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 diff --git a/stepmania/src/crypto51/osrng.h b/stepmania/src/crypto51/osrng.h new file mode 100644 index 0000000000..902b2eeecf --- /dev/null +++ b/stepmania/src/crypto51/osrng.h @@ -0,0 +1,162 @@ +#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 +#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 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); + // exposed for testing + void Reseed(const byte *key, unsigned int keylength, const byte *seed, unsigned long timeVector); + + byte GenerateByte(); + +private: + member_ptr m_rng; + SecByteBlock m_lastBlock; + bool m_isDifferent; + unsigned int m_counter; +}; + +template +void AutoSeededX917RNG::Reseed(const byte *key, unsigned int keylength, const byte *seed, unsigned long timeVector) +{ + m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector)); + + // for FIPS 140-2 + m_lastBlock.resize(16); + m_rng->GenerateBlock(m_lastBlock, m_lastBlock.size()); + m_counter = 0; + m_isDifferent = false; +} + +template +void AutoSeededX917RNG::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); + + Reseed(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH, seed, 0); +} + +template +byte AutoSeededX917RNG::GenerateByte() +{ + byte b = m_rng->GenerateByte(); + + // for FIPS 140-2 + 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/stepmania/src/crypto51/pch.h b/stepmania/src/crypto51/pch.h new file mode 100644 index 0000000000..7391e5ed7f --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/pkcspad.cpp b/stepmania/src/crypto51/pkcspad.cpp new file mode 100644 index 0000000000..e04ac9ddee --- /dev/null +++ b/stepmania/src/crypto51/pkcspad.cpp @@ -0,0 +1,126 @@ +// pkcspad.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pkcspad.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::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::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::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::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x29,0x30,0x0D,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0C,0x02,0x05,0x00,0x04,0x18}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::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::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::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::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::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::length = sizeof(PKCS_DigestDecoration::decoration); + +unsigned int PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(unsigned int paddedLength) const +{ + return SaturatingSubtract(paddedLength/8, 10U); +} + +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 separator + unsigned i=1; + while (i maxOutputLen) || invalid; + + if (invalid) + return DecodingResult(); + + memcpy (output, pkcsBlock+i, outputLen); + return DecodingResult(outputLen); +} + +// ******************************************************** + +void PKCS1v15_SignatureMessageEncodingMethod::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const +{ + unsigned int digestSize = hash.DigestSize(); + if (digestSize + hashIdentifier.second + 10 > representativeBitLength/8) + throw PK_Signer::KeyTooShort(); + + unsigned int pkcsBlockLen = representativeBitLength; + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + representative[0] = 0; + representative++; + } + pkcsBlockLen /= 8; + + representative[0] = 1; // block type 1 + + byte *pPadding = representative + 1; + byte *pDigest = representative + pkcsBlockLen - digestSize; + byte *pHashId = pDigest - hashIdentifier.second; + byte *pSeparator = pHashId - 1; + + // pad with 0xff + memset(pPadding, 0xff, pSeparator-pPadding); + *pSeparator = 0; + memcpy(pHashId, hashIdentifier.first, hashIdentifier.second); + hash.Final(pDigest); +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/pkcspad.h b/stepmania/src/crypto51/pkcspad.h new file mode 100644 index 0000000000..2e14a5e00d --- /dev/null +++ b/stepmania/src/crypto51/pkcspad.h @@ -0,0 +1,70 @@ +#ifndef CRYPTOPP_PKCSPAD_H +#define CRYPTOPP_PKCSPAD_H + +#include "cryptlib.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +//! EME-PKCS1-v1_5 +class PKCS_EncryptionPaddingScheme : public PK_EncryptionMessageEncodingMethod +{ +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; +}; + +template struct PKCS_DigestDecoration +{ + static const byte decoration[]; + static const unsigned int length; +}; + +//! EMSA-PKCS1-v1_5 +class PKCS1v15_SignatureMessageEncodingMethod : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + static const char * StaticAlgorithmName() {return "EMSA-PKCS1-v1_5";} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; + + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(PKCS_DigestDecoration::decoration, PKCS_DigestDecoration::length); + } + }; + }; +}; + +//! PKCS #1 version 1.5, for use with RSAES and RSASS +/*! The following hash functions are supported for signature: SHA, MD2, MD5, RIPEMD160, SHA256, SHA384, SHA512. */ +struct PKCS1v15 : public SignatureStandard, public EncryptionStandard +{ + typedef PKCS_EncryptionPaddingScheme EncryptionMessageEncodingMethod; + typedef PKCS1v15_SignatureMessageEncodingMethod SignatureMessageEncodingMethod; +}; + +// 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 Tiger; +class SHA256; +class SHA384; +class SHA512; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/polynomi.cpp b/stepmania/src/crypto51/polynomi.cpp new file mode 100644 index 0000000000..5607cafb0d --- /dev/null +++ b/stepmania/src/crypto51/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 +#include + +NAMESPACE_BEGIN(CryptoPP) + +template +void PolynomialOver::Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) +{ + m_coefficients.resize(parameter.m_coefficientCount); + for (unsigned int i=0; i +void PolynomialOver::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 +unsigned int PolynomialOver::CoefficientCount(const Ring &ring) const +{ + unsigned count = m_coefficients.size(); + while (count && ring.Equal(m_coefficients[count-1], ring.Identity())) + count--; + const_cast &>(m_coefficients).resize(count); + return count; +} + +template +typename PolynomialOver::CoefficientType PolynomialOver::GetCoefficient(unsigned int i, const Ring &ring) const +{ + return (i < m_coefficients.size()) ? m_coefficients[i] : ring.Identity(); +} + +template +PolynomialOver& PolynomialOver::operator=(const PolynomialOver& t) +{ + if (this != &t) + { + m_coefficients.resize(t.m_coefficients.size()); + for (unsigned int i=0; i +PolynomialOver& PolynomialOver::Accumulate(const PolynomialOver& 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 +PolynomialOver& PolynomialOver::Reduce(const PolynomialOver& 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 +typename PolynomialOver::CoefficientType PolynomialOver::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 +PolynomialOver& PolynomialOver::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 +PolynomialOver& PolynomialOver::ShiftRight(unsigned int n, const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + if (count > n) + { + for (unsigned int i=0; i +void PolynomialOver::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 +void PolynomialOver::Negate(const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + for (unsigned int i=0; i +void PolynomialOver::swap(PolynomialOver &t) +{ + m_coefficients.swap(t.m_coefficients); +} + +template +bool PolynomialOver::Equals(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + + if (count != t.CoefficientCount(ring)) + return false; + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::Plus(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver result(ring, count); + + for (i=0; i result(ring, tCount); + + for (i=0; i +PolynomialOver PolynomialOver::Minus(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver result(ring, count); + + for (i=0; i result(ring, tCount); + + for (i=0; i +PolynomialOver PolynomialOver::Inverse(const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + PolynomialOver result(ring, count); + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::Times(const PolynomialOver& t, const Ring &ring) const +{ + if (IsZero(ring) || t.IsZero(ring)) + return PolynomialOver(); + + unsigned int count1 = CoefficientCount(ring), count2 = t.CoefficientCount(ring); + PolynomialOver result(ring, count1 + count2 - 1); + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::DividedBy(const PolynomialOver& t, const Ring &ring) const +{ + PolynomialOver remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return quotient; +} + +template +PolynomialOver PolynomialOver::Modulo(const PolynomialOver& t, const Ring &ring) const +{ + PolynomialOver remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return remainder; +} + +template +PolynomialOver PolynomialOver::MultiplicativeInverse(const Ring &ring) const +{ + return Degree(ring)==0 ? ring.MultiplicativeInverse(m_coefficients[0]) : ring.Identity(); +} + +template +bool PolynomialOver::IsUnit(const Ring &ring) const +{ + return Degree(ring)==0 && ring.IsUnit(m_coefficients[0]); +} + +template +std::istream& PolynomialOver::Input(std::istream &in, const Ring &ring) +{ + char c; + unsigned int length = 0; + SecBlock 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(str, ring); + + return in; +} + +template +std::ostream& PolynomialOver::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 +void PolynomialOver::Divide(PolynomialOver &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &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 +void RingOfPolynomialsOver::CalculateAlpha(std::vector &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + for (unsigned int j=0; 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 +typename RingOfPolynomialsOver::Element RingOfPolynomialsOver::Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + assert(n > 0); + + std::vector alpha(n); + CalculateAlpha(alpha, x, y, n); + + std::vector 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(coefficients.begin(), coefficients.end()); +} + +template +typename RingOfPolynomialsOver::CoefficientType RingOfPolynomialsOver::InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + assert(n > 0); + + std::vector 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 +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n) +{ + for (unsigned int i=0; i +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n) +{ + assert(n > 0); + + std::vector a(2*n-1); + unsigned int i; + + for (i=0; i1; i--) + a[i-1] = ring.Multiply(a[2*i], a[2*i-1]); + + a[0] = ring.MultiplicativeIdentity(); + + for (i=0; i +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n) +{ + Element result = ring.Identity(); + for (unsigned int i=0; i +const PolynomialOverFixedRing &PolynomialOverFixedRing::Zero() +{ + static const PolynomialOverFixedRing zero; + return zero; +} + +template +const PolynomialOverFixedRing &PolynomialOverFixedRing::One() +{ + static const PolynomialOverFixedRing one = fixedRing.MultiplicativeIdentity(); + return one; +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/polynomi.h b/stepmania/src/crypto51/polynomi.h new file mode 100644 index 0000000000..ce4295ebf0 --- /dev/null +++ b/stepmania/src/crypto51/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 +#include + +NAMESPACE_BEGIN(CryptoPP) + +//! represents single-variable polynomials over arbitrary rings +/*! \nosubgrouping */ +template class PolynomialOver +{ +public: + //! \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + //! division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialOver: 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; + }; + + 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 &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 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 + 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& operator=(const PolynomialOver& 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 &t); + //@} + + + //! \name BASIC ARITHMETIC ON POLYNOMIALS + //@{ + bool Equals(const PolynomialOver &t, const Ring &ring) const; + bool IsZero(const Ring &ring) const {return CoefficientCount(ring)==0;} + + PolynomialOver Plus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Minus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Inverse(const Ring &ring) const; + + PolynomialOver Times(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver DividedBy(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Modulo(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver MultiplicativeInverse(const Ring &ring) const; + bool IsUnit(const Ring &ring) const; + + PolynomialOver& Accumulate(const PolynomialOver& t, const Ring &ring); + PolynomialOver& Reduce(const PolynomialOver& t, const Ring &ring); + + //! + PolynomialOver Doubled(const Ring &ring) const {return Plus(*this, ring);} + //! + PolynomialOver Squared(const Ring &ring) const {return Times(*this, ring);} + + CoefficientType EvaluateAt(const CoefficientType &x, const Ring &ring) const; + + PolynomialOver& ShiftLeft(unsigned int n, const Ring &ring); + PolynomialOver& 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 &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &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 m_coefficients; +}; + +//! Polynomials over a fixed ring +/*! Having a fixed ring allows overloaded operators */ +template class PolynomialOverFixedRing : private PolynomialOver +{ + typedef PolynomialOver B; + typedef PolynomialOverFixedRing ThisType; + +public: + typedef T Ring; + typedef typename T::Element CoefficientType; + typedef typename B::DivideByZero DivideByZero; + typedef typename 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 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 RingOfPolynomialsOver : public AbstractEuclideanDomain > +{ +public: + typedef T CoefficientRing; + typedef PolynomialOver Element; + typedef typename Element::CoefficientType CoefficientType; + typedef typename 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: 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 &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + CoefficientRing m_ring; +}; + +template +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n); +template +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n); +template +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n); + +//! +template +inline bool operator==(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Equals(b, fixedRing);} +//! +template +inline bool operator!=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return !(a==b);} + +//! +template +inline bool operator> (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() > b.Degree();} +//! +template +inline bool operator>=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() >= b.Degree();} +//! +template +inline bool operator< (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() < b.Degree();} +//! +template +inline bool operator<=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() <= b.Degree();} + +//! +template +inline CryptoPP::PolynomialOverFixedRing operator+(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Plus(b, fixedRing));} +//! +template +inline CryptoPP::PolynomialOverFixedRing operator-(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Minus(b, fixedRing));} +//! +template +inline CryptoPP::PolynomialOverFixedRing operator*(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Times(b, fixedRing));} +//! +template +inline CryptoPP::PolynomialOverFixedRing operator/(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.DividedBy(b, fixedRing));} +//! +template +inline CryptoPP::PolynomialOverFixedRing operator%(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Modulo(b, fixedRing));} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template inline void swap(CryptoPP::PolynomialOver &a, CryptoPP::PolynomialOver &b) +{ + a.swap(b); +} +template inline void swap(CryptoPP::PolynomialOverFixedRing &a, CryptoPP::PolynomialOverFixedRing &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/pssr.cpp b/stepmania/src/crypto51/pssr.cpp new file mode 100644 index 0000000000..5dc959aa1c --- /dev/null +++ b/stepmania/src/crypto51/pssr.cpp @@ -0,0 +1,126 @@ +// pssr.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pssr.h" + +NAMESPACE_BEGIN(CryptoPP) + +template<> const byte EMSA2HashId::id = 0x33; +template<> const byte EMSA2HashId::id = 0x31; + +unsigned int PSSR_MEM_Base::MaxRecoverableLength(unsigned int representativeBitLength, unsigned int hashIdentifierLength, unsigned int digestLength) const +{ + if (AllowRecovery()) + { + unsigned int saltLen = SaltLen(digestLength); + unsigned int minPadLen = MinPadLen(digestLength); + return SaturatingSubtract(representativeBitLength, 8*(minPadLen + saltLen + digestLength + hashIdentifierLength) + 9) / 8; + } + return 0; +} + +bool PSSR_MEM_Base::IsProbabilistic() const +{ + return SaltLen(1) > 0; +} + +bool PSSR_MEM_Base::AllowNonrecoverablePart() const +{ + return true; +} + +bool PSSR_MEM_Base::RecoverablePartFirst() const +{ + return false; +} + +void PSSR_MEM_Base::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const +{ + const unsigned int u = hashIdentifier.second + 1; + const unsigned int representativeByteLength = BitsToBytes(representativeBitLength); + const unsigned int digestSize = hash.DigestSize(); + const unsigned int saltSize = SaltLen(digestSize); + byte *const h = representative + representativeByteLength - u - digestSize; + + SecByteBlock digest(digestSize), salt(saltSize); + hash.Final(digest); + rng.GenerateBlock(salt, saltSize); + + // compute H = hash of M' + byte c[8]; + UnalignedPutWord(BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength)); + UnalignedPutWord(BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3)); + hash.Update(c, 8); + hash.Update(recoverableMessage, recoverableMessageLength); + hash.Update(digest, digestSize); + hash.Update(salt, saltSize); + hash.Final(h); + + // compute representative + GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize, false); + byte *xorStart = representative + representativeByteLength - u - digestSize - salt.size() - recoverableMessageLength - 1; + xorStart[0] ^= 1; + xorbuf(xorStart + 1, recoverableMessage, recoverableMessageLength); + xorbuf(xorStart + 1 + recoverableMessageLength, salt, salt.size()); + memcpy(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second); + representative[representativeByteLength - 1] = hashIdentifier.second ? 0xcc : 0xbc; + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); +} + +DecodingResult PSSR_MEM_Base::RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength, + byte *recoverableMessage) const +{ + const unsigned int u = hashIdentifier.second + 1; + const unsigned int representativeByteLength = BitsToBytes(representativeBitLength); + const unsigned int digestSize = hash.DigestSize(); + const unsigned int saltSize = SaltLen(digestSize); + const byte *const h = representative + representativeByteLength - u - digestSize; + + SecByteBlock digest(digestSize); + hash.Final(digest); + + DecodingResult result(0); + bool &valid = result.isValidCoding; + unsigned int &recoverableMessageLength = result.messageLength; + + valid = (representative[representativeByteLength - 1] == (hashIdentifier.second ? 0xcc : 0xbc)) && valid; + valid = (memcmp(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second) == 0) && valid; + + GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize); + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); + + // extract salt and recoverableMessage from DB = 00 ... || 01 || M || salt + byte *salt = representative + representativeByteLength - u - digestSize - saltSize; + byte *M = std::find_if(representative, salt-1, std::bind2nd(std::not_equal_to(), 0)); + if (*M == 0x01 && (unsigned int)(M - representative - (representativeBitLength % 8 != 0)) >= MinPadLen(digestSize)) + { + recoverableMessageLength = salt-M-1; + memcpy(recoverableMessage, M+1, recoverableMessageLength); + } + else + valid = false; + + // verify H = hash of M' + byte c[8]; + UnalignedPutWord(BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength)); + UnalignedPutWord(BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3)); + hash.Update(c, 8); + hash.Update(recoverableMessage, recoverableMessageLength); + hash.Update(digest, digestSize); + hash.Update(salt, saltSize); + valid = hash.Verify(h) && valid; + + if (!AllowRecovery() && valid && recoverableMessageLength != 0) + {throw NotImplemented("PSSR_MEM: message recovery disabled");} + + return result; +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/pssr.h b/stepmania/src/crypto51/pssr.h new file mode 100644 index 0000000000..4ba2950966 --- /dev/null +++ b/stepmania/src/crypto51/pssr.h @@ -0,0 +1,86 @@ +#ifndef CRYPTOPP_PSSR_H +#define CRYPTOPP_PSSR_H + +#include "pubkey.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +class PSSR_MEM_Base : public PK_RecoverableSignatureMessageEncodingMethod +{ + virtual bool AllowRecovery() const =0; + virtual unsigned int SaltLen(unsigned int hashLen) const =0; + virtual unsigned int MinPadLen(unsigned int hashLen) const =0; + virtual const MaskGeneratingFunction & GetMGF() const =0; + +public: + unsigned int MaxRecoverableLength(unsigned int representativeBitLength, unsigned int hashIdentifierLength, unsigned int digestLength) const; + bool IsProbabilistic() const; + bool AllowNonrecoverablePart() const; + bool RecoverablePartFirst() const; + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; + DecodingResult RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength, + byte *recoverableMessage) const; +}; + +template struct EMSA2HashId +{ + static const byte id; +}; + +// EMSA2HashId can be instantiated with the following two classes. +class SHA; +class RIPEMD160; + +template +class EMSA2HashIdLookup : public BASE +{ +public: + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(&EMSA2HashId::id, 1); + } + }; + }; +}; + +template class PSSR_MEM_BaseWithHashId; +template<> class PSSR_MEM_BaseWithHashId : public EMSA2HashIdLookup {}; +template<> class PSSR_MEM_BaseWithHashId : public PSSR_MEM_Base {}; + +template +class PSSR_MEM : public PSSR_MEM_BaseWithHashId +{ + virtual bool AllowRecovery() const {return ALLOW_RECOVERY;} + virtual unsigned int SaltLen(unsigned int hashLen) const {return SALT_LEN < 0 ? hashLen : SALT_LEN;} + virtual unsigned int MinPadLen(unsigned int hashLen) const {return MIN_PAD_LEN < 0 ? hashLen : MIN_PAD_LEN;} + virtual const MaskGeneratingFunction & GetMGF() const {static MGF mgf; return mgf;} + +public: + static std::string StaticAlgorithmName() {return std::string(ALLOW_RECOVERY ? "PSSR-" : "PSS-") + MGF::StaticAlgorithmName();} +}; + +//! PSSR-MGF1 +struct PSSR : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +//! PSS-MGF1 +struct PSS : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/pubkey.cpp b/stepmania/src/crypto51/pubkey.cpp new file mode 100644 index 0000000000..000258997a --- /dev/null +++ b/stepmania/src/crypto51/pubkey.cpp @@ -0,0 +1,122 @@ +// pubkey.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pubkey.h" + +NAMESPACE_BEGIN(CryptoPP) + +void P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength, bool mask, unsigned int counterStart) +{ + ArraySink *sink; + HashFilter filter(hash, sink = mask ? new ArrayXorSink(output, outputLength) : new ArraySink(output, outputLength)); + word32 counter = counterStart; + while (sink->AvailableSize() > 0) + { + filter.Put(input, inputLength); + filter.PutWord32(counter++); + filter.MessageEnd(); + } +} + +bool PK_DeterministicSignatureMessageEncodingMethod::VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const +{ + SecByteBlock computedRepresentative(BitsToBytes(representativeBitLength)); + ComputeMessageRepresentative(NullRNG(), NULL, 0, hash, hashIdentifier, messageEmpty, computedRepresentative, representativeBitLength); + return memcmp(representative, computedRepresentative, computedRepresentative.size()) == 0; +} + +bool PK_RecoverableSignatureMessageEncodingMethod::VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const +{ + SecByteBlock recoveredMessage(MaxRecoverableLength(representativeBitLength, hashIdentifier.second, hash.DigestSize())); + DecodingResult result = RecoverMessageFromRepresentative( + hash, hashIdentifier, messageEmpty, representative, representativeBitLength, recoveredMessage); + return result.isValidCoding && result.messageLength == 0; +} + +void TF_SignerBase::InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, unsigned int recoverableMessageLength) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const MessageEncodingInterface &mei = GetMessageEncodingInterface(); + unsigned int maxRecoverableLength = mei.MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, ma.AccessHash().DigestSize()); + + if (maxRecoverableLength == 0) + {throw NotImplemented("TF_SignerBase: this algorithm does not support messsage recovery or the key is too short");} + if (recoverableMessageLength > maxRecoverableLength) + throw InvalidArgument("TF_SignerBase: the recoverable message part is too long for the given key and algorithm"); + + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + mei.ProcessRecoverableMessage( + ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + NULL, 0, ma.m_semisignature); +} + +unsigned int TF_SignerBase::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + SecByteBlock representative(MessageRepresentativeLength()); + GetMessageEncodingInterface().ComputeMessageRepresentative(rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, + representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + + Integer r(representative, representative.size()); + unsigned int signatureLength = SignatureLength(); + GetTrapdoorFunctionInterface().CalculateRandomizedInverse(rng, r).Encode(signature, signatureLength); + return signatureLength; +} + +void TF_VerifierBase::InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, unsigned int signatureLength) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + ma.m_representative.New(MessageRepresentativeLength()); + Integer x = GetTrapdoorFunctionInterface().ApplyFunction(Integer(signature, signatureLength)); + if (x.BitCount() > MessageRepresentativeBitLength()) + x = Integer::Zero(); // don't return false here to prevent timing attack + x.Encode(ma.m_representative, ma.m_representative.size()); +} + +bool TF_VerifierBase::VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + bool result = GetMessageEncodingInterface().VerifyMessageRepresentative( + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, ma.m_representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + return result; +} + +DecodingResult TF_VerifierBase::RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + DecodingResult result = GetMessageEncodingInterface().RecoverMessageFromRepresentative( + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, ma.m_representative, MessageRepresentativeBitLength(), recoveredMessage); + ma.m_empty = true; + return result; +} + +DecodingResult TF_DecryptorBase::FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const +{ + SecByteBlock paddedBlock(PaddedBlockByteLength()); + Integer x = GetTrapdoorFunctionInterface().CalculateInverse(rng, 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 GetMessageEncodingInterface().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()); + GetMessageEncodingInterface().Pad(rng, plainText, plainTextLength, paddedBlock, PaddedBlockBitLength()); + GetTrapdoorFunctionInterface().ApplyRandomizedFunction(rng, Integer(paddedBlock, paddedBlock.size())).Encode(cipherText, FixedCiphertextLength()); +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/pubkey.h b/stepmania/src/crypto51/pubkey.h new file mode 100644 index 0000000000..a31d5366b8 --- /dev/null +++ b/stepmania/src/crypto51/pubkey.h @@ -0,0 +1,1708 @@ +// 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: +

+                  x1
+                 / \
+                y1  z1
+                 |  |
+            x2  x2
+                 |  |
+                y2  z2
+                 |  |
+            x3  x3
+                 |  |
+                y3  z3
+
+ - 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 + +// 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); + +// ******************************************************** + +//! . +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; + virtual bool IsRandomized() const {return true;} +}; + +//! . +class TrapdoorFunction : public RandomizedTrapdoorFunction +{ +public: + Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const + {return ApplyFunction(x);} + bool IsRandomized() const {return false;} + + virtual Integer ApplyFunction(const Integer &x) const =0; +}; + +//! . +class RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~RandomizedTrapdoorFunctionInverse() {} + + virtual Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const =0; + virtual bool IsRandomized() const {return true;} +}; + +//! . +class TrapdoorFunctionInverse : public RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~TrapdoorFunctionInverse() {} + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const + {return CalculateInverse(rng, x);} + bool IsRandomized() const {return false;} + + virtual Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +// ******************************************************** + +//! . +class PK_EncryptionMessageEncodingMethod +{ +public: + virtual ~PK_EncryptionMessageEncodingMethod() {} + + //! max size of unpadded message in bytes, given max size of padded message in bits (1 less than size of modulus) + 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; +}; + +// ******************************************************** + +//! . +template +class TF_Base +{ +protected: + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; + + typedef TFI TrapdoorFunctionInterface; + virtual const TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const =0; + + typedef MEI MessageEncodingInterface; + virtual const MessageEncodingInterface & GetMessageEncodingInterface() const =0; +}; + +// ******************************************************** + +//! . +template +class TF_CryptoSystemBase : public INTERFACE, protected BASE +{ +public: + unsigned int FixedMaxPlaintextLength() const {return GetMessageEncodingInterface().MaxUnpaddedLength(PaddedBlockBitLength());} + unsigned int FixedCiphertextLength() const {return GetTrapdoorFunctionBounds().MaxImage().ByteCount();} + +protected: + unsigned int PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + unsigned int PaddedBlockBitLength() const {return GetTrapdoorFunctionBounds().PreimageBound().BitCount()-1;} +}; + +//! . +class TF_DecryptorBase : public TF_CryptoSystemBase > +{ +public: + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const; +}; + +//! . +class TF_EncryptorBase : public TF_CryptoSystemBase > +{ +public: + void Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const; +}; + +// ******************************************************** + +typedef std::pair HashIdentifier; + +//! . +class PK_SignatureMessageEncodingMethod +{ +public: + virtual ~PK_SignatureMessageEncodingMethod() {} + + virtual unsigned int MaxRecoverableLength(unsigned int representativeBitLength, unsigned int hashIdentifierLength, unsigned int digestLength) const + {return 0;} + + bool IsProbabilistic() const + {return true;} + bool AllowNonrecoverablePart() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + virtual bool RecoverablePartFirst() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // for verification, DL + virtual void ProcessSemisignature(HashTransformation &hash, const byte *semisignature, unsigned int semisignatureLength) const {} + + // for signature + virtual void ProcessRecoverableMessage(HashTransformation &hash, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + const byte *presignature, unsigned int presignatureLength, + SecByteBlock &semisignature) const + { + if (RecoverablePartFirst()) + assert(!"ProcessRecoverableMessage() not implemented"); + } + + virtual void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const =0; + + virtual bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const =0; + + virtual DecodingResult RecoverMessageFromRepresentative( // for TF + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength, + byte *recoveredMessage) const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + virtual DecodingResult RecoverMessageFromSemisignature( // for DL + HashTransformation &hash, HashIdentifier hashIdentifier, + const byte *presignature, unsigned int presignatureLength, + const byte *semisignature, unsigned int semisignatureLength, + byte *recoveredMessage) const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // VC60 workaround + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(NULL, 0); + } + }; + }; +}; + +class PK_DeterministicSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; +}; + +class PK_RecoverableSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; +}; + +class DL_SignatureMessageEncodingMethod_DSA : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; +}; + +class DL_SignatureMessageEncodingMethod_NR : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, unsigned int recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, unsigned int representativeBitLength) const; +}; + +class PK_MessageAccumulatorBase : public PK_MessageAccumulator +{ +public: + PK_MessageAccumulatorBase() : m_empty(true) {} + + virtual HashTransformation & AccessHash() =0; + + void Update(const byte *input, unsigned int length) + { + AccessHash().Update(input, length); + m_empty = m_empty && length == 0; + } + + SecByteBlock m_recoverableMessage, m_representative, m_presignature, m_semisignature; + Integer m_k, m_s; + bool m_empty; +}; + +template +class PK_MessageAccumulatorImpl : public PK_MessageAccumulatorBase, protected ObjectHolder +{ +public: + HashTransformation & AccessHash() {return m_object;} +}; + +//! . +template +class TF_SignatureSchemeBase : public INTERFACE, protected BASE +{ +public: + unsigned int SignatureLength() const + {return GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + unsigned int MaxRecoverableLength() const + {return GetMessageEncodingInterface().MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, GetDigestSize());} + unsigned int MaxRecoverableLengthFromSignatureLength(unsigned int signatureLength) const + {return MaxRecoverableLength();} + + bool IsProbabilistic() const + {return GetTrapdoorFunctionInterface().IsRandomized() || GetMessageEncodingInterface().IsProbabilistic();} + bool AllowNonrecoverablePart() const + {return GetMessageEncodingInterface().AllowNonrecoverablePart();} + bool RecoverablePartFirst() const + {return GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + unsigned int MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + unsigned int MessageRepresentativeBitLength() const {return GetTrapdoorFunctionBounds().ImageBound().BitCount()-1;} + virtual HashIdentifier GetHashIdentifier() const =0; + virtual unsigned int GetDigestSize() const =0; +}; + +//! . +class TF_SignerBase : public TF_SignatureSchemeBase > +{ +public: + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, unsigned int recoverableMessageLength) const; + unsigned int SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const; +}; + +//! . +class TF_VerifierBase : public TF_SignatureSchemeBase > +{ +public: + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, unsigned int signatureLength) const; + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &recoveryAccumulator) const; +}; + +// ******************************************************** + +//! . +template +struct TF_CryptoSchemeOptions +{ + typedef T1 AlgorithmInfo; + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; + typedef T3 MessageEncodingMethod; +}; + +//! . +template +struct TF_SignatureSchemeOptions : public TF_CryptoSchemeOptions +{ + typedef T4 HashFunction; +}; + +//! . +template +class PublicKeyCopier +{ +public: + virtual void CopyKeyInto(typename KEYS::PublicKey &key) const =0; +}; + +//! . +template +class PrivateKeyCopier +{ +public: + virtual void CopyKeyInto(typename KEYS::PublicKey &key) const =0; + virtual void CopyKeyInto(typename KEYS::PrivateKey &key) const =0; +}; + +//! . +template +class TF_ObjectImplBase : public AlgorithmImpl +{ +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 typename BASE::MessageEncodingInterface & GetMessageEncodingInterface() const + {static typename SCHEME_OPTIONS::MessageEncodingMethod messageEncodingMethod; return messageEncodingMethod;} + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const + {return GetKey();} + const typename BASE::TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const + {return GetKey();} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef CPP_TYPENAME SchemeOptions::MessageEncodingMethod::HashIdentifierLookup::HashIdentifierLookup2 L; + return L::Lookup(); + } + unsigned int GetDigestSize() const + { + typedef CPP_TYPENAME SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } +}; + +//! . +template +class TF_ObjectImplExtRef : public TF_ObjectImplBase +{ +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 TF_ObjectImpl : public TF_ObjectImplBase +{ +public: + const KEY & GetKey() const {return m_trapdoorFunction;} + KEY & AccessKey() {return m_trapdoorFunction;} + +private: + KEY m_trapdoorFunction; +}; + +//! . +template +class TF_PublicObjectImpl : public TF_ObjectImpl, public PublicKeyCopier +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const {key = GetKey();} +}; + +//! . +template +class TF_PrivateObjectImpl : public TF_ObjectImpl, public PrivateKeyCopier +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PrivateKey &key) const {key = GetKey();} + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const {key = GetKey();} +}; + +//! . +template +class TF_DecryptorImpl : public TF_PrivateObjectImpl +{ +}; + +//! . +template +class TF_EncryptorImpl : public TF_PublicObjectImpl +{ +}; + +//! . +template +class TF_SignerImpl : public TF_PrivateObjectImpl +{ + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng = NullRNG()) const + { + return new PK_MessageAccumulatorImpl; + } +}; + +//! . +template +class TF_VerifierImpl : public TF_PublicObjectImpl +{ + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } +}; + +// ******************************************************** + +class MaskGeneratingFunction +{ +public: + virtual ~MaskGeneratingFunction() {} + virtual void GenerateAndMask(HashTransformation &hash, byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength, bool mask = true) const =0; +}; + +void P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength, bool mask, unsigned int counterStart); + +//! . +class P1363_MGF1 : public MaskGeneratingFunction +{ +public: + static const char * StaticAlgorithmName() {return "MGF1";} +#if 0 + // VC60 workaround: this function causes internal compiler error + template + static void GenerateAndMaskTemplate(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength, H* dummy=NULL) + { + H h; + P1363_MGF1KDF2_Common(h, output, outputLength, input, inputLength, mask, 0); + } +#endif + void GenerateAndMask(HashTransformation &hash, byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength, bool mask = true) const + { + P1363_MGF1KDF2_Common(hash, output, outputLength, input, inputLength, mask, 0); + } +}; + +// ******************************************************** + +//! . +template +class P1363_KDF2 +{ +public: + static void DeriveKey(byte *output, unsigned int outputLength, const byte *input, unsigned int inputLength) + { + H h; + P1363_MGF1KDF2_Common(h, output, outputLength, input, inputLength, false, 1); + } +}; + +// ******************************************************** + +// to be thrown by DecodeElement and AgreeWithStaticPrivateKey +class DL_BadElement : public InvalidDataFormat +{ +public: + DL_BadElement() : InvalidDataFormat("CryptoPP: invalid group element") {} +}; + +//! . +template +class DL_GroupParameters : public CryptoParameters +{ + typedef DL_GroupParameters 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 & GetGroupPrecomputation() const =0; + virtual const DL_FixedBasePrecomputation & GetBasePrecomputation() const =0; + virtual DL_FixedBasePrecomputation & 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 *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 BASE = DL_GroupParameters > +class DL_GroupParametersImpl : public BASE +{ +public: + typedef GROUP_PRECOMP GroupPrecomputation; + typedef typename GROUP_PRECOMP::Element Element; + typedef BASE_PRECOMP BasePrecomputation; + + const DL_GroupPrecomputation & GetGroupPrecomputation() const {return m_groupPrecomputation;} + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return m_gpc;} + +protected: + GROUP_PRECOMP m_groupPrecomputation; + BASE_PRECOMP m_gpc; +}; + +//! . +template +class DL_Key +{ +public: + virtual const DL_GroupParameters & GetAbstractGroupParameters() const =0; + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; +}; + +//! . +template +class DL_PublicKey : public DL_Key +{ + typedef DL_PublicKey ThisClass; + +public: + typedef T Element; + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &GetAbstractGroupParameters()) + 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 ¶ms = GetAbstractGroupParameters(); + return GetPublicPrecomputation().Exponentiate(params.GetGroupPrecomputation(), exponent); + } + virtual Element CascadeExponentiateBaseAndPublicElement(const Integer &baseExp, const Integer &publicExp) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + return params.GetBasePrecomputation().CascadeExponentiate(params.GetGroupPrecomputation(), baseExp, GetPublicPrecomputation(), publicExp); + } + + virtual const DL_FixedBasePrecomputation & GetPublicPrecomputation() const =0; + virtual DL_FixedBasePrecomputation & AccessPublicPrecomputation() =0; +}; + +//! . +template +class DL_PrivateKey : public DL_Key +{ + typedef DL_PrivateKey ThisClass; + +public: + typedef T Element; + + void MakePublicKey(DL_PublicKey &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 GetValueHelper(this, name, valueType, pValue, &GetAbstractGroupParameters()) + 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 +void DL_PublicKey::AssignFrom(const NameValuePairs &source) +{ + DL_PrivateKey *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 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 DL_PrivateKeyImpl : public DL_PrivateKey, public DL_KeyImpl +{ +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 >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + if (!params.GetThisObject(AccessGroupParameters())) + AccessGroupParameters().GenerateRandom(rng, params); +// std::pair 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 & GetAbstractGroupParameters() const {return GetGroupParameters();} + DL_GroupParameters & 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 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_FIPS_140_Only(signer, verifier); + } + } +}; + +//! . +template +class DL_PublicKeyImpl : public DL_PublicKey, public DL_KeyImpl +{ +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 >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(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 & GetAbstractGroupParameters() const {return GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return AccessGroupParameters();} + + // DL_PublicKey + const DL_FixedBasePrecomputation & GetPublicPrecomputation() const {return m_ypc;} + DL_FixedBasePrecomputation & AccessPublicPrecomputation() {return m_ypc;} + + // non-inherited + bool operator==(const DL_PublicKeyImpl &rhs) const + {return GetGroupParameters() == rhs.GetGroupParameters() && GetPublicElement() == rhs.GetPublicElement();} + +private: + typename GP::BasePrecomputation m_ypc; +}; + +//! . +template +class DL_ElgamalLikeSignatureAlgorithm +{ +public: +// virtual Integer EncodeDigest(unsigned int modulusBits, const byte *digest, unsigned int digestLength) const =0; + virtual void Sign(const DL_GroupParameters ¶ms, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; + virtual bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0; + virtual Integer RecoverPresignature(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &r, const Integer &s) const + {throw NotImplemented("DL_ElgamalLikeSignatureAlgorithm: this signature scheme does not support message recovery");} + virtual unsigned int RLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + virtual unsigned int SLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} +}; + +//! . +template +class DL_KeyAgreementAlgorithm +{ +public: + typedef T Element; + + virtual Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const =0; + virtual Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const =0; +}; + +//! . +template +class DL_KeyDerivationAlgorithm +{ +public: + virtual void Derive(const DL_GroupParameters ¶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 DL_Base +{ +protected: + typedef KI KeyInterface; + typedef typename KI::Element Element; + + const DL_GroupParameters & GetAbstractGroupParameters() const {return GetKeyInterface().GetAbstractGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return AccessKeyInterface().AccessAbstractGroupParameters();} + + virtual KeyInterface & AccessKeyInterface() =0; + virtual const KeyInterface & GetKeyInterface() const =0; +}; + +//! . +template +class DL_SignatureSchemeBase : public INTERFACE, public DL_Base +{ +public: + unsigned int SignatureLength() const + { + return GetSignatureAlgorithm().RLen(GetAbstractGroupParameters()) + + GetSignatureAlgorithm().SLen(GetAbstractGroupParameters()); + } + unsigned int MaxRecoverableLength() const + {return GetMessageEncodingInterface().MaxRecoverableLength(0, GetHashIdentifier().second, GetDigestSize());} + unsigned int MaxRecoverableLengthFromSignatureLength(unsigned int signatureLength) const + {assert(false); return 0;} // TODO + + bool IsProbabilistic() const + {return true;} + bool AllowNonrecoverablePart() const + {return GetMessageEncodingInterface().AllowNonrecoverablePart();} + bool RecoverablePartFirst() const + {return GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + unsigned int MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + unsigned int MessageRepresentativeBitLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().BitCount();} + + virtual const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const =0; + virtual const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const =0; + virtual HashIdentifier GetHashIdentifier() const =0; + virtual unsigned int GetDigestSize() const =0; +}; + +//! . +template +class DL_SignerBase : public DL_SignatureSchemeBase > +{ +public: + // for validation testing + void RawSign(const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey &key = GetKeyInterface(); + + r = params.ConvertElementToInteger(params.ExponentiateBase(k)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, unsigned int recoverableMessageLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + GetMessageEncodingInterface().ProcessRecoverableMessage(ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature); + } + + unsigned int SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const + { + GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey &key = GetKeyInterface(); + + SecByteBlock representative(MessageRepresentativeLength()); + GetMessageEncodingInterface().ComputeMessageRepresentative( + rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, + representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + Integer r; + if (MaxRecoverableLength() > 0) + r.Decode(ma.m_semisignature, ma.m_semisignature.size()); + else + r.Decode(ma.m_presignature, ma.m_presignature.size()); + Integer s; + alg.Sign(params, key.GetPrivateExponent(), ma.m_k, e, r, s); + + unsigned int rLen = alg.RLen(params); + r.Encode(signature, rLen); + s.Encode(signature+rLen, alg.SLen(params)); + + if (restart) + RestartMessageAccumulator(rng, ma); + + return SignatureLength(); + } + +protected: + void RestartMessageAccumulator(RandomNumberGenerator &rng, PK_MessageAccumulatorBase &ma) const + { + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + ma.m_k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + ma.m_presignature.New(params.GetEncodedElementSize(false)); + params.ConvertElementToInteger(params.ExponentiateBase(ma.m_k)).Encode(ma.m_presignature, ma.m_presignature.size()); + } +}; + +//! . +template +class DL_VerifierBase : public DL_SignatureSchemeBase > +{ +public: + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, unsigned int signatureLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + unsigned int rLen = alg.RLen(params); + ma.m_semisignature.Assign(signature, rLen); + ma.m_s.Decode(signature+rLen, alg.SLen(params)); + + GetMessageEncodingInterface().ProcessSemisignature(ma.AccessHash(), ma.m_semisignature, ma.m_semisignature.size()); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const + { + GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PublicKey &key = GetKeyInterface(); + + SecByteBlock representative(MessageRepresentativeLength()); + GetMessageEncodingInterface().ComputeMessageRepresentative(NullRNG(), ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, + representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + return alg.Verify(params, key, e, r, ma.m_s); + } + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const + { + GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PublicKey &key = GetKeyInterface(); + + SecByteBlock representative(MessageRepresentativeLength()); + GetMessageEncodingInterface().ComputeMessageRepresentative( + NullRNG(), + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), GetHashIdentifier(), ma.m_empty, + representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + ma.m_presignature.New(params.GetEncodedElementSize(false)); + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + alg.RecoverPresignature(params, key, r, ma.m_s).Encode(ma.m_presignature, ma.m_presignature.size()); + + return GetMessageEncodingInterface().RecoverMessageFromSemisignature( + ma.AccessHash(), GetHashIdentifier(), + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature, ma.m_semisignature.size(), + recoveredMessage); + } +}; + +//! . +template +class DL_CryptoSystemBase : public PK, public DL_Base +{ +public: + typedef typename DL_Base::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 & GetKeyAgreementAlgorithm() const =0; + virtual const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const =0; + virtual const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const =0; +}; + +//! . +template +class DL_DecryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *cipherText, unsigned int cipherTextLength, byte *plainText) const + { + try + { + const DL_KeyAgreementAlgorithm &agreeAlg = GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PrivateKey &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 DL_EncryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + void Encrypt(RandomNumberGenerator &rng, const byte *plainText, unsigned int plainTextLength, byte *cipherText) const + { + const DL_KeyAgreementAlgorithm &agreeAlg = GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + const DL_PublicKey &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 +struct DL_SchemeOptionsBase +{ + typedef T1 AlgorithmInfo; + typedef T2 GroupParameters; + typedef typename GroupParameters::Element Element; +}; + +//! . +template +struct DL_KeyedSchemeOptions : public DL_SchemeOptionsBase +{ + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; +}; + +//! . +template +struct DL_SignatureSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 SignatureAlgorithm; + typedef T4 MessageEncodingMethod; + typedef T5 HashFunction; +}; + +//! . +template +struct DL_CryptoSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 KeyAgreementAlgorithm; + typedef T4 KeyDerivationAlgorithm; + typedef T5 SymmetricEncryptionAlgorithm; +}; + +//! . +template +class DL_ObjectImplBase : public AlgorithmImpl +{ +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;} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef CPP_TYPENAME SchemeOptions::MessageEncodingMethod::HashIdentifierLookup::HashIdentifierLookup2 L; + return L::Lookup(); + } + unsigned int GetDigestSize() const + { + typedef CPP_TYPENAME SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } + +private: + KeyClass m_key; +}; + +//! . +template +class DL_ObjectImpl : public DL_ObjectImplBase +{ +public: + typedef typename KEY::Element Element; + +protected: + const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const + {static typename SCHEME_OPTIONS::SignatureAlgorithm a; return a;} + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {static typename SCHEME_OPTIONS::KeyAgreementAlgorithm a; return a;} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const + {static typename SCHEME_OPTIONS::KeyDerivationAlgorithm a; return a;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const + {static typename SCHEME_OPTIONS::SymmetricEncryptionAlgorithm a; return a;} + HashIdentifier GetHashIdentifier() const + {return HashIdentifier();} + const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const + {static typename SCHEME_OPTIONS::MessageEncodingMethod a; return a;} +}; + +//! . +template +class DL_PublicObjectImpl : public DL_ObjectImpl, public PublicKeyCopier +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const + {key = GetKey();} +}; + +//! . +template +class DL_PrivateObjectImpl : public DL_ObjectImpl, public PrivateKeyCopier +{ +public: + void CopyKeyInto(typename SCHEME_OPTIONS::PublicKey &key) const + {GetKey().MakePublicKey(key);} + void CopyKeyInto(typename SCHEME_OPTIONS::PrivateKey &key) const + {key = GetKey();} +}; + +//! . +template +class DL_SignerImpl : public DL_PrivateObjectImpl, SCHEME_OPTIONS> +{ + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng = NullRNG()) const + { + std::auto_ptr p(new PK_MessageAccumulatorImpl); + RestartMessageAccumulator(rng, *p); + return p.release(); + } +}; + +//! . +template +class DL_VerifierImpl : public DL_PublicObjectImpl, SCHEME_OPTIONS> +{ + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } +}; + +//! . +template +class DL_EncryptorImpl : public DL_PublicObjectImpl, SCHEME_OPTIONS> +{ +}; + +//! . +template +class DL_DecryptorImpl : public DL_PrivateObjectImpl, SCHEME_OPTIONS> +{ +}; + +// ******************************************************** + +//! . +template +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 ¶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 ¶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 & GetKeyAgreementAlgorithm() const =0; + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; + const DL_GroupParameters & GetAbstractGroupParameters() const {return const_cast *>(this)->AccessAbstractGroupParameters();} +}; + +enum CofactorMultiplicationOption {NO_COFACTOR_MULTIPLICTION, COMPATIBLE_COFACTOR_MULTIPLICTION, INCOMPATIBLE_COFACTOR_MULTIPLICTION}; +typedef EnumToType NoCofactorMultiplication; +typedef EnumToType CompatibleCofactorMultiplication; +typedef EnumToType IncompatibleCofactorMultiplication; + +//! DH key agreement algorithm +template +class DL_KeyAgreementAlgorithm_DH : public DL_KeyAgreementAlgorithm +{ +public: + typedef ELEMENT Element; + + static const char *StaticAlgorithmName() + {return COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION ? "DH" : "DHC";} + + Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &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 ¶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 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 + PK_FinalTemplate(const PublicKeyCopier &key) + {key.CopyKeyInto(AccessKey());} + + template + PK_FinalTemplate(const PrivateKeyCopier &key) + {key.CopyKeyInto(AccessKey());} + + PK_FinalTemplate(BufferedTransformation &bt) {AccessKey().BERDecode(bt);} + +#if (defined(_MSC_VER) && _MSC_VER < 1300) + + template + PK_FinalTemplate(T1 &v1, T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5) + {AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(T1 &v1, T2 &v2, T3 &v3, T4 &v4, T5 &v5, T6 &v6) + {AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + 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 + 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 + PK_FinalTemplate(const T1 &v1, const T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template + 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 + 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 + 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 + 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 + PK_FinalTemplate(T1 &v1, const T2 &v2) + {AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3) + {AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + 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 + 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 + 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 TF_ES; + +//! Trapdoor Function Based Encryption Scheme +template > +class TF_ES : public KEYS +{ + typedef typename STANDARD::EncryptionMessageEncodingMethod MessageEncodingMethod; + +public: + //! see EncryptionStandard for a list of standards + typedef STANDARD Standard; + typedef TF_CryptoSchemeOptions SchemeOptions; + + static std::string StaticAlgorithmName() {return KEYS::StaticAlgorithmName() + "/" + MessageEncodingMethod::StaticAlgorithmName();} + + //! implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + //! implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +template // VC60 workaround: doesn't work if KEYS is first parameter +class TF_SS; + +//! Trapdoor Function Based Signature Scheme +template > // VC60 workaround: doesn't work if KEYS is first parameter +class TF_SS : public KEYS +{ +public: + //! see SignatureStandard for a list of standards + typedef STANDARD Standard; + typedef typename Standard::SignatureMessageEncodingMethod MessageEncodingMethod; + typedef TF_SignatureSchemeOptions SchemeOptions; + + static std::string StaticAlgorithmName() {return KEYS::StaticAlgorithmName() + "/" + MessageEncodingMethod::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + + //! implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + //! implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +template +class DL_SS; + +//! Discrete Log Based Signature Scheme +template > +class DL_SS : public KEYS +{ + typedef DL_SignatureSchemeOptions SchemeOptions; + +public: + static std::string StaticAlgorithmName() {return SA::StaticAlgorithmName() + std::string("/EMSA1(") + H::StaticAlgorithmName() + ")";} + + //! implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + //! implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +//! Discrete Log Based Encryption Scheme +template +class DL_ES : public KEYS +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + +public: + //! implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + //! implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/queue.cpp b/stepmania/src/crypto51/queue.cpp new file mode 100644 index 0000000000..a01e213845 --- /dev/null +++ b/stepmania/src/crypto51/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 diff --git a/stepmania/src/crypto51/queue.h b/stepmania/src/crypto51/queue.h new file mode 100644 index 0000000000..e247d9f690 --- /dev/null +++ b/stepmania/src/crypto51/queue.h @@ -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 + +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 +{ +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 + { + 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/stepmania/src/crypto51/randpool.cpp b/stepmania/src/crypto51/randpool.cpp new file mode 100644 index 0000000000..9fa0b4beec --- /dev/null +++ b/stepmania/src/crypto51/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 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::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/stepmania/src/crypto51/randpool.h b/stepmania/src/crypto51/randpool.h new file mode 100644 index 0000000000..6bbe32f788 --- /dev/null +++ b/stepmania/src/crypto51/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 +{ +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 diff --git a/stepmania/src/crypto51/rng.h b/stepmania/src/crypto51/rng.h new file mode 100644 index 0000000000..5b0998d4e7 --- /dev/null +++ b/stepmania/src/crypto51/rng.h @@ -0,0 +1,78 @@ +#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, deterministicTimeVector = 0 means obtain time vector from system + X917RNG(BlockTransformation *cipher, const byte *seed, unsigned long deterministicTimeVector = 0); + + byte GenerateByte(); + +private: + member_ptr 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 + unsigned long m_deterministicTimeVector; +}; + +/** 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 diff --git a/stepmania/src/crypto51/rsa.cpp b/stepmania/src/crypto51/rsa.cpp new file mode 100644 index 0000000000..62e9592168 --- /dev/null +++ b/stepmania/src/crypto51/rsa.cpp @@ -0,0 +1,277 @@ +// 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 "modarith.h" +#include "nbtheory.h" +#include "sha.h" +#include "algparam.h" +#include "fips140.h" + +#ifndef NDEBUG +#include "pssr.h" +#endif + +#include "oaep.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +#ifndef NDEBUG +void RSA_TestInstantiations() +{ + RSASS::Verifier x1(1, 1); + RSASS::Signer x2(NullRNG(), 1); + RSASS::Verifier x3(x2); + RSASS::Verifier x4(x2.GetKey()); + RSASS::Verifier x5(x3); +#ifndef __MWERKS__ + RSASS::Signer x6 = x2; + x3 = x2; + x6 = x2; +#endif + RSAES::Encryptor x7(x2); +#ifndef __GNUC__ + RSAES::Encryptor x8(x3); +#endif + RSAES >::Encryptor x9(x2); + + x4 = x2.GetKey(); +} +#endif + +template class OAEP; + +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()) + { + RSASS::Signer signer(*this); + RSASS::Verifier verifier(signer); + SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier); + + RSAES >::Decryptor decryptor(*this); + RSAES >::Encryptor encryptor(decryptor); + EncryptionPairwiseConsistencyTest_FIPS_140_Only(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::Initialize(const Integer &n, const Integer &e, const Integer &d) +{ + m_n = n; + m_e = e; + m_d = d; + + Integer r = --(d*e); + while (r.IsEven()) + r >>= 1; + + ModularArithmetic modn(n); + for (Integer i = 2; ; ++i) + { + Integer a = modn.Exponentiate(i, r); + if (a == 1) + continue; + Integer b; + while (a != -1) + { + b = modn.Square(a); + if (b == 1) + { + m_p = GCD(a-1, n); + m_q = n/m_p; + m_dp = m_d % (m_p-1); + m_dq = m_d % (m_q-1); + m_u = m_q.InverseMod(m_p); + return; + } + a = b; + } + } +} + +void InvertibleRSAFunction::BERDecodeKey(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKey(bt); + word32 version; + BERDecodeUnsigned(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(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(RandomNumberGenerator &rng, const Integer &x) const +{ + DoQuickSanityCheck(); + ModularArithmetic modn(m_n); + Integer r(rng, Integer::One(), m_n - Integer::One()); + Integer re = modn.Exponentiate(r, m_e); + re = modn.Multiply(re, x); // blind + // 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 + Integer y = ModularRoot(re, m_dq, m_dp, m_q, m_p, m_u); + y = modn.Divide(y, r); // unblind + if (modn.Exponentiate(y, m_e) != x) // check + throw Exception(Exception::OTHER_ERROR, "InvertibleRSAFunction: computational error during private key operation"); + return y; +} + +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(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(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) + ; +} + +NAMESPACE_END diff --git a/stepmania/src/crypto51/rsa.h b/stepmania/src/crypto51/rsa.h new file mode 100644 index 0000000000..7f82134088 --- /dev/null +++ b/stepmania/src/crypto51/rsa.h @@ -0,0 +1,143 @@ +#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;} + //! factor n given private exponent + void Initialize(const Integer &n, const Integer &e, const Integer &d); + + // 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(RandomNumberGenerator &rng, 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; +}; + +//! . +struct RSA +{ + static std::string StaticAlgorithmName() {return "RSA";} + typedef RSAFunction PublicKey; + typedef InvertibleRSAFunction PrivateKey; +}; + +//! RSA cryptosystem +template +struct RSAES : public TF_ES +{ +}; + +//! RSA signature scheme with appendix +/*! See documentation of PKCS1v15 for a list of hash functions that can be used with it. */ +template +struct RSASS : public TF_SS +{ +}; + +// The two RSA encryption schemes defined in PKCS #1 v2.0 +typedef RSAES::Decryptor RSAES_PKCS1v15_Decryptor; +typedef RSAES::Encryptor RSAES_PKCS1v15_Encryptor; + +typedef RSAES >::Decryptor RSAES_OAEP_SHA_Decryptor; +typedef RSAES >::Encryptor RSAES_OAEP_SHA_Encryptor; + +// The three RSA signature schemes defined in PKCS #1 v2.0 +typedef RSASS::Signer RSASSA_PKCS1v15_SHA_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_SHA_Verifier; + +typedef RSASS::Signer RSASSA_PKCS1v15_MD2_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_MD2_Verifier; + +typedef RSASS::Signer RSASSA_PKCS1v15_MD5_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_MD5_Verifier; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/rsa1024.dat b/stepmania/src/crypto51/rsa1024.dat new file mode 100644 index 0000000000..70fb172465 --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/rsa2048.dat b/stepmania/src/crypto51/rsa2048.dat new file mode 100644 index 0000000000..83200c2757 --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/rsa400pb.dat b/stepmania/src/crypto51/rsa400pb.dat new file mode 100644 index 0000000000..ccbc6ae2cd --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/rsa400pv.dat b/stepmania/src/crypto51/rsa400pv.dat new file mode 100644 index 0000000000..2a73123413 --- /dev/null +++ b/stepmania/src/crypto51/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/stepmania/src/crypto51/rsa512a.dat b/stepmania/src/crypto51/rsa512a.dat new file mode 100644 index 0000000000..e7edefae70 --- /dev/null +++ b/stepmania/src/crypto51/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 diff --git a/stepmania/src/crypto51/secblock.h b/stepmania/src/crypto51/secblock.h new file mode 100644 index 0000000000..e07c6a213e --- /dev/null +++ b/stepmania/src/crypto51/secblock.h @@ -0,0 +1,385 @@ +// 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 // CodeWarrior doesn't have memory.h +#include + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +template +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::value_type value_type;\ +typedef typename AllocatorBase::size_type size_type;\ +typedef typename AllocatorBase::difference_type difference_type;\ +typedef typename AllocatorBase::pointer pointer;\ +typedef typename AllocatorBase::const_pointer const_pointer;\ +typedef typename AllocatorBase::reference reference;\ +typedef typename AllocatorBase::const_reference const_reference; + +template +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 AllocatorWithCleanup : public AllocatorBase +{ +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 struct rebind { typedef AllocatorWithCleanup other; }; +}; + +template +class NullAllocator : public AllocatorBase +{ +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 FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +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 SecBlock +{ +public: + explicit SecBlock(unsigned int size=0) + : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);} + SecBlock(const SecBlock &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 + T *operator +(I offset) + {return m_ptr+offset;} + + template + const T *operator +(I offset) const + {return m_ptr+offset;} + + template + T& operator[](I index) + {assert(index >= 0 && (unsigned int)index < m_size); return m_ptr[index];} + + template + 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) + { + New(t.m_size); + memcpy(m_ptr, t.m_ptr, m_size*sizeof(T)); + } + + SecBlock& operator=(const SecBlock &t) + { + Assign(t); + return *this; + } + + bool operator==(const SecBlock &t) const + { + return m_size == t.m_size && memcmp(m_ptr, t.m_ptr, m_size*sizeof(T)) == 0; + } + + bool operator!=(const SecBlock &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 &b); + +//private: + A m_alloc; + unsigned int m_size; + T *m_ptr; +}; + +template void SecBlock::swap(SecBlock &b) +{ + std::swap(m_alloc, b.m_alloc); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); +} + +typedef SecBlock SecByteBlock; +typedef SecBlock SecWordBlock; + +template > +class FixedSizeSecBlock : public SecBlock +{ +public: + explicit FixedSizeSecBlock() : SecBlock(S) {} +}; + +template > > +class SecBlockWithHint : public SecBlock +{ +public: + explicit SecBlockWithHint(unsigned int size) : SecBlock(size) {} +}; + +template +inline bool operator==(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (true);} +template +inline bool operator!=(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template +inline void swap(CryptoPP::SecBlock &a, CryptoPP::SecBlock &b) +{ + a.swap(b); +} + +#if defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES) +template +inline CryptoPP::AllocatorWithCleanup<_Tp2>& +__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) +{ + return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); +} +#endif + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/seckey.h b/stepmania/src/crypto51/seckey.h new file mode 100644 index 0000000000..36ecd36a96 --- /dev/null +++ b/stepmania/src/crypto51/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 +class FixedBlockSize +{ +public: + enum {BLOCKSIZE = N}; +}; + +// ************** rounds *************** + +//! . +template +class FixedRounds +{ +public: + enum {ROUNDS = R}; + +protected: + template + 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 // 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 + 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 +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 +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 (unsigned int)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 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 +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 +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 SimpleKeyingInterfaceImpl : public BASE +{ +public: + unsigned int MinKeyLength() const {return INFO::MIN_KEYLENGTH;} + unsigned int MaxKeyLength() const {return (unsigned int)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 BlockCipherBaseTemplate : public AlgorithmImpl > > +{ +public: + unsigned int BlockSize() const {return BLOCKSIZE;} +}; + +//! . +template +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() const {return new BlockCipherTemplate(*this);} +}; + +//! . +template +class MessageAuthenticationCodeTemplate : public +#ifdef CRYPTOPP_DOXYGEN_PROCESSING + MessageAuthenticationCode +#else + SimpleKeyingInterfaceImpl +#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() const {return new MessageAuthenticationCodeTemplate(*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/stepmania/src/crypto51/sha.cpp b/stepmania/src/crypto51/sha.cpp new file mode 100644 index 0000000000..958d9ea07b --- /dev/null +++ b/stepmania/src/crypto51/sha.cpp @@ -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 diff --git a/stepmania/src/crypto51/sha.h b/stepmania/src/crypto51/sha.h new file mode 100644 index 0000000000..9c1cce5ae2 --- /dev/null +++ b/stepmania/src/crypto51/sha.h @@ -0,0 +1,72 @@ +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// SHA-1 +class SHA : public IteratedHashWithStaticTransform +{ +public: + enum {DIGESTSIZE = 20}; + SHA() : IteratedHashWithStaticTransform(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 +{ +public: + enum {DIGESTSIZE = 32}; + SHA256() : IteratedHashWithStaticTransform(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 +{ +public: + enum {DIGESTSIZE = 64}; + SHA512() : IteratedHashWithStaticTransform(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 +{ +public: + enum {DIGESTSIZE = 48}; + SHA384() : IteratedHashWithStaticTransform(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/stepmania/src/crypto51/simple.h b/stepmania/src/crypto51/simple.h new file mode 100644 index 0000000000..e26cefd40f --- /dev/null +++ b/stepmania/src/crypto51/simple.h @@ -0,0 +1,230 @@ +// 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 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 Bufferless : public T +{ +public: + Bufferless() {} + Bufferless(BufferedTransformation *q) : T(q) {} + bool IsolatedFlush(bool hardFlush, bool blocking) {return false;} +}; + +template +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: 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 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 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 Multichannel : public CustomSignalPropagation +{ +public: + Multichannel() {} + Multichannel(BufferedTransformation *q) : CustomSignalPropagation(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);} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return ChannelMessageSeriesEnd(NULL_CHANNEL, propagation, blocking);} + 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 *inString, unsigned int length, int messageEnd, bool blocking) + {return ChannelPutModifiable2(NULL_CHANNEL, inString, length, 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; + unsigned int ChannelPutModifiable2(const std::string &channel, byte *begin, unsigned int length, int messageEnd, bool blocking) + {return ChannelPut2(channel, begin, length, messageEnd, blocking);} + + 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 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 > +{ +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 +{ +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/stepmania/src/crypto51/smartptr.h b/stepmania/src/crypto51/smartptr.h new file mode 100644 index 0000000000..00dab21042 --- /dev/null +++ b/stepmania/src/crypto51/smartptr.h @@ -0,0 +1,215 @@ +#ifndef CRYPTOPP_SMARTPTR_H +#define CRYPTOPP_SMARTPTR_H + +#include "config.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +template 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& rhs); // copy not allowed + void operator=(const member_ptr& rhs); // assignment not allowed + + T *m_p; +}; + +template member_ptr::~member_ptr() {delete m_p;} +template void member_ptr::reset(T *p) {delete m_p; m_p = p;} + +// ******************************************************** + +template class value_ptr : public member_ptr +{ +public: + value_ptr(const T &obj) : member_ptr(new T(obj)) {} + value_ptr(T *p = NULL) : member_ptr(p) {} + value_ptr(const value_ptr& rhs) + : member_ptr(rhs.m_p ? new T(*rhs.m_p) : NULL) {} + + value_ptr& operator=(const value_ptr& rhs); + bool operator==(const value_ptr& rhs) + { + return (!m_p && !rhs.m_p) || (m_p && rhs.m_p && *m_p == *rhs.m_p); + } +}; + +template value_ptr& value_ptr::operator=(const value_ptr& rhs) +{ + T *old_p = m_p; + m_p = rhs.m_p ? new T(*rhs.m_p) : NULL; + delete old_p; + return *this; +} + +// ******************************************************** + +template class clonable_ptr : public member_ptr +{ +public: + clonable_ptr(const T &obj) : member_ptr(obj.Clone()) {} + clonable_ptr(T *p = NULL) : member_ptr(p) {} + clonable_ptr(const clonable_ptr& rhs) + : member_ptr(rhs.m_p ? rhs.m_p->Clone() : NULL) {} + + clonable_ptr& operator=(const clonable_ptr& rhs); +}; + +template clonable_ptr& clonable_ptr::operator=(const clonable_ptr& rhs) +{ + T *old_p = m_p; + m_p = rhs.m_p ? rhs.m_p->Clone() : NULL; + delete old_p; + return *this; +} + +// ******************************************************** + +template 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& 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 & operator=(const counted_ptr& rhs); + +private: + T *m_p; +}; + +template counted_ptr::counted_ptr(T *p) + : m_p(p) +{ + if (m_p) + m_p->m_referenceCount = 1; +} + +template counted_ptr::counted_ptr(const counted_ptr& rhs) + : m_p(rhs.m_p) +{ + if (m_p) + m_p->m_referenceCount++; +} + +template counted_ptr::~counted_ptr() +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; +} + +template void counted_ptr::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(&r); + m_p->m_referenceCount++; + } +} + +template T* counted_ptr::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 counted_ptr & counted_ptr::operator=(const counted_ptr& 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 vector_member_ptrs +{ +public: + vector_member_ptrs(unsigned int size=0) + : _size(size) {ptr = new member_ptr[_size];} + ~vector_member_ptrs() + {delete [] ptr;} + + member_ptr& operator[](unsigned int index) + {assert(index<_size); return ptr[index];} + const member_ptr& operator[](unsigned int index) const + {assert(index<_size); return ptr[index];} + + unsigned int size() const {return _size;} + void resize(unsigned int newSize) + { + member_ptr *newPtr = new member_ptr[newSize]; + for (unsigned int i=0; i &c); // copy not allowed + void operator=(const vector_member_ptrs &x); // assignment not allowed + + unsigned int _size; + member_ptr *ptr; +}; + +NAMESPACE_END + +#endif diff --git a/stepmania/src/crypto51/strciphr.cpp b/stepmania/src/crypto51/strciphr.cpp new file mode 100644 index 0000000000..d948c57920 --- /dev/null +++ b/stepmania/src/crypto51/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 +byte AdditiveCipherTemplate::GenerateByte() +{ + PolicyInterface &policy = AccessPolicy(); + + if (m_leftOver == 0) + { + policy.WriteKeystream(m_buffer, policy.GetIterationsToBuffer()); + m_leftOver = policy.GetBytesPerIteration(); + } + + return *(KeystreamBufferEnd()-m_leftOver--); +} + +template +inline void AdditiveCipherTemplate::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 +void AdditiveCipherTemplate::Resynchronize(const byte *iv) +{ + PolicyInterface &policy = AccessPolicy(); + m_leftOver = 0; + m_buffer.New(GetBufferByteSize(policy)); + policy.CipherResynchronize(m_buffer, iv); +} + +template +void AdditiveCipherTemplate::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 - (unsigned int)position; + } + else + m_leftOver = 0; +} + +template +void CFB_CipherTemplate::Resynchronize(const byte *iv) +{ + PolicyInterface &policy = AccessPolicy(); + policy.CipherResynchronize(iv); + m_leftOver = policy.GetBytesPerIteration(); +} + +template +void CFB_CipherTemplate::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 +void CFB_EncryptionTemplate::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length) +{ + xorbuf(reg, message, length); + memcpy(output, reg, length); +} + +template +void CFB_DecryptionTemplate::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length) +{ + for (unsigned int i=0; i, 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 AbstractPolicyHolder : public BASE +{ +public: + typedef POLICY_INTERFACE PolicyInterface; + +protected: + virtual const POLICY_INTERFACE & GetPolicy() const =0; + virtual POLICY_INTERFACE & AccessPolicy() =0; +}; + +template +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 +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 + 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(m_input)); + assert(IsAligned(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 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); + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + 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 +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 + 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(m_output)); + assert(IsAligned(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 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;} + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + 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 CFB_EncryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return true;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length); +}; + +template > +class CFB_DecryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return false;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, unsigned int length); +}; + +template +class SymmetricCipherFinalTemplate : public AlgorithmImpl, 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() const {return static_cast(new SymmetricCipherFinalTemplate(*this));} +}; + +template +void AdditiveCipherTemplate::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 +void CFB_CipherTemplate::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 diff --git a/stepmania/src/crypto51/test.cpp b/stepmania/src/crypto51/test.cpp new file mode 100644 index 0000000000..1b832192d0 --- /dev/null +++ b/stepmania/src/crypto51/test.cpp @@ -0,0 +1,166 @@ +// test.cpp - written and placed in the public domain by Wei Dai + +#include "sha.h" +#include "files.h" +#include "rng.h" +#include "rsa.h" +#include "randpool.h" + +#include +#include + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#include +#endif + +#if (_MSC_VER >= 1000) +#include // for the debug heap +#endif + +#if defined(__MWERKS__) && defined(macintosh) +#include +#endif + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +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); + +int (*AdhocTest)(int argc, char *argv[]) = NULL; + +#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]; + + 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: + 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; + } +} + + +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_PKCS1v15_Decryptor priv(randPool, keyLength); + FileSink privFile(privFilename); + priv.DEREncode(privFile); + privFile.MessageEnd(); + + RSAES_PKCS1v15_Encryptor pub(priv); + FileSink pubFile(pubFilename); + pub.DEREncode(pubFile); + pubFile.MessageEnd(); +} + +void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource privFile(privFilename, true); + 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(GlobalRNG(), priv, new FileSink(signatureFilename))); +} + +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource pubFile(pubFilename, true); + RSASSA_PKCS1v15_SHA_Verifier pub(pubFile); + + FileSource signatureFile(signatureFilename, true); + 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(); +} + diff --git a/stepmania/src/crypto51/trdlocal.h b/stepmania/src/crypto51/trdlocal.h new file mode 100644 index 0000000000..f07b793766 --- /dev/null +++ b/stepmania/src/crypto51/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 +typedef DWORD ThreadLocalIndexType; +#else +#include +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/stepmania/src/crypto51/words.h b/stepmania/src/crypto51/words.h new file mode 100644 index 0000000000..8849b61071 --- /dev/null +++ b/stepmania/src/crypto51/words.h @@ -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> (WORD_BITS-shiftBits); + } + return carry; +} + +inline word ShiftWordsRightByBits(word *r, unsigned int n, unsigned int shiftBits) +{ + assert (shiftBits=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 +#include + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#include +#endif + +#if (_MSC_VER >= 1000) +#include // for the debug heap +#endif + +#if defined(__MWERKS__) && defined(macintosh) +#include +#endif + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename); + +int (*AdhocTest)(int argc, char *argv[]) = NULL; + +#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 != 4) + { + cout << "\nUsage: RSAPubKeyData.exe publickey_fn data_fn signature_fn" << endl; + return -1; + } + + if( RSAVerifyFile(argv[2], argv[3], argv[4]) ) + { + cout << "The signature is valid." << endl; + } + else + { + cout << "The signature is not valid." << endl; + } + return 0; + } + 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; + } +} + +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource pubFile(pubFilename, true); + RSASSA_PKCS1v15_SHA_Verifier pub(pubFile); + + FileSource signatureFile(signatureFilename, true); + 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(); +} + diff --git a/stepmania/src/verify_signature/csharp/VerifySignature.cs b/stepmania/src/verify_signature/csharp/VerifySignature.cs new file mode 100644 index 0000000000..4d0dc9e2d2 --- /dev/null +++ b/stepmania/src/verify_signature/csharp/VerifySignature.cs @@ -0,0 +1,395 @@ +// Based on http://www.jensign.com/VerifySignature/dotnet/JKeyNet/ +// Parameters: +// public_key - X.509 standard SubjectPublicKeyInfo key in binary format +// data_file - the data file whose signature to verify +// signature - the signature of data_file in binary format +using System; +using System.IO; +using System.Text; +using System.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Runtime.InteropServices; + +namespace VerifySignature +{ + + //--- P/Invoke CryptoAPI wrapper classes ----- + public class Win32 + { + + [DllImport("crypt32.dll")] + public static extern bool CryptDecodeObject( + uint CertEncodingType, + uint lpszStructType, + byte[] pbEncoded, + uint cbEncoded, + uint flags, + [In, Out] byte[] pvStructInfo, + ref uint cbStructInfo); + + + [DllImport("crypt32.dll")] + public static extern bool CryptDecodeObject( + uint CertEncodingType, + uint lpszStructType, + byte[] pbEncoded, + uint cbEncoded, + uint flags, + IntPtr pvStructInfo, + ref uint cbStructInfo); + } + + + [StructLayout(LayoutKind.Sequential)] + public struct PUBKEYBLOBHEADERS + { + public byte bType; //BLOBHEADER + public byte bVersion; //BLOBHEADER + public short reserved; //BLOBHEADER + public uint aiKeyAlg; //BLOBHEADER + public uint magic; //RSAPUBKEY + public uint bitlen; //RSAPUBKEY + public uint pubexp; //RSAPUBKEY + } + + + [StructLayout(LayoutKind.Sequential)] + public struct CERT_PUBLIC_KEY_INFO + { + public IntPtr SubjPKIAlgpszObjId; + public int SubjPKIAlgParameterscbData; + public IntPtr SubjPKIAlgParameterspbData; + public int PublicKeycbData; + public IntPtr PublicKeypbData; + public int PublicKeycUnusedBits; + } + + + public class RSAPubKeyData + { + + const uint X509_ASN_ENCODING = 0x00000001; + const uint PKCS_7_ASN_ENCODING = 0x00010000; + + const uint RSA_CSP_PUBLICKEYBLOB = 19; + const uint X509_PUBLIC_KEY_INFO = 8; + + const int AT_KEYEXCHANGE = 1; //keyspec values + const int AT_SIGNATURE = 2; + static uint ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ; + + const byte PUBLICKEYBLOB = 0x06; + const byte CUR_BLOB_VERSION = 0x02; + const ushort reserved = 0x0000; + const uint CALG_RSA_KEYX = 0x0000a400; + const uint CALG_RSA_SIGN = 0x00002400; + + + private byte[] keyModulus; // big-Endian + private byte[] keyExponent; // big-Endian + private byte[] publicKeyBlob; //Microsoft PUBLICKEYBLOB format + private uint keySize; //modulus size in bits + private bool verbose = false; + + + public uint keysize + { + get{return keySize;} + } + + public byte[] keymodulus + { + get{return keyModulus;} + } + + public byte[] keyexponent + { + get{return keyExponent;} + } + + public byte[] MSpublickeyblob + { + get{return publicKeyBlob;} + } + + public static string readFile(string file) + { + string finalStr=""; + try + { + // Create an instance of StreamReader to read from a file. + // The using statement also closes the StreamReader. + using (StreamReader sr = new StreamReader(file)) + { + String line; + // Read and display lines from the file until the end of + // the file is reached. + while ((line = sr.ReadLine()) != null) + { + //Console.WriteLine(line); + finalStr = finalStr+line; + } + return finalStr; + } + } + catch (Exception e) + { + // Let the user know what went wrong. + Console.WriteLine("The file could not be read:"); + Console.WriteLine(e.Message); + } + return null; + } + + public static void Main(String[] args) + { + RSAPubKeyData orsakey = new RSAPubKeyData(); + + if(args.Length<3) + { + Console.WriteLine("\nUsage: RSAPubKeyData.exe public_key data_fn signature_fn"); + return; + } + + String publickeyfn = args[0]; + String datafn = args[1]; + String signaturefn = args[2]; + + if (!File.Exists(publickeyfn)) + { + Console.WriteLine("File '{0}' not found.", publickeyfn); + return; + } + if (!File.Exists(datafn)) + { + Console.WriteLine("File '{0}' not found.", datafn); + return; + } + if (!File.Exists(signaturefn)) + { + Console.WriteLine("File '{0}' not found.", signaturefn); + return; + } + + Console.WriteLine("\n\n-------- Trying to decode keyfile as X.509 SubjectPublicKeyInfo format --------"); + if(!orsakey.DecodeSubjectPublicKeyInfo(publickeyfn)) + { + Console.WriteLine("FAILED to decode as X.509 SubjectPublicKeyInfo"); + return; + } + + Console.WriteLine("Decoded successfully as X.509 SubjectPublicKeyInfo"); + + RSAParameters RSAKeyInfo = new RSAParameters(); + RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); + + RSAKeyInfo.Modulus = orsakey.keymodulus; + RSAKeyInfo.Exponent = orsakey.keyexponent; + RSA.ImportParameters(RSAKeyInfo); + + byte[] data = GetFileBytes(datafn); + byte[] signature = GetFileBytes(signaturefn); + + if(RSA.VerifyData(data,"SHA1",signature)) + { + Console.WriteLine("The signature is valid."); + } + else + { + Console.WriteLine("The signature is not valid."); + } + } + + + //---- RSAPublicKey, PKCS #1 format ----- + public bool DecodeRSAPublicKey(String RSAPublicKeyfile) + { + if (!File.Exists(RSAPublicKeyfile)) + return false; + byte[] encodeddata = GetFileBytes(RSAPublicKeyfile); + return DecodeRSAPublicKey(encodeddata); + } + + + + + //---- SubjectPublicKeyInfo, X.509 standard format; e.g. Java getEncoded(); OpenSSL exported etc. + // --- decode first to RSAPublicKey encoded format ---- + public bool DecodeSubjectPublicKeyInfo(String SubjectPublicKeyInfoFile) + { + if (!File.Exists(SubjectPublicKeyInfoFile)) + return false; + byte[] subjectpublickeydata = GetFileBytes(SubjectPublicKeyInfoFile); + + IntPtr pcertpublickeyinfo = IntPtr.Zero ; + uint cbytes=0; + if(Win32.CryptDecodeObject(ENCODING_TYPE, X509_PUBLIC_KEY_INFO, subjectpublickeydata, (uint)subjectpublickeydata.Length, 0, IntPtr.Zero, ref cbytes)) + { + pcertpublickeyinfo = Marshal.AllocHGlobal((int)cbytes); + Win32.CryptDecodeObject(ENCODING_TYPE, X509_PUBLIC_KEY_INFO, subjectpublickeydata, (uint)subjectpublickeydata.Length, 0, pcertpublickeyinfo, ref cbytes); + CERT_PUBLIC_KEY_INFO pkinfo = (CERT_PUBLIC_KEY_INFO) Marshal.PtrToStructure(pcertpublickeyinfo, typeof(CERT_PUBLIC_KEY_INFO) ); + IntPtr pencodeddata = pkinfo.PublicKeypbData; + int cblob = pkinfo.PublicKeycbData ; + byte[] encodeddata = new byte[cblob]; + Marshal.Copy(pencodeddata, encodeddata, 0,cblob) ; //copy bytes from IntPtr to byte[] + Marshal.FreeHGlobal(pcertpublickeyinfo) ; + return DecodeRSAPublicKey(encodeddata); + } + else + { + return false; + } + } + + + + + + //----- decode public key and extract modulus and exponent from RSAPublicKey, PKCS #1 format byte[] ---- + public bool DecodeRSAPublicKey(byte[] encodedpubkey) + { + byte[] publickeyblob ; + + uint blobbytes=0; + if(Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB, encodedpubkey, (uint)encodedpubkey.Length, 0, null, ref blobbytes)) + { + publickeyblob = new byte[blobbytes]; + if(Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB, encodedpubkey, (uint)encodedpubkey.Length, 0, publickeyblob, ref blobbytes)) + if(verbose) + showBytes("CryptoAPI publickeyblob", publickeyblob); + } + else + { + return false; + } + this.publicKeyBlob = publickeyblob; + return DecodeMSPublicKeyBlob(publickeyblob); + } + + + + //---- Microsoft PUBLICKEYBLOB format ----- + public bool DecodeMSPublicKeyBlob(String publickeyblobfile) + { + if (!File.Exists(publickeyblobfile)) + return false; + byte[] publickeyblobdata = GetFileBytes(publickeyblobfile); + return DecodeMSPublicKeyBlob(publickeyblobdata); + } + + + + //----- Microsoft PUBLICKEYBLOB format ---- + public bool DecodeMSPublicKeyBlob(byte[] publickeyblob) + { + PUBKEYBLOBHEADERS pkheaders = new PUBKEYBLOBHEADERS() ; + int headerslength = Marshal.SizeOf(pkheaders); + IntPtr buffer = Marshal.AllocHGlobal( headerslength); + Marshal.Copy( publickeyblob, 0, buffer, headerslength ); + pkheaders = (PUBKEYBLOBHEADERS) Marshal.PtrToStructure( buffer, typeof(PUBKEYBLOBHEADERS) ); + Marshal.FreeHGlobal( buffer ); + + //----- basic sanity check of PUBLICKEYBLOB fields ------------ + if(pkheaders.bType != PUBLICKEYBLOB) + return false; + if(pkheaders.bVersion != CUR_BLOB_VERSION) + return false; + if(pkheaders.aiKeyAlg != CALG_RSA_KEYX && pkheaders.aiKeyAlg != CALG_RSA_SIGN) + return false; + + if(verbose) + { + Console.WriteLine("\n ---- PUBLICKEYBLOB headers ------"); + Console.WriteLine(" btype {0}", pkheaders.bType); + Console.WriteLine(" bversion {0}", pkheaders.bVersion); + Console.WriteLine(" reserved {0}", pkheaders.reserved); + Console.WriteLine(" aiKeyAlg 0x{0:x8}", pkheaders.aiKeyAlg); + String magicstring = (new ASCIIEncoding()).GetString(BitConverter.GetBytes(pkheaders.magic)) ; + Console.WriteLine(" magic 0x{0:x8} '{1}'", pkheaders.magic, magicstring); + Console.WriteLine(" bitlen {0}", pkheaders.bitlen); + Console.WriteLine(" pubexp {0}", pkheaders.pubexp); + Console.WriteLine(" --------------------------------"); + } + //----- Get public key size in bits ------------- + this.keySize = pkheaders.bitlen; + + //----- Get public exponent ------------- + byte[] exponent = BitConverter.GetBytes(pkheaders.pubexp); //little-endian ordered + Array.Reverse(exponent); //convert to big-endian order + this.keyExponent = exponent; + if(verbose) + showBytes("\nPublic key exponent (big-endian order):", exponent); + + //----- Get modulus ------------- + int modulusbytes = (int)pkheaders.bitlen/8 ; + byte[] modulus = new byte[modulusbytes]; + try + { + Array.Copy(publickeyblob, headerslength, modulus, 0, modulusbytes); + Array.Reverse(modulus); //convert from little to big-endian ordering. + this.keyModulus = modulus; + if(verbose) + showBytes("\nPublic key modulus (big-endian order):", modulus); + } + catch(Exception) + { + Console.WriteLine("Problem getting modulus from publickeyblob"); + return false; + } + return true; + } + + + private static byte[] GetFileBytes(String filename) + { + if(!File.Exists(filename)) + return null; + Stream stream=new FileStream(filename,FileMode.Open); + int datalen = (int)stream.Length; + byte[] filebytes =new byte[datalen]; + stream.Seek(0,SeekOrigin.Begin); + stream.Read(filebytes,0,datalen); + stream.Close(); + return filebytes; + } + + + private void PutFileBytes(String outfile, byte[] data, int bytes) + { + FileStream fs = null; + if(bytes > data.Length) + { + Console.WriteLine("Too many bytes"); + return; + } + try + { + fs = new FileStream(outfile, FileMode.Create); + fs.Write(data, 0, bytes); + } + catch(Exception e) + { + Console.WriteLine(e.Message) ; + } + finally + { + fs.Close(); + } + } + + + private static void showBytes(String info, byte[] data) + { + Console.WriteLine("{0} [{1} bytes]", info, data.Length); + for(int i=1; i<=data.Length; i++) + { + Console.Write("{0:X2} ", data[i-1]) ; + if(i%16 == 0) + Console.WriteLine(); + } + Console.WriteLine(); + } + + } +} diff --git a/stepmania/src/verify_signature/java/VerifySignature.java b/stepmania/src/verify_signature/java/VerifySignature.java new file mode 100644 index 0000000000..9b958f56fb --- /dev/null +++ b/stepmania/src/verify_signature/java/VerifySignature.java @@ -0,0 +1,221 @@ +// Based on http://www.thecodeproject.com/useritems/Porting_Java_Public_Key.asp +// Parameters: +// public_key - X.509 standard SubjectPublicKeyInfo key in binary format +// data_file - the data file whose signature to verify +// signature - the signature of data_file in binary format + +/**

Title: RSA Security

+* Description: This class generates a RSA private and public key, reinstantiates +* the keys from the corresponding key files.It also generates compatible .Net Public Key, +* which we will read later in C# program using .Net Securtiy Framework +* The reinstantiated keys are used to sign and verify the given data.

+* +* @author Shaheryar +* @version 1.0 +*/ + +import java.security.*; +import java.security.spec.*; +import java.io.*; +import java.security.interfaces.*; +import java.security.cert.*; +import javax.xml.transform.stream.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.*; +import org.w3c.dom.*; +import javax.xml.parsers.*; + +public class VerifySignature { + + private KeyPairGenerator keyGen; //Key pair generator for RSA + public PrivateKey privateKey; // Private Key Class + public PublicKey publicKey; // Public Key Class + public KeyPair keypair; // KeyPair Class + private Signature sign; // Signature, used to sign the data + /** + * Default Constructor. Instantiates the key paths and signature algorithm. + */ + public VerifySignature() { + try { + + //Get the instance of Signature Engine. + sign = Signature.getInstance("SHA1withRSA"); + } + catch (NoSuchAlgorithmException nsa) { + System.out.println("" + nsa.getMessage()); + } + } + + /** + * Initializes the public and private keys. + */ + private void initializePublicKey(String publickey_fn) { + try { + //Read key files back and decode them from BASE64 + byte[] publicKeyBytes = readKeyBytesFromFile(publickey_fn); + + // Convert back to public and private key objects + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); + publicKey = keyFactory.generatePublic(publicKeySpec); + + } + catch (IOException io) { + System.out.println( + "Public/ Private Key File Not found."+ io.getCause()); + } + catch (InvalidKeySpecException e) { + System.out.println( + "Invalid Key Specs. Not valid Key files."+ e.getCause()); + } + catch (NoSuchAlgorithmException e) { + System.out.println( + "There is no such algorithm. Please check the JDK ver."+ e.getCause()); + } + } + + /** + * Verifies the signature for the given bytes using the public key. + * @param signature Signature + * @param data Data that was signed + * @return boolean True if valid signature else false + */ + public boolean verifySignature(String publickey_fn, byte[] signature, byte[] data) { + try { + initializePublicKey(publickey_fn); + sign.initVerify(publicKey); + sign.update(data); + return sign.verify(signature); + } + catch (SignatureException e) { + e.printStackTrace(); + } + catch (InvalidKeyException e) { + } + + return false; + } + + /** + * Returns the contents of the file in a byte array. + * @param fileName File Name + * @return byte[] Teh data read from a given file as a byte array. + */ + private byte[] readKeyBytesFromFile(String fileName) throws IOException{ + File file = new File(fileName); + InputStream is = new FileInputStream(file); + + // Get the size of the file + long length = file.length(); + + // You cannot create an array using a long type. + // It needs to be an int type. + // Before converting to an int type, check + // to ensure that file is not larger than Integer.MAX_VALUE. + if (length > Integer.MAX_VALUE) { + // File is too large + } + + // Create the byte array to hold the data + byte[] bytes = new byte[ (int) length]; + + // Read in the bytes + int offset = 0; + int numRead = 0; + while (offset < bytes.length + && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { + offset += numRead; + } + + // Ensure all the bytes have been read in + if (offset < bytes.length) { + throw new IOException("Key File Error: Could not completely read file " + file.getName()); + } + + // Close the input stream and return bytes + is.close(); + return bytes; + + + } + + + public static void main(String args[]) + { + VerifySignature sm = new VerifySignature(); + + /* + Uncomment next line for first time when you run the code,it will generate the keys. + Afterwards,the application will read the generated key files from the given location. + If you want to generate the key files each time, then you should keep it uncommented always. + */ + if( args.length != 3 ) + { + System.out.println("\nUsage: RSAPubKeyData.exe publickey_fn data_fn signature_fn"); + return; + } + + + String publickeyfn = args[0]; + String datafn = args[1]; + String signaturefn = args[2]; + + + byte[] data = sm.readBytesFromFile(datafn); + byte[] signature = sm.readBytesFromFile(signaturefn); + + if( sm.verifySignature(publickeyfn,signature,data) ) + { + System.out.println("The signature is valid."); + } + else + { + System.out.println("The signature is not valid."); + } + } + + private byte[] readBytesFromFile(String fileName) + { + try + { + File file = new File(fileName); + InputStream is = new FileInputStream(file); + + // Get the size of the file + long length = file.length(); + + // You cannot create an array using a long type. + // It needs to be an int type. + // Before converting to an int type, check + // to ensure that file is not larger than Integer.MAX_VALUE. + if (length > Integer.MAX_VALUE) { + // File is too large + } + + // Create the byte array to hold the data + byte[] bytes = new byte[ (int) length]; + + // Read in the bytes + int offset = 0; + int numRead = 0; + while (offset < bytes.length + && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { + offset += numRead; + } + + // Ensure all the bytes have been read in + if (offset < bytes.length) { + throw new IOException("Key File Error: Could not completely read file " + file.getName()); + } + + // Close the input stream and return bytes + is.close(); + return bytes; + }catch(IOException ioe) + { + System.out.println("Exception occured while writing file"+ioe.getMessage()); + } + byte[] bytes = new byte[ 1]; + return bytes; + } +} \ No newline at end of file