From c06a37d98d64faa86a21a2b7588e454e31990570 Mon Sep 17 00:00:00 2001
From: psoares33
Date: Sun, 20 Jul 2008 16:50:45 +0000
Subject: [PATCH] Move from CVS.
git-svn-id: svn://svn.code.sf.net/p/itextsharp/code/trunk@4 820d3149-562b-4f88-9aa4-a8e61a3485cf
---
.../srcbc/crypto/AsymmetricCipherKeyPair.cs | 52 +
.../srcbc/crypto/AsymmetricKeyParameter.cs | 47 +
.../srcbc/crypto/BufferedAeadBlockCipher.cs | 259 ++
.../crypto/BufferedAsymmetricBlockCipher.cs | 152 +
src/core/srcbc/crypto/BufferedBlockCipher.cs | 372 ++
src/core/srcbc/crypto/BufferedCipherBase.cs | 113 +
src/core/srcbc/crypto/BufferedIesCipher.cs | 113 +
src/core/srcbc/crypto/BufferedStreamCipher.cs | 131 +
src/core/srcbc/crypto/CipherKeyGenerator.cs | 83 +
src/core/srcbc/crypto/CryptoException.cs | 25 +
src/core/srcbc/crypto/DataLengthException.cs | 39 +
.../srcbc/crypto/IAsymmetricBlockCipher.cs | 30 +
.../IAsymmetricCipherKeyPairGenerator.cs | 24 +
src/core/srcbc/crypto/IBasicAgreement.cs | 24 +
src/core/srcbc/crypto/IBlockCipher.cs | 36 +
src/core/srcbc/crypto/IBufferedCipher.cs | 44 +
src/core/srcbc/crypto/ICipherParameters.cs | 11 +
src/core/srcbc/crypto/IDSA.cs | 40 +
src/core/srcbc/crypto/IDerivationFunction.cs | 24 +
.../srcbc/crypto/IDerivationParameters.cs | 11 +
src/core/srcbc/crypto/IDigest.cs | 61 +
src/core/srcbc/crypto/IMac.cs | 69 +
src/core/srcbc/crypto/ISigner.cs | 50 +
src/core/srcbc/crypto/ISignerWithRecovery.cs | 28 +
src/core/srcbc/crypto/IStreamCipher.cs | 45 +
src/core/srcbc/crypto/IWrapper.cs | 18 +
.../crypto/InvalidCipherTextException.cs | 37 +
.../srcbc/crypto/KeyGenerationParameters.cs | 55 +
.../srcbc/crypto/MaxBytesExceededException.cs | 29 +
.../srcbc/crypto/PbeParametersGenerator.cs | 169 +
src/core/srcbc/crypto/StreamBlockCipher.cs | 109 +
.../srcbc/crypto/agreement/DHAgreement.cs | 89 +
.../crypto/agreement/DHBasicAgreement.cs | 60 +
.../crypto/agreement/ECDHBasicAgreement.cs | 50 +
.../crypto/agreement/ECDHCBasicAgreement.cs | 58 +
.../agreement/ECDHWithKdfBasicAgreement.cs | 68 +
.../crypto/agreement/kdf/DHKdfParameters.cs | 57 +
.../crypto/agreement/kdf/DHKekGenerator.cs | 129 +
.../crypto/agreement/kdf/ECDHKekGenerator.cs | 70 +
.../srcbc/crypto/digests/GOST3411Digest.cs | 338 ++
.../srcbc/crypto/digests/GeneralDigest.cs | 118 +
src/core/srcbc/crypto/digests/LongDigest.cs | 380 ++
src/core/srcbc/crypto/digests/MD2Digest.cs | 247 ++
src/core/srcbc/crypto/digests/MD4Digest.cs | 271 ++
src/core/srcbc/crypto/digests/MD5Digest.cs | 301 ++
.../srcbc/crypto/digests/RipeMD128Digest.cs | 462 +++
.../srcbc/crypto/digests/RipeMD160Digest.cs | 423 +++
.../srcbc/crypto/digests/RipeMD256Digest.cs | 409 +++
.../srcbc/crypto/digests/RipeMD320Digest.cs | 438 +++
src/core/srcbc/crypto/digests/Sha1Digest.cs | 285 ++
src/core/srcbc/crypto/digests/Sha224Digest.cs | 287 ++
src/core/srcbc/crypto/digests/Sha256Digest.cs | 310 ++
src/core/srcbc/crypto/digests/Sha384Digest.cs | 85 +
src/core/srcbc/crypto/digests/Sha512Digest.cs | 88 +
.../srcbc/crypto/digests/ShortenedDigest.cs | 82 +
src/core/srcbc/crypto/digests/TigerDigest.cs | 868 +++++
.../srcbc/crypto/digests/WhirlpoolDigest.cs | 397 +++
.../crypto/encodings/ISO9796d1Encoding.cs | 253 ++
.../srcbc/crypto/encodings/OaepEncoding.cs | 334 ++
.../srcbc/crypto/encodings/Pkcs1Encoding.cs | 229 ++
src/core/srcbc/crypto/engines/AesEngine.cs | 550 +++
.../srcbc/crypto/engines/AesFastEngine.cs | 865 +++++
.../srcbc/crypto/engines/AesLightEngine.cs | 438 +++
.../srcbc/crypto/engines/AesWrapEngine.cs | 16 +
.../srcbc/crypto/engines/BlowfishEngine.cs | 577 +++
.../srcbc/crypto/engines/CamelliaEngine.cs | 579 +++
.../crypto/engines/CamelliaWrapEngine.cs | 16 +
src/core/srcbc/crypto/engines/Cast5Engine.cs | 829 +++++
src/core/srcbc/crypto/engines/Cast6Engine.cs | 277 ++
src/core/srcbc/crypto/engines/DesEdeEngine.cs | 96 +
.../srcbc/crypto/engines/DesEdeWrapEngine.cs | 299 ++
src/core/srcbc/crypto/engines/DesEngine.cs | 493 +++
.../srcbc/crypto/engines/ElGamalEngine.cs | 178 +
.../srcbc/crypto/engines/GOST28147Engine.cs | 364 ++
src/core/srcbc/crypto/engines/HC128Engine.cs | 241 ++
src/core/srcbc/crypto/engines/HC256Engine.cs | 207 ++
src/core/srcbc/crypto/engines/ISAACEngine.cs | 252 ++
src/core/srcbc/crypto/engines/IdeaEngine.cs | 333 ++
src/core/srcbc/crypto/engines/IesEngine.cs | 236 ++
.../crypto/engines/NaccacheSternEngine.cs | 432 +++
.../srcbc/crypto/engines/NoekeonEngine.cs | 256 ++
src/core/srcbc/crypto/engines/NullEngine.cs | 70 +
src/core/srcbc/crypto/engines/RC2Engine.cs | 312 ++
.../srcbc/crypto/engines/RC2WrapEngine.cs | 372 ++
src/core/srcbc/crypto/engines/RC4Engine.cs | 147 +
src/core/srcbc/crypto/engines/RC532Engine.cs | 294 ++
src/core/srcbc/crypto/engines/RC564Engine.cs | 295 ++
src/core/srcbc/crypto/engines/RC6Engine.cs | 362 ++
.../srcbc/crypto/engines/RFC3211WrapEngine.cs | 166 +
.../srcbc/crypto/engines/RFC3394WrapEngine.cs | 181 +
.../srcbc/crypto/engines/RSABlindedEngine.cs | 139 +
.../srcbc/crypto/engines/RSABlindingEngine.cs | 139 +
.../srcbc/crypto/engines/RSACoreEngine.cs | 156 +
.../srcbc/crypto/engines/RijndaelEngine.cs | 740 ++++
src/core/srcbc/crypto/engines/RsaEngine.cs | 78 +
src/core/srcbc/crypto/engines/SEEDEngine.cs | 361 ++
.../srcbc/crypto/engines/SEEDWrapEngine.cs | 16 +
.../srcbc/crypto/engines/Salsa20Engine.cs | 363 ++
.../srcbc/crypto/engines/SerpentEngine.cs | 779 ++++
.../srcbc/crypto/engines/SkipjackEngine.cs | 255 ++
src/core/srcbc/crypto/engines/TEAEngine.cs | 191 +
.../srcbc/crypto/engines/TwofishEngine.cs | 673 ++++
src/core/srcbc/crypto/engines/VMPCEngine.cs | 139 +
.../srcbc/crypto/engines/VMPCKSA3Engine.cs | 51 +
src/core/srcbc/crypto/engines/XTEAEngine.cs | 185 +
.../generators/BaseKdfBytesGenerator.cs | 141 +
.../generators/DHBasicKeyPairGenerator.cs | 40 +
.../crypto/generators/DHKeyGeneratorHelper.cs | 78 +
.../crypto/generators/DHKeyPairGenerator.cs | 40 +
.../generators/DHParametersGenerator.cs | 45 +
.../crypto/generators/DHParametersHelper.cs | 244 ++
.../crypto/generators/DesEdeKeyGenerator.cs | 66 +
.../crypto/generators/DesKeyGenerator.cs | 34 +
.../crypto/generators/DsaKeyPairGenerator.cs | 56 +
.../generators/DsaParametersGenerator.cs | 184 +
.../crypto/generators/ECKeyPairGenerator.cs | 130 +
.../generators/ElGamalKeyPairGenerator.cs | 40 +
.../generators/ElGamalParametersGenerator.cs | 46 +
.../generators/GOST3410KeyPairGenerator.cs | 73 +
.../generators/GOST3410ParametersGenerator.cs | 530 +++
.../crypto/generators/Kdf1BytesGenerator.cs | 27 +
.../crypto/generators/Kdf2BytesGenerator.cs | 28 +
.../crypto/generators/Mgf1BytesGenerator.cs | 117 +
.../NaccacheSternKeyPairGenerator.cs | 330 ++
.../OpenSSLPBEParametersGenerator.cs | 167 +
.../generators/Pkcs12ParametersGenerator.cs | 245 ++
.../generators/Pkcs5S1ParametersGenerator.cs | 162 +
.../generators/Pkcs5S2ParametersGenerator.cs | 175 +
.../generators/RSABlindingFactorGenerator.cs | 69 +
.../crypto/generators/RsaKeyPairGenerator.cs | 139 +
src/core/srcbc/crypto/io/CipherStream.cs | 224 ++
src/core/srcbc/crypto/io/DigestStream.cs | 116 +
src/core/srcbc/crypto/io/MacStream.cs | 116 +
src/core/srcbc/crypto/macs/CMac.cs | 240 ++
.../srcbc/crypto/macs/CbcBlockCipherMac.cs | 213 ++
.../srcbc/crypto/macs/CfbBlockCipherMac.cs | 368 ++
src/core/srcbc/crypto/macs/GOST28147Mac.cs | 296 ++
src/core/srcbc/crypto/macs/HMac.cs | 141 +
src/core/srcbc/crypto/macs/ISO9797Alg3Mac.cs | 259 ++
src/core/srcbc/crypto/macs/VMPCMac.cs | 173 +
src/core/srcbc/crypto/modes/CbcBlockCipher.cs | 230 ++
src/core/srcbc/crypto/modes/CcmBlockCipher.cs | 345 ++
src/core/srcbc/crypto/modes/CfbBlockCipher.cs | 218 ++
src/core/srcbc/crypto/modes/CtsBlockCipher.cs | 253 ++
src/core/srcbc/crypto/modes/EAXBlockCipher.cs | 302 ++
src/core/srcbc/crypto/modes/GCMBlockCipher.cs | 447 +++
.../srcbc/crypto/modes/GOFBBlockCipher.cs | 223 ++
.../srcbc/crypto/modes/IAeadBlockCipher.cs | 90 +
src/core/srcbc/crypto/modes/OfbBlockCipher.cs | 178 +
.../crypto/modes/OpenPgpCfbBlockCipher.cs | 344 ++
src/core/srcbc/crypto/modes/SicBlockCipher.cs | 106 +
.../crypto/paddings/BlockCipherPadding.cs | 43 +
.../crypto/paddings/ISO10126d2Padding.cs | 76 +
.../srcbc/crypto/paddings/ISO7816d4Padding.cs | 79 +
.../paddings/PaddedBufferedBlockCipher.cs | 287 ++
.../srcbc/crypto/paddings/Pkcs7Padding.cs | 77 +
src/core/srcbc/crypto/paddings/TbcPadding.cs | 79 +
src/core/srcbc/crypto/paddings/X923Padding.cs | 82 +
.../srcbc/crypto/paddings/ZeroBytePadding.cs | 68 +
.../srcbc/crypto/parameters/AEADParameters.cs | 53 +
.../srcbc/crypto/parameters/CcmParameters.cs | 25 +
.../parameters/DHKeyGenerationParameters.cs | 25 +
.../crypto/parameters/DHKeyParameters.cs | 59 +
.../srcbc/crypto/parameters/DHParameters.cs | 178 +
.../parameters/DHPrivateKeyParameters.cs | 50 +
.../parameters/DHPublicKeyParameters.cs | 53 +
.../parameters/DHValidationParameters.cs | 59 +
.../crypto/parameters/DesEdeParameters.cs | 95 +
.../srcbc/crypto/parameters/DesParameters.cs | 130 +
.../parameters/DsaKeyGenerationParameters.cs | 26 +
.../crypto/parameters/DsaKeyParameters.cs | 59 +
.../srcbc/crypto/parameters/DsaParameters.cs | 85 +
.../parameters/DsaPrivateKeyParameters.cs | 53 +
.../parameters/DsaPublicKeyParameters.cs | 52 +
.../parameters/DsaValidationParameters.cs | 59 +
.../crypto/parameters/ECDomainParameters.cs | 116 +
.../parameters/ECKeyGenerationParameters.cs | 55 +
.../crypto/parameters/ECKeyParameters.cs | 121 +
.../parameters/ECPrivateKeyParameters.cs | 74 +
.../parameters/ECPublicKeyParameters.cs | 73 +
.../ElGamalKeyGenerationParameters.cs | 25 +
.../crypto/parameters/ElGamalKeyParameters.cs | 59 +
.../crypto/parameters/ElGamalParameters.cs | 81 +
.../parameters/ElGamalPrivateKeyParameters.cs | 53 +
.../parameters/ElGamalPublicKeyParameters.cs | 53 +
.../GOST3410KeyGenerationParameters.cs | 55 +
.../parameters/GOST3410KeyParameters.cs | 58 +
.../crypto/parameters/GOST3410Parameters.cs | 86 +
.../GOST3410PrivateKeyParameters.cs | 41 +
.../parameters/GOST3410PublicKeyParameters.cs | 40 +
.../GOST3410ValidationParameters.cs | 51 +
.../parameters/ISO18033KDFParameters.cs | 25 +
.../srcbc/crypto/parameters/IesParameters.cs | 49 +
.../parameters/IesWithCipherParameters.cs | 33 +
.../srcbc/crypto/parameters/KdfParameters.cs | 33 +
.../srcbc/crypto/parameters/KeyParameter.cs | 43 +
.../srcbc/crypto/parameters/MgfParameters.cs | 31 +
.../NaccacheSternKeyGenerationParameters.cs | 101 +
.../parameters/NaccacheSternKeyParameters.cs | 44 +
.../NaccacheSternPrivateKeyParameters.cs | 56 +
.../crypto/parameters/ParametersWithIV.cs | 44 +
.../crypto/parameters/ParametersWithRandom.cs | 48 +
.../crypto/parameters/ParametersWithSBox.cs | 24 +
.../crypto/parameters/ParametersWithSalt.cs | 39 +
.../srcbc/crypto/parameters/RC2Parameters.cs | 47 +
.../srcbc/crypto/parameters/RC5Parameters.cs | 27 +
.../parameters/RSABlindingParameters.cs | 34 +
.../parameters/RsaKeyGenerationParameters.cs | 55 +
.../crypto/parameters/RsaKeyParameters.cs | 54 +
.../parameters/RsaPrivateCrtKeyParameters.cs | 89 +
.../crypto/prng/CryptoApiRandomGenerator.cs | 61 +
.../crypto/prng/DigestRandomGenerator.cs | 107 +
.../srcbc/crypto/prng/IRandomGenerator.cs | 26 +
.../crypto/prng/ReversedWindowGenerator.cs | 98 +
.../crypto/prng/ThreadedSeedGenerator.cs | 97 +
.../srcbc/crypto/prng/VMPCRandomGenerator.cs | 115 +
.../srcbc/crypto/signers/DsaDigestSigner.cs | 158 +
src/core/srcbc/crypto/signers/DsaSigner.cs | 136 +
src/core/srcbc/crypto/signers/ECDsaSigner.cs | 150 +
.../srcbc/crypto/signers/ECGOST3410Signer.cs | 154 +
src/core/srcbc/crypto/signers/ECNRSigner.cs | 186 +
.../crypto/signers/GOST3410DigestSigner.cs | 145 +
.../srcbc/crypto/signers/GOST3410Signer.cs | 132 +
.../crypto/signers/Iso9796d2PssSigner.cs | 561 +++
.../srcbc/crypto/signers/Iso9796d2Signer.cs | 451 +++
src/core/srcbc/crypto/signers/PssSigner.cs | 299 ++
.../srcbc/crypto/signers/RsaDigestSigner.cs | 213 ++
.../srcbc/crypto/tls/AlwaysValidVerifyer.cs | 23 +
src/core/srcbc/crypto/tls/ByteQueue.cs | 125 +
src/core/srcbc/crypto/tls/Certificate.cs | 78 +
src/core/srcbc/crypto/tls/CombinedHash.cs | 70 +
.../srcbc/crypto/tls/ICertificateVerifyer.cs | 17 +
src/core/srcbc/crypto/tls/RecordStream.cs | 107 +
.../crypto/tls/TlsBlockCipherCipherSuite.cs | 196 +
src/core/srcbc/crypto/tls/TlsCipherSuite.cs | 26 +
.../srcbc/crypto/tls/TlsCipherSuiteManager.cs | 72 +
src/core/srcbc/crypto/tls/TlsException.cs | 11 +
src/core/srcbc/crypto/tls/TlsInputStream.cs | 42 +
src/core/srcbc/crypto/tls/TlsMac.cs | 86 +
.../srcbc/crypto/tls/TlsNullCipherSuite.cs | 45 +
src/core/srcbc/crypto/tls/TlsOutputStream.cs | 50 +
.../srcbc/crypto/tls/TlsProtocolHandler.cs | 1152 ++++++
src/core/srcbc/crypto/tls/TlsUtilities.cs | 223 ++
src/core/srcbc/math/BigInteger.cs | 3152 +++++++++++++++++
src/core/srcbc/math/ec/ECAlgorithms.cs | 94 +
src/core/srcbc/math/ec/ECCurve.cs | 661 ++++
src/core/srcbc/math/ec/ECFieldElement.cs | 1253 +++++++
src/core/srcbc/math/ec/ECPoint.cs | 566 +++
src/core/srcbc/math/ec/IntArray.cs | 486 +++
.../srcbc/math/ec/abc/SimpleBigDecimal.cs | 241 ++
src/core/srcbc/math/ec/abc/Tnaf.cs | 834 +++++
src/core/srcbc/math/ec/abc/ZTauElement.cs | 36 +
.../srcbc/math/ec/multiplier/ECMultiplier.cs | 18 +
.../math/ec/multiplier/FpNafMultiplier.cs | 39 +
.../srcbc/math/ec/multiplier/PreCompInfo.cs | 11 +
.../math/ec/multiplier/ReferenceMultiplier.cs | 30 +
.../math/ec/multiplier/WNafMultiplier.cs | 241 ++
.../math/ec/multiplier/WNafPreCompInfo.cs | 46 +
.../math/ec/multiplier/WTauNafMultiplier.cs | 120 +
.../math/ec/multiplier/WTauNafPreCompInfo.cs | 41 +
src/core/srcbc/ocsp/BasicOCSPResp.cs | 215 ++
src/core/srcbc/ocsp/BasicOCSPRespGenerator.cs | 318 ++
src/core/srcbc/ocsp/CertificateID.cs | 118 +
src/core/srcbc/ocsp/CertificateStatus.cs | 9 +
src/core/srcbc/ocsp/OCSPException.cs | 25 +
src/core/srcbc/ocsp/OCSPReq.cs | 263 ++
src/core/srcbc/ocsp/OCSPReqGenerator.cs | 242 ++
src/core/srcbc/ocsp/OCSPResp.cs | 100 +
src/core/srcbc/ocsp/OCSPRespGenerator.cs | 54 +
src/core/srcbc/ocsp/OCSPRespStatus.cs | 22 +
src/core/srcbc/ocsp/OCSPUtil.cs | 132 +
src/core/srcbc/ocsp/Req.cs | 38 +
src/core/srcbc/ocsp/RespData.cs | 60 +
src/core/srcbc/ocsp/RespID.cs | 86 +
src/core/srcbc/ocsp/RevokedStatus.cs | 58 +
src/core/srcbc/ocsp/SingleResp.cs | 81 +
src/core/srcbc/ocsp/UnknownStatus.cs | 15 +
src/core/srcbc/openpgp/IStreamGenerator.cs | 7 +
src/core/srcbc/openpgp/PGPKeyRing.cs | 77 +
src/core/srcbc/openpgp/PGPObject.cs | 9 +
...GPUserAttributeSubpacketVectorGenerator.cs | 28 +
src/core/srcbc/openpgp/PgpCompressedData.cs | 50 +
.../openpgp/PgpCompressedDataGenerator.cs | 177 +
.../openpgp/PgpDataValidationException.cs | 15 +
src/core/srcbc/openpgp/PgpEncryptedData.cs | 151 +
.../openpgp/PgpEncryptedDataGenerator.cs | 495 +++
.../srcbc/openpgp/PgpEncryptedDataList.cs | 71 +
src/core/srcbc/openpgp/PgpException.cs | 19 +
src/core/srcbc/openpgp/PgpExperimental.cs | 16 +
src/core/srcbc/openpgp/PgpKeyFlags.cs | 13 +
src/core/srcbc/openpgp/PgpKeyPair.cs | 67 +
src/core/srcbc/openpgp/PgpKeyRingGenerator.cs | 166 +
.../openpgp/PgpKeyValidationException.cs | 15 +
src/core/srcbc/openpgp/PgpLiteralData.cs | 56 +
.../srcbc/openpgp/PgpLiteralDataGenerator.cs | 177 +
src/core/srcbc/openpgp/PgpMarker.cs | 18 +
src/core/srcbc/openpgp/PgpObjectFactory.cs | 130 +
src/core/srcbc/openpgp/PgpOnePassSignature.cs | 179 +
.../srcbc/openpgp/PgpOnePassSignatureList.cs | 51 +
src/core/srcbc/openpgp/PgpPbeEncryptedData.cs | 135 +
src/core/srcbc/openpgp/PgpPrivateKey.cs | 42 +
src/core/srcbc/openpgp/PgpPublicKey.cs | 835 +++++
.../openpgp/PgpPublicKeyEncryptedData.cs | 233 ++
src/core/srcbc/openpgp/PgpPublicKeyRing.cs | 187 +
.../srcbc/openpgp/PgpPublicKeyRingBundle.cs | 269 ++
src/core/srcbc/openpgp/PgpSecretKey.cs | 707 ++++
src/core/srcbc/openpgp/PgpSecretKeyRing.cs | 208 ++
.../srcbc/openpgp/PgpSecretKeyRingBundle.cs | 270 ++
src/core/srcbc/openpgp/PgpSignature.cs | 409 +++
.../srcbc/openpgp/PgpSignatureGenerator.cs | 393 ++
src/core/srcbc/openpgp/PgpSignatureList.cs | 51 +
.../openpgp/PgpSignatureSubpacketGenerator.cs | 141 +
.../openpgp/PgpSignatureSubpacketVector.cs | 193 +
.../PgpUserAttributeSubpacketVector.cs | 81 +
src/core/srcbc/openpgp/PgpUtilities.cs | 431 +++
.../srcbc/openpgp/PgpV3SignatureGenerator.cs | 199 ++
.../srcbc/openpgp/WrappedGeneratorStream.cs | 25 +
src/core/srcbc/openssl/IPasswordFinder.cs | 9 +
src/core/srcbc/openssl/PEMReader.cs | 453 +++
src/core/srcbc/openssl/PEMUtilities.cs | 138 +
src/core/srcbc/openssl/PEMWriter.cs | 278 ++
src/core/srcbc/pkcs/AsymmetricKeyEntry.cs | 32 +
.../pkcs/EncryptedPrivateKeyInfoFactory.cs | 75 +
.../srcbc/pkcs/Pkcs10CertificationRequest.cs | 447 +++
src/core/srcbc/pkcs/Pkcs12Entry.cs | 64 +
src/core/srcbc/pkcs/Pkcs12Store.cs | 1129 ++++++
src/core/srcbc/pkcs/PrivateKeyInfoFactory.cs | 211 ++
src/core/srcbc/pkcs/X509CertificateEntry.cs | 32 +
src/core/srcbc/security/AgreementUtilities.cs | 99 +
src/core/srcbc/security/CipherUtilities.cs | 566 +++
src/core/srcbc/security/DigestUtilities.cs | 150 +
src/core/srcbc/security/DotNetUtilities.cs | 163 +
.../security/GeneralSecurityException.cs | 26 +
src/core/srcbc/security/GeneratorUtilities.cs | 352 ++
.../srcbc/security/InvalidKeyException.cs | 11 +
.../security/InvalidParameterException.cs | 11 +
src/core/srcbc/security/KeyException.cs | 11 +
src/core/srcbc/security/MacUtilities.cs | 220 ++
.../security/NoSuchAlgorithmException.cs | 12 +
src/core/srcbc/security/ParameterUtilities.cs | 318 ++
src/core/srcbc/security/PbeUtilities.cs | 554 +++
src/core/srcbc/security/PrivateKeyFactory.cs | 181 +
src/core/srcbc/security/PublicKeyFactory.cs | 211 ++
src/core/srcbc/security/SecureRandom.cs | 224 ++
.../security/SecurityUtilityException.cs | 33 +
src/core/srcbc/security/SignatureException.cs | 11 +
src/core/srcbc/security/SignerUtilities.cs | 517 +++
src/core/srcbc/security/WrapperUtilities.cs | 145 +
.../cert/CertificateEncodingException.cs | 11 +
.../security/cert/CertificateException.cs | 11 +
.../cert/CertificateExpiredException.cs | 11 +
.../cert/CertificateNotYetValidException.cs | 11 +
.../cert/CertificateParsingException.cs | 11 +
src/core/srcbc/security/cert/CrlException.cs | 11 +
src/core/srcbc/tsp/GenTimeAccuracy.cs | 33 +
src/core/srcbc/tsp/TSPAlgorithms.cs | 47 +
src/core/srcbc/tsp/TSPException.cs | 25 +
src/core/srcbc/tsp/TSPUtil.cs | 115 +
src/core/srcbc/tsp/TSPValidationException.cs | 39 +
src/core/srcbc/tsp/TimeStampRequest.cs | 179 +
.../srcbc/tsp/TimeStampRequestGenerator.cs | 99 +
src/core/srcbc/tsp/TimeStampResponse.cs | 173 +
.../srcbc/tsp/TimeStampResponseGenerator.cs | 150 +
src/core/srcbc/tsp/TimeStampToken.cs | 304 ++
src/core/srcbc/tsp/TimeStampTokenGenerator.cs | 252 ++
src/core/srcbc/tsp/TimeStampTokenInfo.cs | 102 +
src/core/srcbc/util/Arrays.cs | 134 +
src/core/srcbc/util/BigIntegers.cs | 28 +
src/core/srcbc/util/Platform.cs | 72 +
src/core/srcbc/util/Strings.cs | 34 +
src/core/srcbc/util/bzip2/BZip2Constants.cs | 139 +
.../srcbc/util/bzip2/CBZip2InputStream.cs | 954 +++++
.../srcbc/util/bzip2/CBZip2OutputStream.cs | 1731 +++++++++
src/core/srcbc/util/bzip2/CRC.cs | 170 +
.../util/collections/CollectionUtilities.cs | 48 +
.../srcbc/util/collections/EmptyEnumerable.cs | 44 +
.../srcbc/util/collections/EnumerableProxy.cs | 25 +
src/core/srcbc/util/collections/HashSet.cs | 63 +
src/core/srcbc/util/collections/ISet.cs | 13 +
src/core/srcbc/util/date/DateTimeObject.cs | 25 +
src/core/srcbc/util/date/DateTimeUtilities.cs | 47 +
src/core/srcbc/util/encoders/Base64.cs | 115 +
src/core/srcbc/util/encoders/Base64Encoder.cs | 307 ++
.../srcbc/util/encoders/BufferedDecoder.cs | 117 +
.../srcbc/util/encoders/BufferedEncoder.cs | 117 +
src/core/srcbc/util/encoders/Hex.cs | 114 +
src/core/srcbc/util/encoders/HexEncoder.cs | 164 +
src/core/srcbc/util/encoders/HexTranslator.cs | 108 +
src/core/srcbc/util/encoders/IEncoder.cs | 18 +
src/core/srcbc/util/encoders/Translator.cs | 19 +
src/core/srcbc/util/encoders/UrlBase64.cs | 127 +
.../srcbc/util/encoders/UrlBase64Encoder.cs | 31 +
src/core/srcbc/util/io/BaseInputStream.cs | 47 +
src/core/srcbc/util/io/BaseOutputStream.cs | 47 +
src/core/srcbc/util/io/PushbackStream.cs | 52 +
src/core/srcbc/util/io/Streams.cs | 57 +
src/core/srcbc/util/net/IPAddress.cs | 112 +
src/core/srcbc/util/zlib/Adler32.cs | 88 +
src/core/srcbc/util/zlib/Deflate.cs | 1640 +++++++++
src/core/srcbc/util/zlib/InfBlocks.cs | 618 ++++
src/core/srcbc/util/zlib/InfCodes.cs | 611 ++++
src/core/srcbc/util/zlib/InfTree.cs | 523 +++
src/core/srcbc/util/zlib/Inflate.cs | 387 ++
src/core/srcbc/util/zlib/JZlib.cs | 70 +
src/core/srcbc/util/zlib/StaticTree.cs | 152 +
src/core/srcbc/util/zlib/Tree.cs | 367 ++
.../srcbc/util/zlib/ZDeflaterOutputStream.cs | 150 +
.../srcbc/util/zlib/ZInflaterInputStream.cs | 126 +
src/core/srcbc/util/zlib/ZStream.cs | 214 ++
.../srcbc/x509/AttributeCertificateHolder.cs | 420 +++
.../srcbc/x509/AttributeCertificateIssuer.cs | 177 +
.../srcbc/x509/IX509AttributeCertificate.cs | 57 +
src/core/srcbc/x509/IX509Extension.cs | 27 +
src/core/srcbc/x509/PEMParser.cs | 94 +
src/core/srcbc/x509/PrincipalUtil.cs | 70 +
.../srcbc/x509/SubjectPublicKeyInfoFactory.cs | 178 +
src/core/srcbc/x509/X509AttrCertParser.cs | 172 +
src/core/srcbc/x509/X509Attribute.cs | 76 +
src/core/srcbc/x509/X509CertPairParser.cs | 94 +
src/core/srcbc/x509/X509Certificate.cs | 579 +++
src/core/srcbc/x509/X509CertificatePair.cs | 117 +
src/core/srcbc/x509/X509CertificateParser.cs | 182 +
src/core/srcbc/x509/X509Crl.cs | 409 +++
src/core/srcbc/x509/X509CrlEntry.cs | 201 ++
src/core/srcbc/x509/X509CrlParser.cs | 194 +
src/core/srcbc/x509/X509ExtensionBase.cs | 82 +
src/core/srcbc/x509/X509KeyUsage.cs | 59 +
src/core/srcbc/x509/X509SignatureUtil.cs | 128 +
src/core/srcbc/x509/X509Utilities.cs | 183 +
.../srcbc/x509/X509V1CertificateGenerator.cs | 205 ++
.../srcbc/x509/X509V2AttributeCertificate.cs | 239 ++
.../X509V2AttributeCertificateGenerator.cs | 180 +
src/core/srcbc/x509/X509V2CRLGenerator.cs | 261 ++
.../srcbc/x509/X509V3CertificateGenerator.cs | 303 ++
.../AuthorityKeyIdentifierStructure.cs | 105 +
.../SubjectKeyIdentifierStructure.cs | 51 +
.../srcbc/x509/extension/X509ExtensionUtil.cs | 88 +
src/core/srcbc/x509/store/IX509Selector.cs | 10 +
src/core/srcbc/x509/store/IX509Store.cs | 11 +
.../srcbc/x509/store/IX509StoreParameters.cs | 8 +
.../srcbc/x509/store/NoSuchStoreException.cs | 25 +
.../x509/store/X509AttrCertStoreSelector.cs | 376 ++
.../x509/store/X509CertPairStoreSelector.cs | 92 +
.../srcbc/x509/store/X509CertStoreSelector.cs | 337 ++
.../srcbc/x509/store/X509CollectionStore.cs | 49 +
.../store/X509CollectionStoreParameters.cs | 58 +
.../srcbc/x509/store/X509CrlStoreSelector.cs | 283 ++
.../srcbc/x509/store/X509StoreException.cs | 25 +
src/core/srcbc/x509/store/X509StoreFactory.cs | 44 +
449 files changed, 81795 insertions(+)
create mode 100644 src/core/srcbc/crypto/AsymmetricCipherKeyPair.cs
create mode 100644 src/core/srcbc/crypto/AsymmetricKeyParameter.cs
create mode 100644 src/core/srcbc/crypto/BufferedAeadBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/BufferedAsymmetricBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/BufferedBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/BufferedCipherBase.cs
create mode 100644 src/core/srcbc/crypto/BufferedIesCipher.cs
create mode 100644 src/core/srcbc/crypto/BufferedStreamCipher.cs
create mode 100644 src/core/srcbc/crypto/CipherKeyGenerator.cs
create mode 100644 src/core/srcbc/crypto/CryptoException.cs
create mode 100644 src/core/srcbc/crypto/DataLengthException.cs
create mode 100644 src/core/srcbc/crypto/IAsymmetricBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/IBasicAgreement.cs
create mode 100644 src/core/srcbc/crypto/IBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/IBufferedCipher.cs
create mode 100644 src/core/srcbc/crypto/ICipherParameters.cs
create mode 100644 src/core/srcbc/crypto/IDSA.cs
create mode 100644 src/core/srcbc/crypto/IDerivationFunction.cs
create mode 100644 src/core/srcbc/crypto/IDerivationParameters.cs
create mode 100644 src/core/srcbc/crypto/IDigest.cs
create mode 100644 src/core/srcbc/crypto/IMac.cs
create mode 100644 src/core/srcbc/crypto/ISigner.cs
create mode 100644 src/core/srcbc/crypto/ISignerWithRecovery.cs
create mode 100644 src/core/srcbc/crypto/IStreamCipher.cs
create mode 100644 src/core/srcbc/crypto/IWrapper.cs
create mode 100644 src/core/srcbc/crypto/InvalidCipherTextException.cs
create mode 100644 src/core/srcbc/crypto/KeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/MaxBytesExceededException.cs
create mode 100644 src/core/srcbc/crypto/PbeParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/StreamBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/agreement/DHAgreement.cs
create mode 100644 src/core/srcbc/crypto/agreement/DHBasicAgreement.cs
create mode 100644 src/core/srcbc/crypto/agreement/ECDHBasicAgreement.cs
create mode 100644 src/core/srcbc/crypto/agreement/ECDHCBasicAgreement.cs
create mode 100644 src/core/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs
create mode 100644 src/core/srcbc/crypto/agreement/kdf/DHKdfParameters.cs
create mode 100644 src/core/srcbc/crypto/agreement/kdf/DHKekGenerator.cs
create mode 100644 src/core/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs
create mode 100644 src/core/srcbc/crypto/digests/GOST3411Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/GeneralDigest.cs
create mode 100644 src/core/srcbc/crypto/digests/LongDigest.cs
create mode 100644 src/core/srcbc/crypto/digests/MD2Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/MD4Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/MD5Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/RipeMD128Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/RipeMD160Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/RipeMD256Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/RipeMD320Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/Sha1Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/Sha224Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/Sha256Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/Sha384Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/Sha512Digest.cs
create mode 100644 src/core/srcbc/crypto/digests/ShortenedDigest.cs
create mode 100644 src/core/srcbc/crypto/digests/TigerDigest.cs
create mode 100644 src/core/srcbc/crypto/digests/WhirlpoolDigest.cs
create mode 100644 src/core/srcbc/crypto/encodings/ISO9796d1Encoding.cs
create mode 100644 src/core/srcbc/crypto/encodings/OaepEncoding.cs
create mode 100644 src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs
create mode 100644 src/core/srcbc/crypto/engines/AesEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/AesFastEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/AesLightEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/AesWrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/BlowfishEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/CamelliaEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/CamelliaWrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/Cast5Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/Cast6Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/DesEdeEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/DesEdeWrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/DesEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/ElGamalEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/GOST28147Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/HC128Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/HC256Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/ISAACEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/IdeaEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/IesEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/NaccacheSternEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/NoekeonEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/NullEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC2Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC2WrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC4Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC532Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC564Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/RC6Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/RFC3211WrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RFC3394WrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RSABlindedEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RSABlindingEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RSACoreEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RijndaelEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/RsaEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/SEEDEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/SEEDWrapEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/Salsa20Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/SerpentEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/SkipjackEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/TEAEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/TwofishEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/VMPCEngine.cs
create mode 100644 src/core/srcbc/crypto/engines/VMPCKSA3Engine.cs
create mode 100644 src/core/srcbc/crypto/engines/XTEAEngine.cs
create mode 100644 src/core/srcbc/crypto/generators/BaseKdfBytesGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DHKeyGeneratorHelper.cs
create mode 100644 src/core/srcbc/crypto/generators/DHKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DHParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DHParametersHelper.cs
create mode 100644 src/core/srcbc/crypto/generators/DesEdeKeyGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DesKeyGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DsaKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/DsaParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/ECKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/ElGamalParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/GOST3410ParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Kdf1BytesGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Kdf2BytesGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Mgf1BytesGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/RSABlindingFactorGenerator.cs
create mode 100644 src/core/srcbc/crypto/generators/RsaKeyPairGenerator.cs
create mode 100644 src/core/srcbc/crypto/io/CipherStream.cs
create mode 100644 src/core/srcbc/crypto/io/DigestStream.cs
create mode 100644 src/core/srcbc/crypto/io/MacStream.cs
create mode 100644 src/core/srcbc/crypto/macs/CMac.cs
create mode 100644 src/core/srcbc/crypto/macs/CbcBlockCipherMac.cs
create mode 100644 src/core/srcbc/crypto/macs/CfbBlockCipherMac.cs
create mode 100644 src/core/srcbc/crypto/macs/GOST28147Mac.cs
create mode 100644 src/core/srcbc/crypto/macs/HMac.cs
create mode 100644 src/core/srcbc/crypto/macs/ISO9797Alg3Mac.cs
create mode 100644 src/core/srcbc/crypto/macs/VMPCMac.cs
create mode 100644 src/core/srcbc/crypto/modes/CbcBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/CcmBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/CfbBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/CtsBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/EAXBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/GCMBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/GOFBBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/IAeadBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/OfbBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/modes/SicBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/paddings/BlockCipherPadding.cs
create mode 100644 src/core/srcbc/crypto/paddings/ISO10126d2Padding.cs
create mode 100644 src/core/srcbc/crypto/paddings/ISO7816d4Padding.cs
create mode 100644 src/core/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs
create mode 100644 src/core/srcbc/crypto/paddings/Pkcs7Padding.cs
create mode 100644 src/core/srcbc/crypto/paddings/TbcPadding.cs
create mode 100644 src/core/srcbc/crypto/paddings/X923Padding.cs
create mode 100644 src/core/srcbc/crypto/paddings/ZeroBytePadding.cs
create mode 100644 src/core/srcbc/crypto/parameters/AEADParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/CcmParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHPrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHPublicKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DHValidationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DesEdeParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DesParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaPublicKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/DsaValidationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ECDomainParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ECKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ECKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ECPrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ECPublicKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ElGamalKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ElGamalParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410KeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410Parameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/GOST3410ValidationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ISO18033KDFParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/IesParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/IesWithCipherParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/KdfParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/KeyParameter.cs
create mode 100644 src/core/srcbc/crypto/parameters/MgfParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/ParametersWithIV.cs
create mode 100644 src/core/srcbc/crypto/parameters/ParametersWithRandom.cs
create mode 100644 src/core/srcbc/crypto/parameters/ParametersWithSBox.cs
create mode 100644 src/core/srcbc/crypto/parameters/ParametersWithSalt.cs
create mode 100644 src/core/srcbc/crypto/parameters/RC2Parameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/RC5Parameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/RSABlindingParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/RsaKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs
create mode 100644 src/core/srcbc/crypto/prng/CryptoApiRandomGenerator.cs
create mode 100644 src/core/srcbc/crypto/prng/DigestRandomGenerator.cs
create mode 100644 src/core/srcbc/crypto/prng/IRandomGenerator.cs
create mode 100644 src/core/srcbc/crypto/prng/ReversedWindowGenerator.cs
create mode 100644 src/core/srcbc/crypto/prng/ThreadedSeedGenerator.cs
create mode 100644 src/core/srcbc/crypto/prng/VMPCRandomGenerator.cs
create mode 100644 src/core/srcbc/crypto/signers/DsaDigestSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/DsaSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/ECDsaSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/ECGOST3410Signer.cs
create mode 100644 src/core/srcbc/crypto/signers/ECNRSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/GOST3410DigestSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/GOST3410Signer.cs
create mode 100644 src/core/srcbc/crypto/signers/Iso9796d2PssSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/Iso9796d2Signer.cs
create mode 100644 src/core/srcbc/crypto/signers/PssSigner.cs
create mode 100644 src/core/srcbc/crypto/signers/RsaDigestSigner.cs
create mode 100644 src/core/srcbc/crypto/tls/AlwaysValidVerifyer.cs
create mode 100644 src/core/srcbc/crypto/tls/ByteQueue.cs
create mode 100644 src/core/srcbc/crypto/tls/Certificate.cs
create mode 100644 src/core/srcbc/crypto/tls/CombinedHash.cs
create mode 100644 src/core/srcbc/crypto/tls/ICertificateVerifyer.cs
create mode 100644 src/core/srcbc/crypto/tls/RecordStream.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsCipherSuite.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsCipherSuiteManager.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsException.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsInputStream.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsMac.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsNullCipherSuite.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsOutputStream.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsProtocolHandler.cs
create mode 100644 src/core/srcbc/crypto/tls/TlsUtilities.cs
create mode 100644 src/core/srcbc/math/BigInteger.cs
create mode 100644 src/core/srcbc/math/ec/ECAlgorithms.cs
create mode 100644 src/core/srcbc/math/ec/ECCurve.cs
create mode 100644 src/core/srcbc/math/ec/ECFieldElement.cs
create mode 100644 src/core/srcbc/math/ec/ECPoint.cs
create mode 100644 src/core/srcbc/math/ec/IntArray.cs
create mode 100644 src/core/srcbc/math/ec/abc/SimpleBigDecimal.cs
create mode 100644 src/core/srcbc/math/ec/abc/Tnaf.cs
create mode 100644 src/core/srcbc/math/ec/abc/ZTauElement.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/ECMultiplier.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/FpNafMultiplier.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/PreCompInfo.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/ReferenceMultiplier.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/WNafMultiplier.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/WNafPreCompInfo.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/WTauNafMultiplier.cs
create mode 100644 src/core/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs
create mode 100644 src/core/srcbc/ocsp/BasicOCSPResp.cs
create mode 100644 src/core/srcbc/ocsp/BasicOCSPRespGenerator.cs
create mode 100644 src/core/srcbc/ocsp/CertificateID.cs
create mode 100644 src/core/srcbc/ocsp/CertificateStatus.cs
create mode 100644 src/core/srcbc/ocsp/OCSPException.cs
create mode 100644 src/core/srcbc/ocsp/OCSPReq.cs
create mode 100644 src/core/srcbc/ocsp/OCSPReqGenerator.cs
create mode 100644 src/core/srcbc/ocsp/OCSPResp.cs
create mode 100644 src/core/srcbc/ocsp/OCSPRespGenerator.cs
create mode 100644 src/core/srcbc/ocsp/OCSPRespStatus.cs
create mode 100644 src/core/srcbc/ocsp/OCSPUtil.cs
create mode 100644 src/core/srcbc/ocsp/Req.cs
create mode 100644 src/core/srcbc/ocsp/RespData.cs
create mode 100644 src/core/srcbc/ocsp/RespID.cs
create mode 100644 src/core/srcbc/ocsp/RevokedStatus.cs
create mode 100644 src/core/srcbc/ocsp/SingleResp.cs
create mode 100644 src/core/srcbc/ocsp/UnknownStatus.cs
create mode 100644 src/core/srcbc/openpgp/IStreamGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PGPKeyRing.cs
create mode 100644 src/core/srcbc/openpgp/PGPObject.cs
create mode 100644 src/core/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpCompressedData.cs
create mode 100644 src/core/srcbc/openpgp/PgpCompressedDataGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpDataValidationException.cs
create mode 100644 src/core/srcbc/openpgp/PgpEncryptedData.cs
create mode 100644 src/core/srcbc/openpgp/PgpEncryptedDataGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpEncryptedDataList.cs
create mode 100644 src/core/srcbc/openpgp/PgpException.cs
create mode 100644 src/core/srcbc/openpgp/PgpExperimental.cs
create mode 100644 src/core/srcbc/openpgp/PgpKeyFlags.cs
create mode 100644 src/core/srcbc/openpgp/PgpKeyPair.cs
create mode 100644 src/core/srcbc/openpgp/PgpKeyRingGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpKeyValidationException.cs
create mode 100644 src/core/srcbc/openpgp/PgpLiteralData.cs
create mode 100644 src/core/srcbc/openpgp/PgpLiteralDataGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpMarker.cs
create mode 100644 src/core/srcbc/openpgp/PgpObjectFactory.cs
create mode 100644 src/core/srcbc/openpgp/PgpOnePassSignature.cs
create mode 100644 src/core/srcbc/openpgp/PgpOnePassSignatureList.cs
create mode 100644 src/core/srcbc/openpgp/PgpPbeEncryptedData.cs
create mode 100644 src/core/srcbc/openpgp/PgpPrivateKey.cs
create mode 100644 src/core/srcbc/openpgp/PgpPublicKey.cs
create mode 100644 src/core/srcbc/openpgp/PgpPublicKeyEncryptedData.cs
create mode 100644 src/core/srcbc/openpgp/PgpPublicKeyRing.cs
create mode 100644 src/core/srcbc/openpgp/PgpPublicKeyRingBundle.cs
create mode 100644 src/core/srcbc/openpgp/PgpSecretKey.cs
create mode 100644 src/core/srcbc/openpgp/PgpSecretKeyRing.cs
create mode 100644 src/core/srcbc/openpgp/PgpSecretKeyRingBundle.cs
create mode 100644 src/core/srcbc/openpgp/PgpSignature.cs
create mode 100644 src/core/srcbc/openpgp/PgpSignatureGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpSignatureList.cs
create mode 100644 src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs
create mode 100644 src/core/srcbc/openpgp/PgpSignatureSubpacketVector.cs
create mode 100644 src/core/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs
create mode 100644 src/core/srcbc/openpgp/PgpUtilities.cs
create mode 100644 src/core/srcbc/openpgp/PgpV3SignatureGenerator.cs
create mode 100644 src/core/srcbc/openpgp/WrappedGeneratorStream.cs
create mode 100644 src/core/srcbc/openssl/IPasswordFinder.cs
create mode 100644 src/core/srcbc/openssl/PEMReader.cs
create mode 100644 src/core/srcbc/openssl/PEMUtilities.cs
create mode 100644 src/core/srcbc/openssl/PEMWriter.cs
create mode 100644 src/core/srcbc/pkcs/AsymmetricKeyEntry.cs
create mode 100644 src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs
create mode 100644 src/core/srcbc/pkcs/Pkcs10CertificationRequest.cs
create mode 100644 src/core/srcbc/pkcs/Pkcs12Entry.cs
create mode 100644 src/core/srcbc/pkcs/Pkcs12Store.cs
create mode 100644 src/core/srcbc/pkcs/PrivateKeyInfoFactory.cs
create mode 100644 src/core/srcbc/pkcs/X509CertificateEntry.cs
create mode 100644 src/core/srcbc/security/AgreementUtilities.cs
create mode 100644 src/core/srcbc/security/CipherUtilities.cs
create mode 100644 src/core/srcbc/security/DigestUtilities.cs
create mode 100644 src/core/srcbc/security/DotNetUtilities.cs
create mode 100644 src/core/srcbc/security/GeneralSecurityException.cs
create mode 100644 src/core/srcbc/security/GeneratorUtilities.cs
create mode 100644 src/core/srcbc/security/InvalidKeyException.cs
create mode 100644 src/core/srcbc/security/InvalidParameterException.cs
create mode 100644 src/core/srcbc/security/KeyException.cs
create mode 100644 src/core/srcbc/security/MacUtilities.cs
create mode 100644 src/core/srcbc/security/NoSuchAlgorithmException.cs
create mode 100644 src/core/srcbc/security/ParameterUtilities.cs
create mode 100644 src/core/srcbc/security/PbeUtilities.cs
create mode 100644 src/core/srcbc/security/PrivateKeyFactory.cs
create mode 100644 src/core/srcbc/security/PublicKeyFactory.cs
create mode 100644 src/core/srcbc/security/SecureRandom.cs
create mode 100644 src/core/srcbc/security/SecurityUtilityException.cs
create mode 100644 src/core/srcbc/security/SignatureException.cs
create mode 100644 src/core/srcbc/security/SignerUtilities.cs
create mode 100644 src/core/srcbc/security/WrapperUtilities.cs
create mode 100644 src/core/srcbc/security/cert/CertificateEncodingException.cs
create mode 100644 src/core/srcbc/security/cert/CertificateException.cs
create mode 100644 src/core/srcbc/security/cert/CertificateExpiredException.cs
create mode 100644 src/core/srcbc/security/cert/CertificateNotYetValidException.cs
create mode 100644 src/core/srcbc/security/cert/CertificateParsingException.cs
create mode 100644 src/core/srcbc/security/cert/CrlException.cs
create mode 100644 src/core/srcbc/tsp/GenTimeAccuracy.cs
create mode 100644 src/core/srcbc/tsp/TSPAlgorithms.cs
create mode 100644 src/core/srcbc/tsp/TSPException.cs
create mode 100644 src/core/srcbc/tsp/TSPUtil.cs
create mode 100644 src/core/srcbc/tsp/TSPValidationException.cs
create mode 100644 src/core/srcbc/tsp/TimeStampRequest.cs
create mode 100644 src/core/srcbc/tsp/TimeStampRequestGenerator.cs
create mode 100644 src/core/srcbc/tsp/TimeStampResponse.cs
create mode 100644 src/core/srcbc/tsp/TimeStampResponseGenerator.cs
create mode 100644 src/core/srcbc/tsp/TimeStampToken.cs
create mode 100644 src/core/srcbc/tsp/TimeStampTokenGenerator.cs
create mode 100644 src/core/srcbc/tsp/TimeStampTokenInfo.cs
create mode 100644 src/core/srcbc/util/Arrays.cs
create mode 100644 src/core/srcbc/util/BigIntegers.cs
create mode 100644 src/core/srcbc/util/Platform.cs
create mode 100644 src/core/srcbc/util/Strings.cs
create mode 100644 src/core/srcbc/util/bzip2/BZip2Constants.cs
create mode 100644 src/core/srcbc/util/bzip2/CBZip2InputStream.cs
create mode 100644 src/core/srcbc/util/bzip2/CBZip2OutputStream.cs
create mode 100644 src/core/srcbc/util/bzip2/CRC.cs
create mode 100644 src/core/srcbc/util/collections/CollectionUtilities.cs
create mode 100644 src/core/srcbc/util/collections/EmptyEnumerable.cs
create mode 100644 src/core/srcbc/util/collections/EnumerableProxy.cs
create mode 100644 src/core/srcbc/util/collections/HashSet.cs
create mode 100644 src/core/srcbc/util/collections/ISet.cs
create mode 100644 src/core/srcbc/util/date/DateTimeObject.cs
create mode 100644 src/core/srcbc/util/date/DateTimeUtilities.cs
create mode 100644 src/core/srcbc/util/encoders/Base64.cs
create mode 100644 src/core/srcbc/util/encoders/Base64Encoder.cs
create mode 100644 src/core/srcbc/util/encoders/BufferedDecoder.cs
create mode 100644 src/core/srcbc/util/encoders/BufferedEncoder.cs
create mode 100644 src/core/srcbc/util/encoders/Hex.cs
create mode 100644 src/core/srcbc/util/encoders/HexEncoder.cs
create mode 100644 src/core/srcbc/util/encoders/HexTranslator.cs
create mode 100644 src/core/srcbc/util/encoders/IEncoder.cs
create mode 100644 src/core/srcbc/util/encoders/Translator.cs
create mode 100644 src/core/srcbc/util/encoders/UrlBase64.cs
create mode 100644 src/core/srcbc/util/encoders/UrlBase64Encoder.cs
create mode 100644 src/core/srcbc/util/io/BaseInputStream.cs
create mode 100644 src/core/srcbc/util/io/BaseOutputStream.cs
create mode 100644 src/core/srcbc/util/io/PushbackStream.cs
create mode 100644 src/core/srcbc/util/io/Streams.cs
create mode 100644 src/core/srcbc/util/net/IPAddress.cs
create mode 100644 src/core/srcbc/util/zlib/Adler32.cs
create mode 100644 src/core/srcbc/util/zlib/Deflate.cs
create mode 100644 src/core/srcbc/util/zlib/InfBlocks.cs
create mode 100644 src/core/srcbc/util/zlib/InfCodes.cs
create mode 100644 src/core/srcbc/util/zlib/InfTree.cs
create mode 100644 src/core/srcbc/util/zlib/Inflate.cs
create mode 100644 src/core/srcbc/util/zlib/JZlib.cs
create mode 100644 src/core/srcbc/util/zlib/StaticTree.cs
create mode 100644 src/core/srcbc/util/zlib/Tree.cs
create mode 100644 src/core/srcbc/util/zlib/ZDeflaterOutputStream.cs
create mode 100644 src/core/srcbc/util/zlib/ZInflaterInputStream.cs
create mode 100644 src/core/srcbc/util/zlib/ZStream.cs
create mode 100644 src/core/srcbc/x509/AttributeCertificateHolder.cs
create mode 100644 src/core/srcbc/x509/AttributeCertificateIssuer.cs
create mode 100644 src/core/srcbc/x509/IX509AttributeCertificate.cs
create mode 100644 src/core/srcbc/x509/IX509Extension.cs
create mode 100644 src/core/srcbc/x509/PEMParser.cs
create mode 100644 src/core/srcbc/x509/PrincipalUtil.cs
create mode 100644 src/core/srcbc/x509/SubjectPublicKeyInfoFactory.cs
create mode 100644 src/core/srcbc/x509/X509AttrCertParser.cs
create mode 100644 src/core/srcbc/x509/X509Attribute.cs
create mode 100644 src/core/srcbc/x509/X509CertPairParser.cs
create mode 100644 src/core/srcbc/x509/X509Certificate.cs
create mode 100644 src/core/srcbc/x509/X509CertificatePair.cs
create mode 100644 src/core/srcbc/x509/X509CertificateParser.cs
create mode 100644 src/core/srcbc/x509/X509Crl.cs
create mode 100644 src/core/srcbc/x509/X509CrlEntry.cs
create mode 100644 src/core/srcbc/x509/X509CrlParser.cs
create mode 100644 src/core/srcbc/x509/X509ExtensionBase.cs
create mode 100644 src/core/srcbc/x509/X509KeyUsage.cs
create mode 100644 src/core/srcbc/x509/X509SignatureUtil.cs
create mode 100644 src/core/srcbc/x509/X509Utilities.cs
create mode 100644 src/core/srcbc/x509/X509V1CertificateGenerator.cs
create mode 100644 src/core/srcbc/x509/X509V2AttributeCertificate.cs
create mode 100644 src/core/srcbc/x509/X509V2AttributeCertificateGenerator.cs
create mode 100644 src/core/srcbc/x509/X509V2CRLGenerator.cs
create mode 100644 src/core/srcbc/x509/X509V3CertificateGenerator.cs
create mode 100644 src/core/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs
create mode 100644 src/core/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs
create mode 100644 src/core/srcbc/x509/extension/X509ExtensionUtil.cs
create mode 100644 src/core/srcbc/x509/store/IX509Selector.cs
create mode 100644 src/core/srcbc/x509/store/IX509Store.cs
create mode 100644 src/core/srcbc/x509/store/IX509StoreParameters.cs
create mode 100644 src/core/srcbc/x509/store/NoSuchStoreException.cs
create mode 100644 src/core/srcbc/x509/store/X509AttrCertStoreSelector.cs
create mode 100644 src/core/srcbc/x509/store/X509CertPairStoreSelector.cs
create mode 100644 src/core/srcbc/x509/store/X509CertStoreSelector.cs
create mode 100644 src/core/srcbc/x509/store/X509CollectionStore.cs
create mode 100644 src/core/srcbc/x509/store/X509CollectionStoreParameters.cs
create mode 100644 src/core/srcbc/x509/store/X509CrlStoreSelector.cs
create mode 100644 src/core/srcbc/x509/store/X509StoreException.cs
create mode 100644 src/core/srcbc/x509/store/X509StoreFactory.cs
diff --git a/src/core/srcbc/crypto/AsymmetricCipherKeyPair.cs b/src/core/srcbc/crypto/AsymmetricCipherKeyPair.cs
new file mode 100644
index 0000000..dca2522
--- /dev/null
+++ b/src/core/srcbc/crypto/AsymmetricCipherKeyPair.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a holding class for public/private parameter pairs.
+ */
+ public class AsymmetricCipherKeyPair
+ {
+ private readonly AsymmetricKeyParameter publicParameter;
+ private readonly AsymmetricKeyParameter privateParameter;
+
+ /**
+ * basic constructor.
+ *
+ * @param publicParam a public key parameters object.
+ * @param privateParam the corresponding private key parameters.
+ */
+ public AsymmetricCipherKeyPair(
+ AsymmetricKeyParameter publicParameter,
+ AsymmetricKeyParameter privateParameter)
+ {
+ if (publicParameter.IsPrivate)
+ throw new ArgumentException("Expected a public key", "publicParameter");
+ if (!privateParameter.IsPrivate)
+ throw new ArgumentException("Expected a private key", "privateParameter");
+
+ this.publicParameter = publicParameter;
+ this.privateParameter = privateParameter;
+ }
+
+ /**
+ * return the public key parameters.
+ *
+ * @return the public key parameters.
+ */
+ public AsymmetricKeyParameter Public
+ {
+ get { return publicParameter; }
+ }
+
+ /**
+ * return the private key parameters.
+ *
+ * @return the private key parameters.
+ */
+ public AsymmetricKeyParameter Private
+ {
+ get { return privateParameter; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/AsymmetricKeyParameter.cs b/src/core/srcbc/crypto/AsymmetricKeyParameter.cs
new file mode 100644
index 0000000..335b587
--- /dev/null
+++ b/src/core/srcbc/crypto/AsymmetricKeyParameter.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public class AsymmetricKeyParameter
+ : ICipherParameters
+ {
+ private readonly bool privateKey;
+
+ public AsymmetricKeyParameter(
+ bool privateKey)
+ {
+ this.privateKey = privateKey;
+ }
+
+ public bool IsPrivate
+ {
+ get { return privateKey; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ AsymmetricKeyParameter other = obj as AsymmetricKeyParameter;
+
+ if (other == null)
+ {
+ return false;
+ }
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ AsymmetricKeyParameter other)
+ {
+ return privateKey == other.privateKey;
+ }
+
+ public override int GetHashCode()
+ {
+ return privateKey.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedAeadBlockCipher.cs b/src/core/srcbc/crypto/BufferedAeadBlockCipher.cs
new file mode 100644
index 0000000..bd11f15
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedAeadBlockCipher.cs
@@ -0,0 +1,259 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The AEAD block ciphers already handle buffering internally, so this class
+ * just takes care of implementing IBufferedCipher methods.
+ */
+ public class BufferedAeadBlockCipher
+ : BufferedCipherBase
+ {
+ private readonly IAeadBlockCipher cipher;
+
+ public BufferedAeadBlockCipher(
+ IAeadBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the blocksize for the underlying cipher.
+ *
+ * @return the blocksize for the underlying cipher.
+ */
+ public override int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ return cipher.GetUpdateOutputSize(length);
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ return cipher.GetOutputSize(length);
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ return cipher.ProcessByte(input, output, outOff);
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ int outLength = GetUpdateOutputSize(1);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessByte(input, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (length < 1)
+ return null;
+
+ int outLength = GetUpdateOutputSize(length);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ return cipher.ProcessBytes(input, inOff, length, output, outOff);
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = EmptyBuffer;
+
+ int length = GetOutputSize(0);
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = DoFinal(outBytes, 0);
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ int length = GetOutputSize(inLen);
+
+ byte[] outBytes = EmptyBuffer;
+
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = (inLen > 0)
+ ? ProcessBytes(input, inOff, inLen, outBytes, 0)
+ : 0;
+
+ pos += DoFinal(outBytes, pos);
+
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output, or the input is not block size aligned and should be.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ * @exception DataLengthException if the input is not block size
+ * aligned.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ return cipher.DoFinal(output, outOff);
+ }
+
+ /**
+ * Reset the buffer and cipher. After resetting the object is in the same
+ * state as it was after the last init (if there was one).
+ */
+ public override void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedAsymmetricBlockCipher.cs b/src/core/srcbc/crypto/BufferedAsymmetricBlockCipher.cs
new file mode 100644
index 0000000..0e5bc3e
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedAsymmetricBlockCipher.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Engines;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a buffer wrapper for an asymmetric block cipher, allowing input
+ * to be accumulated in a piecemeal fashion until final processing.
+ */
+ public class BufferedAsymmetricBlockCipher
+ : BufferedCipherBase
+ {
+ private readonly IAsymmetricBlockCipher cipher;
+
+ private byte[] buffer;
+ private int bufOff;
+
+ /**
+ * base constructor.
+ *
+ * @param cipher the cipher this buffering object wraps.
+ */
+ public BufferedAsymmetricBlockCipher(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ /**
+ * return the amount of data sitting in the buffer.
+ *
+ * @return the amount of data sitting in the buffer.
+ */
+ internal int GetBufferPosition()
+ {
+ return bufOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public override int GetBlockSize()
+ {
+ return cipher.GetInputBlockSize();
+ }
+
+ public override int GetOutputSize(
+ int length)
+ {
+ return cipher.GetOutputBlockSize();
+ }
+
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ return 0;
+ }
+
+ /**
+ * initialise the buffer and the underlying cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(forEncryption, parameters);
+
+ //
+ // we allow for an extra byte where people are using their own padding
+ // mechanisms on a raw cipher.
+ //
+ this.buffer = new byte[cipher.GetInputBlockSize() + (forEncryption ? 1 : 0)];
+ this.bufOff = 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ if (bufOff >= buffer.Length)
+ throw new DataLengthException("attempt to process message to long for cipher");
+
+ buffer[bufOff++] = input;
+ return null;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return null;
+
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (bufOff + length > buffer.Length)
+ throw new DataLengthException("attempt to process message to long for cipher");
+
+ Array.Copy(input, inOff, buffer, bufOff, length);
+ bufOff += length;
+ return null;
+ }
+
+ /**
+ * process the contents of the buffer using the underlying
+ * cipher.
+ *
+ * @return the result of the encryption/decryption process on the
+ * buffer.
+ * @exception InvalidCipherTextException if we are given a garbage block.
+ */
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = bufOff > 0
+ ? cipher.ProcessBlock(buffer, 0, bufOff)
+ : EmptyBuffer;
+
+ Reset();
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ ProcessBytes(input, inOff, length);
+ return DoFinal();
+ }
+
+ /// Reset the buffer
+ public override void Reset()
+ {
+ if (buffer != null)
+ {
+ Array.Clear(buffer, 0, buffer.Length);
+ bufOff = 0;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedBlockCipher.cs b/src/core/srcbc/crypto/BufferedBlockCipher.cs
new file mode 100644
index 0000000..3c6cc49
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedBlockCipher.cs
@@ -0,0 +1,372 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+ * buffer is full and more data is being added, or on a doFinal.
+ *
+ * Note: in the case where the underlying cipher is either a CFB cipher or an
+ * OFB one the last block may not be a multiple of the block size.
+ *
+ */
+ public class BufferedBlockCipher
+ : BufferedCipherBase
+ {
+ internal byte[] buf;
+ internal int bufOff;
+ internal bool forEncryption;
+ internal IBlockCipher cipher;
+
+ /**
+ * constructor for subclasses
+ */
+ protected BufferedBlockCipher()
+ {
+ }
+
+ /**
+ * Create a buffered block cipher without padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ * false otherwise.
+ */
+ public BufferedBlockCipher(
+ IBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the blocksize for the underlying cipher.
+ *
+ * @return the blocksize for the underlying cipher.
+ */
+ public override int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+ if (leftOver == 0)
+ {
+ return total;
+ }
+ return total - leftOver + buf.Length;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ buf[bufOff++] = input;
+
+ if (bufOff == buf.Length)
+ {
+ if ((outOff + buf.Length) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ bufOff = 0;
+ return cipher.ProcessBlock(buf, 0, output, outOff);
+ }
+
+ return 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ int outLength = GetUpdateOutputSize(1);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessByte(input, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (length < 1)
+ return null;
+
+ int outLength = GetUpdateOutputSize(length);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 1)
+ {
+ if (length < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ return 0;
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ if ((outOff + outLength) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ length -= gapLen;
+ inOff += gapLen;
+ while (length > buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+ Array.Copy(input, inOff, buf, bufOff, length);
+ bufOff += length;
+ if (bufOff == buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+ bufOff = 0;
+ }
+ return resultLen;
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = EmptyBuffer;
+
+ int length = GetOutputSize(0);
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = DoFinal(outBytes, 0);
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ int length = GetOutputSize(inLen);
+
+ byte[] outBytes = EmptyBuffer;
+
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = (inLen > 0)
+ ? ProcessBytes(input, inOff, inLen, outBytes, 0)
+ : 0;
+
+ pos += DoFinal(outBytes, pos);
+
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output, or the input is not block size aligned and should be.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ * @exception DataLengthException if the input is not block size
+ * aligned.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ if (bufOff != 0)
+ {
+ if (!cipher.IsPartialBlockOkay)
+ {
+ throw new DataLengthException("data not block size aligned");
+ }
+
+ if (outOff + bufOff > output.Length)
+ {
+ throw new DataLengthException("output buffer too short for DoFinal()");
+ }
+
+ // NB: Can't copy directly, or we may write too much output
+ cipher.ProcessBlock(buf, 0, buf, 0);
+ Array.Copy(buf, 0, output, outOff, bufOff);
+ }
+
+ int resultLen = bufOff;
+
+ Reset();
+
+ return resultLen;
+ }
+
+ /**
+ * Reset the buffer and cipher. After resetting the object is in the same
+ * state as it was after the last init (if there was one).
+ */
+ public override void Reset()
+ {
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedCipherBase.cs b/src/core/srcbc/crypto/BufferedCipherBase.cs
new file mode 100644
index 0000000..f87f38c
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedCipherBase.cs
@@ -0,0 +1,113 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public abstract class BufferedCipherBase
+ : IBufferedCipher
+ {
+ protected static readonly byte[] EmptyBuffer = new byte[0];
+
+ public abstract string AlgorithmName { get; }
+
+ public abstract void Init(bool forEncryption, ICipherParameters parameters);
+
+ public abstract int GetBlockSize();
+
+ public abstract int GetOutputSize(int inputLen);
+ public abstract int GetUpdateOutputSize(int inputLen);
+
+ public abstract byte[] ProcessByte(byte input);
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = ProcessByte(input);
+ if (outBytes == null)
+ return 0;
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public virtual byte[] ProcessBytes(
+ byte[] input)
+ {
+ return ProcessBytes(input, 0, input.Length);
+ }
+
+ public abstract byte[] ProcessBytes(byte[] input, int inOff, int length);
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ byte[] output,
+ int outOff)
+ {
+ return ProcessBytes(input, 0, input.Length, output, outOff);
+ }
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = ProcessBytes(input, inOff, length);
+ if (outBytes == null)
+ return 0;
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public abstract byte[] DoFinal();
+
+ public virtual byte[] DoFinal(
+ byte[] input)
+ {
+ return DoFinal(input, 0, input.Length);
+ }
+
+ public abstract byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length);
+
+ public virtual int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = DoFinal();
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public virtual int DoFinal(
+ byte[] input,
+ byte[] output,
+ int outOff)
+ {
+ return DoFinal(input, 0, input.Length, output, outOff);
+ }
+
+ public virtual int DoFinal(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ int len = ProcessBytes(input, inOff, length, output, outOff);
+ len += DoFinal(output, outOff + len);
+ return len;
+ }
+
+ public abstract void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedIesCipher.cs b/src/core/srcbc/crypto/BufferedIesCipher.cs
new file mode 100644
index 0000000..95555c0
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedIesCipher.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public class BufferedIesCipher
+ : BufferedCipherBase
+ {
+ private readonly IesEngine engine;
+ private bool forEncryption;
+ private MemoryStream buffer = new MemoryStream();
+
+ public BufferedIesCipher(
+ IesEngine engine)
+ {
+ if (engine == null)
+ throw new ArgumentNullException("engine");
+
+ this.engine = engine;
+ }
+
+ public override string AlgorithmName
+ {
+ // TODO Create IESEngine.AlgorithmName
+ get { return "IES"; }
+ }
+
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ // TODO
+ throw Platform.CreateNotImplementedException("IES");
+ }
+
+ public override int GetBlockSize()
+ {
+ return 0;
+ }
+
+ public override int GetOutputSize(
+ int inputLen)
+ {
+ if (engine == null)
+ throw new InvalidOperationException("cipher not initialised");
+
+ int baseLen = inputLen + (int) buffer.Length;
+ return forEncryption
+ ? baseLen + 20
+ : baseLen - 20;
+ }
+
+ public override int GetUpdateOutputSize(
+ int inputLen)
+ {
+ return 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ buffer.WriteByte(input);
+ return null;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (inOff < 0)
+ throw new ArgumentException("inOff");
+ if (length < 0)
+ throw new ArgumentException("length");
+ if (inOff + length > input.Length)
+ throw new ArgumentException("invalid offset/length specified for input array");
+
+ buffer.Write(input, inOff, length);
+ return null;
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] buf = buffer.ToArray();
+
+ Reset();
+
+ return engine.ProcessBlock(buf, 0, buf.Length);
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ ProcessBytes(input, inOff, length);
+ return DoFinal();
+ }
+
+ public override void Reset()
+ {
+ buffer.SetLength(0);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/BufferedStreamCipher.cs b/src/core/srcbc/crypto/BufferedStreamCipher.cs
new file mode 100644
index 0000000..0c565b7
--- /dev/null
+++ b/src/core/srcbc/crypto/BufferedStreamCipher.cs
@@ -0,0 +1,131 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public class BufferedStreamCipher
+ : BufferedCipherBase
+ {
+ private readonly IStreamCipher cipher;
+
+ public BufferedStreamCipher(
+ IStreamCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ public override int GetBlockSize()
+ {
+ return 0;
+ }
+
+ public override int GetOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ public override int GetUpdateOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ return new byte[]{ cipher.ReturnByte(input) };
+ }
+
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ if (outOff >= output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ output[outOff] = cipher.ReturnByte(input);
+ return 1;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return null;
+
+ byte[] output = new byte[length];
+ cipher.ProcessBytes(input, inOff, length, output, 0);
+ return output;
+ }
+
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 1)
+ return 0;
+
+ if (length > 0)
+ {
+ cipher.ProcessBytes(input, inOff, length, output, outOff);
+ }
+
+ return length;
+ }
+
+ public override byte[] DoFinal()
+ {
+ Reset();
+
+ return EmptyBuffer;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return EmptyBuffer;
+
+ byte[] output = ProcessBytes(input, inOff, length);
+
+ Reset();
+
+ return output;
+ }
+
+ public override void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/CipherKeyGenerator.cs b/src/core/srcbc/crypto/CipherKeyGenerator.cs
new file mode 100644
index 0000000..afd1982
--- /dev/null
+++ b/src/core/srcbc/crypto/CipherKeyGenerator.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base class for symmetric, or secret, cipher key generators.
+ */
+ public class CipherKeyGenerator
+ {
+ protected internal SecureRandom random;
+ protected internal int strength;
+ private bool uninitialised = true;
+ private int defaultStrength;
+
+ public CipherKeyGenerator()
+ {
+ }
+
+ internal CipherKeyGenerator(
+ int defaultStrength)
+ {
+ if (defaultStrength < 1)
+ throw new ArgumentException("strength must be a positive value", "defaultStrength");
+
+ this.defaultStrength = defaultStrength;
+ }
+
+ public int DefaultStrength
+ {
+ get { return defaultStrength; }
+ }
+
+ /**
+ * initialise the key generator.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ this.uninitialised = false;
+
+ engineInit(parameters);
+ }
+
+ protected virtual void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ this.strength = (parameters.Strength + 7) / 8;
+ }
+
+ /**
+ * Generate a secret key.
+ *
+ * @return a byte array containing the key value.
+ */
+ public byte[] GenerateKey()
+ {
+ if (uninitialised)
+ {
+ if (defaultStrength < 1)
+ throw new InvalidOperationException("Generator has not been initialised");
+
+ uninitialised = false;
+
+ engineInit(new KeyGenerationParameters(new SecureRandom(), defaultStrength));
+ }
+
+ return engineGenerateKey();
+ }
+
+ protected virtual byte[] engineGenerateKey()
+ {
+ return random.GenerateSeed(strength);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/CryptoException.cs b/src/core/srcbc/crypto/CryptoException.cs
new file mode 100644
index 0000000..644bbb9
--- /dev/null
+++ b/src/core/srcbc/crypto/CryptoException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public abstract class CryptoException
+ : Exception
+ {
+ protected CryptoException()
+ {
+ }
+
+ protected CryptoException(
+ string message)
+ : base(message)
+ {
+ }
+
+ protected CryptoException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/DataLengthException.cs b/src/core/srcbc/crypto/DataLengthException.cs
new file mode 100644
index 0000000..a3476a0
--- /dev/null
+++ b/src/core/srcbc/crypto/DataLengthException.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given
+ * insufficient input. In general this exception will Get thrown rather
+ * than an ArrayOutOfBounds exception.
+ */
+ public class DataLengthException
+ : CryptoException
+ {
+ /**
+ * base constructor.
+ */
+ public DataLengthException()
+ {
+ }
+
+ /**
+ * create a DataLengthException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public DataLengthException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public DataLengthException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/IAsymmetricBlockCipher.cs b/src/core/srcbc/crypto/IAsymmetricBlockCipher.cs
new file mode 100644
index 0000000..31c5a85
--- /dev/null
+++ b/src/core/srcbc/crypto/IAsymmetricBlockCipher.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Base interface for a public/private key block cipher.
+ public interface IAsymmetricBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The maximum size, in bytes, an input block may be.
+ int GetInputBlockSize();
+
+ /// The maximum size, in bytes, an output block will be.
+ int GetOutputBlockSize();
+
+ /// Process a block.
+ /// The input buffer.
+ /// The offset into inBuf that the input block begins.
+ /// The length of the input block.
+ /// Input decrypts improperly.
+ /// Input is too large for the cipher.
+ byte[] ProcessBlock(byte[] inBuf, int inOff, int inLen);
+ }
+}
diff --git a/src/core/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs b/src/core/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs
new file mode 100644
index 0000000..0104315
--- /dev/null
+++ b/src/core/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface that a public/private key pair generator should conform to.
+ */
+ public interface IAsymmetricCipherKeyPairGenerator
+ {
+ /**
+ * intialise the key pair generator.
+ *
+ * @param the parameters the key pair is to be initialised with.
+ */
+ void Init(KeyGenerationParameters parameters);
+
+ /**
+ * return an AsymmetricCipherKeyPair containing the Generated keys.
+ *
+ * @return an AsymmetricCipherKeyPair containing the Generated keys.
+ */
+ AsymmetricCipherKeyPair GenerateKeyPair();
+ }
+}
diff --git a/src/core/srcbc/crypto/IBasicAgreement.cs b/src/core/srcbc/crypto/IBasicAgreement.cs
new file mode 100644
index 0000000..310c590
--- /dev/null
+++ b/src/core/srcbc/crypto/IBasicAgreement.cs
@@ -0,0 +1,24 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The basic interface that basic Diffie-Hellman implementations
+ * conforms to.
+ */
+ public interface IBasicAgreement
+ {
+ /**
+ * initialise the agreement engine.
+ */
+ void Init(ICipherParameters parameters);
+
+ /**
+ * given a public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ BigInteger CalculateAgreement(ICipherParameters pubKey);
+ }
+
+}
diff --git a/src/core/srcbc/crypto/IBlockCipher.cs b/src/core/srcbc/crypto/IBlockCipher.cs
new file mode 100644
index 0000000..7abb773
--- /dev/null
+++ b/src/core/srcbc/crypto/IBlockCipher.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Base interface for a symmetric key block cipher.
+ public interface IBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The block size for this cipher, in bytes.
+ int GetBlockSize();
+
+ /// Indicates whether this cipher can handle partial blocks.
+ bool IsPartialBlockOkay { get; }
+
+ /// Process a block.
+ /// The input buffer.
+ /// The offset into inBuf that the input block begins.
+ /// The output buffer.
+ /// The offset into outBuf to write the output block.
+ /// If input block is wrong size, or outBuf too small.
+ /// The number of bytes processed and produced.
+ int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/IBufferedCipher.cs b/src/core/srcbc/crypto/IBufferedCipher.cs
new file mode 100644
index 0000000..207b9f0
--- /dev/null
+++ b/src/core/srcbc/crypto/IBufferedCipher.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Block cipher engines are expected to conform to this interface.
+ public interface IBufferedCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// If true the cipher is initialised for encryption,
+ /// if false for decryption.
+ /// The key and other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ int GetBlockSize();
+
+ int GetOutputSize(int inputLen);
+
+ int GetUpdateOutputSize(int inputLen);
+
+ byte[] ProcessByte(byte input);
+ int ProcessByte(byte input, byte[] output, int outOff);
+
+ byte[] ProcessBytes(byte[] input);
+ byte[] ProcessBytes(byte[] input, int inOff, int length);
+ int ProcessBytes(byte[] input, byte[] output, int outOff);
+ int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ byte[] DoFinal();
+ byte[] DoFinal(byte[] input);
+ byte[] DoFinal(byte[] input, int inOff, int length);
+ int DoFinal(byte[] output, int outOff);
+ int DoFinal(byte[] input, byte[] output, int outOff);
+ int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ ///
+ /// Reset the cipher. After resetting the cipher is in the same state
+ /// as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/ICipherParameters.cs b/src/core/srcbc/crypto/ICipherParameters.cs
new file mode 100644
index 0000000..d2805cc
--- /dev/null
+++ b/src/core/srcbc/crypto/ICipherParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * all parameter classes implement this.
+ */
+ public interface ICipherParameters
+ {
+ }
+}
diff --git a/src/core/srcbc/crypto/IDSA.cs b/src/core/srcbc/crypto/IDSA.cs
new file mode 100644
index 0000000..5c879e1
--- /dev/null
+++ b/src/core/srcbc/crypto/IDSA.cs
@@ -0,0 +1,40 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface for classes implementing the Digital Signature Algorithm
+ */
+ public interface IDsa
+ {
+ string AlgorithmName { get; }
+
+ /**
+ * initialise the signer for signature generation or signature
+ * verification.
+ *
+ * @param forSigning true if we are generating a signature, false
+ * otherwise.
+ * @param param key parameters for signature generation.
+ */
+ void Init(bool forSigning, ICipherParameters parameters);
+
+ /**
+ * sign the passed in message (usually the output of a hash function).
+ *
+ * @param message the message to be signed.
+ * @return two big integers representing the r and s values respectively.
+ */
+ BigInteger[] GenerateSignature(byte[] message);
+
+ /**
+ * verify the message message against the signature values r and s.
+ *
+ * @param message the message that was supposed to have been signed.
+ * @param r the r signature value.
+ * @param s the s signature value.
+ */
+ bool VerifySignature(byte[] message, BigInteger r, BigInteger s);
+ }
+}
diff --git a/src/core/srcbc/crypto/IDerivationFunction.cs b/src/core/srcbc/crypto/IDerivationFunction.cs
new file mode 100644
index 0000000..f89c079
--- /dev/null
+++ b/src/core/srcbc/crypto/IDerivationFunction.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * base interface for general purpose byte derivation functions.
+ */
+ public interface IDerivationFunction
+ {
+ void Init(IDerivationParameters parameters);
+
+ /**
+ * return the message digest used as the basis for the function
+ */
+ IDigest Digest
+ {
+ get;
+ }
+
+ int GenerateBytes(byte[] output, int outOff, int length);
+ //throws DataLengthException, ArgumentException;
+ }
+
+}
diff --git a/src/core/srcbc/crypto/IDerivationParameters.cs b/src/core/srcbc/crypto/IDerivationParameters.cs
new file mode 100644
index 0000000..714fc3f
--- /dev/null
+++ b/src/core/srcbc/crypto/IDerivationParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * Parameters for key/byte stream derivation classes
+ */
+ public interface IDerivationParameters
+ {
+ }
+}
diff --git a/src/core/srcbc/crypto/IDigest.cs b/src/core/srcbc/crypto/IDigest.cs
new file mode 100644
index 0000000..b62877a
--- /dev/null
+++ b/src/core/srcbc/crypto/IDigest.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface that a message digest conforms to.
+ */
+ public interface IDigest
+ {
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ int GetDigestSize();
+
+ /**
+ * return the size, in bytes, of the internal buffer used by this digest.
+ *
+ * @return the size, in bytes, of the internal buffer used by this digest.
+ */
+ int GetByteLength();
+
+ /**
+ * update the message digest with a single byte.
+ *
+ * @param inByte the input byte to be entered.
+ */
+ void Update(byte input);
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param input the byte array containing the data.
+ * @param inOff the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ void BlockUpdate(byte[] input, int inOff, int length);
+
+ /**
+ * Close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param output the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ int DoFinal(byte[] output, int outOff);
+
+ /**
+ * reset the digest back to it's initial state.
+ */
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/IMac.cs b/src/core/srcbc/crypto/IMac.cs
new file mode 100644
index 0000000..8fea66f
--- /dev/null
+++ b/src/core/srcbc/crypto/IMac.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base interface for implementations of message authentication codes (MACs).
+ */
+ public interface IMac
+ {
+ /**
+ * Initialise the MAC.
+ *
+ * @param param the key and other data required by the MAC.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ void Init(ICipherParameters parameters);
+
+ /**
+ * Return the name of the algorithm the MAC implements.
+ *
+ * @return the name of the algorithm the MAC implements.
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * Return the block size for this MAC (in bytes).
+ *
+ * @return the block size for this MAC in bytes.
+ */
+ int GetMacSize();
+
+ /**
+ * add a single byte to the mac for processing.
+ *
+ * @param in the byte to be processed.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ */
+ void Update(byte input);
+
+ /**
+ * @param in the array containing the input.
+ * @param inOff the index in the array the data begins at.
+ * @param len the length of the input starting at inOff.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ * @exception DataLengthException if there isn't enough data in in.
+ */
+ void BlockUpdate(byte[] input, int inOff, int len);
+
+ /**
+ * Compute the final stage of the MAC writing the output to the out
+ * parameter.
+ *
+ * doFinal leaves the MAC in the same state it was after the last init.
+ *
+ * @param out the array the MAC is to be output to.
+ * @param outOff the offset into the out buffer the output is to start at.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ */
+ int DoFinal(byte[] output, int outOff);
+
+ /**
+ * Reset the MAC. At the end of resetting the MAC should be in the
+ * in the same state it was after the last init (if there was one).
+ */
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/ISigner.cs b/src/core/srcbc/crypto/ISigner.cs
new file mode 100644
index 0000000..2e13ccb
--- /dev/null
+++ b/src/core/srcbc/crypto/ISigner.cs
@@ -0,0 +1,50 @@
+
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface ISigner
+ {
+ /**
+ * Return the name of the algorithm the signer implements.
+ *
+ * @return the name of the algorithm the signer implements.
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * Initialise the signer for signing or verification.
+ *
+ * @param forSigning true if for signing, false otherwise
+ * @param param necessary parameters.
+ */
+ void Init(bool forSigning, ICipherParameters parameters);
+
+ /**
+ * update the internal digest with the byte b
+ */
+ void Update(byte input);
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ void BlockUpdate(byte[] input, int inOff, int length);
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ byte[] GenerateSignature();
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ bool VerifySignature(byte[] signature);
+
+ /**
+ * reset the internal state
+ */
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/ISignerWithRecovery.cs b/src/core/srcbc/crypto/ISignerWithRecovery.cs
new file mode 100644
index 0000000..b8bd822
--- /dev/null
+++ b/src/core/srcbc/crypto/ISignerWithRecovery.cs
@@ -0,0 +1,28 @@
+
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * Signer with message recovery.
+ */
+ public interface ISignerWithRecovery
+ : ISigner
+ {
+ /**
+ * Returns true if the signer has recovered the full message as
+ * part of signature verification.
+ *
+ * @return true if full message recovered.
+ */
+ bool HasFullMessage();
+
+ /**
+ * Returns a reference to what message was recovered (if any).
+ *
+ * @return full/partial message, null if nothing.
+ */
+ byte[] GetRecoveredMessage();
+ }
+}
diff --git a/src/core/srcbc/crypto/IStreamCipher.cs b/src/core/srcbc/crypto/IStreamCipher.cs
new file mode 100644
index 0000000..2d0e536
--- /dev/null
+++ b/src/core/srcbc/crypto/IStreamCipher.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// The interface stream ciphers conform to.
+ public interface IStreamCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// If true the cipher is initialised for encryption,
+ /// if false for decryption.
+ /// The key and other data required by the cipher.
+ ///
+ /// If the parameters argument is inappropriate.
+ ///
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// encrypt/decrypt a single byte returning the result.
+ /// the byte to be processed.
+ /// the result of processing the input byte.
+ byte ReturnByte(byte input);
+
+ ///
+ /// Process a block of bytes from input putting the result into output.
+ ///
+ /// The input byte array.
+ ///
+ /// The offset into input where the data to be processed starts.
+ ///
+ /// The number of bytes to be processed.
+ /// The output buffer the processed bytes go into.
+ ///
+ /// The offset into output the processed data starts at.
+ ///
+ /// If the output buffer is too small.
+ void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/IWrapper.cs b/src/core/srcbc/crypto/IWrapper.cs
new file mode 100644
index 0000000..8e963cb
--- /dev/null
+++ b/src/core/srcbc/crypto/IWrapper.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface IWrapper
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ void Init(bool forWrapping, ICipherParameters parameters);
+
+ byte[] Wrap(byte[] input, int inOff, int length);
+
+ byte[] Unwrap(byte[] input, int inOff, int length);
+ }
+}
diff --git a/src/core/srcbc/crypto/InvalidCipherTextException.cs b/src/core/srcbc/crypto/InvalidCipherTextException.cs
new file mode 100644
index 0000000..e862c73
--- /dev/null
+++ b/src/core/srcbc/crypto/InvalidCipherTextException.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ */
+ public class InvalidCipherTextException
+ : CryptoException
+ {
+ /**
+ * base constructor.
+ */
+ public InvalidCipherTextException()
+ {
+ }
+
+ /**
+ * create a InvalidCipherTextException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public InvalidCipherTextException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public InvalidCipherTextException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/KeyGenerationParameters.cs b/src/core/srcbc/crypto/KeyGenerationParameters.cs
new file mode 100644
index 0000000..7ae0d83
--- /dev/null
+++ b/src/core/srcbc/crypto/KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base class for parameters to key generators.
+ */
+ public class KeyGenerationParameters
+ {
+ private SecureRandom random;
+ private int strength;
+
+ /**
+ * initialise the generator with a source of randomness
+ * and a strength (in bits).
+ *
+ * @param random the random byte source.
+ * @param strength the size, in bits, of the keys we want to produce.
+ */
+ public KeyGenerationParameters(
+ SecureRandom random,
+ int strength)
+ {
+ if (random == null)
+ throw new ArgumentNullException("random");
+ if (strength < 1)
+ throw new ArgumentException("strength must be a positive value", "strength");
+
+ this.random = random;
+ this.strength = strength;
+ }
+
+ /**
+ * return the random source associated with this
+ * generator.
+ *
+ * @return the generators random source.
+ */
+ public SecureRandom Random
+ {
+ get { return random; }
+ }
+
+ /**
+ * return the bit strength for keys produced by this generator,
+ *
+ * @return the strength of the keys this generator produces (in bits).
+ */
+ public int Strength
+ {
+ get { return strength; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/MaxBytesExceededException.cs b/src/core/srcbc/crypto/MaxBytesExceededException.cs
new file mode 100644
index 0000000..ba8c40a
--- /dev/null
+++ b/src/core/srcbc/crypto/MaxBytesExceededException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// This exception is thrown whenever a cipher requires a change of key, iv
+ /// or similar after x amount of bytes enciphered
+ ///
+ public class MaxBytesExceededException
+ : CryptoException
+ {
+ public MaxBytesExceededException()
+ {
+ }
+
+ public MaxBytesExceededException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public MaxBytesExceededException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/PbeParametersGenerator.cs b/src/core/srcbc/crypto/PbeParametersGenerator.cs
new file mode 100644
index 0000000..cefc897
--- /dev/null
+++ b/src/core/srcbc/crypto/PbeParametersGenerator.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * super class for all Password Based Encyrption (Pbe) parameter generator classes.
+ */
+ public abstract class PbeParametersGenerator
+ {
+ protected byte[] mPassword;
+ protected byte[] mSalt;
+ protected int mIterationCount;
+
+ /**
+ * base constructor.
+ */
+ protected PbeParametersGenerator()
+ {
+ }
+
+ /**
+ * initialise the Pbe generator.
+ *
+ * @param password the password converted into bytes (see below).
+ * @param salt the salt to be mixed with the password.
+ * @param iterationCount the number of iterations the "mixing" function
+ * is to be applied for.
+ */
+ public virtual void Init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (salt == null)
+ throw new ArgumentNullException("salt");
+
+ this.mPassword = Arrays.Clone(password);
+ this.mSalt = Arrays.Clone(salt);
+ this.mIterationCount = iterationCount;
+ }
+
+ public virtual byte[] Password
+ {
+ get { return Arrays.Clone(mPassword); }
+ }
+
+ /**
+ * return the password byte array.
+ *
+ * @return the password byte array.
+ */
+ [Obsolete("Use 'Password' property")]
+ public byte[] GetPassword()
+ {
+ return Password;
+ }
+
+ public virtual byte[] Salt
+ {
+ get { return Arrays.Clone(mSalt); }
+ }
+
+ /**
+ * return the salt byte array.
+ *
+ * @return the salt byte array.
+ */
+ [Obsolete("Use 'Salt' property")]
+ public byte[] GetSalt()
+ {
+ return Salt;
+ }
+
+ /**
+ * return the iteration count.
+ *
+ * @return the iteration count.
+ */
+ public virtual int IterationCount
+ {
+ get { return mIterationCount; }
+ }
+
+ /**
+ * Generate derived parameters for a key of length keySize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public abstract ICipherParameters GenerateDerivedParameters(int keySize);
+ public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize);
+
+ /**
+ * Generate derived parameters for a key of length keySize, and
+ * an initialisation vector (IV) of length ivSize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @param ivSize the length, in bits, of the iv required.
+ * @return a parameters object representing a key and an IV.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public abstract ICipherParameters GenerateDerivedParameters(int keySize, int ivSize);
+ public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize, int ivSize);
+
+ /**
+ * Generate derived parameters for a key of length keySize, specifically
+ * for use with a MAC.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ public abstract ICipherParameters GenerateDerivedMacParameters(int keySize);
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * Pkcs5 (ascii, no padding)
+ *
+ * @param password a character array reqpresenting the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] Pkcs5PasswordToBytes(
+ char[] password)
+ {
+ return Encoding.ASCII.GetBytes(password);
+ }
+
+ public static byte[] Pkcs5PasswordToBytes(
+ string password)
+ {
+ return Encoding.ASCII.GetBytes(password);
+ }
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * Pkcs12 (unicode, big endian, 2 zero pad bytes at the end).
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] Pkcs12PasswordToBytes(
+ char[] password)
+ {
+ return Pkcs12PasswordToBytes(password, false);
+ }
+
+ public static byte[] Pkcs12PasswordToBytes(
+ char[] password,
+ bool wrongPkcs12Zero)
+ {
+ if (password.Length < 1)
+ {
+ return new byte[wrongPkcs12Zero ? 2 : 0];
+ }
+
+ // +1 for extra 2 pad bytes.
+ byte[] bytes = new byte[(password.Length + 1) * 2];
+
+ Encoding.BigEndianUnicode.GetBytes(password, 0, password.Length, bytes, 0);
+
+ return bytes;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/StreamBlockCipher.cs b/src/core/srcbc/crypto/StreamBlockCipher.cs
new file mode 100644
index 0000000..14af8bd
--- /dev/null
+++ b/src/core/srcbc/crypto/StreamBlockCipher.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a wrapper for block ciphers with a single byte block size, so that they
+ * can be treated like stream ciphers.
+ */
+ public class StreamBlockCipher
+ : IStreamCipher
+ {
+ private readonly IBlockCipher cipher;
+ private readonly byte[] oneByte = new byte[1];
+
+ /**
+ * basic constructor.
+ *
+ * @param cipher the block cipher to be wrapped.
+ * @exception ArgumentException if the cipher has a block size other than
+ * one.
+ */
+ public StreamBlockCipher(
+ IBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+ if (cipher.GetBlockSize() != 1)
+ throw new ArgumentException("block cipher block size != 1.", "cipher");
+
+ this.cipher = cipher;
+ }
+
+ /**
+ * initialise the underlying cipher.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param param the necessary parameters for the underlying cipher to be initialised.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the name of the algorithm we are wrapping.
+ *
+ * @return the name of the algorithm we are wrapping.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * encrypt/decrypt a single byte returning the result.
+ *
+ * @param in the byte to be processed.
+ * @return the result of processing the input byte.
+ */
+ public byte ReturnByte(
+ byte input)
+ {
+ oneByte[0] = input;
+
+ cipher.ProcessBlock(oneByte, 0, oneByte, 0);
+
+ return oneByte[0];
+ }
+
+ /**
+ * process a block of bytes from in putting the result into out.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param out the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data stars at.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (outOff + length > output.Length)
+ throw new DataLengthException("output buffer too small in ProcessBytes()");
+
+ for (int i = 0; i != length; i++)
+ {
+ cipher.ProcessBlock(input, inOff + i, output, outOff + i);
+ }
+ }
+
+ /**
+ * reset the underlying cipher. This leaves it in the same state
+ * it was at after the last init (if there was one).
+ */
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/agreement/DHAgreement.cs b/src/core/srcbc/crypto/agreement/DHAgreement.cs
new file mode 100644
index 0000000..0812c6c
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/DHAgreement.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * a Diffie-Hellman key exchange engine.
+ *
+ * note: This uses MTI/A0 key agreement in order to make the key agreement
+ * secure against passive attacks. If you're doing Diffie-Hellman and both
+ * parties have long term public keys you should look at using this. For
+ * further information have a look at RFC 2631.
+ *
+ * It's possible to extend this to more than two parties as well, for the moment
+ * that is left as an exercise for the reader.
+ */
+ public class DHAgreement
+ {
+ private DHPrivateKeyParameters key;
+ private DHParameters dhParams;
+ private BigInteger privateValue;
+ private SecureRandom random;
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ AsymmetricKeyParameter kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ kParam = (AsymmetricKeyParameter)rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (!(kParam is DHPrivateKeyParameters))
+ {
+ throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+ }
+
+ this.key = (DHPrivateKeyParameters)kParam;
+ this.dhParams = key.Parameters;
+ }
+
+ /**
+ * calculate our initial message.
+ */
+ public BigInteger CalculateMessage()
+ {
+ int bits = dhParams.P.BitLength - 1;
+
+ // TODO Should the generated numbers always have length 'P.BitLength - 1'?
+ this.privateValue = new BigInteger(bits, random).SetBit(bits - 1);
+
+ return dhParams.G.ModPow(privateValue, dhParams.P);
+ }
+
+ /**
+ * given a message from a given party and the corresponding public key
+ * calculate the next message in the agreement sequence. In this case
+ * this will represent the shared secret.
+ */
+ public BigInteger CalculateAgreement(
+ DHPublicKeyParameters pub,
+ BigInteger message)
+ {
+ if (pub == null)
+ throw new ArgumentNullException("pub");
+ if (message == null)
+ throw new ArgumentNullException("message");
+
+ if (!pub.Parameters.Equals(dhParams))
+ {
+ throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+ }
+
+ return message.ModPow(key.X, dhParams.P).Multiply(pub.Y.ModPow(privateValue, dhParams.P)).Mod(dhParams.P);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/agreement/DHBasicAgreement.cs b/src/core/srcbc/crypto/agreement/DHBasicAgreement.cs
new file mode 100644
index 0000000..3a2f3e2
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/DHBasicAgreement.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * a Diffie-Hellman key agreement class.
+ *
+ * note: This is only the basic algorithm, it doesn't take advantage of
+ * long term public keys if they are available. See the DHAgreement class
+ * for a "better" implementation.
+ */
+ public class DHBasicAgreement
+ : IBasicAgreement
+ {
+ private DHPrivateKeyParameters key;
+ private DHParameters dhParams;
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (!(parameters is DHPrivateKeyParameters))
+ {
+ throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+ }
+
+ this.key = (DHPrivateKeyParameters) parameters;
+ this.dhParams = key.Parameters;
+ }
+
+ /**
+ * given a short term public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ public BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ if (this.key == null)
+ throw new InvalidOperationException("Agreement algorithm not initialised");
+
+ DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
+
+ if (!pub.Parameters.Equals(dhParams))
+ {
+ throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+ }
+
+ return pub.Y.ModPow(key.X, dhParams.P);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/agreement/ECDHBasicAgreement.cs b/src/core/srcbc/crypto/agreement/ECDHBasicAgreement.cs
new file mode 100644
index 0000000..162bfa8
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/ECDHBasicAgreement.cs
@@ -0,0 +1,50 @@
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * P1363 7.2.1 ECSVDP-DH
+ *
+ * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+ * and [Kob87]. This primitive derives a shared secret value from one
+ * party's private key and another party's public key, where both have
+ * the same set of EC domain parameters. If two parties correctly
+ * execute this primitive, they will produce the same output. This
+ * primitive can be invoked by a scheme to derive a shared secret key;
+ * specifically, it may be used with the schemes ECKAS-DH1 and
+ * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+ * Section 7.2.2).
+ */
+ public class ECDHBasicAgreement
+ : IBasicAgreement
+ {
+ private ECPrivateKeyParameters key;
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+
+ public virtual BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+ ECPoint P = pub.Q.Multiply(key.D);
+
+ // if ( p.IsInfinity ) throw new Exception("d*Q == infinity");
+
+ return P.X.ToBigInteger();
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/agreement/ECDHCBasicAgreement.cs b/src/core/srcbc/crypto/agreement/ECDHCBasicAgreement.cs
new file mode 100644
index 0000000..3bfa3e3
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/ECDHCBasicAgreement.cs
@@ -0,0 +1,58 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * P1363 7.2.2 ECSVDP-DHC
+ *
+ * ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version with cofactor multiplication. It is based on
+ * the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
+ * primitive derives a shared secret value from one party's private key
+ * and another party's public key, where both have the same set of EC
+ * domain parameters. If two parties correctly execute this primitive,
+ * they will produce the same output. This primitive can be invoked by a
+ * scheme to derive a shared secret key; specifically, it may be used
+ * with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
+ * validity of the input public key (see also Section 7.2.1).
+ *
+ * Note: As stated P1363 compatibility mode with ECDH can be preset, and
+ * in this case the implementation doesn't have a ECDH compatibility mode
+ * (if you want that just use ECDHBasicAgreement and note they both implement
+ * BasicAgreement!).
+ */
+ public class ECDHCBasicAgreement
+ : IBasicAgreement
+ {
+ private ECPrivateKeyParameters key;
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ this.key = (ECPrivateKeyParameters)parameters;
+ }
+
+ public BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+ ECDomainParameters parameters = pub.Parameters;
+ ECPoint P = pub.Q.Multiply(parameters.H.Multiply(key.D));
+
+ // if ( p.IsInfinity ) throw new Exception("Invalid public key");
+
+ return P.X.ToBigInteger();
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/src/core/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs
new file mode 100644
index 0000000..0b0f3d2
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public class ECDHWithKdfBasicAgreement
+ : ECDHBasicAgreement
+ {
+ private static readonly Hashtable algorithms = new Hashtable();
+
+ static ECDHWithKdfBasicAgreement()
+ {
+ algorithms.Add(NistObjectIdentifiers.IdAes128Cbc.Id, 128);
+ algorithms.Add(NistObjectIdentifiers.IdAes192Cbc.Id, 192);
+ algorithms.Add(NistObjectIdentifiers.IdAes256Cbc.Id, 256);
+ algorithms.Add(NistObjectIdentifiers.IdAes128Wrap.Id, 128);
+ algorithms.Add(NistObjectIdentifiers.IdAes192Wrap.Id, 192);
+ algorithms.Add(NistObjectIdentifiers.IdAes256Wrap.Id, 256);
+ algorithms.Add(PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id, 192);
+ }
+
+ private readonly string algorithm;
+ private readonly IDerivationFunction kdf;
+
+ public ECDHWithKdfBasicAgreement(
+ string algorithm,
+ IDerivationFunction kdf)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (!algorithms.Contains(algorithm))
+ throw new ArgumentException("Unknown algorithm", "algorithm");
+ if (kdf == null)
+ throw new ArgumentNullException("kdf");
+
+ this.algorithm = algorithm;
+ this.kdf = kdf;
+ }
+
+ public override BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ BigInteger result = base.CalculateAgreement(pubKey);
+
+ int keySize = (int) algorithms[algorithm];
+
+ DHKdfParameters dhKdfParams = new DHKdfParameters(
+ new DerObjectIdentifier(algorithm),
+ keySize,
+ // TODO Fix the way bytes are derived from the secret
+ result.ToByteArrayUnsigned());
+
+ kdf.Init(dhKdfParams);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
+
+ return new BigInteger(1, keyBytes);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/agreement/kdf/DHKdfParameters.cs b/src/core/srcbc/crypto/agreement/kdf/DHKdfParameters.cs
new file mode 100644
index 0000000..eee337e
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/kdf/DHKdfParameters.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ public class DHKdfParameters
+ : IDerivationParameters
+ {
+ private readonly DerObjectIdentifier algorithm;
+ private readonly int keySize;
+ private readonly byte[] z;
+ private readonly byte[] extraInfo;
+
+ public DHKdfParameters(
+ DerObjectIdentifier algorithm,
+ int keySize,
+ byte[] z)
+ : this(algorithm, keySize, z, null)
+ {
+ }
+
+ public DHKdfParameters(
+ DerObjectIdentifier algorithm,
+ int keySize,
+ byte[] z,
+ byte[] extraInfo)
+ {
+ this.algorithm = algorithm;
+ this.keySize = keySize;
+ this.z = z; // TODO Clone?
+ this.extraInfo = extraInfo;
+ }
+
+ public DerObjectIdentifier Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ public int KeySize
+ {
+ get { return keySize; }
+ }
+
+ public byte[] GetZ()
+ {
+ // TODO Clone?
+ return z;
+ }
+
+ public byte[] GetExtraInfo()
+ {
+ // TODO Clone?
+ return extraInfo;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/agreement/kdf/DHKekGenerator.cs b/src/core/srcbc/crypto/agreement/kdf/DHKekGenerator.cs
new file mode 100644
index 0000000..e2a00ad
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/kdf/DHKekGenerator.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ /**
+ * RFC 2631 Diffie-hellman KEK derivation function.
+ */
+ public class DHKekGenerator
+ : IDerivationFunction
+ {
+ private readonly IDigest digest;
+
+ private DerObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+ private byte[] partyAInfo;
+
+ public DHKekGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ public void Init(
+ IDerivationParameters param)
+ {
+ DHKdfParameters parameters = (DHKdfParameters)param;
+
+ this.algorithm = parameters.Algorithm;
+ this.keySize = parameters.KeySize;
+ this.z = parameters.GetZ(); // TODO Clone?
+ this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
+ }
+
+ public IDigest Digest
+ {
+ get { return digest; }
+ }
+
+ public int GenerateBytes(
+ byte[] outBytes,
+ int outOff,
+ int len)
+ {
+ if ((outBytes.Length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = len;
+ int outLen = digest.GetDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new ArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ int counter = 1;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.BlockUpdate(z, 0, z.Length);
+
+ // KeySpecificInfo
+ DerSequence keyInfo = new DerSequence(
+ algorithm,
+ new DerOctetString(integerToBytes(counter)));
+
+ // OtherInfo
+ Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
+
+ if (partyAInfo != null)
+ {
+ v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
+ }
+
+ v1.Add(new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
+
+ byte[] other = new DerSequence(v1).GetDerEncoded();
+
+ digest.BlockUpdate(other, 0, other.Length);
+
+ digest.DoFinal(dig, 0);
+
+ if (len > outLen)
+ {
+ Array.Copy(dig, 0, outBytes, outOff, outLen);
+ outOff += outLen;
+ len -= outLen;
+ }
+ else
+ {
+ Array.Copy(dig, 0, outBytes, outOff, len);
+ }
+
+ counter++;
+ }
+
+ digest.Reset();
+
+ return len;
+ }
+
+ private byte[] integerToBytes(
+ int keySize)
+ {
+ byte[] val = new byte[4];
+
+ val[0] = (byte)(keySize >> 24);
+ val[1] = (byte)(keySize >> 16);
+ val[2] = (byte)(keySize >> 8);
+ val[3] = (byte)keySize;
+
+ return val;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs b/src/core/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs
new file mode 100644
index 0000000..810153e
--- /dev/null
+++ b/src/core/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ /**
+ * X9.63 based key derivation function for ECDH CMS.
+ */
+ public class ECDHKekGenerator
+ : IDerivationFunction
+ {
+ private readonly IDerivationFunction kdf;
+
+ private DerObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+
+ public ECDHKekGenerator(
+ IDigest digest)
+ {
+ this.kdf = new Kdf2BytesGenerator(digest);
+ }
+
+ public void Init(
+ IDerivationParameters param)
+ {
+ DHKdfParameters parameters = (DHKdfParameters)param;
+
+ this.algorithm = parameters.Algorithm;
+ this.keySize = parameters.KeySize;
+ this.z = parameters.GetZ(); // TODO Clone?
+ }
+
+ public IDigest Digest
+ {
+ get { return kdf.Digest; }
+ }
+
+ public int GenerateBytes(
+ byte[] outBytes,
+ int outOff,
+ int len)
+ {
+ // ECC-CMS-SharedInfo
+ DerSequence s = new DerSequence(
+ new AlgorithmIdentifier(algorithm, DerNull.Instance),
+ new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
+
+ kdf.Init(new KdfParameters(z, s.GetDerEncoded()));
+
+ return kdf.GenerateBytes(outBytes, outOff, len);
+ }
+
+ private byte[] integerToBytes(int keySize)
+ {
+ byte[] val = new byte[4];
+
+ val[0] = (byte)(keySize >> 24);
+ val[1] = (byte)(keySize >> 16);
+ val[2] = (byte)(keySize >> 8);
+ val[3] = (byte)keySize;
+
+ return val;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/GOST3411Digest.cs b/src/core/srcbc/crypto/digests/GOST3411Digest.cs
new file mode 100644
index 0000000..9326d43
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/GOST3411Digest.cs
@@ -0,0 +1,338 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of GOST R 34.11-94
+ */
+ public class Gost3411Digest
+ : IDigest
+ {
+ private const int DIGEST_LENGTH = 32;
+
+ private byte[] H = new byte[32], L = new byte[32],
+ M = new byte[32], Sum = new byte[32];
+ private byte[][] C = new byte[4][];
+
+ private byte[] xBuf = new byte[32];
+ private int xBufOff;
+ private long byteCount;
+
+ private readonly IBlockCipher cipher = new Gost28147Engine();
+
+ /**
+ * Standard constructor
+ */
+ public Gost3411Digest()
+ {
+ // TODO Is it possible to declare multi-dimensional arrays as in Java?
+ for (int i = 0; i < 4; ++i)
+ {
+ C[i] = new byte[32];
+ }
+
+ cipher.Init(true, new ParametersWithSBox(null, Gost28147Engine.GetSBox("D-A")));
+
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Gost3411Digest(Gost3411Digest t)
+ : this()
+ {
+// cipher.Init(true, new ParametersWithSBox(null, Gost28147Engine.GetSBox("D-A")));
+//
+// Reset();
+
+ Array.Copy(t.H, 0, this.H, 0, t.H.Length);
+ Array.Copy(t.L, 0, this.L, 0, t.L.Length);
+ Array.Copy(t.M, 0, this.M, 0, t.M.Length);
+ Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
+ Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
+ Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
+ Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
+ Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
+
+ this.xBufOff = t.xBufOff;
+ this.byteCount = t.byteCount;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Gost3411"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ public void Update(
+ byte input)
+ {
+ xBuf[xBufOff++] = input;
+ if (xBufOff == xBuf.Length)
+ {
+ sumByteArray(xBuf); // calc sum M
+ processBlock(xBuf, 0);
+ xBufOff = 0;
+ }
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ while (length > xBuf.Length)
+ {
+ Array.Copy(input, inOff, xBuf, 0, xBuf.Length);
+
+ sumByteArray(xBuf); // calc sum M
+ processBlock(xBuf, 0);
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount += xBuf.Length;
+ }
+
+ // load in the remainder.
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+ }
+
+ // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8
+ private byte[] K = new byte[32];
+
+ private byte[] P(byte[] input)
+ {
+ int fourK = 0;
+ for(int k = 0; k < 8; k++)
+ {
+ K[fourK++] = input[k];
+ K[fourK++] = input[8 + k];
+ K[fourK++] = input[16 + k];
+ K[fourK++] = input[24 + k];
+ }
+
+ return K;
+ }
+
+ //A (x) = (x0 ^ x1) || x3 || x2 || x1
+ byte[] a = new byte[8];
+ private byte[] A(byte[] input)
+ {
+ for(int j=0; j<8; j++)
+ {
+ a[j]=(byte)(input[j] ^ input[j+8]);
+ }
+
+ Array.Copy(input, 8, input, 0, 24);
+ Array.Copy(a, 0, input, 24, 8);
+
+ return input;
+ }
+
+ //Encrypt function, ECB mode
+ private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff)
+ {
+ cipher.Init(true, new KeyParameter(key));
+
+ cipher.ProcessBlock(input, inOff, s, sOff);
+ }
+
+ // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
+ internal short[] wS = new short[16], w_S = new short[16];
+
+ private void fw(byte[] input)
+ {
+ cpyBytesToShort(input, wS);
+ w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
+ Array.Copy(wS, 1, w_S, 0, 15);
+ cpyShortToBytes(w_S, input);
+ }
+
+ // block processing
+ internal byte[] S = new byte[32], U = new byte[32], V = new byte[32], W = new byte[32];
+
+ private void processBlock(byte[] input, int inOff)
+ {
+ Array.Copy(input, inOff, M, 0, 32);
+
+ //key step 1
+
+ // H = h3 || h2 || h1 || h0
+ // S = s3 || s2 || s1 || s0
+ H.CopyTo(U, 0);
+ M.CopyTo(V, 0);
+ for (int j=0; j<32; j++)
+ {
+ W[j] = (byte)(U[j]^V[j]);
+ }
+ // Encrypt gost28147-ECB
+ E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
+
+ //keys step 2,3,4
+ for (int i=1; i<4; i++)
+ {
+ byte[] tmpA = A(U);
+ for (int j=0; j<32; j++)
+ {
+ U[j] = (byte)(tmpA[j] ^ C[i][j]);
+ }
+ V = A(A(V));
+ for (int j=0; j<32; j++)
+ {
+ W[j] = (byte)(U[j]^V[j]);
+ }
+ // Encrypt gost28147-ECB
+ E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
+ }
+
+ // x(M, H) = y61(H^y(M^y12(S)))
+ for(int n = 0; n < 12; n++)
+ {
+ fw(S);
+ }
+ for(int n = 0; n < 32; n++)
+ {
+ S[n] = (byte)(S[n] ^ M[n]);
+ }
+
+ fw(S);
+
+ for(int n = 0; n < 32; n++)
+ {
+ S[n] = (byte)(H[n] ^ S[n]);
+ }
+ for(int n = 0; n < 61; n++)
+ {
+ fw(S);
+ }
+ Array.Copy(S, 0, H, 0, H.Length);
+ }
+
+ private void finish()
+ {
+ LongToBytes(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount)
+
+ while (xBufOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ processBlock(L, 0);
+ processBlock(Sum, 0);
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ finish();
+
+ H.CopyTo(output, outOff);
+
+ Reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ private static readonly byte[] C2 = {
+ 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,
+ (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,
+ 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF,
+ (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF
+ };
+
+ public void Reset()
+ {
+ byteCount = 0;
+ xBufOff = 0;
+
+ Array.Clear(H, 0, H.Length);
+ Array.Clear(L, 0, L.Length);
+ Array.Clear(M, 0, M.Length);
+ Array.Clear(C[1], 0, C[1].Length); // real index C = +1 because index array with 0.
+ Array.Clear(C[3], 0, C[3].Length);
+ Array.Clear(Sum, 0, Sum.Length);
+ Array.Clear(xBuf, 0, xBuf.Length);
+
+ C2.CopyTo(C[2], 0);
+ }
+
+ // 256 bitsblock modul -> (Sum + a mod (2^256))
+ private void sumByteArray(
+ byte[] input)
+ {
+ int carry = 0;
+
+ for (int i = 0; i != Sum.Length; i++)
+ {
+ int sum = (Sum[i] & 0xff) + (input[i] & 0xff) + carry;
+
+ Sum[i] = (byte)sum;
+
+ carry = sum >> 8;
+ }
+ }
+
+ // TODO Refactor as utility function
+ private static void LongToBytes(
+ long r,
+ byte[] output,
+ int outOff)
+ {
+ output[outOff + 7] = (byte)(r >> 56);
+ output[outOff + 6] = (byte)(r >> 48);
+ output[outOff + 5] = (byte)(r >> 40);
+ output[outOff + 4] = (byte)(r >> 32);
+ output[outOff + 3] = (byte)(r >> 24);
+ output[outOff + 2] = (byte)(r >> 16);
+ output[outOff + 1] = (byte)(r >> 8);
+ output[outOff] = (byte)r;
+ }
+
+ private static void cpyBytesToShort(byte[] S, short[] wS)
+ {
+ for(int i = 0; i < S.Length / 2; i++)
+ {
+ wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF));
+ }
+ }
+
+ private static void cpyShortToBytes(short[] wS, byte[] S)
+ {
+ for(int i=0; i> 8);
+ S[i*2] = (byte)wS[i];
+ }
+ }
+
+ public int GetByteLength()
+ {
+ return 32;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/GeneralDigest.cs b/src/core/srcbc/crypto/digests/GeneralDigest.cs
new file mode 100644
index 0000000..89f76f6
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/GeneralDigest.cs
@@ -0,0 +1,118 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ */
+ public abstract class GeneralDigest
+ : IDigest
+ {
+ private const int BYTE_LENGTH = 64;
+
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount;
+
+ internal GeneralDigest()
+ {
+ xBuf = new byte[4];
+ }
+
+ internal GeneralDigest(GeneralDigest t)
+ {
+ xBuf = new byte[t.xBuf.Length];
+ Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+ xBufOff = t.xBufOff;
+ byteCount = t.byteCount;
+ }
+
+ public void Update(byte input)
+ {
+ xBuf[xBufOff++] = input;
+
+ if (xBufOff == xBuf.Length)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > xBuf.Length)
+ {
+ ProcessWord(input, inOff);
+
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount += xBuf.Length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+
+ public void Finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ //
+ // add the pad bytes.
+ //
+ Update((byte)128);
+
+ while (xBufOff != 0) Update((byte)0);
+ ProcessLength(bitLength);
+ ProcessBlock();
+ }
+
+ public virtual void Reset()
+ {
+ byteCount = 0;
+ xBufOff = 0;
+ for ( int i = 0; i < xBuf.Length; i++ ) xBuf[i] = 0;
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ internal abstract void ProcessWord(byte[] input, int inOff);
+ internal abstract void ProcessLength(long bitLength);
+ internal abstract void ProcessBlock();
+ public abstract string AlgorithmName { get; }
+ public abstract int GetDigestSize();
+ public abstract int DoFinal(byte[] output, int outOff);
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/LongDigest.cs b/src/core/srcbc/crypto/digests/LongDigest.cs
new file mode 100644
index 0000000..8ff6eb0
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/LongDigest.cs
@@ -0,0 +1,380 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Base class for SHA-384 and SHA-512.
+ */
+ public abstract class LongDigest
+ : IDigest
+ {
+ private int MyByteLength = 128;
+
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount1;
+ private long byteCount2;
+
+ internal long H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private long[] W = new long[80];
+ private int wOff;
+
+ /**
+ * Constructor for variable length word
+ */
+ internal LongDigest()
+ {
+ xBuf = new byte[8];
+
+ Reset();
+ }
+
+ /**
+ * Copy constructor. We are using copy constructors in place
+ * of the object.Clone() interface as this interface is not
+ * supported by J2ME.
+ */
+ internal LongDigest(
+ LongDigest t)
+ {
+ xBuf = new byte[t.xBuf.Length];
+ Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+ xBufOff = t.xBufOff;
+ byteCount1 = t.byteCount1;
+ byteCount2 = t.byteCount2;
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.W, 0, W, 0, t.W.Length);
+ wOff = t.wOff;
+ }
+
+ public void Update(
+ byte input)
+ {
+ xBuf[xBufOff++] = input;
+
+ if (xBufOff == xBuf.Length)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount1++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > xBuf.Length)
+ {
+ ProcessWord(input, inOff);
+
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount1 += xBuf.Length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+
+ public void Finish()
+ {
+ AdjustByteCounts();
+
+ long lowBitLength = byteCount1 << 3;
+ long hiBitLength = byteCount2;
+
+ //
+ // add the pad bytes.
+ //
+ Update((byte)128);
+
+ while (xBufOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ ProcessLength(lowBitLength, hiBitLength);
+
+ ProcessBlock();
+ }
+
+ public virtual void Reset()
+ {
+ byteCount1 = 0;
+ byteCount2 = 0;
+
+ xBufOff = 0;
+ for ( int i = 0; i < xBuf.Length; i++ )
+ {
+ xBuf[i] = 0;
+ }
+
+ wOff = 0;
+ for (int i = 0; i != W.Length; i++)
+ {
+ W[i] = 0;
+ }
+ }
+
+ internal void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ W[wOff++] = ((long)(input[inOff] & 0xff) << 56)
+ | ((long)(input[inOff + 1] & 0xff) << 48)
+ | ((long)(input[inOff + 2] & 0xff) << 40)
+ | ((long)(input[inOff + 3] & 0xff) << 32)
+ | ((long)(input[inOff + 4] & 0xff) << 24)
+ | ((long)(input[inOff + 5] & 0xff) << 16)
+ | ((long)(input[inOff + 6] & 0xff) << 8)
+ | ((uint)(input[inOff + 7] & 0xff) );
+
+ if (wOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal static void UnpackWord(
+ long word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)((ulong) word >> 56);
+ outBytes[outOff + 1] = (byte)((ulong) word >> 48);
+ outBytes[outOff + 2] = (byte)((ulong) word >> 40);
+ outBytes[outOff + 3] = (byte)((ulong) word >> 32);
+ outBytes[outOff + 4] = (byte)((ulong) word >> 24);
+ outBytes[outOff + 5] = (byte)((ulong) word >> 16);
+ outBytes[outOff + 6] = (byte)((ulong) word >> 8);
+ outBytes[outOff + 7] = (byte)word;
+ }
+
+ /**
+ * adjust the byte counts so that byteCount2 represents the
+ * upper long (less 3 bits) word of the byte count.
+ */
+ private void AdjustByteCounts()
+ {
+ if (byteCount1 > 0x1fffffffffffffffL)
+ {
+ byteCount2 += (long) ((ulong) byteCount1 >> 61);
+ byteCount1 &= 0x1fffffffffffffffL;
+ }
+ }
+
+ internal void ProcessLength(
+ long lowW,
+ long hiW)
+ {
+ if (wOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ W[14] = hiW;
+ W[15] = lowW;
+ }
+
+ internal void ProcessBlock()
+ {
+ AdjustByteCounts();
+
+ //
+ // expand 16 word block into 80 word blocks.
+ //
+ for (int ti = 16; ti <= 79; ++ti)
+ {
+ W[ti] = Sigma1(W[ti - 2]) + W[ti - 7] + Sigma0(W[ti - 15]) + W[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ long a = H1;
+ long b = H2;
+ long c = H3;
+ long d = H4;
+ long e = H5;
+ long f = H6;
+ long g = H7;
+ long h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 10; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ wOff = 0;
+
+ Array.Clear(W, 0, 16);
+ }
+
+ /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+ private static long Ch(
+ long x,
+ long y,
+ long z)
+ {
+ return ((x & y) ^ ((~x) & z));
+ }
+
+ private static long Maj(
+ long x,
+ long y,
+ long z)
+ {
+ return ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+ private static long Sum0(
+ long x)
+ {
+ return ((x << 36)|((long)((ulong)x >> 28))) ^ ((x << 30)|((long)((ulong)x >> 34))) ^ ((x << 25)|((long)((ulong)x >> 39)));
+ }
+
+ private static long Sum1(
+ long x)
+ {
+ return ((x << 50)|((long)((ulong)x >> 14))) ^ ((x << 46)|((long)((ulong)x >> 18))) ^ ((x << 23)|((long)((ulong)x >> 41)));
+ }
+
+ private static long Sigma0(
+ long x)
+ {
+ return ((x << 63)|((long)((ulong)x >> 1))) ^ ((x << 56)|((long)((ulong)x >> 8))) ^ ((long)((ulong)x >> 7));
+ }
+
+ private static long Sigma1(
+ long x)
+ {
+ return ((x << 45)|((long)((ulong)x >> 19))) ^ ((x << 3)|((long)((ulong)x >> 61))) ^ ((long)((ulong)x >> 6));
+ }
+
+ /* SHA-384 and SHA-512 Constants
+ * (represent the first 64 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ internal static readonly long[] K =
+ {
+ unchecked((long) 0x428a2f98d728ae22L), unchecked((long) 0x7137449123ef65cdL), unchecked((long) 0xb5c0fbcfec4d3b2fL), unchecked((long) 0xe9b5dba58189dbbcL),
+ unchecked((long) 0x3956c25bf348b538L), unchecked((long) 0x59f111f1b605d019L), unchecked((long) 0x923f82a4af194f9bL), unchecked((long) 0xab1c5ed5da6d8118L),
+ unchecked((long) 0xd807aa98a3030242L), unchecked((long) 0x12835b0145706fbeL), unchecked((long) 0x243185be4ee4b28cL), unchecked((long) 0x550c7dc3d5ffb4e2L),
+ unchecked((long) 0x72be5d74f27b896fL), unchecked((long) 0x80deb1fe3b1696b1L), unchecked((long) 0x9bdc06a725c71235L), unchecked((long) 0xc19bf174cf692694L),
+ unchecked((long) 0xe49b69c19ef14ad2L), unchecked((long) 0xefbe4786384f25e3L), unchecked((long) 0x0fc19dc68b8cd5b5L), unchecked((long) 0x240ca1cc77ac9c65L),
+ unchecked((long) 0x2de92c6f592b0275L), unchecked((long) 0x4a7484aa6ea6e483L), unchecked((long) 0x5cb0a9dcbd41fbd4L), unchecked((long) 0x76f988da831153b5L),
+ unchecked((long) 0x983e5152ee66dfabL), unchecked((long) 0xa831c66d2db43210L), unchecked((long) 0xb00327c898fb213fL), unchecked((long) 0xbf597fc7beef0ee4L),
+ unchecked((long) 0xc6e00bf33da88fc2L), unchecked((long) 0xd5a79147930aa725L), unchecked((long) 0x06ca6351e003826fL), unchecked((long) 0x142929670a0e6e70L),
+ unchecked((long) 0x27b70a8546d22ffcL), unchecked((long) 0x2e1b21385c26c926L), unchecked((long) 0x4d2c6dfc5ac42aedL), unchecked((long) 0x53380d139d95b3dfL),
+ unchecked((long) 0x650a73548baf63deL), unchecked((long) 0x766a0abb3c77b2a8L), unchecked((long) 0x81c2c92e47edaee6L), unchecked((long) 0x92722c851482353bL),
+ unchecked((long) 0xa2bfe8a14cf10364L), unchecked((long) 0xa81a664bbc423001L), unchecked((long) 0xc24b8b70d0f89791L), unchecked((long) 0xc76c51a30654be30L),
+ unchecked((long) 0xd192e819d6ef5218L), unchecked((long) 0xd69906245565a910L), unchecked((long) 0xf40e35855771202aL), unchecked((long) 0x106aa07032bbd1b8L),
+ unchecked((long) 0x19a4c116b8d2d0c8L), unchecked((long) 0x1e376c085141ab53L), unchecked((long) 0x2748774cdf8eeb99L), unchecked((long) 0x34b0bcb5e19b48a8L),
+ unchecked((long) 0x391c0cb3c5c95a63L), unchecked((long) 0x4ed8aa4ae3418acbL), unchecked((long) 0x5b9cca4f7763e373L), unchecked((long) 0x682e6ff3d6b2b8a3L),
+ unchecked((long) 0x748f82ee5defb2fcL), unchecked((long) 0x78a5636f43172f60L), unchecked((long) 0x84c87814a1f0ab72L), unchecked((long) 0x8cc702081a6439ecL),
+ unchecked((long) 0x90befffa23631e28L), unchecked((long) 0xa4506cebde82bde9L), unchecked((long) 0xbef9a3f7b2c67915L), unchecked((long) 0xc67178f2e372532bL),
+ unchecked((long) 0xca273eceea26619cL), unchecked((long) 0xd186b8c721c0c207L), unchecked((long) 0xeada7dd6cde0eb1eL), unchecked((long) 0xf57d4f7fee6ed178L),
+ unchecked((long) 0x06f067aa72176fbaL), unchecked((long) 0x0a637dc5a2c898a6L), unchecked((long) 0x113f9804bef90daeL), unchecked((long) 0x1b710b35131c471bL),
+ unchecked((long) 0x28db77f523047d84L), unchecked((long) 0x32caab7b40c72493L), unchecked((long) 0x3c9ebe0a15c9bebcL), unchecked((long) 0x431d67c49c100d4cL),
+ unchecked((long) 0x4cc5d4becb3e42b6L), unchecked((long) 0x597f299cfc657e2aL), unchecked((long) 0x5fcb6fab3ad6faecL), unchecked((long) 0x6c44198c4a475817L)
+ };
+
+ public int GetByteLength()
+ {
+ return MyByteLength;
+ }
+
+ public abstract string AlgorithmName { get; }
+ public abstract int GetDigestSize();
+ public abstract int DoFinal(byte[] output, int outOff);
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/MD2Digest.cs b/src/core/srcbc/crypto/digests/MD2Digest.cs
new file mode 100644
index 0000000..2842680
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/MD2Digest.cs
@@ -0,0 +1,247 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /**
+ * implementation of MD2
+ * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+ */
+ public class MD2Digest
+ : IDigest
+ {
+ private const int DigestLength = 16;
+ private const int BYTE_LENGTH = 16;
+
+ /* X buffer */
+ private byte[] X = new byte[48];
+ private int xOff;
+
+ /* M buffer */
+
+ private byte[] M = new byte[16];
+ private int mOff;
+
+ /* check sum */
+
+ private byte[] C = new byte[16];
+ private int COff;
+
+ public MD2Digest()
+ {
+ Reset();
+ }
+ public MD2Digest(MD2Digest t)
+ {
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ Array.Copy(t.M, 0, M, 0, t.M.Length);
+ mOff = t.mOff;
+ Array.Copy(t.C, 0, C, 0, t.C.Length);
+ COff = t.COff;
+ }
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public string AlgorithmName
+ {
+ get { return "MD2"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ /**
+ * Close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ public int DoFinal(byte[] output, int outOff)
+ {
+ // add padding
+ byte paddingByte = (byte)(M.Length - mOff);
+ for (int i=mOff;i 0))
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > 16)
+ {
+ Array.Copy(input,inOff,M,0,16);
+ ProcessChecksum(M);
+ ProcessBlock(M);
+ length -= 16;
+ inOff += 16;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+ }
+
+ internal void ProcessChecksum(byte[] m)
+ {
+ int L = C[15];
+ for (int i=0;i<16;i++)
+ {
+ C[i] ^= S[(m[i] ^ L) & 0xff];
+ L = C[i];
+ }
+ }
+ internal void ProcessBlock(byte[] m)
+ {
+ for (int i=0;i<16;i++)
+ {
+ X[i+16] = m[i];
+ X[i+32] = (byte)(m[i] ^ X[i]);
+ }
+ // encrypt block
+ int t = 0;
+
+ for (int j=0;j<18;j++)
+ {
+ for (int k=0;k<48;k++)
+ {
+ t = X[k] ^= S[t];
+ t = t & 0xff;
+ }
+ t = (t + j)%256;
+ }
+ }
+
+
+
+ // 256-byte random permutation constructed from the digits of PI
+ private static readonly byte[] S = {
+ (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124,
+ (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240,
+ (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192,
+ (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217,
+ (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87,
+ (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66,
+ (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190,
+ (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73,
+ (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238,
+ (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178,
+ (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11,
+ (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154,
+ (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204,
+ (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25,
+ (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215,
+ (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198,
+ (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125,
+ (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116,
+ (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100,
+ (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101,
+ (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37,
+ (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70,
+ (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85,
+ (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58,
+ (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234,
+ (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40,
+ (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65,
+ (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200,
+ (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123,
+ (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136,
+ (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233,
+ (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57,
+ (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208,
+ (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117,
+ (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143,
+ (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
+ (byte)159,(byte)17,(byte)131,(byte)20
+ };
+ }
+
+}
diff --git a/src/core/srcbc/crypto/digests/MD4Digest.cs b/src/core/srcbc/crypto/digests/MD4Digest.cs
new file mode 100644
index 0000000..1494f04
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/MD4Digest.cs
@@ -0,0 +1,271 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+ * Computer Science and RSA Data Security, Inc.
+ *
+ * NOTE: This algorithm is only included for backwards compatibility
+ * with legacy applications, it's not secure, don't use it for anything new!
+ */
+ public class MD4Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private int H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public MD4Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD4Digest(MD4Digest t) : base(t)
+ {
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "MD4"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = unchecked((int) 0x67452301);
+ H2 = unchecked((int) 0xefcdab89);
+ H3 = unchecked((int) 0x98badcfe);
+ H4 = unchecked((int) 0x10325476);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private const int S11 = 3;
+ private const int S12 = 7;
+ private const int S13 = 11;
+ private const int S14 = 19;
+
+ //
+ // round 2 left rotates
+ //
+ private const int S21 = 3;
+ private const int S22 = 5;
+ private const int S23 = 9;
+ private const int S24 = 13;
+
+ //
+ // round 3 left rotates
+ //
+ private const int S31 = 3;
+ private const int S32 = 9;
+ private const int S33 = 11;
+ private const int S34 = 15;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD4 functions.
+ */
+ private int F(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private int G(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (u & w) | (v & w);
+ }
+
+ private int H(
+ int u,
+ int v,
+ int w)
+ {
+ return u ^ v ^ w;
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = RotateLeft((a + F(b, c, d) + X[ 0]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 1]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[ 2]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[ 3]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[ 4]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 5]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[ 6]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[ 7]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[ 8]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 9]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[10]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[11]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[12]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[13]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[14]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[15]), S14);
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = RotateLeft((a + G(b, c, d) + X[ 0] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 4] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[ 8] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[12] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 1] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 5] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[ 9] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[13] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 2] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 6] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[10] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[14] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 3] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 7] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[11] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[15] + 0x5a827999), S24);
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = RotateLeft((a + H(b, c, d) + X[ 0] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[ 8] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 4] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[12] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 2] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[10] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 6] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[14] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 1] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[ 9] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 5] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[13] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 3] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[11] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 7] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[15] + 0x6ed9eba1), S34);
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/digests/MD5Digest.cs b/src/core/srcbc/crypto/digests/MD5Digest.cs
new file mode 100644
index 0000000..e9385d6
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/MD5Digest.cs
@@ -0,0 +1,301 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ */
+ public class MD5Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private int H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ public MD5Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD5Digest(MD5Digest t)
+ : base(t)
+ {
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "MD5"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = unchecked((int) 0x67452301);
+ H2 = unchecked((int) 0xefcdab89);
+ H3 = unchecked((int) 0x98badcfe);
+ H4 = unchecked((int) 0x10325476);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private static readonly int S11 = 7;
+ private static readonly int S12 = 12;
+ private static readonly int S13 = 17;
+ private static readonly int S14 = 22;
+
+ //
+ // round 2 left rotates
+ //
+ private static readonly int S21 = 5;
+ private static readonly int S22 = 9;
+ private static readonly int S23 = 14;
+ private static readonly int S24 = 20;
+
+ //
+ // round 3 left rotates
+ //
+ private static readonly int S31 = 4;
+ private static readonly int S32 = 11;
+ private static readonly int S33 = 16;
+ private static readonly int S34 = 23;
+
+ //
+ // round 4 left rotates
+ //
+ private static readonly int S41 = 6;
+ private static readonly int S42 = 10;
+ private static readonly int S43 = 15;
+ private static readonly int S44 = 21;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD5 functions.
+ */
+ private int F(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private int G(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & w) | (v & ~w);
+ }
+
+ private int H(
+ int u,
+ int v,
+ int w)
+ {
+ return u ^ v ^ w;
+ }
+
+ private int K(
+ int u,
+ int v,
+ int w)
+ {
+ return v ^ (u | ~w);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = RotateLeft((a + F(b, c, d) + X[ 0] + unchecked((int) 0xd76aa478)), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[ 1] + unchecked((int) 0xe8c7b756)), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[ 2] + unchecked((int) 0x242070db)), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[ 3] + unchecked((int) 0xc1bdceee)), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[ 4] + unchecked((int) 0xf57c0faf)), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[ 5] + unchecked((int) 0x4787c62a)), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[ 6] + unchecked((int) 0xa8304613)), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[ 7] + unchecked((int) 0xfd469501)), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[ 8] + unchecked((int) 0x698098d8)), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[ 9] + unchecked((int) 0x8b44f7af)), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[10] + unchecked((int) 0xffff5bb1)), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[11] + unchecked((int) 0x895cd7be)), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[12] + unchecked((int) 0x6b901122)), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[13] + unchecked((int) 0xfd987193)), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[14] + unchecked((int) 0xa679438e)), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[15] + unchecked((int) 0x49b40821)), S14) + c;
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = RotateLeft((a + G(b, c, d) + X[ 1] + unchecked((int) 0xf61e2562)), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[ 6] + unchecked((int) 0xc040b340)), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[11] + unchecked((int) 0x265e5a51)), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[ 0] + unchecked((int) 0xe9b6c7aa)), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[ 5] + unchecked((int) 0xd62f105d)), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[10] + unchecked((int) 0x02441453)), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[15] + unchecked((int) 0xd8a1e681)), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[ 4] + unchecked((int) 0xe7d3fbc8)), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[ 9] + unchecked((int) 0x21e1cde6)), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[14] + unchecked((int) 0xc33707d6)), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[ 3] + unchecked((int) 0xf4d50d87)), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[ 8] + unchecked((int) 0x455a14ed)), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[13] + unchecked((int) 0xa9e3e905)), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[ 2] + unchecked((int) 0xfcefa3f8)), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[ 7] + unchecked((int) 0x676f02d9)), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[12] + unchecked((int) 0x8d2a4c8a)), S24) + c;
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = RotateLeft((a + H(b, c, d) + X[ 5] + unchecked((int) 0xfffa3942)), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[ 8] + unchecked((int) 0x8771f681)), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[11] + unchecked((int) 0x6d9d6122)), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[14] + unchecked((int) 0xfde5380c)), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[ 1] + unchecked((int) 0xa4beea44)), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[ 4] + unchecked((int) 0x4bdecfa9)), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[ 7] + unchecked((int) 0xf6bb4b60)), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[10] + unchecked((int) 0xbebfbc70)), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[13] + unchecked((int) 0x289b7ec6)), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[ 0] + unchecked((int) 0xeaa127fa)), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[ 3] + unchecked((int) 0xd4ef3085)), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[ 6] + unchecked((int) 0x04881d05)), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[ 9] + unchecked((int) 0xd9d4d039)), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[12] + unchecked((int) 0xe6db99e5)), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[15] + unchecked((int) 0x1fa27cf8)), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[ 2] + unchecked((int) 0xc4ac5665)), S34) + c;
+
+ //
+ // Round 4 - K cycle, 16 times.
+ //
+ a = RotateLeft((a + K(b, c, d) + X[ 0] + unchecked((int) 0xf4292244)), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[ 7] + unchecked((int) 0x432aff97)), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[14] + unchecked((int) 0xab9423a7)), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[ 5] + unchecked((int) 0xfc93a039)), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[12] + unchecked((int) 0x655b59c3)), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[ 3] + unchecked((int) 0x8f0ccc92)), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[10] + unchecked((int) 0xffeff47d)), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[ 1] + unchecked((int) 0x85845dd1)), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[ 8] + unchecked((int) 0x6fa87e4f)), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[15] + unchecked((int) 0xfe2ce6e0)), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[ 6] + unchecked((int) 0xa3014314)), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[13] + unchecked((int) 0x4e0811a1)), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[ 4] + unchecked((int) 0xf7537e82)), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[11] + unchecked((int) 0xbd3af235)), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[ 2] + unchecked((int) 0x2ad7d2bb)), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[ 9] + unchecked((int) 0xeb86d391)), S44) + c;
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/digests/RipeMD128Digest.cs b/src/core/srcbc/crypto/digests/RipeMD128Digest.cs
new file mode 100644
index 0000000..c263796
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/RipeMD128Digest.cs
@@ -0,0 +1,462 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of RipeMD128
+ */
+ public class RipeMD128Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private int H0, H1, H2, H3; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public RipeMD128Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public RipeMD128Digest(RipeMD128Digest t) : base(t)
+ {
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD128"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4 are the basic RipeMD128 functions.
+ */
+
+ /*
+ * F
+ */
+ private int F1(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * G
+ */
+ private int F2(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ /*
+ * H
+ */
+ private int F3(
+ int x,
+ int y,
+ int z)
+ {
+ return (x | ~y) ^ z;
+ }
+
+ /*
+ * I
+ */
+ private int F4(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ private int F1(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int F2(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int) 0x5a827999), s);
+ }
+
+ private int F3(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int) 0x6ed9eba1), s);
+ }
+
+ private int F4(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int) 0x8f1bbcdc), s);
+ }
+
+ private int FF1(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int FF2(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int) 0x6d703ef3), s);
+ }
+
+ private int FF3(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int) 0x5c4dd124), s);
+ }
+
+ private int FF4(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int) 0x50a28be6), s);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+
+ a = aa = H0;
+ b = bb = H1;
+ c = cc = H2;
+ d = dd = H3;
+
+ //
+ // Round 1
+ //
+ a = F1(a, b, c, d, X[ 0], 11);
+ d = F1(d, a, b, c, X[ 1], 14);
+ c = F1(c, d, a, b, X[ 2], 15);
+ b = F1(b, c, d, a, X[ 3], 12);
+ a = F1(a, b, c, d, X[ 4], 5);
+ d = F1(d, a, b, c, X[ 5], 8);
+ c = F1(c, d, a, b, X[ 6], 7);
+ b = F1(b, c, d, a, X[ 7], 9);
+ a = F1(a, b, c, d, X[ 8], 11);
+ d = F1(d, a, b, c, X[ 9], 13);
+ c = F1(c, d, a, b, X[10], 14);
+ b = F1(b, c, d, a, X[11], 15);
+ a = F1(a, b, c, d, X[12], 6);
+ d = F1(d, a, b, c, X[13], 7);
+ c = F1(c, d, a, b, X[14], 9);
+ b = F1(b, c, d, a, X[15], 8);
+
+ //
+ // Round 2
+ //
+ a = F2(a, b, c, d, X[ 7], 7);
+ d = F2(d, a, b, c, X[ 4], 6);
+ c = F2(c, d, a, b, X[13], 8);
+ b = F2(b, c, d, a, X[ 1], 13);
+ a = F2(a, b, c, d, X[10], 11);
+ d = F2(d, a, b, c, X[ 6], 9);
+ c = F2(c, d, a, b, X[15], 7);
+ b = F2(b, c, d, a, X[ 3], 15);
+ a = F2(a, b, c, d, X[12], 7);
+ d = F2(d, a, b, c, X[ 0], 12);
+ c = F2(c, d, a, b, X[ 9], 15);
+ b = F2(b, c, d, a, X[ 5], 9);
+ a = F2(a, b, c, d, X[ 2], 11);
+ d = F2(d, a, b, c, X[14], 7);
+ c = F2(c, d, a, b, X[11], 13);
+ b = F2(b, c, d, a, X[ 8], 12);
+
+ //
+ // Round 3
+ //
+ a = F3(a, b, c, d, X[ 3], 11);
+ d = F3(d, a, b, c, X[10], 13);
+ c = F3(c, d, a, b, X[14], 6);
+ b = F3(b, c, d, a, X[ 4], 7);
+ a = F3(a, b, c, d, X[ 9], 14);
+ d = F3(d, a, b, c, X[15], 9);
+ c = F3(c, d, a, b, X[ 8], 13);
+ b = F3(b, c, d, a, X[ 1], 15);
+ a = F3(a, b, c, d, X[ 2], 14);
+ d = F3(d, a, b, c, X[ 7], 8);
+ c = F3(c, d, a, b, X[ 0], 13);
+ b = F3(b, c, d, a, X[ 6], 6);
+ a = F3(a, b, c, d, X[13], 5);
+ d = F3(d, a, b, c, X[11], 12);
+ c = F3(c, d, a, b, X[ 5], 7);
+ b = F3(b, c, d, a, X[12], 5);
+
+ //
+ // Round 4
+ //
+ a = F4(a, b, c, d, X[ 1], 11);
+ d = F4(d, a, b, c, X[ 9], 12);
+ c = F4(c, d, a, b, X[11], 14);
+ b = F4(b, c, d, a, X[10], 15);
+ a = F4(a, b, c, d, X[ 0], 14);
+ d = F4(d, a, b, c, X[ 8], 15);
+ c = F4(c, d, a, b, X[12], 9);
+ b = F4(b, c, d, a, X[ 4], 8);
+ a = F4(a, b, c, d, X[13], 9);
+ d = F4(d, a, b, c, X[ 3], 14);
+ c = F4(c, d, a, b, X[ 7], 5);
+ b = F4(b, c, d, a, X[15], 6);
+ a = F4(a, b, c, d, X[14], 8);
+ d = F4(d, a, b, c, X[ 5], 6);
+ c = F4(c, d, a, b, X[ 6], 5);
+ b = F4(b, c, d, a, X[ 2], 12);
+
+ //
+ // Parallel round 1
+ //
+ aa = FF4(aa, bb, cc, dd, X[ 5], 8);
+ dd = FF4(dd, aa, bb, cc, X[14], 9);
+ cc = FF4(cc, dd, aa, bb, X[ 7], 9);
+ bb = FF4(bb, cc, dd, aa, X[ 0], 11);
+ aa = FF4(aa, bb, cc, dd, X[ 9], 13);
+ dd = FF4(dd, aa, bb, cc, X[ 2], 15);
+ cc = FF4(cc, dd, aa, bb, X[11], 15);
+ bb = FF4(bb, cc, dd, aa, X[ 4], 5);
+ aa = FF4(aa, bb, cc, dd, X[13], 7);
+ dd = FF4(dd, aa, bb, cc, X[ 6], 7);
+ cc = FF4(cc, dd, aa, bb, X[15], 8);
+ bb = FF4(bb, cc, dd, aa, X[ 8], 11);
+ aa = FF4(aa, bb, cc, dd, X[ 1], 14);
+ dd = FF4(dd, aa, bb, cc, X[10], 14);
+ cc = FF4(cc, dd, aa, bb, X[ 3], 12);
+ bb = FF4(bb, cc, dd, aa, X[12], 6);
+
+ //
+ // Parallel round 2
+ //
+ aa = FF3(aa, bb, cc, dd, X[ 6], 9);
+ dd = FF3(dd, aa, bb, cc, X[11], 13);
+ cc = FF3(cc, dd, aa, bb, X[ 3], 15);
+ bb = FF3(bb, cc, dd, aa, X[ 7], 7);
+ aa = FF3(aa, bb, cc, dd, X[ 0], 12);
+ dd = FF3(dd, aa, bb, cc, X[13], 8);
+ cc = FF3(cc, dd, aa, bb, X[ 5], 9);
+ bb = FF3(bb, cc, dd, aa, X[10], 11);
+ aa = FF3(aa, bb, cc, dd, X[14], 7);
+ dd = FF3(dd, aa, bb, cc, X[15], 7);
+ cc = FF3(cc, dd, aa, bb, X[ 8], 12);
+ bb = FF3(bb, cc, dd, aa, X[12], 7);
+ aa = FF3(aa, bb, cc, dd, X[ 4], 6);
+ dd = FF3(dd, aa, bb, cc, X[ 9], 15);
+ cc = FF3(cc, dd, aa, bb, X[ 1], 13);
+ bb = FF3(bb, cc, dd, aa, X[ 2], 11);
+
+ //
+ // Parallel round 3
+ //
+ aa = FF2(aa, bb, cc, dd, X[15], 9);
+ dd = FF2(dd, aa, bb, cc, X[ 5], 7);
+ cc = FF2(cc, dd, aa, bb, X[ 1], 15);
+ bb = FF2(bb, cc, dd, aa, X[ 3], 11);
+ aa = FF2(aa, bb, cc, dd, X[ 7], 8);
+ dd = FF2(dd, aa, bb, cc, X[14], 6);
+ cc = FF2(cc, dd, aa, bb, X[ 6], 6);
+ bb = FF2(bb, cc, dd, aa, X[ 9], 14);
+ aa = FF2(aa, bb, cc, dd, X[11], 12);
+ dd = FF2(dd, aa, bb, cc, X[ 8], 13);
+ cc = FF2(cc, dd, aa, bb, X[12], 5);
+ bb = FF2(bb, cc, dd, aa, X[ 2], 14);
+ aa = FF2(aa, bb, cc, dd, X[10], 13);
+ dd = FF2(dd, aa, bb, cc, X[ 0], 13);
+ cc = FF2(cc, dd, aa, bb, X[ 4], 7);
+ bb = FF2(bb, cc, dd, aa, X[13], 5);
+
+ //
+ // Parallel round 4
+ //
+ aa = FF1(aa, bb, cc, dd, X[ 8], 15);
+ dd = FF1(dd, aa, bb, cc, X[ 6], 5);
+ cc = FF1(cc, dd, aa, bb, X[ 4], 8);
+ bb = FF1(bb, cc, dd, aa, X[ 1], 11);
+ aa = FF1(aa, bb, cc, dd, X[ 3], 14);
+ dd = FF1(dd, aa, bb, cc, X[11], 14);
+ cc = FF1(cc, dd, aa, bb, X[15], 6);
+ bb = FF1(bb, cc, dd, aa, X[ 0], 14);
+ aa = FF1(aa, bb, cc, dd, X[ 5], 6);
+ dd = FF1(dd, aa, bb, cc, X[12], 9);
+ cc = FF1(cc, dd, aa, bb, X[ 2], 12);
+ bb = FF1(bb, cc, dd, aa, X[13], 9);
+ aa = FF1(aa, bb, cc, dd, X[ 9], 12);
+ dd = FF1(dd, aa, bb, cc, X[ 7], 5);
+ cc = FF1(cc, dd, aa, bb, X[10], 15);
+ bb = FF1(bb, cc, dd, aa, X[14], 8);
+
+ dd += c + H1; // final result for H0
+
+ //
+ // combine the results
+ //
+ H1 = H2 + d + aa;
+ H2 = H3 + a + bb;
+ H3 = H0 + b + cc;
+ H0 = dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/digests/RipeMD160Digest.cs b/src/core/srcbc/crypto/digests/RipeMD160Digest.cs
new file mode 100644
index 0000000..3b4979c
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/RipeMD160Digest.cs
@@ -0,0 +1,423 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of RipeMD see,
+ * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+ */
+ public class RipeMD160Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 20;
+
+ private int H0, H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public RipeMD160Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public RipeMD160Digest(RipeMD160Digest t) : base(t)
+ {
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD160"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+ H4 = unchecked((int) 0xc3d2e1f0);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+ */
+
+ /*
+ * rounds 0-15
+ */
+ private int F1(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * rounds 16-31
+ */
+ private int F2(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ /*
+ * rounds 32-47
+ */
+ private int F3(
+ int x,
+ int y,
+ int z)
+ {
+ return (x | ~y) ^ z;
+ }
+
+ /*
+ * rounds 48-63
+ */
+ private int F4(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ /*
+ * rounds 64-79
+ */
+ private int F5(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ (y | ~z);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int e, ee;
+
+ a = aa = H0;
+ b = bb = H1;
+ c = cc = H2;
+ d = dd = H3;
+ e = ee = H4;
+
+ //
+ // Rounds 1 - 16
+ //
+ // left
+ a = RL(a + F1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[ 4], 5) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[ 5], 8) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[ 6], 7) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[ 7], 9) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[10], 14) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[11], 15) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[12], 6) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[13], 7) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[14], 9) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[15], 8) + e; c = RL(c, 10);
+
+ // right
+ aa = RL(aa + F5(bb,cc,dd) + X[ 5] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[14] + unchecked((int) 0x50a28be6), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 7] + unchecked((int) 0x50a28be6), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[ 0] + unchecked((int) 0x50a28be6), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 9] + unchecked((int) 0x50a28be6), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[ 2] + unchecked((int) 0x50a28be6), 15) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[11] + unchecked((int) 0x50a28be6), 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 4] + unchecked((int) 0x50a28be6), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[13] + unchecked((int) 0x50a28be6), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 6] + unchecked((int) 0x50a28be6), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[15] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[ 8] + unchecked((int) 0x50a28be6), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 1] + unchecked((int) 0x50a28be6), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[10] + unchecked((int) 0x50a28be6), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 3] + unchecked((int) 0x50a28be6), 12) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[12] + unchecked((int) 0x50a28be6), 6) + ee; cc = RL(cc, 10);
+
+ //
+ // Rounds 16-31
+ //
+ // left
+ e = RL(e + F2(a,b,c) + X[ 7] + unchecked((int) 0x5a827999), 7) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[ 4] + unchecked((int) 0x5a827999), 6) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[13] + unchecked((int) 0x5a827999), 8) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[ 1] + unchecked((int) 0x5a827999), 13) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[10] + unchecked((int) 0x5a827999), 11) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 6] + unchecked((int) 0x5a827999), 9) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[15] + unchecked((int) 0x5a827999), 7) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[ 3] + unchecked((int) 0x5a827999), 15) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[12] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[ 0] + unchecked((int) 0x5a827999), 12) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 9] + unchecked((int) 0x5a827999), 15) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[ 5] + unchecked((int) 0x5a827999), 9) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[ 2] + unchecked((int) 0x5a827999), 11) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[14] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[11] + unchecked((int) 0x5a827999), 13) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 8] + unchecked((int) 0x5a827999), 12) + d; b = RL(b, 10);
+
+ // right
+ ee = RL(ee + F4(aa,bb,cc) + X[ 6] + unchecked((int) 0x5c4dd124), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[11] + unchecked((int) 0x5c4dd124), 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[ 3] + unchecked((int) 0x5c4dd124), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[ 7] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[ 0] + unchecked((int) 0x5c4dd124), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[13] + unchecked((int) 0x5c4dd124), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[ 5] + unchecked((int) 0x5c4dd124), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[10] + unchecked((int) 0x5c4dd124), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[14] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[15] + unchecked((int) 0x5c4dd124), 7) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[ 8] + unchecked((int) 0x5c4dd124), 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[12] + unchecked((int) 0x5c4dd124), 7) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[ 4] + unchecked((int) 0x5c4dd124), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[ 9] + unchecked((int) 0x5c4dd124), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[ 1] + unchecked((int) 0x5c4dd124), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[ 2] + unchecked((int) 0x5c4dd124), 11) + dd; bb = RL(bb, 10);
+
+ //
+ // Rounds 32-47
+ //
+ // left
+ d = RL(d + F3(e,a,b) + X[ 3] + unchecked((int) 0x6ed9eba1), 11) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[10] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[14] + unchecked((int) 0x6ed9eba1), 6) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[ 4] + unchecked((int) 0x6ed9eba1), 7) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 9] + unchecked((int) 0x6ed9eba1), 14) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[15] + unchecked((int) 0x6ed9eba1), 9) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[ 8] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[ 1] + unchecked((int) 0x6ed9eba1), 15) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[ 2] + unchecked((int) 0x6ed9eba1), 14) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 7] + unchecked((int) 0x6ed9eba1), 8) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[ 0] + unchecked((int) 0x6ed9eba1), 13) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[ 6] + unchecked((int) 0x6ed9eba1), 6) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[13] + unchecked((int) 0x6ed9eba1), 5) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[11] + unchecked((int) 0x6ed9eba1), 12) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 5] + unchecked((int) 0x6ed9eba1), 7) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[12] + unchecked((int) 0x6ed9eba1), 5) + c; a = RL(a, 10);
+
+ // right
+ dd = RL(dd + F3(ee,aa,bb) + X[15] + unchecked((int) 0x6d703ef3), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 5] + unchecked((int) 0x6d703ef3), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[ 1] + unchecked((int) 0x6d703ef3), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[ 3] + unchecked((int) 0x6d703ef3), 11) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 7] + unchecked((int) 0x6d703ef3), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[14] + unchecked((int) 0x6d703ef3), 6) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 6] + unchecked((int) 0x6d703ef3), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[ 9] + unchecked((int) 0x6d703ef3), 14) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[11] + unchecked((int) 0x6d703ef3), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 8] + unchecked((int) 0x6d703ef3), 13) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[12] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 2] + unchecked((int) 0x6d703ef3), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[10] + unchecked((int) 0x6d703ef3), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[ 0] + unchecked((int) 0x6d703ef3), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 4] + unchecked((int) 0x6d703ef3), 7) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[13] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+
+ //
+ // Rounds 48-63
+ //
+ // left
+ c = RL(c + F4(d,e,a) + X[ 1] + unchecked((int) 0x8f1bbcdc), 11) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[ 9] + unchecked((int) 0x8f1bbcdc), 12) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[11] + unchecked((int) 0x8f1bbcdc), 14) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[10] + unchecked((int) 0x8f1bbcdc), 15) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 0] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 8] + unchecked((int) 0x8f1bbcdc), 15) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[12] + unchecked((int) 0x8f1bbcdc), 9) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[ 4] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[13] + unchecked((int) 0x8f1bbcdc), 9) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 3] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 7] + unchecked((int) 0x8f1bbcdc), 5) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[15] + unchecked((int) 0x8f1bbcdc), 6) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[14] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[ 5] + unchecked((int) 0x8f1bbcdc), 6) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 6] + unchecked((int) 0x8f1bbcdc), 5) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 2] + unchecked((int) 0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+ // right
+ cc = RL(cc + F2(dd,ee,aa) + X[ 8] + unchecked((int) 0x7a6d76e9), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[ 6] + unchecked((int) 0x7a6d76e9), 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 4] + unchecked((int) 0x7a6d76e9), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 1] + unchecked((int) 0x7a6d76e9), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[ 3] + unchecked((int) 0x7a6d76e9), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[11] + unchecked((int) 0x7a6d76e9), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[15] + unchecked((int) 0x7a6d76e9), 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 0] + unchecked((int) 0x7a6d76e9), 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 5] + unchecked((int) 0x7a6d76e9), 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[12] + unchecked((int) 0x7a6d76e9), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[ 2] + unchecked((int) 0x7a6d76e9), 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[13] + unchecked((int) 0x7a6d76e9), 9) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 9] + unchecked((int) 0x7a6d76e9), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 7] + unchecked((int) 0x7a6d76e9), 5) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[10] + unchecked((int) 0x7a6d76e9), 15) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[14] + unchecked((int) 0x7a6d76e9), 8) + bb; ee = RL(ee, 10);
+
+ //
+ // Rounds 64-79
+ //
+ // left
+ b = RL(b + F5(c,d,e) + X[ 4] + unchecked((int) 0xa953fd4e), 9) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 0] + unchecked((int) 0xa953fd4e), 15) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[ 5] + unchecked((int) 0xa953fd4e), 5) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[ 9] + unchecked((int) 0xa953fd4e), 11) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[ 7] + unchecked((int) 0xa953fd4e), 6) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[12] + unchecked((int) 0xa953fd4e), 8) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 2] + unchecked((int) 0xa953fd4e), 13) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[10] + unchecked((int) 0xa953fd4e), 12) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[14] + unchecked((int) 0xa953fd4e), 5) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[ 1] + unchecked((int) 0xa953fd4e), 12) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[ 3] + unchecked((int) 0xa953fd4e), 13) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 8] + unchecked((int) 0xa953fd4e), 14) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[11] + unchecked((int) 0xa953fd4e), 11) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[ 6] + unchecked((int) 0xa953fd4e), 8) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[15] + unchecked((int) 0xa953fd4e), 5) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[13] + unchecked((int) 0xa953fd4e), 6) + a; d = RL(d, 10);
+
+ // right
+ bb = RL(bb + F1(cc,dd,ee) + X[12], 8) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[15], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 4], 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[ 5], 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[ 7], 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 6], 8) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[13], 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[14], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+ dd += c + H1;
+ H1 = H2 + d + ee;
+ H2 = H3 + e + aa;
+ H3 = H4 + a + bb;
+ H4 = H0 + b + cc;
+ H0 = dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/digests/RipeMD256Digest.cs b/src/core/srcbc/crypto/digests/RipeMD256Digest.cs
new file mode 100644
index 0000000..ccaa774
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/RipeMD256Digest.cs
@@ -0,0 +1,409 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of RipeMD256.
+ /// Note: this algorithm offers the same level of security as RipeMD128.
+ ///
+ public class RipeMD256Digest
+ : GeneralDigest
+ {
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD256"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ private const int DigestLength = 32;
+
+ private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /// Standard constructor
+ public RipeMD256Digest()
+ {
+ Reset();
+ }
+
+ /// Copy constructor. This will copy the state of the provided
+ /// message digest.
+ ///
+ public RipeMD256Digest(RipeMD256Digest t):base(t)
+ {
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong)bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)(uint)word;
+ outBytes[outOff + 1] = (byte)((uint)word >> 8);
+ outBytes[outOff + 2] = (byte)((uint)word >> 16);
+ outBytes[outOff + 3] = (byte)((uint)word >> 24);
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+ UnpackWord(H5, output, outOff + 20);
+ UnpackWord(H6, output, outOff + 24);
+ UnpackWord(H7, output, outOff + 28);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /// reset the chaining variables to the IV values.
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int)0x67452301);
+ H1 = unchecked((int)0xefcdab89);
+ H2 = unchecked((int)0x98badcfe);
+ H3 = unchecked((int)0x10325476);
+ H4 = unchecked((int)0x76543210);
+ H5 = unchecked((int)0xFEDCBA98);
+ H6 = unchecked((int)0x89ABCDEF);
+ H7 = unchecked((int)0x01234567);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int)((uint)x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4 are the basic RipeMD128 functions.
+ */
+
+ /*
+ * F
+ */
+ private int F1(int x, int y, int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * G
+ */
+ private int F2(int x, int y, int z)
+ {
+ return (x & y) | (~ x & z);
+ }
+
+ /*
+ * H
+ */
+ private int F3(int x, int y, int z)
+ {
+ return (x | ~ y) ^ z;
+ }
+
+ /*
+ * I
+ */
+ private int F4(int x, int y, int z)
+ {
+ return (x & z) | (y & ~ z);
+ }
+
+ private int F1(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int F2(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int)0x5a827999), s);
+ }
+
+ private int F3(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int)0x6ed9eba1), s);
+ }
+
+ private int F4(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int)0x8f1bbcdc), s);
+ }
+
+ private int FF1(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int FF2(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int)0x6d703ef3), s);
+ }
+
+ private int FF3(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int)0x5c4dd124), s);
+ }
+
+ private int FF4(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int)0x50a28be6), s);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int t;
+
+ a = H0;
+ b = H1;
+ c = H2;
+ d = H3;
+ aa = H4;
+ bb = H5;
+ cc = H6;
+ dd = H7;
+
+ //
+ // Round 1
+ //
+
+ a = F1(a, b, c, d, X[0], 11);
+ d = F1(d, a, b, c, X[1], 14);
+ c = F1(c, d, a, b, X[2], 15);
+ b = F1(b, c, d, a, X[3], 12);
+ a = F1(a, b, c, d, X[4], 5);
+ d = F1(d, a, b, c, X[5], 8);
+ c = F1(c, d, a, b, X[6], 7);
+ b = F1(b, c, d, a, X[7], 9);
+ a = F1(a, b, c, d, X[8], 11);
+ d = F1(d, a, b, c, X[9], 13);
+ c = F1(c, d, a, b, X[10], 14);
+ b = F1(b, c, d, a, X[11], 15);
+ a = F1(a, b, c, d, X[12], 6);
+ d = F1(d, a, b, c, X[13], 7);
+ c = F1(c, d, a, b, X[14], 9);
+ b = F1(b, c, d, a, X[15], 8);
+
+ aa = FF4(aa, bb, cc, dd, X[5], 8);
+ dd = FF4(dd, aa, bb, cc, X[14], 9);
+ cc = FF4(cc, dd, aa, bb, X[7], 9);
+ bb = FF4(bb, cc, dd, aa, X[0], 11);
+ aa = FF4(aa, bb, cc, dd, X[9], 13);
+ dd = FF4(dd, aa, bb, cc, X[2], 15);
+ cc = FF4(cc, dd, aa, bb, X[11], 15);
+ bb = FF4(bb, cc, dd, aa, X[4], 5);
+ aa = FF4(aa, bb, cc, dd, X[13], 7);
+ dd = FF4(dd, aa, bb, cc, X[6], 7);
+ cc = FF4(cc, dd, aa, bb, X[15], 8);
+ bb = FF4(bb, cc, dd, aa, X[8], 11);
+ aa = FF4(aa, bb, cc, dd, X[1], 14);
+ dd = FF4(dd, aa, bb, cc, X[10], 14);
+ cc = FF4(cc, dd, aa, bb, X[3], 12);
+ bb = FF4(bb, cc, dd, aa, X[12], 6);
+
+ t = a; a = aa; aa = t;
+
+ //
+ // Round 2
+ //
+ a = F2(a, b, c, d, X[7], 7);
+ d = F2(d, a, b, c, X[4], 6);
+ c = F2(c, d, a, b, X[13], 8);
+ b = F2(b, c, d, a, X[1], 13);
+ a = F2(a, b, c, d, X[10], 11);
+ d = F2(d, a, b, c, X[6], 9);
+ c = F2(c, d, a, b, X[15], 7);
+ b = F2(b, c, d, a, X[3], 15);
+ a = F2(a, b, c, d, X[12], 7);
+ d = F2(d, a, b, c, X[0], 12);
+ c = F2(c, d, a, b, X[9], 15);
+ b = F2(b, c, d, a, X[5], 9);
+ a = F2(a, b, c, d, X[2], 11);
+ d = F2(d, a, b, c, X[14], 7);
+ c = F2(c, d, a, b, X[11], 13);
+ b = F2(b, c, d, a, X[8], 12);
+
+ aa = FF3(aa, bb, cc, dd, X[6], 9);
+ dd = FF3(dd, aa, bb, cc, X[11], 13);
+ cc = FF3(cc, dd, aa, bb, X[3], 15);
+ bb = FF3(bb, cc, dd, aa, X[7], 7);
+ aa = FF3(aa, bb, cc, dd, X[0], 12);
+ dd = FF3(dd, aa, bb, cc, X[13], 8);
+ cc = FF3(cc, dd, aa, bb, X[5], 9);
+ bb = FF3(bb, cc, dd, aa, X[10], 11);
+ aa = FF3(aa, bb, cc, dd, X[14], 7);
+ dd = FF3(dd, aa, bb, cc, X[15], 7);
+ cc = FF3(cc, dd, aa, bb, X[8], 12);
+ bb = FF3(bb, cc, dd, aa, X[12], 7);
+ aa = FF3(aa, bb, cc, dd, X[4], 6);
+ dd = FF3(dd, aa, bb, cc, X[9], 15);
+ cc = FF3(cc, dd, aa, bb, X[1], 13);
+ bb = FF3(bb, cc, dd, aa, X[2], 11);
+
+ t = b; b = bb; bb = t;
+
+ //
+ // Round 3
+ //
+ a = F3(a, b, c, d, X[3], 11);
+ d = F3(d, a, b, c, X[10], 13);
+ c = F3(c, d, a, b, X[14], 6);
+ b = F3(b, c, d, a, X[4], 7);
+ a = F3(a, b, c, d, X[9], 14);
+ d = F3(d, a, b, c, X[15], 9);
+ c = F3(c, d, a, b, X[8], 13);
+ b = F3(b, c, d, a, X[1], 15);
+ a = F3(a, b, c, d, X[2], 14);
+ d = F3(d, a, b, c, X[7], 8);
+ c = F3(c, d, a, b, X[0], 13);
+ b = F3(b, c, d, a, X[6], 6);
+ a = F3(a, b, c, d, X[13], 5);
+ d = F3(d, a, b, c, X[11], 12);
+ c = F3(c, d, a, b, X[5], 7);
+ b = F3(b, c, d, a, X[12], 5);
+
+ aa = FF2(aa, bb, cc, dd, X[15], 9);
+ dd = FF2(dd, aa, bb, cc, X[5], 7);
+ cc = FF2(cc, dd, aa, bb, X[1], 15);
+ bb = FF2(bb, cc, dd, aa, X[3], 11);
+ aa = FF2(aa, bb, cc, dd, X[7], 8);
+ dd = FF2(dd, aa, bb, cc, X[14], 6);
+ cc = FF2(cc, dd, aa, bb, X[6], 6);
+ bb = FF2(bb, cc, dd, aa, X[9], 14);
+ aa = FF2(aa, bb, cc, dd, X[11], 12);
+ dd = FF2(dd, aa, bb, cc, X[8], 13);
+ cc = FF2(cc, dd, aa, bb, X[12], 5);
+ bb = FF2(bb, cc, dd, aa, X[2], 14);
+ aa = FF2(aa, bb, cc, dd, X[10], 13);
+ dd = FF2(dd, aa, bb, cc, X[0], 13);
+ cc = FF2(cc, dd, aa, bb, X[4], 7);
+ bb = FF2(bb, cc, dd, aa, X[13], 5);
+
+ t = c; c = cc; cc = t;
+
+ //
+ // Round 4
+ //
+ a = F4(a, b, c, d, X[1], 11);
+ d = F4(d, a, b, c, X[9], 12);
+ c = F4(c, d, a, b, X[11], 14);
+ b = F4(b, c, d, a, X[10], 15);
+ a = F4(a, b, c, d, X[0], 14);
+ d = F4(d, a, b, c, X[8], 15);
+ c = F4(c, d, a, b, X[12], 9);
+ b = F4(b, c, d, a, X[4], 8);
+ a = F4(a, b, c, d, X[13], 9);
+ d = F4(d, a, b, c, X[3], 14);
+ c = F4(c, d, a, b, X[7], 5);
+ b = F4(b, c, d, a, X[15], 6);
+ a = F4(a, b, c, d, X[14], 8);
+ d = F4(d, a, b, c, X[5], 6);
+ c = F4(c, d, a, b, X[6], 5);
+ b = F4(b, c, d, a, X[2], 12);
+
+ aa = FF1(aa, bb, cc, dd, X[8], 15);
+ dd = FF1(dd, aa, bb, cc, X[6], 5);
+ cc = FF1(cc, dd, aa, bb, X[4], 8);
+ bb = FF1(bb, cc, dd, aa, X[1], 11);
+ aa = FF1(aa, bb, cc, dd, X[3], 14);
+ dd = FF1(dd, aa, bb, cc, X[11], 14);
+ cc = FF1(cc, dd, aa, bb, X[15], 6);
+ bb = FF1(bb, cc, dd, aa, X[0], 14);
+ aa = FF1(aa, bb, cc, dd, X[5], 6);
+ dd = FF1(dd, aa, bb, cc, X[12], 9);
+ cc = FF1(cc, dd, aa, bb, X[2], 12);
+ bb = FF1(bb, cc, dd, aa, X[13], 9);
+ aa = FF1(aa, bb, cc, dd, X[9], 12);
+ dd = FF1(dd, aa, bb, cc, X[7], 5);
+ cc = FF1(cc, dd, aa, bb, X[10], 15);
+ bb = FF1(bb, cc, dd, aa, X[14], 8);
+
+ t = d; d = dd; dd = t;
+
+ H0 += a;
+ H1 += b;
+ H2 += c;
+ H3 += d;
+ H4 += aa;
+ H5 += bb;
+ H6 += cc;
+ H7 += dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/RipeMD320Digest.cs b/src/core/srcbc/crypto/digests/RipeMD320Digest.cs
new file mode 100644
index 0000000..dad6801
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/RipeMD320Digest.cs
@@ -0,0 +1,438 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of RipeMD 320.
+ /// Note: this algorithm offers the same level of security as RipeMD160.
+ ///
+ public class RipeMD320Digest
+ : GeneralDigest
+ {
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD320"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ private const int DigestLength = 40;
+
+ private int H0, H1, H2, H3, H4, H5, H6, H7, H8, H9; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /// Standard constructor
+ public RipeMD320Digest()
+ {
+ Reset();
+ }
+
+ /// Copy constructor. This will copy the state of the provided
+ /// message digest.
+ ///
+ public RipeMD320Digest(RipeMD320Digest t)
+ : base(t)
+ {
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+ H9 = t.H9;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong)bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint)word >> 8);
+ outBytes[outOff + 2] = (byte)((uint)word >> 16);
+ outBytes[outOff + 3] = (byte)((uint)word >> 24);
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+ UnpackWord(H5, output, outOff + 20);
+ UnpackWord(H6, output, outOff + 24);
+ UnpackWord(H7, output, outOff + 28);
+ UnpackWord(H8, output, outOff + 32);
+ UnpackWord(H9, output, outOff + 36);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /// reset the chaining variables to the IV values.
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+ H4 = unchecked((int) 0xc3d2e1f0);
+ H5 = unchecked((int) 0x76543210);
+ H6 = unchecked((int) 0xFEDCBA98);
+ H7 = unchecked((int) 0x89ABCDEF);
+ H8 = unchecked((int) 0x01234567);
+ H9 = unchecked((int) 0x3C2D1E0F);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int)(((uint)x) >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+ */
+
+ /*
+ * rounds 0-15
+ */
+ private int F1(int x, int y, int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * rounds 16-31
+ */
+ private int F2(int x, int y, int z)
+ {
+ return (x & y) | (~ x & z);
+ }
+
+ /*
+ * rounds 32-47
+ */
+ private int F3(int x, int y, int z)
+ {
+ return (x | ~ y) ^ z;
+ }
+
+ /*
+ * rounds 48-63
+ */
+ private int F4(int x, int y, int z)
+ {
+ return (x & z) | (y & ~ z);
+ }
+
+ /*
+ * rounds 64-79
+ */
+ private int F5(int x, int y, int z)
+ {
+ return x ^ (y | ~z);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int e, ee;
+ int t;
+
+ a = H0;
+ b = H1;
+ c = H2;
+ d = H3;
+ e = H4;
+ aa = H5;
+ bb = H6;
+ cc = H7;
+ dd = H8;
+ ee = H9;
+
+ //
+ // Rounds 1 - 16
+ //
+ // left
+ a = RL(a + F1(b, c, d) + X[0], 11) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[1], 14) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[2], 15) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[3], 12) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[4], 5) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[5], 8) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[6], 7) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[7], 9) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[8], 11) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[9], 13) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[10], 14) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[11], 15) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[12], 6) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[13], 7) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[14], 9) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[15], 8) + e; c = RL(c, 10);
+
+ // right
+ aa = RL(aa + F5(bb, cc, dd) + X[5] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[14] + unchecked((int)0x50a28be6), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[7] + unchecked((int)0x50a28be6), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[0] + unchecked((int)0x50a28be6), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[9] + unchecked((int)0x50a28be6), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[2] + unchecked((int)0x50a28be6), 15) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[11] + unchecked((int)0x50a28be6), 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[4] + unchecked((int)0x50a28be6), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[13] + unchecked((int)0x50a28be6), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[6] + unchecked((int)0x50a28be6), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[15] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[8] + unchecked((int)0x50a28be6), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[1] + unchecked((int)0x50a28be6), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[10] + unchecked((int)0x50a28be6), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[3] + unchecked((int)0x50a28be6), 12) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[12] + unchecked((int)0x50a28be6), 6) + ee; cc = RL(cc, 10);
+
+ t = a; a = aa; aa = t;
+ //
+ // Rounds 16-31
+ //
+ // left
+ e = RL(e + F2(a, b, c) + X[7] + unchecked((int)0x5a827999), 7) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[4] + unchecked((int)0x5a827999), 6) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[13] + unchecked((int)0x5a827999), 8) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[1] + unchecked((int)0x5a827999), 13) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[10] + unchecked((int)0x5a827999), 11) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[6] + unchecked((int)0x5a827999), 9) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[15] + unchecked((int)0x5a827999), 7) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[3] + unchecked((int)0x5a827999), 15) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[12] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[0] + unchecked((int)0x5a827999), 12) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[9] + unchecked((int)0x5a827999), 15) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[5] + unchecked((int)0x5a827999), 9) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[2] + unchecked((int)0x5a827999), 11) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[14] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[11] + unchecked((int)0x5a827999), 13) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[8] + unchecked((int)0x5a827999), 12) + d; b = RL(b, 10);
+
+ // right
+ ee = RL(ee + F4(aa, bb, cc) + X[6] + unchecked((int)0x5c4dd124), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[11] + unchecked((int)0x5c4dd124), 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[3] + unchecked((int)0x5c4dd124), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[7] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[0] + unchecked((int)0x5c4dd124), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[13] + unchecked((int)0x5c4dd124), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[5] + unchecked((int)0x5c4dd124), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[10] + unchecked((int)0x5c4dd124), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[14] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[15] + unchecked((int)0x5c4dd124), 7) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[8] + unchecked((int)0x5c4dd124), 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[12] + unchecked((int)0x5c4dd124), 7) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[4] + unchecked((int)0x5c4dd124), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[9] + unchecked((int)0x5c4dd124), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[1] + unchecked((int)0x5c4dd124), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[2] + unchecked((int)0x5c4dd124), 11) + dd; bb = RL(bb, 10);
+
+ t = b; b = bb; bb = t;
+
+ //
+ // Rounds 32-47
+ //
+ // left
+ d = RL(d + F3(e, a, b) + X[3] + unchecked((int)0x6ed9eba1), 11) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[10] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[14] + unchecked((int)0x6ed9eba1), 6) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[4] + unchecked((int)0x6ed9eba1), 7) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[9] + unchecked((int)0x6ed9eba1), 14) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[15] + unchecked((int)0x6ed9eba1), 9) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[8] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[1] + unchecked((int)0x6ed9eba1), 15) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[2] + unchecked((int)0x6ed9eba1), 14) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[7] + unchecked((int)0x6ed9eba1), 8) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[0] + unchecked((int)0x6ed9eba1), 13) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[6] + unchecked((int)0x6ed9eba1), 6) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[13] + unchecked((int)0x6ed9eba1), 5) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[11] + unchecked((int)0x6ed9eba1), 12) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[5] + unchecked((int)0x6ed9eba1), 7) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[12] + unchecked((int)0x6ed9eba1), 5) + c; a = RL(a, 10);
+
+ // right
+ dd = RL(dd + F3(ee, aa, bb) + X[15] + unchecked((int)0x6d703ef3), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[5] + unchecked((int)0x6d703ef3), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[1] + unchecked((int)0x6d703ef3), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[3] + unchecked((int)0x6d703ef3), 11) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[7] + unchecked((int)0x6d703ef3), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[14] + unchecked((int)0x6d703ef3), 6) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[6] + unchecked((int)0x6d703ef3), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[9] + unchecked((int)0x6d703ef3), 14) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[11] + unchecked((int)0x6d703ef3), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[8] + unchecked((int)0x6d703ef3), 13) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[12] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[2] + unchecked((int)0x6d703ef3), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[10] + unchecked((int)0x6d703ef3), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[0] + unchecked((int)0x6d703ef3), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[4] + unchecked((int)0x6d703ef3), 7) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[13] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+
+ t = c; c = cc; cc = t;
+
+ //
+ // Rounds 48-63
+ //
+ // left
+ c = RL(c + F4(d, e, a) + X[1] + unchecked((int)0x8f1bbcdc), 11) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[9] + unchecked((int)0x8f1bbcdc), 12) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[11] + unchecked((int)0x8f1bbcdc), 14) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[10] + unchecked((int)0x8f1bbcdc), 15) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[0] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[8] + unchecked((int)0x8f1bbcdc), 15) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[12] + unchecked((int)0x8f1bbcdc), 9) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[4] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[13] + unchecked((int)0x8f1bbcdc), 9) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[3] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[7] + unchecked((int)0x8f1bbcdc), 5) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[15] + unchecked((int)0x8f1bbcdc), 6) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[14] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[5] + unchecked((int)0x8f1bbcdc), 6) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[6] + unchecked((int)0x8f1bbcdc), 5) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[2] + unchecked((int)0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+ // right
+ cc = RL(cc + F2(dd, ee, aa) + X[8] + unchecked((int)0x7a6d76e9), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[6] + unchecked((int)0x7a6d76e9), 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[4] + unchecked((int)0x7a6d76e9), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[1] + unchecked((int)0x7a6d76e9), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[3] + unchecked((int)0x7a6d76e9), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[11] + unchecked((int)0x7a6d76e9), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[15] + unchecked((int)0x7a6d76e9), 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[0] + unchecked((int)0x7a6d76e9), 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[5] + unchecked((int)0x7a6d76e9), 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[12] + unchecked((int)0x7a6d76e9), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[2] + unchecked((int)0x7a6d76e9), 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[13] + unchecked((int)0x7a6d76e9), 9) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[9] + unchecked((int)0x7a6d76e9), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[7] + unchecked((int)0x7a6d76e9), 5) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[10] + unchecked((int)0x7a6d76e9), 15) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[14] + unchecked((int)0x7a6d76e9), 8) + bb; ee = RL(ee, 10);
+
+ t = d; d = dd; dd = t;
+
+ //
+ // Rounds 64-79
+ //
+ // left
+ b = RL(b + F5(c, d, e) + X[4] + unchecked((int)0xa953fd4e), 9) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[0] + unchecked((int)0xa953fd4e), 15) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[5] + unchecked((int)0xa953fd4e), 5) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[9] + unchecked((int)0xa953fd4e), 11) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[7] + unchecked((int)0xa953fd4e), 6) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[12] + unchecked((int)0xa953fd4e), 8) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[2] + unchecked((int)0xa953fd4e), 13) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[10] + unchecked((int)0xa953fd4e), 12) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[14] + unchecked((int)0xa953fd4e), 5) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[1] + unchecked((int)0xa953fd4e), 12) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[3] + unchecked((int)0xa953fd4e), 13) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[8] + unchecked((int)0xa953fd4e), 14) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[11] + unchecked((int)0xa953fd4e), 11) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[6] + unchecked((int)0xa953fd4e), 8) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[15] + unchecked((int)0xa953fd4e), 5) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[13] + unchecked((int)0xa953fd4e), 6) + a; d = RL(d, 10);
+
+ // right
+ bb = RL(bb + F1(cc, dd, ee) + X[12], 8) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[15], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[10], 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[4], 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[1], 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[5], 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[8], 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[7], 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[6], 8) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[2], 13) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[13], 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[14], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[0], 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[3], 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[9], 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+ //
+ // do (e, ee) swap as part of assignment.
+ //
+
+ H0 += a;
+ H1 += b;
+ H2 += c;
+ H3 += d;
+ H4 += ee;
+ H5 += aa;
+ H6 += bb;
+ H7 += cc;
+ H8 += dd;
+ H9 += e;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/Sha1Digest.cs b/src/core/srcbc/crypto/digests/Sha1Digest.cs
new file mode 100644
index 0000000..de469b4
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/Sha1Digest.cs
@@ -0,0 +1,285 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endienness" of the word processing!
+ */
+ public class Sha1Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 20;
+
+ private int H1, H2, H3, H4, H5;
+
+ private int[] X = new int[80];
+ private int xOff;
+
+ public Sha1Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha1Digest(Sha1Digest t)
+ : base(t)
+ {
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-1"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16)
+ | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff));
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ private static void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff++] = (byte)((uint)word >> 24);
+ outBytes[outOff++] = (byte)((uint)word >> 16);
+ outBytes[outOff++] = (byte)((uint)word >> 8);
+ outBytes[outOff++] = (byte)word;
+ }
+
+ internal override void ProcessLength(long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)((ulong) bitLength >> 32);
+ X[15] = (int)(bitLength & 0xffffffff);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+ UnpackWord(H5, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = unchecked( (int) 0x67452301 );
+ H2 = unchecked( (int) 0xefcdab89 );
+ H3 = unchecked( (int) 0x98badcfe );
+ H4 = unchecked( (int) 0x10325476 );
+ H5 = unchecked( (int) 0xc3d2e1f0 );
+
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++) X[i] = 0;
+ }
+
+ //
+ // Additive constants
+ //
+ private const int Y1 = unchecked( (int) 0x5a827999);
+ private const int Y2 = unchecked( (int) 0x6ed9eba1);
+ private const int Y3 = unchecked( (int) 0x8f1bbcdc);
+ private const int Y4 = unchecked( (int) 0xca62c1d6);
+
+ private static int F(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | ((~u) & w));
+ }
+
+ private static int H(
+ int u,
+ int v,
+ int w)
+ {
+ return (u ^ v ^ w);
+ }
+
+ private static int G(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | (u & w) | (v & w));
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 80 word block.
+ //
+ for (int i = 16; i < 80; i++)
+ {
+ int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+ X[i] = t << 1 | (int)((uint)t >> 31);
+ }
+
+ //
+ // set up working variables.
+ //
+ int A = H1;
+ int B = H2;
+ int C = H3;
+ int D = H4;
+ int E = H5;
+
+ //
+ // round 1
+ //
+ int idx = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (int)((uint)A >> 27)) + F(B, C, D) + X[idx++] + Y1;
+ B = B << 30 | (int)((uint)B >> 2);
+
+ D += (E << 5 | (int)((uint)E >> 27)) + F(A, B, C) + X[idx++] + Y1;
+ A = A << 30 | (int)((uint)A >> 2);
+
+ C += (D << 5 | (int)((uint)D >> 27)) + F(E, A, B) + X[idx++] + Y1;
+ E = E << 30 | (int)((uint)E >> 2);
+
+ B += (C << 5 | (int)((uint)C >> 27)) + F(D, E, A) + X[idx++] + Y1;
+ D = D << 30 | (int)((uint)D >> 2);
+
+ A += (B << 5 | (int)((uint)B >> 27)) + F(C, D, E) + X[idx++] + Y1;
+ C = C << 30 | (int)((uint)C >> 2);
+ }
+
+ //
+ // round 2
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (int)((uint)A >> 27)) + H(B, C, D) + X[idx++] + Y2;
+ B = B << 30 | (int)((uint)B >> 2);
+
+ D += (E << 5 | (int)((uint)E >> 27)) + H(A, B, C) + X[idx++] + Y2;
+ A = A << 30 | (int)((uint)A >> 2);
+
+ C += (D << 5 | (int)((uint)D >> 27)) + H(E, A, B) + X[idx++] + Y2;
+ E = E << 30 | (int)((uint)E >> 2);
+
+ B += (C << 5 | (int)((uint)C >> 27)) + H(D, E, A) + X[idx++] + Y2;
+ D = D << 30 | (int)((uint)D >> 2);
+
+ A += (B << 5 | (int)((uint)B >> 27)) + H(C, D, E) + X[idx++] + Y2;
+ C = C << 30 | (int)((uint)C >> 2);
+ }
+
+ //
+ // round 3
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (int)((uint)A >> 27)) + G(B, C, D) + X[idx++] + Y3;
+ B = B << 30 | (int)((uint)B >> 2);
+
+ D += (E << 5 | (int)((uint)E >> 27)) + G(A, B, C) + X[idx++] + Y3;
+ A = A << 30 | (int)((uint)A >> 2);
+
+ C += (D << 5 | (int)((uint)D >> 27)) + G(E, A, B) + X[idx++] + Y3;
+ E = E << 30 | (int)((uint)E >> 2);
+
+ B += (C << 5 | (int)((uint)C >> 27)) + G(D, E, A) + X[idx++] + Y3;
+ D = D << 30 | (int)((uint)D >> 2);
+
+ A += (B << 5 | (int)((uint)B >> 27)) + G(C, D, E) + X[idx++] + Y3;
+ C = C << 30 | (int)((uint)C >> 2);
+ }
+
+ //
+ // round 4
+ //
+ for (int j = 0; j <= 3; j++)
+ {
+ // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (int)((uint)A >> 27)) + H(B, C, D) + X[idx++] + Y4;
+ B = B << 30 | (int)((uint)B >> 2);
+
+ D += (E << 5 | (int)((uint)E >> 27)) + H(A, B, C) + X[idx++] + Y4;
+ A = A << 30 | (int)((uint)A >> 2);
+
+ C += (D << 5 | (int)((uint)D >> 27)) + H(E, A, B) + X[idx++] + Y4;
+ E = E << 30 | (int)((uint)E >> 2);
+
+ B += (C << 5 | (int)((uint)C >> 27)) + H(D, E, A) + X[idx++] + Y4;
+ D = D << 30 | (int)((uint)D >> 2);
+
+ A += (B << 5 | (int)((uint)B >> 27)) + H(C, D, E) + X[idx++] + Y4;
+ C = C << 30 | (int)((uint)C >> 2);
+ }
+
+ H1 += A;
+ H2 += B;
+ H3 += C;
+ H4 += D;
+ H5 += E;
+
+ //
+ // reset start of the buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/Sha224Digest.cs b/src/core/srcbc/crypto/digests/Sha224Digest.cs
new file mode 100644
index 0000000..da51ccf
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/Sha224Digest.cs
@@ -0,0 +1,287 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * SHA-224 as described in RFC 3874
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-224 512 32 224
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha224Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 28;
+
+ private int H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private int[] X = new int[64];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public Sha224Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha224Digest(
+ Sha224Digest t)
+ : base(t)
+ {
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-224"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16)
+ | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff));
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)((uint) word >> 24);
+ outBytes[outOff + 1] = (byte)((uint) word >> 16);
+ outBytes[outOff + 2] = (byte)((uint) word >> 8);
+ outBytes[outOff + 3] = (byte)word;
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)((ulong) bitLength >> 32);
+ X[15] = (int)(bitLength & 0xffffffff);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+ UnpackWord(H5, output, outOff + 16);
+ UnpackWord(H6, output, outOff + 20);
+ UnpackWord(H7, output, outOff + 24);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-224 initial hash value
+ */
+
+ unchecked
+ {
+ H1 = (int) 0xc1059ed8;
+ H2 = (int) 0x367cd507;
+ H3 = (int) 0x3070dd17;
+ H4 = (int) 0xf70e5939;
+ H5 = (int) 0xffc00b31;
+ H6 = (int) 0x68581511;
+ H7 = (int) 0x64f98fa7;
+ H8 = (int) 0xbefa4fa4;
+ }
+
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 64 word blocks.
+ //
+ for (int ti = 16; ti <= 63; ti++)
+ {
+ X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+ int e = H5;
+ int f = H6;
+ int g = H7;
+ int h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 8; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + (int)K[t] + X[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + (int)K[t] + X[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + (int)K[t] + X[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + (int)K[t] + X[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + (int)K[t] + X[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + (int)K[t] + X[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + (int)K[t] + X[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + (int)K[t] + X[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+
+ Array.Clear(X, 0, 16);
+ }
+
+ /* SHA-224 functions */
+ private static int Ch(
+ int x,
+ int y,
+ int z)
+ {
+ return ((x & y) ^ ((~x) & z));
+ }
+
+ private static int Maj(
+ int x,
+ int y,
+ int z)
+ {
+ return ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+ private static int Sum0(
+ int x)
+ {
+ return (((int)((uint)x >> 2)) | (x << 30)) ^ (((int)((uint)x >> 13)) | (x << 19)) ^ (((int)((uint)x >> 22)) | (x << 10));
+ }
+
+ private static int Sum1(
+ int x)
+ {
+ return (((int)((uint)x >> 6)) | (x << 26)) ^ (((int)((uint)x >> 11)) | (x << 21)) ^ (((int)((uint)x >> 25)) | (x << 7));
+ }
+
+ private static int Theta0(
+ int x)
+ {
+ return (((int)((uint)x >> 7)) | (x << 25)) ^ (((int)((uint)x >> 18)) | (x << 14)) ^ ((int)((uint)x >> 3));
+ }
+
+ private static int Theta1(
+ int x)
+ {
+ return (((int)((uint)x >> 17)) | (x << 15)) ^ (((int)((uint)x >> 19)) | (x << 13)) ^ ((int)((uint)x >> 10));
+ }
+
+ /* SHA-224 Constants
+ * (represent the first 32 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ internal static readonly uint[] K = {
+ 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
+ };
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/Sha256Digest.cs b/src/core/srcbc/crypto/digests/Sha256Digest.cs
new file mode 100644
index 0000000..de9c9da
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/Sha256Digest.cs
@@ -0,0 +1,310 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-256. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha256Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 32;
+
+ private int H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private int[] X = new int[64];
+ private int xOff;
+
+ public Sha256Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha256Digest(Sha256Digest t) : base(t)
+ {
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-256"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16)
+ | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff));
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)((uint) word >> 24);
+ outBytes[outOff + 1] = (byte)((uint) word >> 16);
+ outBytes[outOff + 2] = (byte)((uint) word >> 8);
+ outBytes[outOff + 3] = (byte)word;
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)((ulong) bitLength >> 32);
+ X[15] = (int)(bitLength & 0xffffffff);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+ UnpackWord(H5, output, outOff + 16);
+ UnpackWord(H6, output, outOff + 20);
+ UnpackWord(H7, output, outOff + 24);
+ UnpackWord(H8, output, outOff + 28);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-256 initial hash value
+ * The first 32 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+ unchecked
+ {
+ H1 = (int) 0x6a09e667;
+ H2 = (int) 0xbb67ae85;
+ H3 = (int) 0x3c6ef372;
+ H4 = (int) 0xa54ff53a;
+ H5 = (int) 0x510e527f;
+ H6 = (int) 0x9b05688c;
+ H7 = (int) 0x1f83d9ab;
+ H8 = (int) 0x5be0cd19;
+ }
+
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 64 word blocks.
+ //
+ for (int ti = 16; ti <= 63; ti++)
+ {
+ X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+ int e = H5;
+ int f = H6;
+ int g = H7;
+ int h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 8; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + X[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + X[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + X[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + X[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + X[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + X[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + X[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + X[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+
+ Array.Clear(X, 0, 16);
+ }
+
+ /* SHA-256 functions */
+ private static int Ch(
+ int x,
+ int y,
+ int z)
+ {
+ return ((x & y) ^ ((~x) & z));
+ }
+
+ private static int Maj(
+ int x,
+ int y,
+ int z)
+ {
+ return ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+ private static int Sum0(
+ int x)
+ {
+ return (((int)((uint)x >> 2)) | (x << 30)) ^ (((int)((uint)x >> 13)) | (x << 19)) ^ (((int)((uint)x >> 22)) | (x << 10));
+ }
+
+ private static int Sum1(
+ int x)
+ {
+ return (((int)((uint)x >> 6)) | (x << 26)) ^ (((int)((uint)x >> 11)) | (x << 21)) ^ (((int)((uint)x >> 25)) | (x << 7));
+ }
+
+ private static int Theta0(
+ int x)
+ {
+ return (((int)((uint)x >> 7)) | (x << 25)) ^ (((int)((uint)x >> 18)) | (x << 14)) ^ ((int)((uint)x >> 3));
+ }
+
+ private static int Theta1(
+ int x)
+ {
+ return (((int)((uint)x >> 17)) | (x << 15)) ^ (((int)((uint)x >> 19)) | (x << 13)) ^ ((int)((uint)x >> 10));
+ }
+
+ /* SHA-256 Constants
+ * (represent the first 32 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ internal static readonly int[] K = {
+ unchecked ((int) 0x428a2f98), unchecked ((int) 0x71374491),
+ unchecked ((int) 0xb5c0fbcf), unchecked ((int) 0xe9b5dba5),
+ unchecked ((int) 0x3956c25b), unchecked ((int) 0x59f111f1),
+ unchecked ((int) 0x923f82a4), unchecked ((int) 0xab1c5ed5),
+ unchecked ((int) 0xd807aa98), unchecked ((int) 0x12835b01),
+ unchecked ((int) 0x243185be), unchecked ((int) 0x550c7dc3),
+ unchecked ((int) 0x72be5d74), unchecked ((int) 0x80deb1fe),
+ unchecked ((int) 0x9bdc06a7), unchecked ((int) 0xc19bf174),
+ unchecked ((int) 0xe49b69c1), unchecked ((int) 0xefbe4786),
+ unchecked ((int) 0x0fc19dc6), unchecked ((int) 0x240ca1cc),
+ unchecked ((int) 0x2de92c6f), unchecked ((int) 0x4a7484aa),
+ unchecked ((int) 0x5cb0a9dc), unchecked ((int) 0x76f988da),
+ unchecked ((int) 0x983e5152), unchecked ((int) 0xa831c66d),
+ unchecked ((int) 0xb00327c8), unchecked ((int) 0xbf597fc7),
+ unchecked ((int) 0xc6e00bf3), unchecked ((int) 0xd5a79147),
+ unchecked ((int) 0x06ca6351), unchecked ((int) 0x14292967),
+ unchecked ((int) 0x27b70a85), unchecked ((int) 0x2e1b2138),
+ unchecked ((int) 0x4d2c6dfc), unchecked ((int) 0x53380d13),
+ unchecked ((int) 0x650a7354), unchecked ((int) 0x766a0abb),
+ unchecked ((int) 0x81c2c92e), unchecked ((int) 0x92722c85),
+ unchecked ((int) 0xa2bfe8a1), unchecked ((int) 0xa81a664b),
+ unchecked ((int) 0xc24b8b70), unchecked ((int) 0xc76c51a3),
+ unchecked ((int) 0xd192e819), unchecked ((int) 0xd6990624),
+ unchecked ((int) 0xf40e3585), unchecked ((int) 0x106aa070),
+ unchecked ((int) 0x19a4c116), unchecked ((int) 0x1e376c08),
+ unchecked ((int) 0x2748774c), unchecked ((int) 0x34b0bcb5),
+ unchecked ((int) 0x391c0cb3), unchecked ((int) 0x4ed8aa4a),
+ unchecked ((int) 0x5b9cca4f), unchecked ((int) 0x682e6ff3),
+ unchecked ((int) 0x748f82ee), unchecked ((int) 0x78a5636f),
+ unchecked ((int) 0x84c87814), unchecked ((int) 0x8cc70208),
+ unchecked ((int) 0x90befffa), unchecked ((int) 0xa4506ceb),
+ unchecked ((int) 0xbef9a3f7), unchecked ((int) 0xc67178f2)
+ };
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/Sha384Digest.cs b/src/core/srcbc/crypto/digests/Sha384Digest.cs
new file mode 100644
index 0000000..7fe6daf
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/Sha384Digest.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-384. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha384Digest
+ : LongDigest
+ {
+ private const int DigestLength = 48;
+
+ public Sha384Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha384Digest(
+ Sha384Digest t)
+ : base(t)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-384"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 16);
+ UnpackWord(H4, output, outOff + 24);
+ UnpackWord(H5, output, outOff + 32);
+ UnpackWord(H6, output, outOff + 40);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-384 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the 9th through 16th prime numbers
+ */
+ H1 = unchecked((long) 0xcbbb9d5dc1059ed8L);
+ H2 = unchecked((long) 0x629a292a367cd507L);
+ H3 = unchecked((long) 0x9159015a3070dd17L);
+ H4 = unchecked((long) 0x152fecd8f70e5939L);
+ H5 = unchecked((long) 0x67332667ffc00b31L);
+ H6 = unchecked((long) 0x8eb44a8768581511L);
+ H7 = unchecked((long) 0xdb0c2e0d64f98fa7L);
+ H8 = unchecked((long) 0x47b5481dbefa4fa4L);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/Sha512Digest.cs b/src/core/srcbc/crypto/digests/Sha512Digest.cs
new file mode 100644
index 0000000..4c47f4b
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/Sha512Digest.cs
@@ -0,0 +1,88 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-512. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha512Digest
+ : LongDigest
+ {
+ private const int DigestLength = 64;
+
+ public Sha512Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha512Digest(
+ Sha512Digest t)
+ : base(t)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-512"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 16);
+ UnpackWord(H4, output, outOff + 24);
+ UnpackWord(H5, output, outOff + 32);
+ UnpackWord(H6, output, outOff + 40);
+ UnpackWord(H7, output, outOff + 48);
+ UnpackWord(H8, output, outOff + 56);
+
+ Reset();
+
+ return DigestLength;
+
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-512 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+ H1 = unchecked((long) 0x6a09e667f3bcc908L);
+ H2 = unchecked((long) 0xbb67ae8584caa73bL);
+ H3 = unchecked((long) 0x3c6ef372fe94f82bL);
+ H4 = unchecked((long) 0xa54ff53a5f1d36f1L);
+ H5 = unchecked((long) 0x510e527fade682d1L);
+ H6 = unchecked((long) 0x9b05688c2b3e6c1fL);
+ H7 = unchecked((long) 0x1f83d9abfb41bd6bL);
+ H8 = unchecked((long) 0x5be0cd19137e2179L);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/ShortenedDigest.cs b/src/core/srcbc/crypto/digests/ShortenedDigest.cs
new file mode 100644
index 0000000..de0d325
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/ShortenedDigest.cs
@@ -0,0 +1,82 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Wrapper class that reduces the output length of a particular digest to
+ * only the first n bytes of the digest function.
+ */
+ public class ShortenedDigest
+ : IDigest
+ {
+ private IDigest baseDigest;
+ private int length;
+
+ /**
+ * Base constructor.
+ *
+ * @param baseDigest underlying digest to use.
+ * @param length length in bytes of the output of doFinal.
+ * @exception ArgumentException if baseDigest is null, or length is greater than baseDigest.GetDigestSize().
+ */
+ public ShortenedDigest(
+ IDigest baseDigest,
+ int length)
+ {
+ if (baseDigest == null)
+ {
+ throw new ArgumentNullException("baseDigest");
+ }
+
+ if (length > baseDigest.GetDigestSize())
+ {
+ throw new ArgumentException("baseDigest output not large enough to support length");
+ }
+
+ this.baseDigest = baseDigest;
+ this.length = length;
+ }
+
+ public string AlgorithmName
+ {
+ get { return baseDigest.AlgorithmName + "(" + length * 8 + ")"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return length;
+ }
+
+ public void Update(byte input)
+ {
+ baseDigest.Update(input);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ baseDigest.BlockUpdate(input, inOff, length);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ byte[] tmp = new byte[baseDigest.GetDigestSize()];
+
+ baseDigest.DoFinal(tmp, 0);
+
+ Array.Copy(tmp, 0, output, outOff, length);
+
+ return length;
+ }
+
+ public void Reset()
+ {
+ baseDigest.Reset();
+ }
+
+ public int GetByteLength()
+ {
+ return baseDigest.GetByteLength();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/TigerDigest.cs b/src/core/srcbc/crypto/digests/TigerDigest.cs
new file mode 100644
index 0000000..16a2b1c
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/TigerDigest.cs
@@ -0,0 +1,868 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of Tiger based on:
+ *
+ * http://www.cs.technion.ac.il/~biham/Reports/Tiger
+ */
+ public class TigerDigest
+ : IDigest
+ {
+ private const int MyByteLength = 64;
+
+ /*
+ * S-Boxes.
+ */
+ private static readonly long[] t1 = {
+ unchecked((long) 0x02AAB17CF7E90C5EL) /* 0 */, unchecked((long) 0xAC424B03E243A8ECL) /* 1 */,
+ unchecked((long) 0x72CD5BE30DD5FCD3L) /* 2 */, unchecked((long) 0x6D019B93F6F97F3AL) /* 3 */,
+ unchecked((long) 0xCD9978FFD21F9193L) /* 4 */, unchecked((long) 0x7573A1C9708029E2L) /* 5 */,
+ unchecked((long) 0xB164326B922A83C3L) /* 6 */, unchecked((long) 0x46883EEE04915870L) /* 7 */,
+ unchecked((long) 0xEAACE3057103ECE6L) /* 8 */, unchecked((long) 0xC54169B808A3535CL) /* 9 */,
+ unchecked((long) 0x4CE754918DDEC47CL) /* 10 */, unchecked((long) 0x0AA2F4DFDC0DF40CL) /* 11 */,
+ unchecked((long) 0x10B76F18A74DBEFAL) /* 12 */, unchecked((long) 0xC6CCB6235AD1AB6AL) /* 13 */,
+ unchecked((long) 0x13726121572FE2FFL) /* 14 */, unchecked((long) 0x1A488C6F199D921EL) /* 15 */,
+ unchecked((long) 0x4BC9F9F4DA0007CAL) /* 16 */, unchecked((long) 0x26F5E6F6E85241C7L) /* 17 */,
+ unchecked((long) 0x859079DBEA5947B6L) /* 18 */, unchecked((long) 0x4F1885C5C99E8C92L) /* 19 */,
+ unchecked((long) 0xD78E761EA96F864BL) /* 20 */, unchecked((long) 0x8E36428C52B5C17DL) /* 21 */,
+ unchecked((long) 0x69CF6827373063C1L) /* 22 */, unchecked((long) 0xB607C93D9BB4C56EL) /* 23 */,
+ unchecked((long) 0x7D820E760E76B5EAL) /* 24 */, unchecked((long) 0x645C9CC6F07FDC42L) /* 25 */,
+ unchecked((long) 0xBF38A078243342E0L) /* 26 */, unchecked((long) 0x5F6B343C9D2E7D04L) /* 27 */,
+ unchecked((long) 0xF2C28AEB600B0EC6L) /* 28 */, unchecked((long) 0x6C0ED85F7254BCACL) /* 29 */,
+ unchecked((long) 0x71592281A4DB4FE5L) /* 30 */, unchecked((long) 0x1967FA69CE0FED9FL) /* 31 */,
+ unchecked((long) 0xFD5293F8B96545DBL) /* 32 */, unchecked((long) 0xC879E9D7F2A7600BL) /* 33 */,
+ unchecked((long) 0x860248920193194EL) /* 34 */, unchecked((long) 0xA4F9533B2D9CC0B3L) /* 35 */,
+ unchecked((long) 0x9053836C15957613L) /* 36 */, unchecked((long) 0xDB6DCF8AFC357BF1L) /* 37 */,
+ unchecked((long) 0x18BEEA7A7A370F57L) /* 38 */, unchecked((long) 0x037117CA50B99066L) /* 39 */,
+ unchecked((long) 0x6AB30A9774424A35L) /* 40 */, unchecked((long) 0xF4E92F02E325249BL) /* 41 */,
+ unchecked((long) 0x7739DB07061CCAE1L) /* 42 */, unchecked((long) 0xD8F3B49CECA42A05L) /* 43 */,
+ unchecked((long) 0xBD56BE3F51382F73L) /* 44 */, unchecked((long) 0x45FAED5843B0BB28L) /* 45 */,
+ unchecked((long) 0x1C813D5C11BF1F83L) /* 46 */, unchecked((long) 0x8AF0E4B6D75FA169L) /* 47 */,
+ unchecked((long) 0x33EE18A487AD9999L) /* 48 */, unchecked((long) 0x3C26E8EAB1C94410L) /* 49 */,
+ unchecked((long) 0xB510102BC0A822F9L) /* 50 */, unchecked((long) 0x141EEF310CE6123BL) /* 51 */,
+ unchecked((long) 0xFC65B90059DDB154L) /* 52 */, unchecked((long) 0xE0158640C5E0E607L) /* 53 */,
+ unchecked((long) 0x884E079826C3A3CFL) /* 54 */, unchecked((long) 0x930D0D9523C535FDL) /* 55 */,
+ unchecked((long) 0x35638D754E9A2B00L) /* 56 */, unchecked((long) 0x4085FCCF40469DD5L) /* 57 */,
+ unchecked((long) 0xC4B17AD28BE23A4CL) /* 58 */, unchecked((long) 0xCAB2F0FC6A3E6A2EL) /* 59 */,
+ unchecked((long) 0x2860971A6B943FCDL) /* 60 */, unchecked((long) 0x3DDE6EE212E30446L) /* 61 */,
+ unchecked((long) 0x6222F32AE01765AEL) /* 62 */, unchecked((long) 0x5D550BB5478308FEL) /* 63 */,
+ unchecked((long) 0xA9EFA98DA0EDA22AL) /* 64 */, unchecked((long) 0xC351A71686C40DA7L) /* 65 */,
+ unchecked((long) 0x1105586D9C867C84L) /* 66 */, unchecked((long) 0xDCFFEE85FDA22853L) /* 67 */,
+ unchecked((long) 0xCCFBD0262C5EEF76L) /* 68 */, unchecked((long) 0xBAF294CB8990D201L) /* 69 */,
+ unchecked((long) 0xE69464F52AFAD975L) /* 70 */, unchecked((long) 0x94B013AFDF133E14L) /* 71 */,
+ unchecked((long) 0x06A7D1A32823C958L) /* 72 */, unchecked((long) 0x6F95FE5130F61119L) /* 73 */,
+ unchecked((long) 0xD92AB34E462C06C0L) /* 74 */, unchecked((long) 0xED7BDE33887C71D2L) /* 75 */,
+ unchecked((long) 0x79746D6E6518393EL) /* 76 */, unchecked((long) 0x5BA419385D713329L) /* 77 */,
+ unchecked((long) 0x7C1BA6B948A97564L) /* 78 */, unchecked((long) 0x31987C197BFDAC67L) /* 79 */,
+ unchecked((long) 0xDE6C23C44B053D02L) /* 80 */, unchecked((long) 0x581C49FED002D64DL) /* 81 */,
+ unchecked((long) 0xDD474D6338261571L) /* 82 */, unchecked((long) 0xAA4546C3E473D062L) /* 83 */,
+ unchecked((long) 0x928FCE349455F860L) /* 84 */, unchecked((long) 0x48161BBACAAB94D9L) /* 85 */,
+ unchecked((long) 0x63912430770E6F68L) /* 86 */, unchecked((long) 0x6EC8A5E602C6641CL) /* 87 */,
+ unchecked((long) 0x87282515337DDD2BL) /* 88 */, unchecked((long) 0x2CDA6B42034B701BL) /* 89 */,
+ unchecked((long) 0xB03D37C181CB096DL) /* 90 */, unchecked((long) 0xE108438266C71C6FL) /* 91 */,
+ unchecked((long) 0x2B3180C7EB51B255L) /* 92 */, unchecked((long) 0xDF92B82F96C08BBCL) /* 93 */,
+ unchecked((long) 0x5C68C8C0A632F3BAL) /* 94 */, unchecked((long) 0x5504CC861C3D0556L) /* 95 */,
+ unchecked((long) 0xABBFA4E55FB26B8FL) /* 96 */, unchecked((long) 0x41848B0AB3BACEB4L) /* 97 */,
+ unchecked((long) 0xB334A273AA445D32L) /* 98 */, unchecked((long) 0xBCA696F0A85AD881L) /* 99 */,
+ unchecked((long) 0x24F6EC65B528D56CL) /* 100 */, unchecked((long) 0x0CE1512E90F4524AL) /* 101 */,
+ unchecked((long) 0x4E9DD79D5506D35AL) /* 102 */, unchecked((long) 0x258905FAC6CE9779L) /* 103 */,
+ unchecked((long) 0x2019295B3E109B33L) /* 104 */, unchecked((long) 0xF8A9478B73A054CCL) /* 105 */,
+ unchecked((long) 0x2924F2F934417EB0L) /* 106 */, unchecked((long) 0x3993357D536D1BC4L) /* 107 */,
+ unchecked((long) 0x38A81AC21DB6FF8BL) /* 108 */, unchecked((long) 0x47C4FBF17D6016BFL) /* 109 */,
+ unchecked((long) 0x1E0FAADD7667E3F5L) /* 110 */, unchecked((long) 0x7ABCFF62938BEB96L) /* 111 */,
+ unchecked((long) 0xA78DAD948FC179C9L) /* 112 */, unchecked((long) 0x8F1F98B72911E50DL) /* 113 */,
+ unchecked((long) 0x61E48EAE27121A91L) /* 114 */, unchecked((long) 0x4D62F7AD31859808L) /* 115 */,
+ unchecked((long) 0xECEBA345EF5CEAEBL) /* 116 */, unchecked((long) 0xF5CEB25EBC9684CEL) /* 117 */,
+ unchecked((long) 0xF633E20CB7F76221L) /* 118 */, unchecked((long) 0xA32CDF06AB8293E4L) /* 119 */,
+ unchecked((long) 0x985A202CA5EE2CA4L) /* 120 */, unchecked((long) 0xCF0B8447CC8A8FB1L) /* 121 */,
+ unchecked((long) 0x9F765244979859A3L) /* 122 */, unchecked((long) 0xA8D516B1A1240017L) /* 123 */,
+ unchecked((long) 0x0BD7BA3EBB5DC726L) /* 124 */, unchecked((long) 0xE54BCA55B86ADB39L) /* 125 */,
+ unchecked((long) 0x1D7A3AFD6C478063L) /* 126 */, unchecked((long) 0x519EC608E7669EDDL) /* 127 */,
+ unchecked((long) 0x0E5715A2D149AA23L) /* 128 */, unchecked((long) 0x177D4571848FF194L) /* 129 */,
+ unchecked((long) 0xEEB55F3241014C22L) /* 130 */, unchecked((long) 0x0F5E5CA13A6E2EC2L) /* 131 */,
+ unchecked((long) 0x8029927B75F5C361L) /* 132 */, unchecked((long) 0xAD139FABC3D6E436L) /* 133 */,
+ unchecked((long) 0x0D5DF1A94CCF402FL) /* 134 */, unchecked((long) 0x3E8BD948BEA5DFC8L) /* 135 */,
+ unchecked((long) 0xA5A0D357BD3FF77EL) /* 136 */, unchecked((long) 0xA2D12E251F74F645L) /* 137 */,
+ unchecked((long) 0x66FD9E525E81A082L) /* 138 */, unchecked((long) 0x2E0C90CE7F687A49L) /* 139 */,
+ unchecked((long) 0xC2E8BCBEBA973BC5L) /* 140 */, unchecked((long) 0x000001BCE509745FL) /* 141 */,
+ unchecked((long) 0x423777BBE6DAB3D6L) /* 142 */, unchecked((long) 0xD1661C7EAEF06EB5L) /* 143 */,
+ unchecked((long) 0xA1781F354DAACFD8L) /* 144 */, unchecked((long) 0x2D11284A2B16AFFCL) /* 145 */,
+ unchecked((long) 0xF1FC4F67FA891D1FL) /* 146 */, unchecked((long) 0x73ECC25DCB920ADAL) /* 147 */,
+ unchecked((long) 0xAE610C22C2A12651L) /* 148 */, unchecked((long) 0x96E0A810D356B78AL) /* 149 */,
+ unchecked((long) 0x5A9A381F2FE7870FL) /* 150 */, unchecked((long) 0xD5AD62EDE94E5530L) /* 151 */,
+ unchecked((long) 0xD225E5E8368D1427L) /* 152 */, unchecked((long) 0x65977B70C7AF4631L) /* 153 */,
+ unchecked((long) 0x99F889B2DE39D74FL) /* 154 */, unchecked((long) 0x233F30BF54E1D143L) /* 155 */,
+ unchecked((long) 0x9A9675D3D9A63C97L) /* 156 */, unchecked((long) 0x5470554FF334F9A8L) /* 157 */,
+ unchecked((long) 0x166ACB744A4F5688L) /* 158 */, unchecked((long) 0x70C74CAAB2E4AEADL) /* 159 */,
+ unchecked((long) 0xF0D091646F294D12L) /* 160 */, unchecked((long) 0x57B82A89684031D1L) /* 161 */,
+ unchecked((long) 0xEFD95A5A61BE0B6BL) /* 162 */, unchecked((long) 0x2FBD12E969F2F29AL) /* 163 */,
+ unchecked((long) 0x9BD37013FEFF9FE8L) /* 164 */, unchecked((long) 0x3F9B0404D6085A06L) /* 165 */,
+ unchecked((long) 0x4940C1F3166CFE15L) /* 166 */, unchecked((long) 0x09542C4DCDF3DEFBL) /* 167 */,
+ unchecked((long) 0xB4C5218385CD5CE3L) /* 168 */, unchecked((long) 0xC935B7DC4462A641L) /* 169 */,
+ unchecked((long) 0x3417F8A68ED3B63FL) /* 170 */, unchecked((long) 0xB80959295B215B40L) /* 171 */,
+ unchecked((long) 0xF99CDAEF3B8C8572L) /* 172 */, unchecked((long) 0x018C0614F8FCB95DL) /* 173 */,
+ unchecked((long) 0x1B14ACCD1A3ACDF3L) /* 174 */, unchecked((long) 0x84D471F200BB732DL) /* 175 */,
+ unchecked((long) 0xC1A3110E95E8DA16L) /* 176 */, unchecked((long) 0x430A7220BF1A82B8L) /* 177 */,
+ unchecked((long) 0xB77E090D39DF210EL) /* 178 */, unchecked((long) 0x5EF4BD9F3CD05E9DL) /* 179 */,
+ unchecked((long) 0x9D4FF6DA7E57A444L) /* 180 */, unchecked((long) 0xDA1D60E183D4A5F8L) /* 181 */,
+ unchecked((long) 0xB287C38417998E47L) /* 182 */, unchecked((long) 0xFE3EDC121BB31886L) /* 183 */,
+ unchecked((long) 0xC7FE3CCC980CCBEFL) /* 184 */, unchecked((long) 0xE46FB590189BFD03L) /* 185 */,
+ unchecked((long) 0x3732FD469A4C57DCL) /* 186 */, unchecked((long) 0x7EF700A07CF1AD65L) /* 187 */,
+ unchecked((long) 0x59C64468A31D8859L) /* 188 */, unchecked((long) 0x762FB0B4D45B61F6L) /* 189 */,
+ unchecked((long) 0x155BAED099047718L) /* 190 */, unchecked((long) 0x68755E4C3D50BAA6L) /* 191 */,
+ unchecked((long) 0xE9214E7F22D8B4DFL) /* 192 */, unchecked((long) 0x2ADDBF532EAC95F4L) /* 193 */,
+ unchecked((long) 0x32AE3909B4BD0109L) /* 194 */, unchecked((long) 0x834DF537B08E3450L) /* 195 */,
+ unchecked((long) 0xFA209DA84220728DL) /* 196 */, unchecked((long) 0x9E691D9B9EFE23F7L) /* 197 */,
+ unchecked((long) 0x0446D288C4AE8D7FL) /* 198 */, unchecked((long) 0x7B4CC524E169785BL) /* 199 */,
+ unchecked((long) 0x21D87F0135CA1385L) /* 200 */, unchecked((long) 0xCEBB400F137B8AA5L) /* 201 */,
+ unchecked((long) 0x272E2B66580796BEL) /* 202 */, unchecked((long) 0x3612264125C2B0DEL) /* 203 */,
+ unchecked((long) 0x057702BDAD1EFBB2L) /* 204 */, unchecked((long) 0xD4BABB8EACF84BE9L) /* 205 */,
+ unchecked((long) 0x91583139641BC67BL) /* 206 */, unchecked((long) 0x8BDC2DE08036E024L) /* 207 */,
+ unchecked((long) 0x603C8156F49F68EDL) /* 208 */, unchecked((long) 0xF7D236F7DBEF5111L) /* 209 */,
+ unchecked((long) 0x9727C4598AD21E80L) /* 210 */, unchecked((long) 0xA08A0896670A5FD7L) /* 211 */,
+ unchecked((long) 0xCB4A8F4309EBA9CBL) /* 212 */, unchecked((long) 0x81AF564B0F7036A1L) /* 213 */,
+ unchecked((long) 0xC0B99AA778199ABDL) /* 214 */, unchecked((long) 0x959F1EC83FC8E952L) /* 215 */,
+ unchecked((long) 0x8C505077794A81B9L) /* 216 */, unchecked((long) 0x3ACAAF8F056338F0L) /* 217 */,
+ unchecked((long) 0x07B43F50627A6778L) /* 218 */, unchecked((long) 0x4A44AB49F5ECCC77L) /* 219 */,
+ unchecked((long) 0x3BC3D6E4B679EE98L) /* 220 */, unchecked((long) 0x9CC0D4D1CF14108CL) /* 221 */,
+ unchecked((long) 0x4406C00B206BC8A0L) /* 222 */, unchecked((long) 0x82A18854C8D72D89L) /* 223 */,
+ unchecked((long) 0x67E366B35C3C432CL) /* 224 */, unchecked((long) 0xB923DD61102B37F2L) /* 225 */,
+ unchecked((long) 0x56AB2779D884271DL) /* 226 */, unchecked((long) 0xBE83E1B0FF1525AFL) /* 227 */,
+ unchecked((long) 0xFB7C65D4217E49A9L) /* 228 */, unchecked((long) 0x6BDBE0E76D48E7D4L) /* 229 */,
+ unchecked((long) 0x08DF828745D9179EL) /* 230 */, unchecked((long) 0x22EA6A9ADD53BD34L) /* 231 */,
+ unchecked((long) 0xE36E141C5622200AL) /* 232 */, unchecked((long) 0x7F805D1B8CB750EEL) /* 233 */,
+ unchecked((long) 0xAFE5C7A59F58E837L) /* 234 */, unchecked((long) 0xE27F996A4FB1C23CL) /* 235 */,
+ unchecked((long) 0xD3867DFB0775F0D0L) /* 236 */, unchecked((long) 0xD0E673DE6E88891AL) /* 237 */,
+ unchecked((long) 0x123AEB9EAFB86C25L) /* 238 */, unchecked((long) 0x30F1D5D5C145B895L) /* 239 */,
+ unchecked((long) 0xBB434A2DEE7269E7L) /* 240 */, unchecked((long) 0x78CB67ECF931FA38L) /* 241 */,
+ unchecked((long) 0xF33B0372323BBF9CL) /* 242 */, unchecked((long) 0x52D66336FB279C74L) /* 243 */,
+ unchecked((long) 0x505F33AC0AFB4EAAL) /* 244 */, unchecked((long) 0xE8A5CD99A2CCE187L) /* 245 */,
+ unchecked((long) 0x534974801E2D30BBL) /* 246 */, unchecked((long) 0x8D2D5711D5876D90L) /* 247 */,
+ unchecked((long) 0x1F1A412891BC038EL) /* 248 */, unchecked((long) 0xD6E2E71D82E56648L) /* 249 */,
+ unchecked((long) 0x74036C3A497732B7L) /* 250 */, unchecked((long) 0x89B67ED96361F5ABL) /* 251 */,
+ unchecked((long) 0xFFED95D8F1EA02A2L) /* 252 */, unchecked((long) 0xE72B3BD61464D43DL) /* 253 */,
+ unchecked((long) 0xA6300F170BDC4820L) /* 254 */, unchecked((long) 0xEBC18760ED78A77AL) /* 255 */,
+ };
+
+ private static readonly long[] t2 = {
+ unchecked((long) 0xE6A6BE5A05A12138L) /* 256 */, unchecked((long) 0xB5A122A5B4F87C98L) /* 257 */,
+ unchecked((long) 0x563C6089140B6990L) /* 258 */, unchecked((long) 0x4C46CB2E391F5DD5L) /* 259 */,
+ unchecked((long) 0xD932ADDBC9B79434L) /* 260 */, unchecked((long) 0x08EA70E42015AFF5L) /* 261 */,
+ unchecked((long) 0xD765A6673E478CF1L) /* 262 */, unchecked((long) 0xC4FB757EAB278D99L) /* 263 */,
+ unchecked((long) 0xDF11C6862D6E0692L) /* 264 */, unchecked((long) 0xDDEB84F10D7F3B16L) /* 265 */,
+ unchecked((long) 0x6F2EF604A665EA04L) /* 266 */, unchecked((long) 0x4A8E0F0FF0E0DFB3L) /* 267 */,
+ unchecked((long) 0xA5EDEEF83DBCBA51L) /* 268 */, unchecked((long) 0xFC4F0A2A0EA4371EL) /* 269 */,
+ unchecked((long) 0xE83E1DA85CB38429L) /* 270 */, unchecked((long) 0xDC8FF882BA1B1CE2L) /* 271 */,
+ unchecked((long) 0xCD45505E8353E80DL) /* 272 */, unchecked((long) 0x18D19A00D4DB0717L) /* 273 */,
+ unchecked((long) 0x34A0CFEDA5F38101L) /* 274 */, unchecked((long) 0x0BE77E518887CAF2L) /* 275 */,
+ unchecked((long) 0x1E341438B3C45136L) /* 276 */, unchecked((long) 0xE05797F49089CCF9L) /* 277 */,
+ unchecked((long) 0xFFD23F9DF2591D14L) /* 278 */, unchecked((long) 0x543DDA228595C5CDL) /* 279 */,
+ unchecked((long) 0x661F81FD99052A33L) /* 280 */, unchecked((long) 0x8736E641DB0F7B76L) /* 281 */,
+ unchecked((long) 0x15227725418E5307L) /* 282 */, unchecked((long) 0xE25F7F46162EB2FAL) /* 283 */,
+ unchecked((long) 0x48A8B2126C13D9FEL) /* 284 */, unchecked((long) 0xAFDC541792E76EEAL) /* 285 */,
+ unchecked((long) 0x03D912BFC6D1898FL) /* 286 */, unchecked((long) 0x31B1AAFA1B83F51BL) /* 287 */,
+ unchecked((long) 0xF1AC2796E42AB7D9L) /* 288 */, unchecked((long) 0x40A3A7D7FCD2EBACL) /* 289 */,
+ unchecked((long) 0x1056136D0AFBBCC5L) /* 290 */, unchecked((long) 0x7889E1DD9A6D0C85L) /* 291 */,
+ unchecked((long) 0xD33525782A7974AAL) /* 292 */, unchecked((long) 0xA7E25D09078AC09BL) /* 293 */,
+ unchecked((long) 0xBD4138B3EAC6EDD0L) /* 294 */, unchecked((long) 0x920ABFBE71EB9E70L) /* 295 */,
+ unchecked((long) 0xA2A5D0F54FC2625CL) /* 296 */, unchecked((long) 0xC054E36B0B1290A3L) /* 297 */,
+ unchecked((long) 0xF6DD59FF62FE932BL) /* 298 */, unchecked((long) 0x3537354511A8AC7DL) /* 299 */,
+ unchecked((long) 0xCA845E9172FADCD4L) /* 300 */, unchecked((long) 0x84F82B60329D20DCL) /* 301 */,
+ unchecked((long) 0x79C62CE1CD672F18L) /* 302 */, unchecked((long) 0x8B09A2ADD124642CL) /* 303 */,
+ unchecked((long) 0xD0C1E96A19D9E726L) /* 304 */, unchecked((long) 0x5A786A9B4BA9500CL) /* 305 */,
+ unchecked((long) 0x0E020336634C43F3L) /* 306 */, unchecked((long) 0xC17B474AEB66D822L) /* 307 */,
+ unchecked((long) 0x6A731AE3EC9BAAC2L) /* 308 */, unchecked((long) 0x8226667AE0840258L) /* 309 */,
+ unchecked((long) 0x67D4567691CAECA5L) /* 310 */, unchecked((long) 0x1D94155C4875ADB5L) /* 311 */,
+ unchecked((long) 0x6D00FD985B813FDFL) /* 312 */, unchecked((long) 0x51286EFCB774CD06L) /* 313 */,
+ unchecked((long) 0x5E8834471FA744AFL) /* 314 */, unchecked((long) 0xF72CA0AEE761AE2EL) /* 315 */,
+ unchecked((long) 0xBE40E4CDAEE8E09AL) /* 316 */, unchecked((long) 0xE9970BBB5118F665L) /* 317 */,
+ unchecked((long) 0x726E4BEB33DF1964L) /* 318 */, unchecked((long) 0x703B000729199762L) /* 319 */,
+ unchecked((long) 0x4631D816F5EF30A7L) /* 320 */, unchecked((long) 0xB880B5B51504A6BEL) /* 321 */,
+ unchecked((long) 0x641793C37ED84B6CL) /* 322 */, unchecked((long) 0x7B21ED77F6E97D96L) /* 323 */,
+ unchecked((long) 0x776306312EF96B73L) /* 324 */, unchecked((long) 0xAE528948E86FF3F4L) /* 325 */,
+ unchecked((long) 0x53DBD7F286A3F8F8L) /* 326 */, unchecked((long) 0x16CADCE74CFC1063L) /* 327 */,
+ unchecked((long) 0x005C19BDFA52C6DDL) /* 328 */, unchecked((long) 0x68868F5D64D46AD3L) /* 329 */,
+ unchecked((long) 0x3A9D512CCF1E186AL) /* 330 */, unchecked((long) 0x367E62C2385660AEL) /* 331 */,
+ unchecked((long) 0xE359E7EA77DCB1D7L) /* 332 */, unchecked((long) 0x526C0773749ABE6EL) /* 333 */,
+ unchecked((long) 0x735AE5F9D09F734BL) /* 334 */, unchecked((long) 0x493FC7CC8A558BA8L) /* 335 */,
+ unchecked((long) 0xB0B9C1533041AB45L) /* 336 */, unchecked((long) 0x321958BA470A59BDL) /* 337 */,
+ unchecked((long) 0x852DB00B5F46C393L) /* 338 */, unchecked((long) 0x91209B2BD336B0E5L) /* 339 */,
+ unchecked((long) 0x6E604F7D659EF19FL) /* 340 */, unchecked((long) 0xB99A8AE2782CCB24L) /* 341 */,
+ unchecked((long) 0xCCF52AB6C814C4C7L) /* 342 */, unchecked((long) 0x4727D9AFBE11727BL) /* 343 */,
+ unchecked((long) 0x7E950D0C0121B34DL) /* 344 */, unchecked((long) 0x756F435670AD471FL) /* 345 */,
+ unchecked((long) 0xF5ADD442615A6849L) /* 346 */, unchecked((long) 0x4E87E09980B9957AL) /* 347 */,
+ unchecked((long) 0x2ACFA1DF50AEE355L) /* 348 */, unchecked((long) 0xD898263AFD2FD556L) /* 349 */,
+ unchecked((long) 0xC8F4924DD80C8FD6L) /* 350 */, unchecked((long) 0xCF99CA3D754A173AL) /* 351 */,
+ unchecked((long) 0xFE477BACAF91BF3CL) /* 352 */, unchecked((long) 0xED5371F6D690C12DL) /* 353 */,
+ unchecked((long) 0x831A5C285E687094L) /* 354 */, unchecked((long) 0xC5D3C90A3708A0A4L) /* 355 */,
+ unchecked((long) 0x0F7F903717D06580L) /* 356 */, unchecked((long) 0x19F9BB13B8FDF27FL) /* 357 */,
+ unchecked((long) 0xB1BD6F1B4D502843L) /* 358 */, unchecked((long) 0x1C761BA38FFF4012L) /* 359 */,
+ unchecked((long) 0x0D1530C4E2E21F3BL) /* 360 */, unchecked((long) 0x8943CE69A7372C8AL) /* 361 */,
+ unchecked((long) 0xE5184E11FEB5CE66L) /* 362 */, unchecked((long) 0x618BDB80BD736621L) /* 363 */,
+ unchecked((long) 0x7D29BAD68B574D0BL) /* 364 */, unchecked((long) 0x81BB613E25E6FE5BL) /* 365 */,
+ unchecked((long) 0x071C9C10BC07913FL) /* 366 */, unchecked((long) 0xC7BEEB7909AC2D97L) /* 367 */,
+ unchecked((long) 0xC3E58D353BC5D757L) /* 368 */, unchecked((long) 0xEB017892F38F61E8L) /* 369 */,
+ unchecked((long) 0xD4EFFB9C9B1CC21AL) /* 370 */, unchecked((long) 0x99727D26F494F7ABL) /* 371 */,
+ unchecked((long) 0xA3E063A2956B3E03L) /* 372 */, unchecked((long) 0x9D4A8B9A4AA09C30L) /* 373 */,
+ unchecked((long) 0x3F6AB7D500090FB4L) /* 374 */, unchecked((long) 0x9CC0F2A057268AC0L) /* 375 */,
+ unchecked((long) 0x3DEE9D2DEDBF42D1L) /* 376 */, unchecked((long) 0x330F49C87960A972L) /* 377 */,
+ unchecked((long) 0xC6B2720287421B41L) /* 378 */, unchecked((long) 0x0AC59EC07C00369CL) /* 379 */,
+ unchecked((long) 0xEF4EAC49CB353425L) /* 380 */, unchecked((long) 0xF450244EEF0129D8L) /* 381 */,
+ unchecked((long) 0x8ACC46E5CAF4DEB6L) /* 382 */, unchecked((long) 0x2FFEAB63989263F7L) /* 383 */,
+ unchecked((long) 0x8F7CB9FE5D7A4578L) /* 384 */, unchecked((long) 0x5BD8F7644E634635L) /* 385 */,
+ unchecked((long) 0x427A7315BF2DC900L) /* 386 */, unchecked((long) 0x17D0C4AA2125261CL) /* 387 */,
+ unchecked((long) 0x3992486C93518E50L) /* 388 */, unchecked((long) 0xB4CBFEE0A2D7D4C3L) /* 389 */,
+ unchecked((long) 0x7C75D6202C5DDD8DL) /* 390 */, unchecked((long) 0xDBC295D8E35B6C61L) /* 391 */,
+ unchecked((long) 0x60B369D302032B19L) /* 392 */, unchecked((long) 0xCE42685FDCE44132L) /* 393 */,
+ unchecked((long) 0x06F3DDB9DDF65610L) /* 394 */, unchecked((long) 0x8EA4D21DB5E148F0L) /* 395 */,
+ unchecked((long) 0x20B0FCE62FCD496FL) /* 396 */, unchecked((long) 0x2C1B912358B0EE31L) /* 397 */,
+ unchecked((long) 0xB28317B818F5A308L) /* 398 */, unchecked((long) 0xA89C1E189CA6D2CFL) /* 399 */,
+ unchecked((long) 0x0C6B18576AAADBC8L) /* 400 */, unchecked((long) 0xB65DEAA91299FAE3L) /* 401 */,
+ unchecked((long) 0xFB2B794B7F1027E7L) /* 402 */, unchecked((long) 0x04E4317F443B5BEBL) /* 403 */,
+ unchecked((long) 0x4B852D325939D0A6L) /* 404 */, unchecked((long) 0xD5AE6BEEFB207FFCL) /* 405 */,
+ unchecked((long) 0x309682B281C7D374L) /* 406 */, unchecked((long) 0xBAE309A194C3B475L) /* 407 */,
+ unchecked((long) 0x8CC3F97B13B49F05L) /* 408 */, unchecked((long) 0x98A9422FF8293967L) /* 409 */,
+ unchecked((long) 0x244B16B01076FF7CL) /* 410 */, unchecked((long) 0xF8BF571C663D67EEL) /* 411 */,
+ unchecked((long) 0x1F0D6758EEE30DA1L) /* 412 */, unchecked((long) 0xC9B611D97ADEB9B7L) /* 413 */,
+ unchecked((long) 0xB7AFD5887B6C57A2L) /* 414 */, unchecked((long) 0x6290AE846B984FE1L) /* 415 */,
+ unchecked((long) 0x94DF4CDEACC1A5FDL) /* 416 */, unchecked((long) 0x058A5BD1C5483AFFL) /* 417 */,
+ unchecked((long) 0x63166CC142BA3C37L) /* 418 */, unchecked((long) 0x8DB8526EB2F76F40L) /* 419 */,
+ unchecked((long) 0xE10880036F0D6D4EL) /* 420 */, unchecked((long) 0x9E0523C9971D311DL) /* 421 */,
+ unchecked((long) 0x45EC2824CC7CD691L) /* 422 */, unchecked((long) 0x575B8359E62382C9L) /* 423 */,
+ unchecked((long) 0xFA9E400DC4889995L) /* 424 */, unchecked((long) 0xD1823ECB45721568L) /* 425 */,
+ unchecked((long) 0xDAFD983B8206082FL) /* 426 */, unchecked((long) 0xAA7D29082386A8CBL) /* 427 */,
+ unchecked((long) 0x269FCD4403B87588L) /* 428 */, unchecked((long) 0x1B91F5F728BDD1E0L) /* 429 */,
+ unchecked((long) 0xE4669F39040201F6L) /* 430 */, unchecked((long) 0x7A1D7C218CF04ADEL) /* 431 */,
+ unchecked((long) 0x65623C29D79CE5CEL) /* 432 */, unchecked((long) 0x2368449096C00BB1L) /* 433 */,
+ unchecked((long) 0xAB9BF1879DA503BAL) /* 434 */, unchecked((long) 0xBC23ECB1A458058EL) /* 435 */,
+ unchecked((long) 0x9A58DF01BB401ECCL) /* 436 */, unchecked((long) 0xA070E868A85F143DL) /* 437 */,
+ unchecked((long) 0x4FF188307DF2239EL) /* 438 */, unchecked((long) 0x14D565B41A641183L) /* 439 */,
+ unchecked((long) 0xEE13337452701602L) /* 440 */, unchecked((long) 0x950E3DCF3F285E09L) /* 441 */,
+ unchecked((long) 0x59930254B9C80953L) /* 442 */, unchecked((long) 0x3BF299408930DA6DL) /* 443 */,
+ unchecked((long) 0xA955943F53691387L) /* 444 */, unchecked((long) 0xA15EDECAA9CB8784L) /* 445 */,
+ unchecked((long) 0x29142127352BE9A0L) /* 446 */, unchecked((long) 0x76F0371FFF4E7AFBL) /* 447 */,
+ unchecked((long) 0x0239F450274F2228L) /* 448 */, unchecked((long) 0xBB073AF01D5E868BL) /* 449 */,
+ unchecked((long) 0xBFC80571C10E96C1L) /* 450 */, unchecked((long) 0xD267088568222E23L) /* 451 */,
+ unchecked((long) 0x9671A3D48E80B5B0L) /* 452 */, unchecked((long) 0x55B5D38AE193BB81L) /* 453 */,
+ unchecked((long) 0x693AE2D0A18B04B8L) /* 454 */, unchecked((long) 0x5C48B4ECADD5335FL) /* 455 */,
+ unchecked((long) 0xFD743B194916A1CAL) /* 456 */, unchecked((long) 0x2577018134BE98C4L) /* 457 */,
+ unchecked((long) 0xE77987E83C54A4ADL) /* 458 */, unchecked((long) 0x28E11014DA33E1B9L) /* 459 */,
+ unchecked((long) 0x270CC59E226AA213L) /* 460 */, unchecked((long) 0x71495F756D1A5F60L) /* 461 */,
+ unchecked((long) 0x9BE853FB60AFEF77L) /* 462 */, unchecked((long) 0xADC786A7F7443DBFL) /* 463 */,
+ unchecked((long) 0x0904456173B29A82L) /* 464 */, unchecked((long) 0x58BC7A66C232BD5EL) /* 465 */,
+ unchecked((long) 0xF306558C673AC8B2L) /* 466 */, unchecked((long) 0x41F639C6B6C9772AL) /* 467 */,
+ unchecked((long) 0x216DEFE99FDA35DAL) /* 468 */, unchecked((long) 0x11640CC71C7BE615L) /* 469 */,
+ unchecked((long) 0x93C43694565C5527L) /* 470 */, unchecked((long) 0xEA038E6246777839L) /* 471 */,
+ unchecked((long) 0xF9ABF3CE5A3E2469L) /* 472 */, unchecked((long) 0x741E768D0FD312D2L) /* 473 */,
+ unchecked((long) 0x0144B883CED652C6L) /* 474 */, unchecked((long) 0xC20B5A5BA33F8552L) /* 475 */,
+ unchecked((long) 0x1AE69633C3435A9DL) /* 476 */, unchecked((long) 0x97A28CA4088CFDECL) /* 477 */,
+ unchecked((long) 0x8824A43C1E96F420L) /* 478 */, unchecked((long) 0x37612FA66EEEA746L) /* 479 */,
+ unchecked((long) 0x6B4CB165F9CF0E5AL) /* 480 */, unchecked((long) 0x43AA1C06A0ABFB4AL) /* 481 */,
+ unchecked((long) 0x7F4DC26FF162796BL) /* 482 */, unchecked((long) 0x6CBACC8E54ED9B0FL) /* 483 */,
+ unchecked((long) 0xA6B7FFEFD2BB253EL) /* 484 */, unchecked((long) 0x2E25BC95B0A29D4FL) /* 485 */,
+ unchecked((long) 0x86D6A58BDEF1388CL) /* 486 */, unchecked((long) 0xDED74AC576B6F054L) /* 487 */,
+ unchecked((long) 0x8030BDBC2B45805DL) /* 488 */, unchecked((long) 0x3C81AF70E94D9289L) /* 489 */,
+ unchecked((long) 0x3EFF6DDA9E3100DBL) /* 490 */, unchecked((long) 0xB38DC39FDFCC8847L) /* 491 */,
+ unchecked((long) 0x123885528D17B87EL) /* 492 */, unchecked((long) 0xF2DA0ED240B1B642L) /* 493 */,
+ unchecked((long) 0x44CEFADCD54BF9A9L) /* 494 */, unchecked((long) 0x1312200E433C7EE6L) /* 495 */,
+ unchecked((long) 0x9FFCC84F3A78C748L) /* 496 */, unchecked((long) 0xF0CD1F72248576BBL) /* 497 */,
+ unchecked((long) 0xEC6974053638CFE4L) /* 498 */, unchecked((long) 0x2BA7B67C0CEC4E4CL) /* 499 */,
+ unchecked((long) 0xAC2F4DF3E5CE32EDL) /* 500 */, unchecked((long) 0xCB33D14326EA4C11L) /* 501 */,
+ unchecked((long) 0xA4E9044CC77E58BCL) /* 502 */, unchecked((long) 0x5F513293D934FCEFL) /* 503 */,
+ unchecked((long) 0x5DC9645506E55444L) /* 504 */, unchecked((long) 0x50DE418F317DE40AL) /* 505 */,
+ unchecked((long) 0x388CB31A69DDE259L) /* 506 */, unchecked((long) 0x2DB4A83455820A86L) /* 507 */,
+ unchecked((long) 0x9010A91E84711AE9L) /* 508 */, unchecked((long) 0x4DF7F0B7B1498371L) /* 509 */,
+ unchecked((long) 0xD62A2EABC0977179L) /* 510 */, unchecked((long) 0x22FAC097AA8D5C0EL) /* 511 */,
+ };
+
+ private static readonly long[] t3 = {
+ unchecked((long) 0xF49FCC2FF1DAF39BL) /* 512 */, unchecked((long) 0x487FD5C66FF29281L) /* 513 */,
+ unchecked((long) 0xE8A30667FCDCA83FL) /* 514 */, unchecked((long) 0x2C9B4BE3D2FCCE63L) /* 515 */,
+ unchecked((long) 0xDA3FF74B93FBBBC2L) /* 516 */, unchecked((long) 0x2FA165D2FE70BA66L) /* 517 */,
+ unchecked((long) 0xA103E279970E93D4L) /* 518 */, unchecked((long) 0xBECDEC77B0E45E71L) /* 519 */,
+ unchecked((long) 0xCFB41E723985E497L) /* 520 */, unchecked((long) 0xB70AAA025EF75017L) /* 521 */,
+ unchecked((long) 0xD42309F03840B8E0L) /* 522 */, unchecked((long) 0x8EFC1AD035898579L) /* 523 */,
+ unchecked((long) 0x96C6920BE2B2ABC5L) /* 524 */, unchecked((long) 0x66AF4163375A9172L) /* 525 */,
+ unchecked((long) 0x2174ABDCCA7127FBL) /* 526 */, unchecked((long) 0xB33CCEA64A72FF41L) /* 527 */,
+ unchecked((long) 0xF04A4933083066A5L) /* 528 */, unchecked((long) 0x8D970ACDD7289AF5L) /* 529 */,
+ unchecked((long) 0x8F96E8E031C8C25EL) /* 530 */, unchecked((long) 0xF3FEC02276875D47L) /* 531 */,
+ unchecked((long) 0xEC7BF310056190DDL) /* 532 */, unchecked((long) 0xF5ADB0AEBB0F1491L) /* 533 */,
+ unchecked((long) 0x9B50F8850FD58892L) /* 534 */, unchecked((long) 0x4975488358B74DE8L) /* 535 */,
+ unchecked((long) 0xA3354FF691531C61L) /* 536 */, unchecked((long) 0x0702BBE481D2C6EEL) /* 537 */,
+ unchecked((long) 0x89FB24057DEDED98L) /* 538 */, unchecked((long) 0xAC3075138596E902L) /* 539 */,
+ unchecked((long) 0x1D2D3580172772EDL) /* 540 */, unchecked((long) 0xEB738FC28E6BC30DL) /* 541 */,
+ unchecked((long) 0x5854EF8F63044326L) /* 542 */, unchecked((long) 0x9E5C52325ADD3BBEL) /* 543 */,
+ unchecked((long) 0x90AA53CF325C4623L) /* 544 */, unchecked((long) 0xC1D24D51349DD067L) /* 545 */,
+ unchecked((long) 0x2051CFEEA69EA624L) /* 546 */, unchecked((long) 0x13220F0A862E7E4FL) /* 547 */,
+ unchecked((long) 0xCE39399404E04864L) /* 548 */, unchecked((long) 0xD9C42CA47086FCB7L) /* 549 */,
+ unchecked((long) 0x685AD2238A03E7CCL) /* 550 */, unchecked((long) 0x066484B2AB2FF1DBL) /* 551 */,
+ unchecked((long) 0xFE9D5D70EFBF79ECL) /* 552 */, unchecked((long) 0x5B13B9DD9C481854L) /* 553 */,
+ unchecked((long) 0x15F0D475ED1509ADL) /* 554 */, unchecked((long) 0x0BEBCD060EC79851L) /* 555 */,
+ unchecked((long) 0xD58C6791183AB7F8L) /* 556 */, unchecked((long) 0xD1187C5052F3EEE4L) /* 557 */,
+ unchecked((long) 0xC95D1192E54E82FFL) /* 558 */, unchecked((long) 0x86EEA14CB9AC6CA2L) /* 559 */,
+ unchecked((long) 0x3485BEB153677D5DL) /* 560 */, unchecked((long) 0xDD191D781F8C492AL) /* 561 */,
+ unchecked((long) 0xF60866BAA784EBF9L) /* 562 */, unchecked((long) 0x518F643BA2D08C74L) /* 563 */,
+ unchecked((long) 0x8852E956E1087C22L) /* 564 */, unchecked((long) 0xA768CB8DC410AE8DL) /* 565 */,
+ unchecked((long) 0x38047726BFEC8E1AL) /* 566 */, unchecked((long) 0xA67738B4CD3B45AAL) /* 567 */,
+ unchecked((long) 0xAD16691CEC0DDE19L) /* 568 */, unchecked((long) 0xC6D4319380462E07L) /* 569 */,
+ unchecked((long) 0xC5A5876D0BA61938L) /* 570 */, unchecked((long) 0x16B9FA1FA58FD840L) /* 571 */,
+ unchecked((long) 0x188AB1173CA74F18L) /* 572 */, unchecked((long) 0xABDA2F98C99C021FL) /* 573 */,
+ unchecked((long) 0x3E0580AB134AE816L) /* 574 */, unchecked((long) 0x5F3B05B773645ABBL) /* 575 */,
+ unchecked((long) 0x2501A2BE5575F2F6L) /* 576 */, unchecked((long) 0x1B2F74004E7E8BA9L) /* 577 */,
+ unchecked((long) 0x1CD7580371E8D953L) /* 578 */, unchecked((long) 0x7F6ED89562764E30L) /* 579 */,
+ unchecked((long) 0xB15926FF596F003DL) /* 580 */, unchecked((long) 0x9F65293DA8C5D6B9L) /* 581 */,
+ unchecked((long) 0x6ECEF04DD690F84CL) /* 582 */, unchecked((long) 0x4782275FFF33AF88L) /* 583 */,
+ unchecked((long) 0xE41433083F820801L) /* 584 */, unchecked((long) 0xFD0DFE409A1AF9B5L) /* 585 */,
+ unchecked((long) 0x4325A3342CDB396BL) /* 586 */, unchecked((long) 0x8AE77E62B301B252L) /* 587 */,
+ unchecked((long) 0xC36F9E9F6655615AL) /* 588 */, unchecked((long) 0x85455A2D92D32C09L) /* 589 */,
+ unchecked((long) 0xF2C7DEA949477485L) /* 590 */, unchecked((long) 0x63CFB4C133A39EBAL) /* 591 */,
+ unchecked((long) 0x83B040CC6EBC5462L) /* 592 */, unchecked((long) 0x3B9454C8FDB326B0L) /* 593 */,
+ unchecked((long) 0x56F56A9E87FFD78CL) /* 594 */, unchecked((long) 0x2DC2940D99F42BC6L) /* 595 */,
+ unchecked((long) 0x98F7DF096B096E2DL) /* 596 */, unchecked((long) 0x19A6E01E3AD852BFL) /* 597 */,
+ unchecked((long) 0x42A99CCBDBD4B40BL) /* 598 */, unchecked((long) 0xA59998AF45E9C559L) /* 599 */,
+ unchecked((long) 0x366295E807D93186L) /* 600 */, unchecked((long) 0x6B48181BFAA1F773L) /* 601 */,
+ unchecked((long) 0x1FEC57E2157A0A1DL) /* 602 */, unchecked((long) 0x4667446AF6201AD5L) /* 603 */,
+ unchecked((long) 0xE615EBCACFB0F075L) /* 604 */, unchecked((long) 0xB8F31F4F68290778L) /* 605 */,
+ unchecked((long) 0x22713ED6CE22D11EL) /* 606 */, unchecked((long) 0x3057C1A72EC3C93BL) /* 607 */,
+ unchecked((long) 0xCB46ACC37C3F1F2FL) /* 608 */, unchecked((long) 0xDBB893FD02AAF50EL) /* 609 */,
+ unchecked((long) 0x331FD92E600B9FCFL) /* 610 */, unchecked((long) 0xA498F96148EA3AD6L) /* 611 */,
+ unchecked((long) 0xA8D8426E8B6A83EAL) /* 612 */, unchecked((long) 0xA089B274B7735CDCL) /* 613 */,
+ unchecked((long) 0x87F6B3731E524A11L) /* 614 */, unchecked((long) 0x118808E5CBC96749L) /* 615 */,
+ unchecked((long) 0x9906E4C7B19BD394L) /* 616 */, unchecked((long) 0xAFED7F7E9B24A20CL) /* 617 */,
+ unchecked((long) 0x6509EADEEB3644A7L) /* 618 */, unchecked((long) 0x6C1EF1D3E8EF0EDEL) /* 619 */,
+ unchecked((long) 0xB9C97D43E9798FB4L) /* 620 */, unchecked((long) 0xA2F2D784740C28A3L) /* 621 */,
+ unchecked((long) 0x7B8496476197566FL) /* 622 */, unchecked((long) 0x7A5BE3E6B65F069DL) /* 623 */,
+ unchecked((long) 0xF96330ED78BE6F10L) /* 624 */, unchecked((long) 0xEEE60DE77A076A15L) /* 625 */,
+ unchecked((long) 0x2B4BEE4AA08B9BD0L) /* 626 */, unchecked((long) 0x6A56A63EC7B8894EL) /* 627 */,
+ unchecked((long) 0x02121359BA34FEF4L) /* 628 */, unchecked((long) 0x4CBF99F8283703FCL) /* 629 */,
+ unchecked((long) 0x398071350CAF30C8L) /* 630 */, unchecked((long) 0xD0A77A89F017687AL) /* 631 */,
+ unchecked((long) 0xF1C1A9EB9E423569L) /* 632 */, unchecked((long) 0x8C7976282DEE8199L) /* 633 */,
+ unchecked((long) 0x5D1737A5DD1F7ABDL) /* 634 */, unchecked((long) 0x4F53433C09A9FA80L) /* 635 */,
+ unchecked((long) 0xFA8B0C53DF7CA1D9L) /* 636 */, unchecked((long) 0x3FD9DCBC886CCB77L) /* 637 */,
+ unchecked((long) 0xC040917CA91B4720L) /* 638 */, unchecked((long) 0x7DD00142F9D1DCDFL) /* 639 */,
+ unchecked((long) 0x8476FC1D4F387B58L) /* 640 */, unchecked((long) 0x23F8E7C5F3316503L) /* 641 */,
+ unchecked((long) 0x032A2244E7E37339L) /* 642 */, unchecked((long) 0x5C87A5D750F5A74BL) /* 643 */,
+ unchecked((long) 0x082B4CC43698992EL) /* 644 */, unchecked((long) 0xDF917BECB858F63CL) /* 645 */,
+ unchecked((long) 0x3270B8FC5BF86DDAL) /* 646 */, unchecked((long) 0x10AE72BB29B5DD76L) /* 647 */,
+ unchecked((long) 0x576AC94E7700362BL) /* 648 */, unchecked((long) 0x1AD112DAC61EFB8FL) /* 649 */,
+ unchecked((long) 0x691BC30EC5FAA427L) /* 650 */, unchecked((long) 0xFF246311CC327143L) /* 651 */,
+ unchecked((long) 0x3142368E30E53206L) /* 652 */, unchecked((long) 0x71380E31E02CA396L) /* 653 */,
+ unchecked((long) 0x958D5C960AAD76F1L) /* 654 */, unchecked((long) 0xF8D6F430C16DA536L) /* 655 */,
+ unchecked((long) 0xC8FFD13F1BE7E1D2L) /* 656 */, unchecked((long) 0x7578AE66004DDBE1L) /* 657 */,
+ unchecked((long) 0x05833F01067BE646L) /* 658 */, unchecked((long) 0xBB34B5AD3BFE586DL) /* 659 */,
+ unchecked((long) 0x095F34C9A12B97F0L) /* 660 */, unchecked((long) 0x247AB64525D60CA8L) /* 661 */,
+ unchecked((long) 0xDCDBC6F3017477D1L) /* 662 */, unchecked((long) 0x4A2E14D4DECAD24DL) /* 663 */,
+ unchecked((long) 0xBDB5E6D9BE0A1EEBL) /* 664 */, unchecked((long) 0x2A7E70F7794301ABL) /* 665 */,
+ unchecked((long) 0xDEF42D8A270540FDL) /* 666 */, unchecked((long) 0x01078EC0A34C22C1L) /* 667 */,
+ unchecked((long) 0xE5DE511AF4C16387L) /* 668 */, unchecked((long) 0x7EBB3A52BD9A330AL) /* 669 */,
+ unchecked((long) 0x77697857AA7D6435L) /* 670 */, unchecked((long) 0x004E831603AE4C32L) /* 671 */,
+ unchecked((long) 0xE7A21020AD78E312L) /* 672 */, unchecked((long) 0x9D41A70C6AB420F2L) /* 673 */,
+ unchecked((long) 0x28E06C18EA1141E6L) /* 674 */, unchecked((long) 0xD2B28CBD984F6B28L) /* 675 */,
+ unchecked((long) 0x26B75F6C446E9D83L) /* 676 */, unchecked((long) 0xBA47568C4D418D7FL) /* 677 */,
+ unchecked((long) 0xD80BADBFE6183D8EL) /* 678 */, unchecked((long) 0x0E206D7F5F166044L) /* 679 */,
+ unchecked((long) 0xE258A43911CBCA3EL) /* 680 */, unchecked((long) 0x723A1746B21DC0BCL) /* 681 */,
+ unchecked((long) 0xC7CAA854F5D7CDD3L) /* 682 */, unchecked((long) 0x7CAC32883D261D9CL) /* 683 */,
+ unchecked((long) 0x7690C26423BA942CL) /* 684 */, unchecked((long) 0x17E55524478042B8L) /* 685 */,
+ unchecked((long) 0xE0BE477656A2389FL) /* 686 */, unchecked((long) 0x4D289B5E67AB2DA0L) /* 687 */,
+ unchecked((long) 0x44862B9C8FBBFD31L) /* 688 */, unchecked((long) 0xB47CC8049D141365L) /* 689 */,
+ unchecked((long) 0x822C1B362B91C793L) /* 690 */, unchecked((long) 0x4EB14655FB13DFD8L) /* 691 */,
+ unchecked((long) 0x1ECBBA0714E2A97BL) /* 692 */, unchecked((long) 0x6143459D5CDE5F14L) /* 693 */,
+ unchecked((long) 0x53A8FBF1D5F0AC89L) /* 694 */, unchecked((long) 0x97EA04D81C5E5B00L) /* 695 */,
+ unchecked((long) 0x622181A8D4FDB3F3L) /* 696 */, unchecked((long) 0xE9BCD341572A1208L) /* 697 */,
+ unchecked((long) 0x1411258643CCE58AL) /* 698 */, unchecked((long) 0x9144C5FEA4C6E0A4L) /* 699 */,
+ unchecked((long) 0x0D33D06565CF620FL) /* 700 */, unchecked((long) 0x54A48D489F219CA1L) /* 701 */,
+ unchecked((long) 0xC43E5EAC6D63C821L) /* 702 */, unchecked((long) 0xA9728B3A72770DAFL) /* 703 */,
+ unchecked((long) 0xD7934E7B20DF87EFL) /* 704 */, unchecked((long) 0xE35503B61A3E86E5L) /* 705 */,
+ unchecked((long) 0xCAE321FBC819D504L) /* 706 */, unchecked((long) 0x129A50B3AC60BFA6L) /* 707 */,
+ unchecked((long) 0xCD5E68EA7E9FB6C3L) /* 708 */, unchecked((long) 0xB01C90199483B1C7L) /* 709 */,
+ unchecked((long) 0x3DE93CD5C295376CL) /* 710 */, unchecked((long) 0xAED52EDF2AB9AD13L) /* 711 */,
+ unchecked((long) 0x2E60F512C0A07884L) /* 712 */, unchecked((long) 0xBC3D86A3E36210C9L) /* 713 */,
+ unchecked((long) 0x35269D9B163951CEL) /* 714 */, unchecked((long) 0x0C7D6E2AD0CDB5FAL) /* 715 */,
+ unchecked((long) 0x59E86297D87F5733L) /* 716 */, unchecked((long) 0x298EF221898DB0E7L) /* 717 */,
+ unchecked((long) 0x55000029D1A5AA7EL) /* 718 */, unchecked((long) 0x8BC08AE1B5061B45L) /* 719 */,
+ unchecked((long) 0xC2C31C2B6C92703AL) /* 720 */, unchecked((long) 0x94CC596BAF25EF42L) /* 721 */,
+ unchecked((long) 0x0A1D73DB22540456L) /* 722 */, unchecked((long) 0x04B6A0F9D9C4179AL) /* 723 */,
+ unchecked((long) 0xEFFDAFA2AE3D3C60L) /* 724 */, unchecked((long) 0xF7C8075BB49496C4L) /* 725 */,
+ unchecked((long) 0x9CC5C7141D1CD4E3L) /* 726 */, unchecked((long) 0x78BD1638218E5534L) /* 727 */,
+ unchecked((long) 0xB2F11568F850246AL) /* 728 */, unchecked((long) 0xEDFABCFA9502BC29L) /* 729 */,
+ unchecked((long) 0x796CE5F2DA23051BL) /* 730 */, unchecked((long) 0xAAE128B0DC93537CL) /* 731 */,
+ unchecked((long) 0x3A493DA0EE4B29AEL) /* 732 */, unchecked((long) 0xB5DF6B2C416895D7L) /* 733 */,
+ unchecked((long) 0xFCABBD25122D7F37L) /* 734 */, unchecked((long) 0x70810B58105DC4B1L) /* 735 */,
+ unchecked((long) 0xE10FDD37F7882A90L) /* 736 */, unchecked((long) 0x524DCAB5518A3F5CL) /* 737 */,
+ unchecked((long) 0x3C9E85878451255BL) /* 738 */, unchecked((long) 0x4029828119BD34E2L) /* 739 */,
+ unchecked((long) 0x74A05B6F5D3CECCBL) /* 740 */, unchecked((long) 0xB610021542E13ECAL) /* 741 */,
+ unchecked((long) 0x0FF979D12F59E2ACL) /* 742 */, unchecked((long) 0x6037DA27E4F9CC50L) /* 743 */,
+ unchecked((long) 0x5E92975A0DF1847DL) /* 744 */, unchecked((long) 0xD66DE190D3E623FEL) /* 745 */,
+ unchecked((long) 0x5032D6B87B568048L) /* 746 */, unchecked((long) 0x9A36B7CE8235216EL) /* 747 */,
+ unchecked((long) 0x80272A7A24F64B4AL) /* 748 */, unchecked((long) 0x93EFED8B8C6916F7L) /* 749 */,
+ unchecked((long) 0x37DDBFF44CCE1555L) /* 750 */, unchecked((long) 0x4B95DB5D4B99BD25L) /* 751 */,
+ unchecked((long) 0x92D3FDA169812FC0L) /* 752 */, unchecked((long) 0xFB1A4A9A90660BB6L) /* 753 */,
+ unchecked((long) 0x730C196946A4B9B2L) /* 754 */, unchecked((long) 0x81E289AA7F49DA68L) /* 755 */,
+ unchecked((long) 0x64669A0F83B1A05FL) /* 756 */, unchecked((long) 0x27B3FF7D9644F48BL) /* 757 */,
+ unchecked((long) 0xCC6B615C8DB675B3L) /* 758 */, unchecked((long) 0x674F20B9BCEBBE95L) /* 759 */,
+ unchecked((long) 0x6F31238275655982L) /* 760 */, unchecked((long) 0x5AE488713E45CF05L) /* 761 */,
+ unchecked((long) 0xBF619F9954C21157L) /* 762 */, unchecked((long) 0xEABAC46040A8EAE9L) /* 763 */,
+ unchecked((long) 0x454C6FE9F2C0C1CDL) /* 764 */, unchecked((long) 0x419CF6496412691CL) /* 765 */,
+ unchecked((long) 0xD3DC3BEF265B0F70L) /* 766 */, unchecked((long) 0x6D0E60F5C3578A9EL) /* 767 */,
+ };
+
+ private static readonly long[] t4 = {
+ unchecked((long) 0x5B0E608526323C55L) /* 768 */, unchecked((long) 0x1A46C1A9FA1B59F5L) /* 769 */,
+ unchecked((long) 0xA9E245A17C4C8FFAL) /* 770 */, unchecked((long) 0x65CA5159DB2955D7L) /* 771 */,
+ unchecked((long) 0x05DB0A76CE35AFC2L) /* 772 */, unchecked((long) 0x81EAC77EA9113D45L) /* 773 */,
+ unchecked((long) 0x528EF88AB6AC0A0DL) /* 774 */, unchecked((long) 0xA09EA253597BE3FFL) /* 775 */,
+ unchecked((long) 0x430DDFB3AC48CD56L) /* 776 */, unchecked((long) 0xC4B3A67AF45CE46FL) /* 777 */,
+ unchecked((long) 0x4ECECFD8FBE2D05EL) /* 778 */, unchecked((long) 0x3EF56F10B39935F0L) /* 779 */,
+ unchecked((long) 0x0B22D6829CD619C6L) /* 780 */, unchecked((long) 0x17FD460A74DF2069L) /* 781 */,
+ unchecked((long) 0x6CF8CC8E8510ED40L) /* 782 */, unchecked((long) 0xD6C824BF3A6ECAA7L) /* 783 */,
+ unchecked((long) 0x61243D581A817049L) /* 784 */, unchecked((long) 0x048BACB6BBC163A2L) /* 785 */,
+ unchecked((long) 0xD9A38AC27D44CC32L) /* 786 */, unchecked((long) 0x7FDDFF5BAAF410ABL) /* 787 */,
+ unchecked((long) 0xAD6D495AA804824BL) /* 788 */, unchecked((long) 0xE1A6A74F2D8C9F94L) /* 789 */,
+ unchecked((long) 0xD4F7851235DEE8E3L) /* 790 */, unchecked((long) 0xFD4B7F886540D893L) /* 791 */,
+ unchecked((long) 0x247C20042AA4BFDAL) /* 792 */, unchecked((long) 0x096EA1C517D1327CL) /* 793 */,
+ unchecked((long) 0xD56966B4361A6685L) /* 794 */, unchecked((long) 0x277DA5C31221057DL) /* 795 */,
+ unchecked((long) 0x94D59893A43ACFF7L) /* 796 */, unchecked((long) 0x64F0C51CCDC02281L) /* 797 */,
+ unchecked((long) 0x3D33BCC4FF6189DBL) /* 798 */, unchecked((long) 0xE005CB184CE66AF1L) /* 799 */,
+ unchecked((long) 0xFF5CCD1D1DB99BEAL) /* 800 */, unchecked((long) 0xB0B854A7FE42980FL) /* 801 */,
+ unchecked((long) 0x7BD46A6A718D4B9FL) /* 802 */, unchecked((long) 0xD10FA8CC22A5FD8CL) /* 803 */,
+ unchecked((long) 0xD31484952BE4BD31L) /* 804 */, unchecked((long) 0xC7FA975FCB243847L) /* 805 */,
+ unchecked((long) 0x4886ED1E5846C407L) /* 806 */, unchecked((long) 0x28CDDB791EB70B04L) /* 807 */,
+ unchecked((long) 0xC2B00BE2F573417FL) /* 808 */, unchecked((long) 0x5C9590452180F877L) /* 809 */,
+ unchecked((long) 0x7A6BDDFFF370EB00L) /* 810 */, unchecked((long) 0xCE509E38D6D9D6A4L) /* 811 */,
+ unchecked((long) 0xEBEB0F00647FA702L) /* 812 */, unchecked((long) 0x1DCC06CF76606F06L) /* 813 */,
+ unchecked((long) 0xE4D9F28BA286FF0AL) /* 814 */, unchecked((long) 0xD85A305DC918C262L) /* 815 */,
+ unchecked((long) 0x475B1D8732225F54L) /* 816 */, unchecked((long) 0x2D4FB51668CCB5FEL) /* 817 */,
+ unchecked((long) 0xA679B9D9D72BBA20L) /* 818 */, unchecked((long) 0x53841C0D912D43A5L) /* 819 */,
+ unchecked((long) 0x3B7EAA48BF12A4E8L) /* 820 */, unchecked((long) 0x781E0E47F22F1DDFL) /* 821 */,
+ unchecked((long) 0xEFF20CE60AB50973L) /* 822 */, unchecked((long) 0x20D261D19DFFB742L) /* 823 */,
+ unchecked((long) 0x16A12B03062A2E39L) /* 824 */, unchecked((long) 0x1960EB2239650495L) /* 825 */,
+ unchecked((long) 0x251C16FED50EB8B8L) /* 826 */, unchecked((long) 0x9AC0C330F826016EL) /* 827 */,
+ unchecked((long) 0xED152665953E7671L) /* 828 */, unchecked((long) 0x02D63194A6369570L) /* 829 */,
+ unchecked((long) 0x5074F08394B1C987L) /* 830 */, unchecked((long) 0x70BA598C90B25CE1L) /* 831 */,
+ unchecked((long) 0x794A15810B9742F6L) /* 832 */, unchecked((long) 0x0D5925E9FCAF8C6CL) /* 833 */,
+ unchecked((long) 0x3067716CD868744EL) /* 834 */, unchecked((long) 0x910AB077E8D7731BL) /* 835 */,
+ unchecked((long) 0x6A61BBDB5AC42F61L) /* 836 */, unchecked((long) 0x93513EFBF0851567L) /* 837 */,
+ unchecked((long) 0xF494724B9E83E9D5L) /* 838 */, unchecked((long) 0xE887E1985C09648DL) /* 839 */,
+ unchecked((long) 0x34B1D3C675370CFDL) /* 840 */, unchecked((long) 0xDC35E433BC0D255DL) /* 841 */,
+ unchecked((long) 0xD0AAB84234131BE0L) /* 842 */, unchecked((long) 0x08042A50B48B7EAFL) /* 843 */,
+ unchecked((long) 0x9997C4EE44A3AB35L) /* 844 */, unchecked((long) 0x829A7B49201799D0L) /* 845 */,
+ unchecked((long) 0x263B8307B7C54441L) /* 846 */, unchecked((long) 0x752F95F4FD6A6CA6L) /* 847 */,
+ unchecked((long) 0x927217402C08C6E5L) /* 848 */, unchecked((long) 0x2A8AB754A795D9EEL) /* 849 */,
+ unchecked((long) 0xA442F7552F72943DL) /* 850 */, unchecked((long) 0x2C31334E19781208L) /* 851 */,
+ unchecked((long) 0x4FA98D7CEAEE6291L) /* 852 */, unchecked((long) 0x55C3862F665DB309L) /* 853 */,
+ unchecked((long) 0xBD0610175D53B1F3L) /* 854 */, unchecked((long) 0x46FE6CB840413F27L) /* 855 */,
+ unchecked((long) 0x3FE03792DF0CFA59L) /* 856 */, unchecked((long) 0xCFE700372EB85E8FL) /* 857 */,
+ unchecked((long) 0xA7BE29E7ADBCE118L) /* 858 */, unchecked((long) 0xE544EE5CDE8431DDL) /* 859 */,
+ unchecked((long) 0x8A781B1B41F1873EL) /* 860 */, unchecked((long) 0xA5C94C78A0D2F0E7L) /* 861 */,
+ unchecked((long) 0x39412E2877B60728L) /* 862 */, unchecked((long) 0xA1265EF3AFC9A62CL) /* 863 */,
+ unchecked((long) 0xBCC2770C6A2506C5L) /* 864 */, unchecked((long) 0x3AB66DD5DCE1CE12L) /* 865 */,
+ unchecked((long) 0xE65499D04A675B37L) /* 866 */, unchecked((long) 0x7D8F523481BFD216L) /* 867 */,
+ unchecked((long) 0x0F6F64FCEC15F389L) /* 868 */, unchecked((long) 0x74EFBE618B5B13C8L) /* 869 */,
+ unchecked((long) 0xACDC82B714273E1DL) /* 870 */, unchecked((long) 0xDD40BFE003199D17L) /* 871 */,
+ unchecked((long) 0x37E99257E7E061F8L) /* 872 */, unchecked((long) 0xFA52626904775AAAL) /* 873 */,
+ unchecked((long) 0x8BBBF63A463D56F9L) /* 874 */, unchecked((long) 0xF0013F1543A26E64L) /* 875 */,
+ unchecked((long) 0xA8307E9F879EC898L) /* 876 */, unchecked((long) 0xCC4C27A4150177CCL) /* 877 */,
+ unchecked((long) 0x1B432F2CCA1D3348L) /* 878 */, unchecked((long) 0xDE1D1F8F9F6FA013L) /* 879 */,
+ unchecked((long) 0x606602A047A7DDD6L) /* 880 */, unchecked((long) 0xD237AB64CC1CB2C7L) /* 881 */,
+ unchecked((long) 0x9B938E7225FCD1D3L) /* 882 */, unchecked((long) 0xEC4E03708E0FF476L) /* 883 */,
+ unchecked((long) 0xFEB2FBDA3D03C12DL) /* 884 */, unchecked((long) 0xAE0BCED2EE43889AL) /* 885 */,
+ unchecked((long) 0x22CB8923EBFB4F43L) /* 886 */, unchecked((long) 0x69360D013CF7396DL) /* 887 */,
+ unchecked((long) 0x855E3602D2D4E022L) /* 888 */, unchecked((long) 0x073805BAD01F784CL) /* 889 */,
+ unchecked((long) 0x33E17A133852F546L) /* 890 */, unchecked((long) 0xDF4874058AC7B638L) /* 891 */,
+ unchecked((long) 0xBA92B29C678AA14AL) /* 892 */, unchecked((long) 0x0CE89FC76CFAADCDL) /* 893 */,
+ unchecked((long) 0x5F9D4E0908339E34L) /* 894 */, unchecked((long) 0xF1AFE9291F5923B9L) /* 895 */,
+ unchecked((long) 0x6E3480F60F4A265FL) /* 896 */, unchecked((long) 0xEEBF3A2AB29B841CL) /* 897 */,
+ unchecked((long) 0xE21938A88F91B4ADL) /* 898 */, unchecked((long) 0x57DFEFF845C6D3C3L) /* 899 */,
+ unchecked((long) 0x2F006B0BF62CAAF2L) /* 900 */, unchecked((long) 0x62F479EF6F75EE78L) /* 901 */,
+ unchecked((long) 0x11A55AD41C8916A9L) /* 902 */, unchecked((long) 0xF229D29084FED453L) /* 903 */,
+ unchecked((long) 0x42F1C27B16B000E6L) /* 904 */, unchecked((long) 0x2B1F76749823C074L) /* 905 */,
+ unchecked((long) 0x4B76ECA3C2745360L) /* 906 */, unchecked((long) 0x8C98F463B91691BDL) /* 907 */,
+ unchecked((long) 0x14BCC93CF1ADE66AL) /* 908 */, unchecked((long) 0x8885213E6D458397L) /* 909 */,
+ unchecked((long) 0x8E177DF0274D4711L) /* 910 */, unchecked((long) 0xB49B73B5503F2951L) /* 911 */,
+ unchecked((long) 0x10168168C3F96B6BL) /* 912 */, unchecked((long) 0x0E3D963B63CAB0AEL) /* 913 */,
+ unchecked((long) 0x8DFC4B5655A1DB14L) /* 914 */, unchecked((long) 0xF789F1356E14DE5CL) /* 915 */,
+ unchecked((long) 0x683E68AF4E51DAC1L) /* 916 */, unchecked((long) 0xC9A84F9D8D4B0FD9L) /* 917 */,
+ unchecked((long) 0x3691E03F52A0F9D1L) /* 918 */, unchecked((long) 0x5ED86E46E1878E80L) /* 919 */,
+ unchecked((long) 0x3C711A0E99D07150L) /* 920 */, unchecked((long) 0x5A0865B20C4E9310L) /* 921 */,
+ unchecked((long) 0x56FBFC1FE4F0682EL) /* 922 */, unchecked((long) 0xEA8D5DE3105EDF9BL) /* 923 */,
+ unchecked((long) 0x71ABFDB12379187AL) /* 924 */, unchecked((long) 0x2EB99DE1BEE77B9CL) /* 925 */,
+ unchecked((long) 0x21ECC0EA33CF4523L) /* 926 */, unchecked((long) 0x59A4D7521805C7A1L) /* 927 */,
+ unchecked((long) 0x3896F5EB56AE7C72L) /* 928 */, unchecked((long) 0xAA638F3DB18F75DCL) /* 929 */,
+ unchecked((long) 0x9F39358DABE9808EL) /* 930 */, unchecked((long) 0xB7DEFA91C00B72ACL) /* 931 */,
+ unchecked((long) 0x6B5541FD62492D92L) /* 932 */, unchecked((long) 0x6DC6DEE8F92E4D5BL) /* 933 */,
+ unchecked((long) 0x353F57ABC4BEEA7EL) /* 934 */, unchecked((long) 0x735769D6DA5690CEL) /* 935 */,
+ unchecked((long) 0x0A234AA642391484L) /* 936 */, unchecked((long) 0xF6F9508028F80D9DL) /* 937 */,
+ unchecked((long) 0xB8E319A27AB3F215L) /* 938 */, unchecked((long) 0x31AD9C1151341A4DL) /* 939 */,
+ unchecked((long) 0x773C22A57BEF5805L) /* 940 */, unchecked((long) 0x45C7561A07968633L) /* 941 */,
+ unchecked((long) 0xF913DA9E249DBE36L) /* 942 */, unchecked((long) 0xDA652D9B78A64C68L) /* 943 */,
+ unchecked((long) 0x4C27A97F3BC334EFL) /* 944 */, unchecked((long) 0x76621220E66B17F4L) /* 945 */,
+ unchecked((long) 0x967743899ACD7D0BL) /* 946 */, unchecked((long) 0xF3EE5BCAE0ED6782L) /* 947 */,
+ unchecked((long) 0x409F753600C879FCL) /* 948 */, unchecked((long) 0x06D09A39B5926DB6L) /* 949 */,
+ unchecked((long) 0x6F83AEB0317AC588L) /* 950 */, unchecked((long) 0x01E6CA4A86381F21L) /* 951 */,
+ unchecked((long) 0x66FF3462D19F3025L) /* 952 */, unchecked((long) 0x72207C24DDFD3BFBL) /* 953 */,
+ unchecked((long) 0x4AF6B6D3E2ECE2EBL) /* 954 */, unchecked((long) 0x9C994DBEC7EA08DEL) /* 955 */,
+ unchecked((long) 0x49ACE597B09A8BC4L) /* 956 */, unchecked((long) 0xB38C4766CF0797BAL) /* 957 */,
+ unchecked((long) 0x131B9373C57C2A75L) /* 958 */, unchecked((long) 0xB1822CCE61931E58L) /* 959 */,
+ unchecked((long) 0x9D7555B909BA1C0CL) /* 960 */, unchecked((long) 0x127FAFDD937D11D2L) /* 961 */,
+ unchecked((long) 0x29DA3BADC66D92E4L) /* 962 */, unchecked((long) 0xA2C1D57154C2ECBCL) /* 963 */,
+ unchecked((long) 0x58C5134D82F6FE24L) /* 964 */, unchecked((long) 0x1C3AE3515B62274FL) /* 965 */,
+ unchecked((long) 0xE907C82E01CB8126L) /* 966 */, unchecked((long) 0xF8ED091913E37FCBL) /* 967 */,
+ unchecked((long) 0x3249D8F9C80046C9L) /* 968 */, unchecked((long) 0x80CF9BEDE388FB63L) /* 969 */,
+ unchecked((long) 0x1881539A116CF19EL) /* 970 */, unchecked((long) 0x5103F3F76BD52457L) /* 971 */,
+ unchecked((long) 0x15B7E6F5AE47F7A8L) /* 972 */, unchecked((long) 0xDBD7C6DED47E9CCFL) /* 973 */,
+ unchecked((long) 0x44E55C410228BB1AL) /* 974 */, unchecked((long) 0xB647D4255EDB4E99L) /* 975 */,
+ unchecked((long) 0x5D11882BB8AAFC30L) /* 976 */, unchecked((long) 0xF5098BBB29D3212AL) /* 977 */,
+ unchecked((long) 0x8FB5EA14E90296B3L) /* 978 */, unchecked((long) 0x677B942157DD025AL) /* 979 */,
+ unchecked((long) 0xFB58E7C0A390ACB5L) /* 980 */, unchecked((long) 0x89D3674C83BD4A01L) /* 981 */,
+ unchecked((long) 0x9E2DA4DF4BF3B93BL) /* 982 */, unchecked((long) 0xFCC41E328CAB4829L) /* 983 */,
+ unchecked((long) 0x03F38C96BA582C52L) /* 984 */, unchecked((long) 0xCAD1BDBD7FD85DB2L) /* 985 */,
+ unchecked((long) 0xBBB442C16082AE83L) /* 986 */, unchecked((long) 0xB95FE86BA5DA9AB0L) /* 987 */,
+ unchecked((long) 0xB22E04673771A93FL) /* 988 */, unchecked((long) 0x845358C9493152D8L) /* 989 */,
+ unchecked((long) 0xBE2A488697B4541EL) /* 990 */, unchecked((long) 0x95A2DC2DD38E6966L) /* 991 */,
+ unchecked((long) 0xC02C11AC923C852BL) /* 992 */, unchecked((long) 0x2388B1990DF2A87BL) /* 993 */,
+ unchecked((long) 0x7C8008FA1B4F37BEL) /* 994 */, unchecked((long) 0x1F70D0C84D54E503L) /* 995 */,
+ unchecked((long) 0x5490ADEC7ECE57D4L) /* 996 */, unchecked((long) 0x002B3C27D9063A3AL) /* 997 */,
+ unchecked((long) 0x7EAEA3848030A2BFL) /* 998 */, unchecked((long) 0xC602326DED2003C0L) /* 999 */,
+ unchecked((long) 0x83A7287D69A94086L) /* 1000 */, unchecked((long) 0xC57A5FCB30F57A8AL) /* 1001 */,
+ unchecked((long) 0xB56844E479EBE779L) /* 1002 */, unchecked((long) 0xA373B40F05DCBCE9L) /* 1003 */,
+ unchecked((long) 0xD71A786E88570EE2L) /* 1004 */, unchecked((long) 0x879CBACDBDE8F6A0L) /* 1005 */,
+ unchecked((long) 0x976AD1BCC164A32FL) /* 1006 */, unchecked((long) 0xAB21E25E9666D78BL) /* 1007 */,
+ unchecked((long) 0x901063AAE5E5C33CL) /* 1008 */, unchecked((long) 0x9818B34448698D90L) /* 1009 */,
+ unchecked((long) 0xE36487AE3E1E8ABBL) /* 1010 */, unchecked((long) 0xAFBDF931893BDCB4L) /* 1011 */,
+ unchecked((long) 0x6345A0DC5FBBD519L) /* 1012 */, unchecked((long) 0x8628FE269B9465CAL) /* 1013 */,
+ unchecked((long) 0x1E5D01603F9C51ECL) /* 1014 */, unchecked((long) 0x4DE44006A15049B7L) /* 1015 */,
+ unchecked((long) 0xBF6C70E5F776CBB1L) /* 1016 */, unchecked((long) 0x411218F2EF552BEDL) /* 1017 */,
+ unchecked((long) 0xCB0C0708705A36A3L) /* 1018 */, unchecked((long) 0xE74D14754F986044L) /* 1019 */,
+ unchecked((long) 0xCD56D9430EA8280EL) /* 1020 */, unchecked((long) 0xC12591D7535F5065L) /* 1021 */,
+ unchecked((long) 0xC83223F1720AEF96L) /* 1022 */, unchecked((long) 0xC3A0396F7363A51FL) /* 1023 */
+ };
+
+ private const int DigestLength = 24;
+
+ //
+ // registers
+ //
+ private long a, b, c;
+ private long byteCount;
+
+ //
+ // buffers
+ //
+ private byte[] Buffer = new byte[8];
+ private int bOff;
+
+ private long[] x = new long[8];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public TigerDigest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public TigerDigest(TigerDigest t)
+ {
+ a = t.a;
+ b = t.b;
+ c = t.c;
+
+ Array.Copy(t.x, 0, x, 0, t.x.Length);
+ xOff = t.xOff;
+
+ Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
+ bOff = t.bOff;
+
+ byteCount = t.byteCount;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Tiger"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public int GetByteLength()
+ {
+ return MyByteLength;
+ }
+
+ private void ProcessWord(
+ byte[] b,
+ int off)
+ {
+ x[xOff++] = ((long)(b[off + 7] & 0xff) << 56)
+ | ((long)(b[off + 6] & 0xff) << 48)
+ | ((long)(b[off + 5] & 0xff) << 40)
+ | ((long)(b[off + 4] & 0xff) << 32)
+ | ((long)(b[off + 3] & 0xff) << 24)
+ | ((long)(b[off + 2] & 0xff) << 16)
+ | ((long)(b[off + 1] & 0xff) << 8)
+ | ((uint)(b[off + 0] & 0xff));
+
+ if (xOff == x.Length)
+ {
+ ProcessBlock();
+ }
+
+ bOff = 0;
+ }
+
+ public void Update(
+ byte input)
+ {
+ Buffer[bOff++] = input;
+
+ if (bOff == Buffer.Length)
+ {
+ ProcessWord(Buffer, 0);
+ }
+
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ //
+ // fill the current word
+ //
+ while ((bOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > 8)
+ {
+ ProcessWord(input, inOff);
+
+ inOff += 8;
+ length -= 8;
+ byteCount += 8;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+
+ private void RoundABC(
+ long x,
+ long mul)
+ {
+ c ^= x ;
+ a -= t1[(int)c & 0xff] ^ t2[(int)(c >> 16) & 0xff]
+ ^ t3[(int)(c >> 32) & 0xff] ^ t4[(int)(c >> 48) & 0xff];
+ b += t4[(int)(c >> 8) & 0xff] ^ t3[(int)(c >> 24) & 0xff]
+ ^ t2[(int)(c >> 40) & 0xff] ^ t1[(int)(c >> 56) & 0xff];
+ b *= mul;
+ }
+
+ private void RoundBCA(
+ long x,
+ long mul)
+ {
+ a ^= x ;
+ b -= t1[(int)a & 0xff] ^ t2[(int)(a >> 16) & 0xff]
+ ^ t3[(int)(a >> 32) & 0xff] ^ t4[(int)(a >> 48) & 0xff];
+ c += t4[(int)(a >> 8) & 0xff] ^ t3[(int)(a >> 24) & 0xff]
+ ^ t2[(int)(a >> 40) & 0xff] ^ t1[(int)(a >> 56) & 0xff];
+ c *= mul;
+ }
+
+ private void RoundCAB(
+ long x,
+ long mul)
+ {
+ b ^= x ;
+ c -= t1[(int)b & 0xff] ^ t2[(int)(b >> 16) & 0xff]
+ ^ t3[(int)(b >> 32) & 0xff] ^ t4[(int)(b >> 48) & 0xff];
+ a += t4[(int)(b >> 8) & 0xff] ^ t3[(int)(b >> 24) & 0xff]
+ ^ t2[(int)(b >> 40) & 0xff] ^ t1[(int)(b >> 56) & 0xff];
+ a *= mul;
+ }
+
+ private void KeySchedule()
+ {
+ x[0] -= x[7] ^ unchecked ((long) 0xA5A5A5A5A5A5A5A5L);
+ x[1] ^= x[0];
+ x[2] += x[1];
+ x[3] -= x[2] ^ ((~x[1]) << 19);
+ x[4] ^= x[3];
+ x[5] += x[4];
+ x[6] -= x[5] ^ (long) ((ulong) (~x[4]) >> 23);
+ x[7] ^= x[6];
+ x[0] += x[7];
+ x[1] -= x[0] ^ ((~x[7]) << 19);
+ x[2] ^= x[1];
+ x[3] += x[2];
+ x[4] -= x[3] ^ (long) ((ulong) (~x[2]) >> 23);
+ x[5] ^= x[4];
+ x[6] += x[5];
+ x[7] -= x[6] ^ 0x0123456789ABCDEFL;
+ }
+
+ private void ProcessBlock()
+ {
+ //
+ // save abc
+ //
+ long aa = a;
+ long bb = b;
+ long cc = c;
+
+ //
+ // rounds and schedule
+ //
+ RoundABC(x[0], 5);
+ RoundBCA(x[1], 5);
+ RoundCAB(x[2], 5);
+ RoundABC(x[3], 5);
+ RoundBCA(x[4], 5);
+ RoundCAB(x[5], 5);
+ RoundABC(x[6], 5);
+ RoundBCA(x[7], 5);
+
+ KeySchedule();
+
+ RoundCAB(x[0], 7);
+ RoundABC(x[1], 7);
+ RoundBCA(x[2], 7);
+ RoundCAB(x[3], 7);
+ RoundABC(x[4], 7);
+ RoundBCA(x[5], 7);
+ RoundCAB(x[6], 7);
+ RoundABC(x[7], 7);
+
+ KeySchedule();
+
+ RoundBCA(x[0], 9);
+ RoundCAB(x[1], 9);
+ RoundABC(x[2], 9);
+ RoundBCA(x[3], 9);
+ RoundCAB(x[4], 9);
+ RoundABC(x[5], 9);
+ RoundBCA(x[6], 9);
+ RoundCAB(x[7], 9);
+
+ //
+ // feed forward
+ //
+ a ^= aa;
+ b -= bb;
+ c += cc;
+
+ //
+ // clear the x buffer
+ //
+ xOff = 0;
+ for (int i = 0; i != x.Length; i++)
+ {
+ x[i] = 0;
+ }
+ }
+
+ private void UnpackWord(
+ long r,
+ byte[] output,
+ int outOff)
+ {
+ output[outOff + 7] = (byte)(r >> 56);
+ output[outOff + 6] = (byte)(r >> 48);
+ output[outOff + 5] = (byte)(r >> 40);
+ output[outOff + 4] = (byte)(r >> 32);
+ output[outOff + 3] = (byte)(r >> 24);
+ output[outOff + 2] = (byte)(r >> 16);
+ output[outOff + 1] = (byte)(r >> 8);
+ output[outOff] = (byte)r;
+ }
+
+ private void ProcessLength(
+ long bitLength)
+ {
+ x[7] = bitLength;
+ }
+
+ private void Finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ Update((byte)0x01);
+
+ while (bOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ ProcessLength(bitLength);
+
+ ProcessBlock();
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(a, output, outOff);
+ UnpackWord(b, output, outOff + 8);
+ UnpackWord(c, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void Reset()
+ {
+ a = unchecked((long) 0x0123456789ABCDEFL);
+ b = unchecked((long) 0xFEDCBA9876543210L);
+ c = unchecked((long) 0xF096A5B4C3B2E187L);
+
+ xOff = 0;
+ for (int i = 0; i != x.Length; i++)
+ {
+ x[i] = 0;
+ }
+
+ bOff = 0;
+ for (int i = 0; i != Buffer.Length; i++)
+ {
+ Buffer[i] = 0;
+ }
+
+ byteCount = 0;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/digests/WhirlpoolDigest.cs b/src/core/srcbc/crypto/digests/WhirlpoolDigest.cs
new file mode 100644
index 0000000..5ac0ff6
--- /dev/null
+++ b/src/core/srcbc/crypto/digests/WhirlpoolDigest.cs
@@ -0,0 +1,397 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Implementation of WhirlpoolDigest, based on Java source published by Barreto
+ * and Rijmen.
+ *
+ */
+ public sealed class WhirlpoolDigest : IDigest
+ {
+ private const int BYTE_LENGTH = 64;
+
+ private const int DIGEST_LENGTH_BYTES = 512 / 8;
+ private const int ROUNDS = 10;
+ private const int REDUCTION_POLYNOMIAL = 0x011d; // 2^8 + 2^4 + 2^3 + 2 + 1;
+
+ private static readonly int[] SBOX =
+ {
+ 0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52,
+ 0x60, 0xbc, 0x9b, 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, 0xfe, 0x57,
+ 0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85,
+ 0xbd, 0x5d, 0x10, 0xf4, 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, 0xd8,
+ 0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33,
+ 0x63, 0x02, 0xaa, 0x71, 0xc8, 0x19, 0x49, 0xd9, 0xf2, 0xe3, 0x5b, 0x88, 0x9a, 0x26, 0x32, 0xb0,
+ 0xe9, 0x0f, 0xd5, 0x80, 0xbe, 0xcd, 0x34, 0x48, 0xff, 0x7a, 0x90, 0x5f, 0x20, 0x68, 0x1a, 0xae,
+ 0xb4, 0x54, 0x93, 0x22, 0x64, 0xf1, 0x73, 0x12, 0x40, 0x08, 0xc3, 0xec, 0xdb, 0xa1, 0x8d, 0x3d,
+ 0x97, 0x00, 0xcf, 0x2b, 0x76, 0x82, 0xd6, 0x1b, 0xb5, 0xaf, 0x6a, 0x50, 0x45, 0xf3, 0x30, 0xef,
+ 0x3f, 0x55, 0xa2, 0xea, 0x65, 0xba, 0x2f, 0xc0, 0xde, 0x1c, 0xfd, 0x4d, 0x92, 0x75, 0x06, 0x8a,
+ 0xb2, 0xe6, 0x0e, 0x1f, 0x62, 0xd4, 0xa8, 0x96, 0xf9, 0xc5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4c,
+ 0x5e, 0x78, 0x38, 0x8c, 0xd1, 0xa5, 0xe2, 0x61, 0xb3, 0x21, 0x9c, 0x1e, 0x43, 0xc7, 0xfc, 0x04,
+ 0x51, 0x99, 0x6d, 0x0d, 0xfa, 0xdf, 0x7e, 0x24, 0x3b, 0xab, 0xce, 0x11, 0x8f, 0x4e, 0xb7, 0xeb,
+ 0x3c, 0x81, 0x94, 0xf7, 0xb9, 0x13, 0x2c, 0xd3, 0xe7, 0x6e, 0xc4, 0x03, 0x56, 0x44, 0x7f, 0xa9,
+ 0x2a, 0xbb, 0xc1, 0x53, 0xdc, 0x0b, 0x9d, 0x6c, 0x31, 0x74, 0xf6, 0x46, 0xac, 0x89, 0x14, 0xe1,
+ 0x16, 0x3a, 0x69, 0x09, 0x70, 0xb6, 0xd0, 0xed, 0xcc, 0x42, 0x98, 0xa4, 0x28, 0x5c, 0xf8, 0x86
+ };
+
+ private static readonly long[] C0 = new long[256];
+ private static readonly long[] C1 = new long[256];
+ private static readonly long[] C2 = new long[256];
+ private static readonly long[] C3 = new long[256];
+ private static readonly long[] C4 = new long[256];
+ private static readonly long[] C5 = new long[256];
+ private static readonly long[] C6 = new long[256];
+ private static readonly long[] C7 = new long[256];
+
+ private readonly long[] _rc = new long[ROUNDS + 1];
+
+ /*
+ * increment() can be implemented in this way using 2 arrays or
+ * by having some temporary variables that are used to set the
+ * value provided by EIGHT[i] and carry within the loop.
+ *
+ * not having done any timing, this seems likely to be faster
+ * at the slight expense of 32*(sizeof short) bytes
+ */
+ private static readonly short[] EIGHT = new short[BITCOUNT_ARRAY_SIZE];
+
+ static WhirlpoolDigest()
+ {
+ EIGHT[BITCOUNT_ARRAY_SIZE - 1] = 8;
+
+ for (int i = 0; i < 256; i++)
+ {
+ int v1 = SBOX[i];
+ int v2 = maskWithReductionPolynomial(v1 << 1);
+ int v4 = maskWithReductionPolynomial(v2 << 1);
+ int v5 = v4 ^ v1;
+ int v8 = maskWithReductionPolynomial(v4 << 1);
+ int v9 = v8 ^ v1;
+
+ C0[i] = packIntoLong(v1, v1, v4, v1, v8, v5, v2, v9);
+ C1[i] = packIntoLong(v9, v1, v1, v4, v1, v8, v5, v2);
+ C2[i] = packIntoLong(v2, v9, v1, v1, v4, v1, v8, v5);
+ C3[i] = packIntoLong(v5, v2, v9, v1, v1, v4, v1, v8);
+ C4[i] = packIntoLong(v8, v5, v2, v9, v1, v1, v4, v1);
+ C5[i] = packIntoLong(v1, v8, v5, v2, v9, v1, v1, v4);
+ C6[i] = packIntoLong(v4, v1, v8, v5, v2, v9, v1, v1);
+ C7[i] = packIntoLong(v1, v4, v1, v8, v5, v2, v9, v1);
+ }
+ }
+
+ public WhirlpoolDigest()
+ {
+ _rc[0] = 0L;
+ for (int r = 1; r <= ROUNDS; r++)
+ {
+ int i = 8 * (r - 1);
+ _rc[r] = (long)((ulong)C0[i] & 0xff00000000000000L) ^
+ (C1[i + 1] & (long) 0x00ff000000000000L) ^
+ (C2[i + 2] & (long) 0x0000ff0000000000L) ^
+ (C3[i + 3] & (long) 0x000000ff00000000L) ^
+ (C4[i + 4] & (long) 0x00000000ff000000L) ^
+ (C5[i + 5] & (long) 0x0000000000ff0000L) ^
+ (C6[i + 6] & (long) 0x000000000000ff00L) ^
+ (C7[i + 7] & (long) 0x00000000000000ffL);
+ }
+ }
+
+ private static long packIntoLong(int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0)
+ {
+ return
+ ((long)b7 << 56) ^
+ ((long)b6 << 48) ^
+ ((long)b5 << 40) ^
+ ((long)b4 << 32) ^
+ ((long)b3 << 24) ^
+ ((long)b2 << 16) ^
+ ((long)b1 << 8) ^
+ b0;
+ }
+
+ /*
+ * int's are used to prevent sign extension. The values that are really being used are
+ * actually just 0..255
+ */
+ private static int maskWithReductionPolynomial(int input)
+ {
+ int rv = input;
+ if (rv >= 0x100L) // high bit set
+ {
+ rv ^= REDUCTION_POLYNOMIAL; // reduced by the polynomial
+ }
+ return rv;
+ }
+
+ // --------------------------------------------------------------------------------------//
+
+ // -- buffer information --
+ private const int BITCOUNT_ARRAY_SIZE = 32;
+ private byte[] _buffer = new byte[64];
+ private int _bufferPos;
+ private short[] _bitCount = new short[BITCOUNT_ARRAY_SIZE];
+
+ // -- internal hash state --
+ private long[] _hash = new long[8];
+ private long[] _K = new long[8]; // the round key
+ private long[] _L = new long[8];
+ private long[] _block = new long[8]; // mu (buffer)
+ private long[] _state = new long[8]; // the current "cipher" state
+
+
+
+ /**
+ * Copy constructor. This will copy the state of the provided message
+ * digest.
+ */
+ public WhirlpoolDigest(WhirlpoolDigest originalDigest)
+ {
+ Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
+
+ Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
+
+ this._bufferPos = originalDigest._bufferPos;
+ Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
+
+ // -- internal hash state --
+ Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
+ Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
+ Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
+ Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
+ Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Whirlpool"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DIGEST_LENGTH_BYTES;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ // sets output[outOff] .. output[outOff+DIGEST_LENGTH_BYTES]
+ finish();
+
+ for (int i = 0; i < 8; i++)
+ {
+ convertLongToByteArray(_hash[i], output, outOff + (i * 8));
+ }
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ /**
+ * Reset the chaining variables
+ */
+ public void Reset()
+ {
+ // set variables to null, blank, whatever
+ _bufferPos = 0;
+ Array.Clear(_bitCount, 0, _bitCount.Length);
+ Array.Clear(_buffer, 0, _buffer.Length);
+ Array.Clear(_hash, 0, _hash.Length);
+ Array.Clear(_K, 0, _K.Length);
+ Array.Clear(_L, 0, _L.Length);
+ Array.Clear(_block, 0, _block.Length);
+ Array.Clear(_state, 0, _state.Length);
+ }
+
+ // this takes a buffer of information and fills the block
+ private void processFilledBuffer()
+ {
+ // copies into the block...
+ for (int i = 0; i < _state.Length; i++)
+ {
+ _block[i] = bytesToLongFromBuffer(_buffer, i * 8);
+ }
+ processBlock();
+ _bufferPos = 0;
+ Array.Clear(_buffer, 0, _buffer.Length);
+ }
+
+ private static long bytesToLongFromBuffer(byte[] buffer, int startPos)
+ {
+ long rv = (((buffer[startPos + 0] & 0xffL) << 56) |
+ ((buffer[startPos + 1] & 0xffL) << 48) |
+ ((buffer[startPos + 2] & 0xffL) << 40) |
+ ((buffer[startPos + 3] & 0xffL) << 32) |
+ ((buffer[startPos + 4] & 0xffL) << 24) |
+ ((buffer[startPos + 5] & 0xffL) << 16) |
+ ((buffer[startPos + 6] & 0xffL) << 8) |
+ ((buffer[startPos + 7]) & 0xffL));
+
+ return rv;
+ }
+
+ private static void convertLongToByteArray(long inputLong, byte[] outputArray, int offSet)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ outputArray[offSet + i] = (byte)((inputLong >> (56 - (i * 8))) & 0xff);
+ }
+ }
+
+ private void processBlock()
+ {
+ // buffer contents have been transferred to the _block[] array via
+ // processFilledBuffer
+
+ // compute and apply K^0
+ for (int i = 0; i < 8; i++)
+ {
+ _state[i] = _block[i] ^ (_K[i] = _hash[i]);
+ }
+
+ // iterate over the rounds
+ for (int round = 1; round <= ROUNDS; round++)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ _L[i] = 0;
+ _L[i] ^= C0[(int)(_K[(i - 0) & 7] >> 56) & 0xff];
+ _L[i] ^= C1[(int)(_K[(i - 1) & 7] >> 48) & 0xff];
+ _L[i] ^= C2[(int)(_K[(i - 2) & 7] >> 40) & 0xff];
+ _L[i] ^= C3[(int)(_K[(i - 3) & 7] >> 32) & 0xff];
+ _L[i] ^= C4[(int)(_K[(i - 4) & 7] >> 24) & 0xff];
+ _L[i] ^= C5[(int)(_K[(i - 5) & 7] >> 16) & 0xff];
+ _L[i] ^= C6[(int)(_K[(i - 6) & 7] >> 8) & 0xff];
+ _L[i] ^= C7[(int)(_K[(i - 7) & 7]) & 0xff];
+ }
+
+ Array.Copy(_L, 0, _K, 0, _K.Length);
+
+ _K[0] ^= _rc[round];
+
+ // apply the round transformation
+ for (int i = 0; i < 8; i++)
+ {
+ _L[i] = _K[i];
+
+ _L[i] ^= C0[(int)(_state[(i - 0) & 7] >> 56) & 0xff];
+ _L[i] ^= C1[(int)(_state[(i - 1) & 7] >> 48) & 0xff];
+ _L[i] ^= C2[(int)(_state[(i - 2) & 7] >> 40) & 0xff];
+ _L[i] ^= C3[(int)(_state[(i - 3) & 7] >> 32) & 0xff];
+ _L[i] ^= C4[(int)(_state[(i - 4) & 7] >> 24) & 0xff];
+ _L[i] ^= C5[(int)(_state[(i - 5) & 7] >> 16) & 0xff];
+ _L[i] ^= C6[(int)(_state[(i - 6) & 7] >> 8) & 0xff];
+ _L[i] ^= C7[(int)(_state[(i - 7) & 7]) & 0xff];
+ }
+
+ // save the current state
+ Array.Copy(_L, 0, _state, 0, _state.Length);
+ }
+
+ // apply Miuaguchi-Preneel compression
+ for (int i = 0; i < 8; i++)
+ {
+ _hash[i] ^= _state[i] ^ _block[i];
+ }
+
+ }
+
+ public void Update(byte input)
+ {
+ _buffer[_bufferPos] = input;
+
+ //Console.WriteLine("adding to buffer = "+_buffer[_bufferPos]);
+
+ ++_bufferPos;
+
+ if (_bufferPos == _buffer.Length)
+ {
+ processFilledBuffer();
+ }
+
+ increment();
+ }
+
+ private void increment()
+ {
+ int carry = 0;
+ for (int i = _bitCount.Length - 1; i >= 0; i--)
+ {
+ int sum = (_bitCount[i] & 0xff) + EIGHT[i] + carry;
+
+ carry = sum >> 8;
+ _bitCount[i] = (short)(sum & 0xff);
+ }
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ ++inOff;
+ --length;
+ }
+
+ }
+
+ private void finish()
+ {
+ /*
+ * this makes a copy of the current bit length. at the expense of an
+ * object creation of 32 bytes rather than providing a _stopCounting
+ * boolean which was the alternative I could think of.
+ */
+ byte[] bitLength = copyBitLength();
+
+ _buffer[_bufferPos++] |= 0x80;
+
+ if (_bufferPos == _buffer.Length)
+ {
+ processFilledBuffer();
+ }
+
+ /*
+ * Final block contains
+ * [ ... data .... ][0][0][0][ length ]
+ *
+ * if [ length ] cannot fit. Need to create a new block.
+ */
+ if (_bufferPos > 32)
+ {
+ while (_bufferPos != 0)
+ {
+ Update((byte)0);
+ }
+ }
+
+ while (_bufferPos <= 32)
+ {
+ Update((byte)0);
+ }
+
+ // copy the length information to the final 32 bytes of the
+ // 64 byte block....
+ Array.Copy(bitLength, 0, _buffer, 32, bitLength.Length);
+
+ processFilledBuffer();
+ }
+
+ private byte[] copyBitLength()
+ {
+ byte[] rv = new byte[BITCOUNT_ARRAY_SIZE];
+ for (int i = 0; i < rv.Length; i++)
+ {
+ rv[i] = (byte)(_bitCount[i] & 0xff);
+ }
+ return rv;
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/encodings/ISO9796d1Encoding.cs b/src/core/srcbc/crypto/encodings/ISO9796d1Encoding.cs
new file mode 100644
index 0000000..02619d5
--- /dev/null
+++ b/src/core/srcbc/crypto/encodings/ISO9796d1Encoding.cs
@@ -0,0 +1,253 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * ISO 9796-1 padding. Note in the light of recent results you should
+ * only use this with RSA (rather than the "simpler" Rabin keys) and you
+ * should never use it with anything other than a hash (ie. even if the
+ * message is small don't sign the message, sign it's hash) or some "random"
+ * value. See your favorite search engine for details.
+ */
+ public class ISO9796d1Encoding
+ : IAsymmetricBlockCipher
+ {
+ private static readonly byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
+ 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
+ private static readonly byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
+ 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
+
+ private readonly IAsymmetricBlockCipher engine;
+ private bool forEncryption;
+ private int bitSize;
+ private int padBits = 0;
+
+ public ISO9796d1Encoding(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/ISO9796-1Padding"; }
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+ kParam = (RsaKeyParameters)rParam.Parameters;
+ }
+ else
+ {
+ kParam = (RsaKeyParameters)parameters;
+ }
+
+ engine.Init(forEncryption, parameters);
+
+ bitSize = kParam.Modulus.BitLength;
+
+ this.forEncryption = forEncryption;
+ }
+
+ /**
+ * return the input block size. The largest message we can process
+ * is (key_size_in_bits + 3)/16, which in our world comes to
+ * key_size_in_bytes / 2.
+ */
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ if (forEncryption)
+ {
+ return (baseBlockSize + 1) / 2;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ /**
+ * return the maximum possible size for the output.
+ */
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return (baseBlockSize + 1) / 2;
+ }
+ }
+
+ /**
+ * set the number of bits in the next message to be treated as
+ * pad bits.
+ */
+ public void SetPadBits(
+ int padBits)
+ {
+ if (padBits > 7)
+ {
+ throw new ArgumentException("padBits > 7");
+ }
+
+ this.padBits = padBits;
+ }
+
+ /**
+ * retrieve the number of pad bits in the last decoded message.
+ */
+ public int GetPadBits()
+ {
+ return padBits;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forEncryption)
+ {
+ return EncodeBlock(input, inOff, length);
+ }
+ else
+ {
+ return DecodeBlock(input, inOff, length);
+ }
+ }
+
+ private byte[] EncodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = new byte[(bitSize + 7) / 8];
+ int r = padBits + 1;
+ int z = inLen;
+ int t = (bitSize + 13) / 16;
+
+ for (int i = 0; i < t; i += z)
+ {
+ if (i > t - z)
+ {
+ Array.Copy(input, inOff + inLen - (t - i),
+ block, block.Length - t, t - i);
+ }
+ else
+ {
+ Array.Copy(input, inOff, block, block.Length - (i + z), z);
+ }
+ }
+
+ for (int i = block.Length - 2 * t; i != block.Length; i += 2)
+ {
+ byte val = block[block.Length - t + i / 2];
+
+ block[i] = (byte)((shadows[(uint) (val & 0xff) >> 4] << 4)
+ | shadows[val & 0x0f]);
+ block[i + 1] = val;
+ }
+
+ block[block.Length - 2 * z] ^= (byte) r;
+ block[block.Length - 1] = (byte)((block[block.Length - 1] << 4) | 0x06);
+
+ int maxBit = (8 - (bitSize - 1) % 8);
+ int offSet = 0;
+
+ if (maxBit != 8)
+ {
+ block[0] &= (byte) ((ushort) 0xff >> maxBit);
+ block[0] |= (byte) ((ushort) 0x80 >> maxBit);
+ }
+ else
+ {
+ block[0] = 0x00;
+ block[1] |= 0x80;
+ offSet = 1;
+ }
+
+ return engine.ProcessBlock(block, offSet, block.Length - offSet);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+ */
+ private byte[] DecodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+ int r = 1;
+ int t = (bitSize + 13) / 16;
+
+ if ((block[block.Length - 1] & 0x0f) != 0x6)
+ {
+ throw new InvalidCipherTextException("invalid forcing byte in block");
+ }
+
+ block[block.Length - 1] =
+ (byte)(((ushort)(block[block.Length - 1] & 0xff) >> 4)
+ | ((inverse[(block[block.Length - 2] & 0xff) >> 4]) << 4));
+
+ block[0] = (byte)((shadows[(uint) (block[1] & 0xff) >> 4] << 4)
+ | shadows[block[1] & 0x0f]);
+
+ bool boundaryFound = false;
+ int boundary = 0;
+
+ for (int i = block.Length - 1; i >= block.Length - 2 * t; i -= 2)
+ {
+ int val = ((shadows[(uint) (block[i] & 0xff) >> 4] << 4)
+ | shadows[block[i] & 0x0f]);
+
+ if (((block[i - 1] ^ val) & 0xff) != 0)
+ {
+ if (!boundaryFound)
+ {
+ boundaryFound = true;
+ r = (block[i - 1] ^ val) & 0xff;
+ boundary = i - 1;
+ }
+ else
+ {
+ throw new InvalidCipherTextException("invalid tsums in block");
+ }
+ }
+ }
+
+ block[boundary] = 0;
+
+ byte[] nblock = new byte[(block.Length - boundary) / 2];
+
+ for (int i = 0; i < nblock.Length; i++)
+ {
+ nblock[i] = block[2 * i + boundary + 1];
+ }
+
+ padBits = r - 1;
+
+ return nblock;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/encodings/OaepEncoding.cs b/src/core/srcbc/crypto/encodings/OaepEncoding.cs
new file mode 100644
index 0000000..1d00171
--- /dev/null
+++ b/src/core/srcbc/crypto/encodings/OaepEncoding.cs
@@ -0,0 +1,334 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+ */
+ public class OaepEncoding
+ : IAsymmetricBlockCipher
+ {
+ private byte[] defHash;
+ private IDigest hash;
+
+ private IAsymmetricBlockCipher engine;
+ private SecureRandom random;
+ private bool forEncryption;
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher)
+ : this(cipher, new Sha1Digest(), null)
+ {
+ }
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher,
+ IDigest hash)
+ : this(cipher, hash, null)
+ {
+ }
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher,
+ IDigest hash,
+ byte[] encodingParams)
+ {
+ this.engine = cipher;
+ this.hash = hash;
+ this.defHash = new byte[hash.GetDigestSize()];
+
+ if (encodingParams != null)
+ {
+ hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
+ }
+
+ hash.DoFinal(defHash, 0);
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/OAEPPadding"; }
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+ this.random = rParam.Random;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ engine.Init(forEncryption, param);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize - 1 - 2 * defHash.Length;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return baseBlockSize - 1 - 2 * defHash.Length;
+ }
+ }
+
+ public byte[] ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (forEncryption)
+ {
+ return encodeBlock(inBytes, inOff, inLen);
+ }
+ else
+ {
+ return decodeBlock(inBytes, inOff, inLen);
+ }
+ }
+
+ private byte[] encodeBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
+
+ //
+ // copy in the message
+ //
+ Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen);
+
+ //
+ // add sentinel
+ //
+ block[block.Length - inLen - 1] = 0x01;
+
+ //
+ // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
+ //
+
+ //
+ // add the hash of the encoding params.
+ //
+ Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
+
+ //
+ // generate the seed.
+ //
+ byte[] seed = random.GenerateSeed(defHash.Length);
+
+ //
+ // mask the message block.
+ //
+ byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length);
+
+ for (int i = defHash.Length; i != block.Length; i++)
+ {
+ block[i] ^= mask[i - defHash.Length];
+ }
+
+ //
+ // add in the seed
+ //
+ Array.Copy(seed, 0, block, 0, defHash.Length);
+
+ //
+ // mask the seed.
+ //
+ mask = maskGeneratorFunction1(
+ block, defHash.Length, block.Length - defHash.Length, defHash.Length);
+
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ return engine.ProcessBlock(block, 0, block.Length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block turns out to
+ * be badly formatted.
+ */
+ private byte[] decodeBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ byte[] data = engine.ProcessBlock(inBytes, inOff, inLen);
+ byte[] block = null;
+
+ //
+ // as we may have zeros in our leading bytes for the block we produced
+ // on encryption, we need to make sure our decrypted block comes back
+ // the same size.
+ //
+ if (data.Length < engine.GetOutputBlockSize())
+ {
+ block = new byte[engine.GetOutputBlockSize()];
+
+ Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
+ }
+ else
+ {
+ block = data;
+ }
+
+ if (block.Length < (2 * defHash.Length) + 1)
+ {
+ throw new InvalidCipherTextException("data too short");
+ }
+
+ //
+ // unmask the seed.
+ //
+ byte[] mask = maskGeneratorFunction1(
+ block, defHash.Length, block.Length - defHash.Length, defHash.Length);
+
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ //
+ // unmask the message block.
+ //
+ mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length);
+
+ for (int i = defHash.Length; i != block.Length; i++)
+ {
+ block[i] ^= mask[i - defHash.Length];
+ }
+
+ //
+ // check the hash of the encoding params.
+ //
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ if (defHash[i] != block[defHash.Length + i])
+ {
+ throw new InvalidCipherTextException("data hash wrong");
+ }
+ }
+
+ //
+ // find the data block
+ //
+ int start;
+ for (start = 2 * defHash.Length; start != block.Length; start++)
+ {
+ if (block[start] == 1 || block[start] != 0)
+ {
+ break;
+ }
+ }
+
+ if (start >= (block.Length - 1) || block[start] != 1)
+ {
+ throw new InvalidCipherTextException("data start wrong " + start);
+ }
+
+ start++;
+
+ //
+ // extract the data block
+ //
+ byte[] output = new byte[block.Length - start];
+
+ Array.Copy(block, start, output, 0, output.Length);
+
+ return output;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint)i >> 24);
+ sp[1] = (byte)((uint)i >> 16);
+ sp[2] = (byte)((uint)i >> 8);
+ sp[3] = (byte)((uint)i >> 0);
+ }
+
+ /**
+ * mask generator function, as described in PKCS1v2.
+ */
+ private byte[] maskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[defHash.Length];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ hash.Reset();
+
+ do
+ {
+ ItoOSP(counter, C);
+
+ hash.BlockUpdate(Z, zOff, zLen);
+ hash.BlockUpdate(C, 0, C.Length);
+ hash.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * defHash.Length, defHash.Length);
+ }
+ while (++counter < (length / defHash.Length));
+
+ if ((counter * defHash.Length) < length)
+ {
+ ItoOSP(counter, C);
+
+ hash.BlockUpdate(Z, zOff, zLen);
+ hash.BlockUpdate(C, 0, C.Length);
+ hash.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * defHash.Length, mask.Length - (counter * defHash.Length));
+ }
+
+ return mask;
+ }
+ }
+}
+
diff --git a/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs b/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs
new file mode 100644
index 0000000..b813728
--- /dev/null
+++ b/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs
@@ -0,0 +1,229 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see Pkcs1 Version 2 for details.
+ */
+ public class Pkcs1Encoding
+ : IAsymmetricBlockCipher
+ {
+ /**
+ * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
+ * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false.
+ */
+ public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
+
+ private const int HeaderLength = 10;
+
+ /**
+ * The same effect can be achieved by setting the static property directly
+ *
+ * The static property is checked during construction of the encoding object, it is set to
+ * true by default.
+ *
+ */
+ public static bool StrictLengthEnabled
+ {
+ get { return strictLengthEnabled[0]; }
+ set { strictLengthEnabled[0] = value; }
+ }
+
+ private static readonly bool[] strictLengthEnabled;
+
+ static Pkcs1Encoding()
+ {
+ string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
+
+ strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
+ }
+
+
+ private SecureRandom random;
+ private IAsymmetricBlockCipher engine;
+ private bool forEncryption;
+ private bool forPrivateKey;
+ private bool useStrictLength;
+
+ /**
+ * Basic constructor.
+ * @param cipher
+ */
+ public Pkcs1Encoding(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/PKCS1Padding"; }
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ AsymmetricKeyParameter kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ kParam = (AsymmetricKeyParameter)rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)parameters;
+ }
+
+ engine.Init(forEncryption, parameters);
+
+ this.forPrivateKey = kParam.IsPrivate;
+ this.forEncryption = forEncryption;
+ }
+
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize - HeaderLength
+ : baseBlockSize;
+ }
+
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize
+ : baseBlockSize - HeaderLength;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ return forEncryption
+ ? EncodeBlock(input, inOff, length)
+ : DecodeBlock(input, inOff, length);
+ }
+
+ private byte[] EncodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = new byte[engine.GetInputBlockSize()];
+
+ if (forPrivateKey)
+ {
+ block[0] = 0x01; // type code 1
+
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ block[i] = (byte)0xFF;
+ }
+ }
+ else
+ {
+ random.NextBytes(block); // random fill
+
+ block[0] = 0x02; // type code 2
+
+ //
+ // a zero byte marks the end of the padding, so all
+ // the pad bytes must be non-zero.
+ //
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ while (block[i] == 0)
+ {
+ block[i] = (byte)random.NextInt();
+ }
+ }
+ }
+
+ block[block.Length - inLen - 1] = 0x00; // mark the end of the padding
+ Array.Copy(input, inOff, block, block.Length - inLen, inLen);
+
+ return engine.ProcessBlock(block, 0, block.Length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+ */
+ private byte[] DecodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+
+ if (block.Length < GetOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block truncated");
+ }
+
+ byte type = block[0];
+
+ if (type != 1 && type != 2)
+ {
+ throw new InvalidCipherTextException("unknown block type");
+ }
+
+ if (useStrictLength && block.Length != engine.GetOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block incorrect size");
+ }
+
+ //
+ // find and extract the message block.
+ //
+ int start;
+ for (start = 1; start != block.Length; start++)
+ {
+ byte pad = block[start];
+
+ if (pad == 0)
+ {
+ break;
+ }
+
+ if (type == 1 && pad != (byte)0xff)
+ {
+ throw new InvalidCipherTextException("block padding incorrect");
+ }
+ }
+
+ start++; // data should start at the next byte
+
+ if (start >= block.Length || start < HeaderLength)
+ {
+ throw new InvalidCipherTextException("no data in block");
+ }
+
+ byte[] result = new byte[block.Length - start];
+
+ Array.Copy(block, start, result, 0, result.Length);
+
+ return result;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/AesEngine.cs b/src/core/srcbc/crypto/engines/AesEngine.cs
new file mode 100644
index 0000000..9b802b1
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/AesEngine.cs
@@ -0,0 +1,550 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ *
+ *
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ *
+ */
+ public class AesEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+ // precomputation tables of calculations for rounds
+ private static readonly int[] T0 =
+ {
+ unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff),
+ unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102),
+ unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d),
+ unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa),
+ unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41),
+ unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453),
+ unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d),
+ unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83),
+ unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2),
+ unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795),
+ unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a),
+ unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df),
+ unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912),
+ unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc),
+ unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7),
+ unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413),
+ unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040),
+ unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d),
+ unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0),
+ unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed),
+ unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a),
+ unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78),
+ unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080),
+ unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1),
+ unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020),
+ unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18),
+ unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488),
+ unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a),
+ unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0),
+ unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54),
+ unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b),
+ unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad),
+ unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992),
+ unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd),
+ unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3),
+ unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda),
+ unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8),
+ unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4),
+ unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a),
+ unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697),
+ unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96),
+ unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c),
+ unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7),
+ unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969),
+ unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9),
+ unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9),
+ unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715),
+ unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5),
+ unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65),
+ unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929),
+ unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d),
+ unchecked((int) 0x3a16162c)
+ };
+
+ private static readonly int[] Tinv0 =
+ {
+ unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b),
+ unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad),
+ unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526),
+ unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d),
+ unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03),
+ unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458),
+ unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899),
+ unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d),
+ unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1),
+ unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f),
+ unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3),
+ unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3),
+ unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a),
+ unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506),
+ unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05),
+ unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd),
+ unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491),
+ unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6),
+ unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7),
+ unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000),
+ unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd),
+ unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68),
+ unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4),
+ unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c),
+ unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e),
+ unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af),
+ unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644),
+ unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8),
+ unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85),
+ unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc),
+ unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411),
+ unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322),
+ unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6),
+ unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850),
+ unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e),
+ unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf),
+ unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd),
+ unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa),
+ unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea),
+ unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235),
+ unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1),
+ unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43),
+ unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1),
+ unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb),
+ unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a),
+ unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7),
+ unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418),
+ unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478),
+ unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16),
+ unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08),
+ unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48),
+ unchecked((int) 0x4257b8d0)
+ };
+
+ private int Shift(
+ int r,
+ int shift)
+ {
+ return ((int)(((uint) r >> shift) | (uint)(r << (32 - shift))));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const int m1 = unchecked((int) 0x80808080);
+ private const int m2 = unchecked((int) 0x7f7f7f7f);
+ private const int m3 = unchecked((int) 0x0000001b);
+
+ private int FFmulX(
+ int x)
+ {
+ return ((int) (((x & m2) << 1) ^ (( (uint) (x & m1) >> 7) * m3)));
+ }
+
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private int Inv_Mcol(
+ int x)
+ {
+ int f2 = FFmulX(x);
+ int f4 = FFmulX(f2);
+ int f8 = FFmulX(f4);
+ int f9 = x ^ f8;
+
+ return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+ }
+
+ private int SubWord(int x) {
+ return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private int[,] GenerateWorkingKey(
+ byte[] key,
+ bool forEncryption)
+ {
+ int KC = key.Length / 4; // key length in words
+ int t;
+
+ if ((KC != 4) && (KC != 6) && (KC != 8)) {
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+ }
+
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ int[,] W = new int[ROUNDS+1, 4]; // 4 words in a block
+
+ //
+ // copy the key into the round key array
+ //
+
+ t = 0;
+ for (int i = 0; i < key.Length; t++)
+ {
+ W[t >> 2, t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+ i+=4;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (int i = KC; (i < k); i++)
+ {
+ int temp = W[(i-1)>>2, (i-1)&3];
+ if ((i % KC) == 0) {
+ temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
+ } else if ((KC > 6) && ((i % KC) == 4)) {
+ temp = SubWord(temp);
+ }
+
+ W[i>>2, i&3] = W[(i - KC)>>2, (i-KC)&3] ^ temp;
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ W[j, i] = Inv_Mcol(W[j, i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private int[,] WorkingKey;
+ private int C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+
+ if (keyParameter == null)
+ throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+
+ WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ {
+ throw new InvalidOperationException("AES engine not initialised");
+ }
+
+ if ((inOff + (32 / 2)) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (32 / 2)) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ C0 = (bytes[index++] & 0xff);
+ C0 |= (bytes[index++] & 0xff) << 8;
+ C0 |= (bytes[index++] & 0xff) << 16;
+ C0 |= bytes[index++] << 24;
+
+ C1 = (bytes[index++] & 0xff);
+ C1 |= (bytes[index++] & 0xff) << 8;
+ C1 |= (bytes[index++] & 0xff) << 16;
+ C1 |= bytes[index++] << 24;
+
+ C2 = (bytes[index++] & 0xff);
+ C2 |= (bytes[index++] & 0xff) << 8;
+ C2 |= (bytes[index++] & 0xff) << 16;
+ C2 |= bytes[index++] << 24;
+
+ C3 = (bytes[index++] & 0xff);
+ C3 |= (bytes[index++] & 0xff) << 8;
+ C3 |= (bytes[index++] & 0xff) << 16;
+ C3 |= bytes[index++] << 24;
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ bytes[index++] = (byte)C0;
+ bytes[index++] = (byte)(C0 >> 8);
+ bytes[index++] = (byte)(C0 >> 16);
+ bytes[index++] = (byte)(C0 >> 24);
+
+ bytes[index++] = (byte)C1;
+ bytes[index++] = (byte)(C1 >> 8);
+ bytes[index++] = (byte)(C1 >> 16);
+ bytes[index++] = (byte)(C1 >> 24);
+
+ bytes[index++] = (byte)C2;
+ bytes[index++] = (byte)(C2 >> 8);
+ bytes[index++] = (byte)(C2 >> 16);
+ bytes[index++] = (byte)(C2 >> 24);
+
+ bytes[index++] = (byte)C3;
+ bytes[index++] = (byte)(C3 >> 8);
+ bytes[index++] = (byte)(C3 >> 16);
+ bytes[index++] = (byte)(C3 >> 24);
+ }
+
+ private void EncryptBlock(
+ int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[0, 0];
+ C1 ^= KW[0, 1];
+ C2 ^= KW[0, 2];
+ C3 ^= KW[0, 3];
+
+ for (r = 1; r < ROUNDS - 1;)
+ {
+ r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255],16) ^ Shift(T0[(C3>>24)&255],8) ^ KW[r,0];
+ r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1];
+ r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2];
+ r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3];
+ C0 = T0[r0&255] ^ Shift(T0[(r1>>8)&255], 24) ^ Shift(T0[(r2>>16)&255], 16) ^ Shift(T0[(r3>>24)&255], 8) ^ KW[r,0];
+ C1 = T0[r1&255] ^ Shift(T0[(r2>>8)&255], 24) ^ Shift(T0[(r3>>16)&255], 16) ^ Shift(T0[(r0>>24)&255], 8) ^ KW[r,1];
+ C2 = T0[r2&255] ^ Shift(T0[(r3>>8)&255], 24) ^ Shift(T0[(r0>>16)&255], 16) ^ Shift(T0[(r1>>24)&255], 8) ^ KW[r,2];
+ C3 = T0[r3&255] ^ Shift(T0[(r0>>8)&255], 24) ^ Shift(T0[(r1>>16)&255], 16) ^ Shift(T0[(r2>>24)&255], 8) ^ KW[r++,3];
+ }
+
+ r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255], 16) ^ Shift(T0[(C3>>24)&255], 8) ^ KW[r,0];
+ r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1];
+ r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2];
+ r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3];
+
+ // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+ C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
+ C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
+ C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
+ C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
+ }
+
+ private void DecryptBlock(
+ int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[ROUNDS,0];
+ C1 ^= KW[ROUNDS,1];
+ C2 ^= KW[ROUNDS,2];
+ C3 ^= KW[ROUNDS,3];
+
+ for (r = ROUNDS-1; r>1;)
+ {
+ r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0];
+ r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1];
+ r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2];
+ r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--,3];
+ C0 = Tinv0[r0&255] ^ Shift(Tinv0[(r3>>8)&255], 24) ^ Shift(Tinv0[(r2>>16)&255], 16) ^ Shift(Tinv0[(r1>>24)&255], 8) ^ KW[r,0];
+ C1 = Tinv0[r1&255] ^ Shift(Tinv0[(r0>>8)&255], 24) ^ Shift(Tinv0[(r3>>16)&255], 16) ^ Shift(Tinv0[(r2>>24)&255], 8) ^ KW[r,1];
+ C2 = Tinv0[r2&255] ^ Shift(Tinv0[(r1>>8)&255], 24) ^ Shift(Tinv0[(r0>>16)&255], 16) ^ Shift(Tinv0[(r3>>24)&255], 8) ^ KW[r,2];
+ C3 = Tinv0[r3&255] ^ Shift(Tinv0[(r2>>8)&255], 24) ^ Shift(Tinv0[(r1>>16)&255], 16) ^ Shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--,3];
+ }
+
+ r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0];
+ r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1];
+ r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2];
+ r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r,3];
+
+ // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+ C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
+ C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
+ C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
+ C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/AesFastEngine.cs b/src/core/srcbc/crypto/engines/AesFastEngine.cs
new file mode 100644
index 0000000..22ef651
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/AesFastEngine.cs
@@ -0,0 +1,865 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the AES (Rijndael)), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor), they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations), 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each), for a total of 2Kbytes),
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values in each round
+ *
+ *
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation
+ *
+ */
+ public class AesFastEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S = {
+ (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+ (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+ (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
+ (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+ (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
+ (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
+ (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
+ (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
+ (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
+ (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
+ (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
+ (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
+ (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
+ (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
+ (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
+ (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
+ (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
+ (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
+ (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
+ (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
+ (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
+ (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+ (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
+ (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
+ (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
+ (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
+ (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
+ (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
+ (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+ (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
+ (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
+ (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si = {
+ (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
+ (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+ (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
+ (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+ (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
+ (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
+ (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
+ (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
+ (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
+ (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
+ (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+ (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+ (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
+ (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
+ (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
+ (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
+ (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
+ (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+ (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
+ (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
+ (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
+ (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
+ (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
+ (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
+ (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
+ (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
+ (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
+ (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+ (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
+ (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
+ (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
+ (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+ // precomputation tables of calculations for rounds
+ private static readonly int[] T0 =
+ {
+ unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff),
+ unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102),
+ unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d),
+ unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa),
+ unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41),
+ unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453),
+ unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d),
+ unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83),
+ unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2),
+ unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795),
+ unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a),
+ unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df),
+ unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912),
+ unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc),
+ unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7),
+ unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413),
+ unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040),
+ unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d),
+ unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0),
+ unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed),
+ unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a),
+ unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78),
+ unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080),
+ unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1),
+ unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020),
+ unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18),
+ unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488),
+ unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a),
+ unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0),
+ unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54),
+ unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b),
+ unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad),
+ unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992),
+ unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd),
+ unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3),
+ unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda),
+ unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8),
+ unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4),
+ unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a),
+ unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697),
+ unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96),
+ unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c),
+ unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7),
+ unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969),
+ unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9),
+ unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9),
+ unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715),
+ unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5),
+ unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65),
+ unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929),
+ unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d),
+ unchecked((int) 0x3a16162c)};
+
+ private static readonly int[] T1 =
+ {
+ unchecked((int) 0x6363c6a5), unchecked((int) 0x7c7cf884), unchecked((int) 0x7777ee99), unchecked((int) 0x7b7bf68d), unchecked((int) 0xf2f2ff0d),
+ unchecked((int) 0x6b6bd6bd), unchecked((int) 0x6f6fdeb1), unchecked((int) 0xc5c59154), unchecked((int) 0x30306050), unchecked((int) 0x01010203),
+ unchecked((int) 0x6767cea9), unchecked((int) 0x2b2b567d), unchecked((int) 0xfefee719), unchecked((int) 0xd7d7b562), unchecked((int) 0xabab4de6),
+ unchecked((int) 0x7676ec9a), unchecked((int) 0xcaca8f45), unchecked((int) 0x82821f9d), unchecked((int) 0xc9c98940), unchecked((int) 0x7d7dfa87),
+ unchecked((int) 0xfafaef15), unchecked((int) 0x5959b2eb), unchecked((int) 0x47478ec9), unchecked((int) 0xf0f0fb0b), unchecked((int) 0xadad41ec),
+ unchecked((int) 0xd4d4b367), unchecked((int) 0xa2a25ffd), unchecked((int) 0xafaf45ea), unchecked((int) 0x9c9c23bf), unchecked((int) 0xa4a453f7),
+ unchecked((int) 0x7272e496), unchecked((int) 0xc0c09b5b), unchecked((int) 0xb7b775c2), unchecked((int) 0xfdfde11c), unchecked((int) 0x93933dae),
+ unchecked((int) 0x26264c6a), unchecked((int) 0x36366c5a), unchecked((int) 0x3f3f7e41), unchecked((int) 0xf7f7f502), unchecked((int) 0xcccc834f),
+ unchecked((int) 0x3434685c), unchecked((int) 0xa5a551f4), unchecked((int) 0xe5e5d134), unchecked((int) 0xf1f1f908), unchecked((int) 0x7171e293),
+ unchecked((int) 0xd8d8ab73), unchecked((int) 0x31316253), unchecked((int) 0x15152a3f), unchecked((int) 0x0404080c), unchecked((int) 0xc7c79552),
+ unchecked((int) 0x23234665), unchecked((int) 0xc3c39d5e), unchecked((int) 0x18183028), unchecked((int) 0x969637a1), unchecked((int) 0x05050a0f),
+ unchecked((int) 0x9a9a2fb5), unchecked((int) 0x07070e09), unchecked((int) 0x12122436), unchecked((int) 0x80801b9b), unchecked((int) 0xe2e2df3d),
+ unchecked((int) 0xebebcd26), unchecked((int) 0x27274e69), unchecked((int) 0xb2b27fcd), unchecked((int) 0x7575ea9f), unchecked((int) 0x0909121b),
+ unchecked((int) 0x83831d9e), unchecked((int) 0x2c2c5874), unchecked((int) 0x1a1a342e), unchecked((int) 0x1b1b362d), unchecked((int) 0x6e6edcb2),
+ unchecked((int) 0x5a5ab4ee), unchecked((int) 0xa0a05bfb), unchecked((int) 0x5252a4f6), unchecked((int) 0x3b3b764d), unchecked((int) 0xd6d6b761),
+ unchecked((int) 0xb3b37dce), unchecked((int) 0x2929527b), unchecked((int) 0xe3e3dd3e), unchecked((int) 0x2f2f5e71), unchecked((int) 0x84841397),
+ unchecked((int) 0x5353a6f5), unchecked((int) 0xd1d1b968), unchecked((int) 0x00000000), unchecked((int) 0xededc12c), unchecked((int) 0x20204060),
+ unchecked((int) 0xfcfce31f), unchecked((int) 0xb1b179c8), unchecked((int) 0x5b5bb6ed), unchecked((int) 0x6a6ad4be), unchecked((int) 0xcbcb8d46),
+ unchecked((int) 0xbebe67d9), unchecked((int) 0x3939724b), unchecked((int) 0x4a4a94de), unchecked((int) 0x4c4c98d4), unchecked((int) 0x5858b0e8),
+ unchecked((int) 0xcfcf854a), unchecked((int) 0xd0d0bb6b), unchecked((int) 0xefefc52a), unchecked((int) 0xaaaa4fe5), unchecked((int) 0xfbfbed16),
+ unchecked((int) 0x434386c5), unchecked((int) 0x4d4d9ad7), unchecked((int) 0x33336655), unchecked((int) 0x85851194), unchecked((int) 0x45458acf),
+ unchecked((int) 0xf9f9e910), unchecked((int) 0x02020406), unchecked((int) 0x7f7ffe81), unchecked((int) 0x5050a0f0), unchecked((int) 0x3c3c7844),
+ unchecked((int) 0x9f9f25ba), unchecked((int) 0xa8a84be3), unchecked((int) 0x5151a2f3), unchecked((int) 0xa3a35dfe), unchecked((int) 0x404080c0),
+ unchecked((int) 0x8f8f058a), unchecked((int) 0x92923fad), unchecked((int) 0x9d9d21bc), unchecked((int) 0x38387048), unchecked((int) 0xf5f5f104),
+ unchecked((int) 0xbcbc63df), unchecked((int) 0xb6b677c1), unchecked((int) 0xdadaaf75), unchecked((int) 0x21214263), unchecked((int) 0x10102030),
+ unchecked((int) 0xffffe51a), unchecked((int) 0xf3f3fd0e), unchecked((int) 0xd2d2bf6d), unchecked((int) 0xcdcd814c), unchecked((int) 0x0c0c1814),
+ unchecked((int) 0x13132635), unchecked((int) 0xececc32f), unchecked((int) 0x5f5fbee1), unchecked((int) 0x979735a2), unchecked((int) 0x444488cc),
+ unchecked((int) 0x17172e39), unchecked((int) 0xc4c49357), unchecked((int) 0xa7a755f2), unchecked((int) 0x7e7efc82), unchecked((int) 0x3d3d7a47),
+ unchecked((int) 0x6464c8ac), unchecked((int) 0x5d5dbae7), unchecked((int) 0x1919322b), unchecked((int) 0x7373e695), unchecked((int) 0x6060c0a0),
+ unchecked((int) 0x81811998), unchecked((int) 0x4f4f9ed1), unchecked((int) 0xdcdca37f), unchecked((int) 0x22224466), unchecked((int) 0x2a2a547e),
+ unchecked((int) 0x90903bab), unchecked((int) 0x88880b83), unchecked((int) 0x46468cca), unchecked((int) 0xeeeec729), unchecked((int) 0xb8b86bd3),
+ unchecked((int) 0x1414283c), unchecked((int) 0xdedea779), unchecked((int) 0x5e5ebce2), unchecked((int) 0x0b0b161d), unchecked((int) 0xdbdbad76),
+ unchecked((int) 0xe0e0db3b), unchecked((int) 0x32326456), unchecked((int) 0x3a3a744e), unchecked((int) 0x0a0a141e), unchecked((int) 0x494992db),
+ unchecked((int) 0x06060c0a), unchecked((int) 0x2424486c), unchecked((int) 0x5c5cb8e4), unchecked((int) 0xc2c29f5d), unchecked((int) 0xd3d3bd6e),
+ unchecked((int) 0xacac43ef), unchecked((int) 0x6262c4a6), unchecked((int) 0x919139a8), unchecked((int) 0x959531a4), unchecked((int) 0xe4e4d337),
+ unchecked((int) 0x7979f28b), unchecked((int) 0xe7e7d532), unchecked((int) 0xc8c88b43), unchecked((int) 0x37376e59), unchecked((int) 0x6d6ddab7),
+ unchecked((int) 0x8d8d018c), unchecked((int) 0xd5d5b164), unchecked((int) 0x4e4e9cd2), unchecked((int) 0xa9a949e0), unchecked((int) 0x6c6cd8b4),
+ unchecked((int) 0x5656acfa), unchecked((int) 0xf4f4f307), unchecked((int) 0xeaeacf25), unchecked((int) 0x6565caaf), unchecked((int) 0x7a7af48e),
+ unchecked((int) 0xaeae47e9), unchecked((int) 0x08081018), unchecked((int) 0xbaba6fd5), unchecked((int) 0x7878f088), unchecked((int) 0x25254a6f),
+ unchecked((int) 0x2e2e5c72), unchecked((int) 0x1c1c3824), unchecked((int) 0xa6a657f1), unchecked((int) 0xb4b473c7), unchecked((int) 0xc6c69751),
+ unchecked((int) 0xe8e8cb23), unchecked((int) 0xdddda17c), unchecked((int) 0x7474e89c), unchecked((int) 0x1f1f3e21), unchecked((int) 0x4b4b96dd),
+ unchecked((int) 0xbdbd61dc), unchecked((int) 0x8b8b0d86), unchecked((int) 0x8a8a0f85), unchecked((int) 0x7070e090), unchecked((int) 0x3e3e7c42),
+ unchecked((int) 0xb5b571c4), unchecked((int) 0x6666ccaa), unchecked((int) 0x484890d8), unchecked((int) 0x03030605), unchecked((int) 0xf6f6f701),
+ unchecked((int) 0x0e0e1c12), unchecked((int) 0x6161c2a3), unchecked((int) 0x35356a5f), unchecked((int) 0x5757aef9), unchecked((int) 0xb9b969d0),
+ unchecked((int) 0x86861791), unchecked((int) 0xc1c19958), unchecked((int) 0x1d1d3a27), unchecked((int) 0x9e9e27b9), unchecked((int) 0xe1e1d938),
+ unchecked((int) 0xf8f8eb13), unchecked((int) 0x98982bb3), unchecked((int) 0x11112233), unchecked((int) 0x6969d2bb), unchecked((int) 0xd9d9a970),
+ unchecked((int) 0x8e8e0789), unchecked((int) 0x949433a7), unchecked((int) 0x9b9b2db6), unchecked((int) 0x1e1e3c22), unchecked((int) 0x87871592),
+ unchecked((int) 0xe9e9c920), unchecked((int) 0xcece8749), unchecked((int) 0x5555aaff), unchecked((int) 0x28285078), unchecked((int) 0xdfdfa57a),
+ unchecked((int) 0x8c8c038f), unchecked((int) 0xa1a159f8), unchecked((int) 0x89890980), unchecked((int) 0x0d0d1a17), unchecked((int) 0xbfbf65da),
+ unchecked((int) 0xe6e6d731), unchecked((int) 0x424284c6), unchecked((int) 0x6868d0b8), unchecked((int) 0x414182c3), unchecked((int) 0x999929b0),
+ unchecked((int) 0x2d2d5a77), unchecked((int) 0x0f0f1e11), unchecked((int) 0xb0b07bcb), unchecked((int) 0x5454a8fc), unchecked((int) 0xbbbb6dd6),
+ unchecked((int) 0x16162c3a)};
+
+ private static readonly int[] T2 =
+ {
+ unchecked((int) 0x63c6a563), unchecked((int) 0x7cf8847c), unchecked((int) 0x77ee9977), unchecked((int) 0x7bf68d7b), unchecked((int) 0xf2ff0df2),
+ unchecked((int) 0x6bd6bd6b), unchecked((int) 0x6fdeb16f), unchecked((int) 0xc59154c5), unchecked((int) 0x30605030), unchecked((int) 0x01020301),
+ unchecked((int) 0x67cea967), unchecked((int) 0x2b567d2b), unchecked((int) 0xfee719fe), unchecked((int) 0xd7b562d7), unchecked((int) 0xab4de6ab),
+ unchecked((int) 0x76ec9a76), unchecked((int) 0xca8f45ca), unchecked((int) 0x821f9d82), unchecked((int) 0xc98940c9), unchecked((int) 0x7dfa877d),
+ unchecked((int) 0xfaef15fa), unchecked((int) 0x59b2eb59), unchecked((int) 0x478ec947), unchecked((int) 0xf0fb0bf0), unchecked((int) 0xad41ecad),
+ unchecked((int) 0xd4b367d4), unchecked((int) 0xa25ffda2), unchecked((int) 0xaf45eaaf), unchecked((int) 0x9c23bf9c), unchecked((int) 0xa453f7a4),
+ unchecked((int) 0x72e49672), unchecked((int) 0xc09b5bc0), unchecked((int) 0xb775c2b7), unchecked((int) 0xfde11cfd), unchecked((int) 0x933dae93),
+ unchecked((int) 0x264c6a26), unchecked((int) 0x366c5a36), unchecked((int) 0x3f7e413f), unchecked((int) 0xf7f502f7), unchecked((int) 0xcc834fcc),
+ unchecked((int) 0x34685c34), unchecked((int) 0xa551f4a5), unchecked((int) 0xe5d134e5), unchecked((int) 0xf1f908f1), unchecked((int) 0x71e29371),
+ unchecked((int) 0xd8ab73d8), unchecked((int) 0x31625331), unchecked((int) 0x152a3f15), unchecked((int) 0x04080c04), unchecked((int) 0xc79552c7),
+ unchecked((int) 0x23466523), unchecked((int) 0xc39d5ec3), unchecked((int) 0x18302818), unchecked((int) 0x9637a196), unchecked((int) 0x050a0f05),
+ unchecked((int) 0x9a2fb59a), unchecked((int) 0x070e0907), unchecked((int) 0x12243612), unchecked((int) 0x801b9b80), unchecked((int) 0xe2df3de2),
+ unchecked((int) 0xebcd26eb), unchecked((int) 0x274e6927), unchecked((int) 0xb27fcdb2), unchecked((int) 0x75ea9f75), unchecked((int) 0x09121b09),
+ unchecked((int) 0x831d9e83), unchecked((int) 0x2c58742c), unchecked((int) 0x1a342e1a), unchecked((int) 0x1b362d1b), unchecked((int) 0x6edcb26e),
+ unchecked((int) 0x5ab4ee5a), unchecked((int) 0xa05bfba0), unchecked((int) 0x52a4f652), unchecked((int) 0x3b764d3b), unchecked((int) 0xd6b761d6),
+ unchecked((int) 0xb37dceb3), unchecked((int) 0x29527b29), unchecked((int) 0xe3dd3ee3), unchecked((int) 0x2f5e712f), unchecked((int) 0x84139784),
+ unchecked((int) 0x53a6f553), unchecked((int) 0xd1b968d1), unchecked((int) 0x00000000), unchecked((int) 0xedc12ced), unchecked((int) 0x20406020),
+ unchecked((int) 0xfce31ffc), unchecked((int) 0xb179c8b1), unchecked((int) 0x5bb6ed5b), unchecked((int) 0x6ad4be6a), unchecked((int) 0xcb8d46cb),
+ unchecked((int) 0xbe67d9be), unchecked((int) 0x39724b39), unchecked((int) 0x4a94de4a), unchecked((int) 0x4c98d44c), unchecked((int) 0x58b0e858),
+ unchecked((int) 0xcf854acf), unchecked((int) 0xd0bb6bd0), unchecked((int) 0xefc52aef), unchecked((int) 0xaa4fe5aa), unchecked((int) 0xfbed16fb),
+ unchecked((int) 0x4386c543), unchecked((int) 0x4d9ad74d), unchecked((int) 0x33665533), unchecked((int) 0x85119485), unchecked((int) 0x458acf45),
+ unchecked((int) 0xf9e910f9), unchecked((int) 0x02040602), unchecked((int) 0x7ffe817f), unchecked((int) 0x50a0f050), unchecked((int) 0x3c78443c),
+ unchecked((int) 0x9f25ba9f), unchecked((int) 0xa84be3a8), unchecked((int) 0x51a2f351), unchecked((int) 0xa35dfea3), unchecked((int) 0x4080c040),
+ unchecked((int) 0x8f058a8f), unchecked((int) 0x923fad92), unchecked((int) 0x9d21bc9d), unchecked((int) 0x38704838), unchecked((int) 0xf5f104f5),
+ unchecked((int) 0xbc63dfbc), unchecked((int) 0xb677c1b6), unchecked((int) 0xdaaf75da), unchecked((int) 0x21426321), unchecked((int) 0x10203010),
+ unchecked((int) 0xffe51aff), unchecked((int) 0xf3fd0ef3), unchecked((int) 0xd2bf6dd2), unchecked((int) 0xcd814ccd), unchecked((int) 0x0c18140c),
+ unchecked((int) 0x13263513), unchecked((int) 0xecc32fec), unchecked((int) 0x5fbee15f), unchecked((int) 0x9735a297), unchecked((int) 0x4488cc44),
+ unchecked((int) 0x172e3917), unchecked((int) 0xc49357c4), unchecked((int) 0xa755f2a7), unchecked((int) 0x7efc827e), unchecked((int) 0x3d7a473d),
+ unchecked((int) 0x64c8ac64), unchecked((int) 0x5dbae75d), unchecked((int) 0x19322b19), unchecked((int) 0x73e69573), unchecked((int) 0x60c0a060),
+ unchecked((int) 0x81199881), unchecked((int) 0x4f9ed14f), unchecked((int) 0xdca37fdc), unchecked((int) 0x22446622), unchecked((int) 0x2a547e2a),
+ unchecked((int) 0x903bab90), unchecked((int) 0x880b8388), unchecked((int) 0x468cca46), unchecked((int) 0xeec729ee), unchecked((int) 0xb86bd3b8),
+ unchecked((int) 0x14283c14), unchecked((int) 0xdea779de), unchecked((int) 0x5ebce25e), unchecked((int) 0x0b161d0b), unchecked((int) 0xdbad76db),
+ unchecked((int) 0xe0db3be0), unchecked((int) 0x32645632), unchecked((int) 0x3a744e3a), unchecked((int) 0x0a141e0a), unchecked((int) 0x4992db49),
+ unchecked((int) 0x060c0a06), unchecked((int) 0x24486c24), unchecked((int) 0x5cb8e45c), unchecked((int) 0xc29f5dc2), unchecked((int) 0xd3bd6ed3),
+ unchecked((int) 0xac43efac), unchecked((int) 0x62c4a662), unchecked((int) 0x9139a891), unchecked((int) 0x9531a495), unchecked((int) 0xe4d337e4),
+ unchecked((int) 0x79f28b79), unchecked((int) 0xe7d532e7), unchecked((int) 0xc88b43c8), unchecked((int) 0x376e5937), unchecked((int) 0x6ddab76d),
+ unchecked((int) 0x8d018c8d), unchecked((int) 0xd5b164d5), unchecked((int) 0x4e9cd24e), unchecked((int) 0xa949e0a9), unchecked((int) 0x6cd8b46c),
+ unchecked((int) 0x56acfa56), unchecked((int) 0xf4f307f4), unchecked((int) 0xeacf25ea), unchecked((int) 0x65caaf65), unchecked((int) 0x7af48e7a),
+ unchecked((int) 0xae47e9ae), unchecked((int) 0x08101808), unchecked((int) 0xba6fd5ba), unchecked((int) 0x78f08878), unchecked((int) 0x254a6f25),
+ unchecked((int) 0x2e5c722e), unchecked((int) 0x1c38241c), unchecked((int) 0xa657f1a6), unchecked((int) 0xb473c7b4), unchecked((int) 0xc69751c6),
+ unchecked((int) 0xe8cb23e8), unchecked((int) 0xdda17cdd), unchecked((int) 0x74e89c74), unchecked((int) 0x1f3e211f), unchecked((int) 0x4b96dd4b),
+ unchecked((int) 0xbd61dcbd), unchecked((int) 0x8b0d868b), unchecked((int) 0x8a0f858a), unchecked((int) 0x70e09070), unchecked((int) 0x3e7c423e),
+ unchecked((int) 0xb571c4b5), unchecked((int) 0x66ccaa66), unchecked((int) 0x4890d848), unchecked((int) 0x03060503), unchecked((int) 0xf6f701f6),
+ unchecked((int) 0x0e1c120e), unchecked((int) 0x61c2a361), unchecked((int) 0x356a5f35), unchecked((int) 0x57aef957), unchecked((int) 0xb969d0b9),
+ unchecked((int) 0x86179186), unchecked((int) 0xc19958c1), unchecked((int) 0x1d3a271d), unchecked((int) 0x9e27b99e), unchecked((int) 0xe1d938e1),
+ unchecked((int) 0xf8eb13f8), unchecked((int) 0x982bb398), unchecked((int) 0x11223311), unchecked((int) 0x69d2bb69), unchecked((int) 0xd9a970d9),
+ unchecked((int) 0x8e07898e), unchecked((int) 0x9433a794), unchecked((int) 0x9b2db69b), unchecked((int) 0x1e3c221e), unchecked((int) 0x87159287),
+ unchecked((int) 0xe9c920e9), unchecked((int) 0xce8749ce), unchecked((int) 0x55aaff55), unchecked((int) 0x28507828), unchecked((int) 0xdfa57adf),
+ unchecked((int) 0x8c038f8c), unchecked((int) 0xa159f8a1), unchecked((int) 0x89098089), unchecked((int) 0x0d1a170d), unchecked((int) 0xbf65dabf),
+ unchecked((int) 0xe6d731e6), unchecked((int) 0x4284c642), unchecked((int) 0x68d0b868), unchecked((int) 0x4182c341), unchecked((int) 0x9929b099),
+ unchecked((int) 0x2d5a772d), unchecked((int) 0x0f1e110f), unchecked((int) 0xb07bcbb0), unchecked((int) 0x54a8fc54), unchecked((int) 0xbb6dd6bb),
+ unchecked((int) 0x162c3a16)};
+
+ private static readonly int[] T3 =
+ {
+ unchecked((int) 0xc6a56363), unchecked((int) 0xf8847c7c), unchecked((int) 0xee997777), unchecked((int) 0xf68d7b7b), unchecked((int) 0xff0df2f2),
+ unchecked((int) 0xd6bd6b6b), unchecked((int) 0xdeb16f6f), unchecked((int) 0x9154c5c5), unchecked((int) 0x60503030), unchecked((int) 0x02030101),
+ unchecked((int) 0xcea96767), unchecked((int) 0x567d2b2b), unchecked((int) 0xe719fefe), unchecked((int) 0xb562d7d7), unchecked((int) 0x4de6abab),
+ unchecked((int) 0xec9a7676), unchecked((int) 0x8f45caca), unchecked((int) 0x1f9d8282), unchecked((int) 0x8940c9c9), unchecked((int) 0xfa877d7d),
+ unchecked((int) 0xef15fafa), unchecked((int) 0xb2eb5959), unchecked((int) 0x8ec94747), unchecked((int) 0xfb0bf0f0), unchecked((int) 0x41ecadad),
+ unchecked((int) 0xb367d4d4), unchecked((int) 0x5ffda2a2), unchecked((int) 0x45eaafaf), unchecked((int) 0x23bf9c9c), unchecked((int) 0x53f7a4a4),
+ unchecked((int) 0xe4967272), unchecked((int) 0x9b5bc0c0), unchecked((int) 0x75c2b7b7), unchecked((int) 0xe11cfdfd), unchecked((int) 0x3dae9393),
+ unchecked((int) 0x4c6a2626), unchecked((int) 0x6c5a3636), unchecked((int) 0x7e413f3f), unchecked((int) 0xf502f7f7), unchecked((int) 0x834fcccc),
+ unchecked((int) 0x685c3434), unchecked((int) 0x51f4a5a5), unchecked((int) 0xd134e5e5), unchecked((int) 0xf908f1f1), unchecked((int) 0xe2937171),
+ unchecked((int) 0xab73d8d8), unchecked((int) 0x62533131), unchecked((int) 0x2a3f1515), unchecked((int) 0x080c0404), unchecked((int) 0x9552c7c7),
+ unchecked((int) 0x46652323), unchecked((int) 0x9d5ec3c3), unchecked((int) 0x30281818), unchecked((int) 0x37a19696), unchecked((int) 0x0a0f0505),
+ unchecked((int) 0x2fb59a9a), unchecked((int) 0x0e090707), unchecked((int) 0x24361212), unchecked((int) 0x1b9b8080), unchecked((int) 0xdf3de2e2),
+ unchecked((int) 0xcd26ebeb), unchecked((int) 0x4e692727), unchecked((int) 0x7fcdb2b2), unchecked((int) 0xea9f7575), unchecked((int) 0x121b0909),
+ unchecked((int) 0x1d9e8383), unchecked((int) 0x58742c2c), unchecked((int) 0x342e1a1a), unchecked((int) 0x362d1b1b), unchecked((int) 0xdcb26e6e),
+ unchecked((int) 0xb4ee5a5a), unchecked((int) 0x5bfba0a0), unchecked((int) 0xa4f65252), unchecked((int) 0x764d3b3b), unchecked((int) 0xb761d6d6),
+ unchecked((int) 0x7dceb3b3), unchecked((int) 0x527b2929), unchecked((int) 0xdd3ee3e3), unchecked((int) 0x5e712f2f), unchecked((int) 0x13978484),
+ unchecked((int) 0xa6f55353), unchecked((int) 0xb968d1d1), unchecked((int) 0x00000000), unchecked((int) 0xc12ceded), unchecked((int) 0x40602020),
+ unchecked((int) 0xe31ffcfc), unchecked((int) 0x79c8b1b1), unchecked((int) 0xb6ed5b5b), unchecked((int) 0xd4be6a6a), unchecked((int) 0x8d46cbcb),
+ unchecked((int) 0x67d9bebe), unchecked((int) 0x724b3939), unchecked((int) 0x94de4a4a), unchecked((int) 0x98d44c4c), unchecked((int) 0xb0e85858),
+ unchecked((int) 0x854acfcf), unchecked((int) 0xbb6bd0d0), unchecked((int) 0xc52aefef), unchecked((int) 0x4fe5aaaa), unchecked((int) 0xed16fbfb),
+ unchecked((int) 0x86c54343), unchecked((int) 0x9ad74d4d), unchecked((int) 0x66553333), unchecked((int) 0x11948585), unchecked((int) 0x8acf4545),
+ unchecked((int) 0xe910f9f9), unchecked((int) 0x04060202), unchecked((int) 0xfe817f7f), unchecked((int) 0xa0f05050), unchecked((int) 0x78443c3c),
+ unchecked((int) 0x25ba9f9f), unchecked((int) 0x4be3a8a8), unchecked((int) 0xa2f35151), unchecked((int) 0x5dfea3a3), unchecked((int) 0x80c04040),
+ unchecked((int) 0x058a8f8f), unchecked((int) 0x3fad9292), unchecked((int) 0x21bc9d9d), unchecked((int) 0x70483838), unchecked((int) 0xf104f5f5),
+ unchecked((int) 0x63dfbcbc), unchecked((int) 0x77c1b6b6), unchecked((int) 0xaf75dada), unchecked((int) 0x42632121), unchecked((int) 0x20301010),
+ unchecked((int) 0xe51affff), unchecked((int) 0xfd0ef3f3), unchecked((int) 0xbf6dd2d2), unchecked((int) 0x814ccdcd), unchecked((int) 0x18140c0c),
+ unchecked((int) 0x26351313), unchecked((int) 0xc32fecec), unchecked((int) 0xbee15f5f), unchecked((int) 0x35a29797), unchecked((int) 0x88cc4444),
+ unchecked((int) 0x2e391717), unchecked((int) 0x9357c4c4), unchecked((int) 0x55f2a7a7), unchecked((int) 0xfc827e7e), unchecked((int) 0x7a473d3d),
+ unchecked((int) 0xc8ac6464), unchecked((int) 0xbae75d5d), unchecked((int) 0x322b1919), unchecked((int) 0xe6957373), unchecked((int) 0xc0a06060),
+ unchecked((int) 0x19988181), unchecked((int) 0x9ed14f4f), unchecked((int) 0xa37fdcdc), unchecked((int) 0x44662222), unchecked((int) 0x547e2a2a),
+ unchecked((int) 0x3bab9090), unchecked((int) 0x0b838888), unchecked((int) 0x8cca4646), unchecked((int) 0xc729eeee), unchecked((int) 0x6bd3b8b8),
+ unchecked((int) 0x283c1414), unchecked((int) 0xa779dede), unchecked((int) 0xbce25e5e), unchecked((int) 0x161d0b0b), unchecked((int) 0xad76dbdb),
+ unchecked((int) 0xdb3be0e0), unchecked((int) 0x64563232), unchecked((int) 0x744e3a3a), unchecked((int) 0x141e0a0a), unchecked((int) 0x92db4949),
+ unchecked((int) 0x0c0a0606), unchecked((int) 0x486c2424), unchecked((int) 0xb8e45c5c), unchecked((int) 0x9f5dc2c2), unchecked((int) 0xbd6ed3d3),
+ unchecked((int) 0x43efacac), unchecked((int) 0xc4a66262), unchecked((int) 0x39a89191), unchecked((int) 0x31a49595), unchecked((int) 0xd337e4e4),
+ unchecked((int) 0xf28b7979), unchecked((int) 0xd532e7e7), unchecked((int) 0x8b43c8c8), unchecked((int) 0x6e593737), unchecked((int) 0xdab76d6d),
+ unchecked((int) 0x018c8d8d), unchecked((int) 0xb164d5d5), unchecked((int) 0x9cd24e4e), unchecked((int) 0x49e0a9a9), unchecked((int) 0xd8b46c6c),
+ unchecked((int) 0xacfa5656), unchecked((int) 0xf307f4f4), unchecked((int) 0xcf25eaea), unchecked((int) 0xcaaf6565), unchecked((int) 0xf48e7a7a),
+ unchecked((int) 0x47e9aeae), unchecked((int) 0x10180808), unchecked((int) 0x6fd5baba), unchecked((int) 0xf0887878), unchecked((int) 0x4a6f2525),
+ unchecked((int) 0x5c722e2e), unchecked((int) 0x38241c1c), unchecked((int) 0x57f1a6a6), unchecked((int) 0x73c7b4b4), unchecked((int) 0x9751c6c6),
+ unchecked((int) 0xcb23e8e8), unchecked((int) 0xa17cdddd), unchecked((int) 0xe89c7474), unchecked((int) 0x3e211f1f), unchecked((int) 0x96dd4b4b),
+ unchecked((int) 0x61dcbdbd), unchecked((int) 0x0d868b8b), unchecked((int) 0x0f858a8a), unchecked((int) 0xe0907070), unchecked((int) 0x7c423e3e),
+ unchecked((int) 0x71c4b5b5), unchecked((int) 0xccaa6666), unchecked((int) 0x90d84848), unchecked((int) 0x06050303), unchecked((int) 0xf701f6f6),
+ unchecked((int) 0x1c120e0e), unchecked((int) 0xc2a36161), unchecked((int) 0x6a5f3535), unchecked((int) 0xaef95757), unchecked((int) 0x69d0b9b9),
+ unchecked((int) 0x17918686), unchecked((int) 0x9958c1c1), unchecked((int) 0x3a271d1d), unchecked((int) 0x27b99e9e), unchecked((int) 0xd938e1e1),
+ unchecked((int) 0xeb13f8f8), unchecked((int) 0x2bb39898), unchecked((int) 0x22331111), unchecked((int) 0xd2bb6969), unchecked((int) 0xa970d9d9),
+ unchecked((int) 0x07898e8e), unchecked((int) 0x33a79494), unchecked((int) 0x2db69b9b), unchecked((int) 0x3c221e1e), unchecked((int) 0x15928787),
+ unchecked((int) 0xc920e9e9), unchecked((int) 0x8749cece), unchecked((int) 0xaaff5555), unchecked((int) 0x50782828), unchecked((int) 0xa57adfdf),
+ unchecked((int) 0x038f8c8c), unchecked((int) 0x59f8a1a1), unchecked((int) 0x09808989), unchecked((int) 0x1a170d0d), unchecked((int) 0x65dabfbf),
+ unchecked((int) 0xd731e6e6), unchecked((int) 0x84c64242), unchecked((int) 0xd0b86868), unchecked((int) 0x82c34141), unchecked((int) 0x29b09999),
+ unchecked((int) 0x5a772d2d), unchecked((int) 0x1e110f0f), unchecked((int) 0x7bcbb0b0), unchecked((int) 0xa8fc5454), unchecked((int) 0x6dd6bbbb),
+ unchecked((int) 0x2c3a1616)};
+
+ private static readonly int[] Tinv0 =
+ {
+ unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b),
+ unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad),
+ unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526),
+ unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d),
+ unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03),
+ unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458),
+ unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899),
+ unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d),
+ unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1),
+ unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f),
+ unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3),
+ unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3),
+ unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a),
+ unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506),
+ unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05),
+ unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd),
+ unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491),
+ unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6),
+ unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7),
+ unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000),
+ unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd),
+ unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68),
+ unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4),
+ unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c),
+ unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e),
+ unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af),
+ unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644),
+ unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8),
+ unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85),
+ unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc),
+ unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411),
+ unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322),
+ unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6),
+ unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850),
+ unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e),
+ unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf),
+ unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd),
+ unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa),
+ unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea),
+ unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235),
+ unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1),
+ unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43),
+ unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1),
+ unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb),
+ unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a),
+ unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7),
+ unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418),
+ unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478),
+ unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16),
+ unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08),
+ unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48),
+ unchecked((int) 0x4257b8d0)};
+
+ private static readonly int[] Tinv1 =
+ {
+ unchecked((int) 0xa7f45150), unchecked((int) 0x65417e53), unchecked((int) 0xa4171ac3), unchecked((int) 0x5e273a96), unchecked((int) 0x6bab3bcb),
+ unchecked((int) 0x459d1ff1), unchecked((int) 0x58faacab), unchecked((int) 0x03e34b93), unchecked((int) 0xfa302055), unchecked((int) 0x6d76adf6),
+ unchecked((int) 0x76cc8891), unchecked((int) 0x4c02f525), unchecked((int) 0xd7e54ffc), unchecked((int) 0xcb2ac5d7), unchecked((int) 0x44352680),
+ unchecked((int) 0xa362b58f), unchecked((int) 0x5ab1de49), unchecked((int) 0x1bba2567), unchecked((int) 0x0eea4598), unchecked((int) 0xc0fe5de1),
+ unchecked((int) 0x752fc302), unchecked((int) 0xf04c8112), unchecked((int) 0x97468da3), unchecked((int) 0xf9d36bc6), unchecked((int) 0x5f8f03e7),
+ unchecked((int) 0x9c921595), unchecked((int) 0x7a6dbfeb), unchecked((int) 0x595295da), unchecked((int) 0x83bed42d), unchecked((int) 0x217458d3),
+ unchecked((int) 0x69e04929), unchecked((int) 0xc8c98e44), unchecked((int) 0x89c2756a), unchecked((int) 0x798ef478), unchecked((int) 0x3e58996b),
+ unchecked((int) 0x71b927dd), unchecked((int) 0x4fe1beb6), unchecked((int) 0xad88f017), unchecked((int) 0xac20c966), unchecked((int) 0x3ace7db4),
+ unchecked((int) 0x4adf6318), unchecked((int) 0x311ae582), unchecked((int) 0x33519760), unchecked((int) 0x7f536245), unchecked((int) 0x7764b1e0),
+ unchecked((int) 0xae6bbb84), unchecked((int) 0xa081fe1c), unchecked((int) 0x2b08f994), unchecked((int) 0x68487058), unchecked((int) 0xfd458f19),
+ unchecked((int) 0x6cde9487), unchecked((int) 0xf87b52b7), unchecked((int) 0xd373ab23), unchecked((int) 0x024b72e2), unchecked((int) 0x8f1fe357),
+ unchecked((int) 0xab55662a), unchecked((int) 0x28ebb207), unchecked((int) 0xc2b52f03), unchecked((int) 0x7bc5869a), unchecked((int) 0x0837d3a5),
+ unchecked((int) 0x872830f2), unchecked((int) 0xa5bf23b2), unchecked((int) 0x6a0302ba), unchecked((int) 0x8216ed5c), unchecked((int) 0x1ccf8a2b),
+ unchecked((int) 0xb479a792), unchecked((int) 0xf207f3f0), unchecked((int) 0xe2694ea1), unchecked((int) 0xf4da65cd), unchecked((int) 0xbe0506d5),
+ unchecked((int) 0x6234d11f), unchecked((int) 0xfea6c48a), unchecked((int) 0x532e349d), unchecked((int) 0x55f3a2a0), unchecked((int) 0xe18a0532),
+ unchecked((int) 0xebf6a475), unchecked((int) 0xec830b39), unchecked((int) 0xef6040aa), unchecked((int) 0x9f715e06), unchecked((int) 0x106ebd51),
+ unchecked((int) 0x8a213ef9), unchecked((int) 0x06dd963d), unchecked((int) 0x053eddae), unchecked((int) 0xbde64d46), unchecked((int) 0x8d5491b5),
+ unchecked((int) 0x5dc47105), unchecked((int) 0xd406046f), unchecked((int) 0x155060ff), unchecked((int) 0xfb981924), unchecked((int) 0xe9bdd697),
+ unchecked((int) 0x434089cc), unchecked((int) 0x9ed96777), unchecked((int) 0x42e8b0bd), unchecked((int) 0x8b890788), unchecked((int) 0x5b19e738),
+ unchecked((int) 0xeec879db), unchecked((int) 0x0a7ca147), unchecked((int) 0x0f427ce9), unchecked((int) 0x1e84f8c9), unchecked((int) 0x00000000),
+ unchecked((int) 0x86800983), unchecked((int) 0xed2b3248), unchecked((int) 0x70111eac), unchecked((int) 0x725a6c4e), unchecked((int) 0xff0efdfb),
+ unchecked((int) 0x38850f56), unchecked((int) 0xd5ae3d1e), unchecked((int) 0x392d3627), unchecked((int) 0xd90f0a64), unchecked((int) 0xa65c6821),
+ unchecked((int) 0x545b9bd1), unchecked((int) 0x2e36243a), unchecked((int) 0x670a0cb1), unchecked((int) 0xe757930f), unchecked((int) 0x96eeb4d2),
+ unchecked((int) 0x919b1b9e), unchecked((int) 0xc5c0804f), unchecked((int) 0x20dc61a2), unchecked((int) 0x4b775a69), unchecked((int) 0x1a121c16),
+ unchecked((int) 0xba93e20a), unchecked((int) 0x2aa0c0e5), unchecked((int) 0xe0223c43), unchecked((int) 0x171b121d), unchecked((int) 0x0d090e0b),
+ unchecked((int) 0xc78bf2ad), unchecked((int) 0xa8b62db9), unchecked((int) 0xa91e14c8), unchecked((int) 0x19f15785), unchecked((int) 0x0775af4c),
+ unchecked((int) 0xdd99eebb), unchecked((int) 0x607fa3fd), unchecked((int) 0x2601f79f), unchecked((int) 0xf5725cbc), unchecked((int) 0x3b6644c5),
+ unchecked((int) 0x7efb5b34), unchecked((int) 0x29438b76), unchecked((int) 0xc623cbdc), unchecked((int) 0xfcedb668), unchecked((int) 0xf1e4b863),
+ unchecked((int) 0xdc31d7ca), unchecked((int) 0x85634210), unchecked((int) 0x22971340), unchecked((int) 0x11c68420), unchecked((int) 0x244a857d),
+ unchecked((int) 0x3dbbd2f8), unchecked((int) 0x32f9ae11), unchecked((int) 0xa129c76d), unchecked((int) 0x2f9e1d4b), unchecked((int) 0x30b2dcf3),
+ unchecked((int) 0x52860dec), unchecked((int) 0xe3c177d0), unchecked((int) 0x16b32b6c), unchecked((int) 0xb970a999), unchecked((int) 0x489411fa),
+ unchecked((int) 0x64e94722), unchecked((int) 0x8cfca8c4), unchecked((int) 0x3ff0a01a), unchecked((int) 0x2c7d56d8), unchecked((int) 0x903322ef),
+ unchecked((int) 0x4e4987c7), unchecked((int) 0xd138d9c1), unchecked((int) 0xa2ca8cfe), unchecked((int) 0x0bd49836), unchecked((int) 0x81f5a6cf),
+ unchecked((int) 0xde7aa528), unchecked((int) 0x8eb7da26), unchecked((int) 0xbfad3fa4), unchecked((int) 0x9d3a2ce4), unchecked((int) 0x9278500d),
+ unchecked((int) 0xcc5f6a9b), unchecked((int) 0x467e5462), unchecked((int) 0x138df6c2), unchecked((int) 0xb8d890e8), unchecked((int) 0xf7392e5e),
+ unchecked((int) 0xafc382f5), unchecked((int) 0x805d9fbe), unchecked((int) 0x93d0697c), unchecked((int) 0x2dd56fa9), unchecked((int) 0x1225cfb3),
+ unchecked((int) 0x99acc83b), unchecked((int) 0x7d1810a7), unchecked((int) 0x639ce86e), unchecked((int) 0xbb3bdb7b), unchecked((int) 0x7826cd09),
+ unchecked((int) 0x18596ef4), unchecked((int) 0xb79aec01), unchecked((int) 0x9a4f83a8), unchecked((int) 0x6e95e665), unchecked((int) 0xe6ffaa7e),
+ unchecked((int) 0xcfbc2108), unchecked((int) 0xe815efe6), unchecked((int) 0x9be7bad9), unchecked((int) 0x366f4ace), unchecked((int) 0x099fead4),
+ unchecked((int) 0x7cb029d6), unchecked((int) 0xb2a431af), unchecked((int) 0x233f2a31), unchecked((int) 0x94a5c630), unchecked((int) 0x66a235c0),
+ unchecked((int) 0xbc4e7437), unchecked((int) 0xca82fca6), unchecked((int) 0xd090e0b0), unchecked((int) 0xd8a73315), unchecked((int) 0x9804f14a),
+ unchecked((int) 0xdaec41f7), unchecked((int) 0x50cd7f0e), unchecked((int) 0xf691172f), unchecked((int) 0xd64d768d), unchecked((int) 0xb0ef434d),
+ unchecked((int) 0x4daacc54), unchecked((int) 0x0496e4df), unchecked((int) 0xb5d19ee3), unchecked((int) 0x886a4c1b), unchecked((int) 0x1f2cc1b8),
+ unchecked((int) 0x5165467f), unchecked((int) 0xea5e9d04), unchecked((int) 0x358c015d), unchecked((int) 0x7487fa73), unchecked((int) 0x410bfb2e),
+ unchecked((int) 0x1d67b35a), unchecked((int) 0xd2db9252), unchecked((int) 0x5610e933), unchecked((int) 0x47d66d13), unchecked((int) 0x61d79a8c),
+ unchecked((int) 0x0ca1377a), unchecked((int) 0x14f8598e), unchecked((int) 0x3c13eb89), unchecked((int) 0x27a9ceee), unchecked((int) 0xc961b735),
+ unchecked((int) 0xe51ce1ed), unchecked((int) 0xb1477a3c), unchecked((int) 0xdfd29c59), unchecked((int) 0x73f2553f), unchecked((int) 0xce141879),
+ unchecked((int) 0x37c773bf), unchecked((int) 0xcdf753ea), unchecked((int) 0xaafd5f5b), unchecked((int) 0x6f3ddf14), unchecked((int) 0xdb447886),
+ unchecked((int) 0xf3afca81), unchecked((int) 0xc468b93e), unchecked((int) 0x3424382c), unchecked((int) 0x40a3c25f), unchecked((int) 0xc31d1672),
+ unchecked((int) 0x25e2bc0c), unchecked((int) 0x493c288b), unchecked((int) 0x950dff41), unchecked((int) 0x01a83971), unchecked((int) 0xb30c08de),
+ unchecked((int) 0xe4b4d89c), unchecked((int) 0xc1566490), unchecked((int) 0x84cb7b61), unchecked((int) 0xb632d570), unchecked((int) 0x5c6c4874),
+ unchecked((int) 0x57b8d042)};
+
+ private static readonly int[] Tinv2 =
+ {
+ unchecked((int) 0xf45150a7), unchecked((int) 0x417e5365), unchecked((int) 0x171ac3a4), unchecked((int) 0x273a965e), unchecked((int) 0xab3bcb6b),
+ unchecked((int) 0x9d1ff145), unchecked((int) 0xfaacab58), unchecked((int) 0xe34b9303), unchecked((int) 0x302055fa), unchecked((int) 0x76adf66d),
+ unchecked((int) 0xcc889176), unchecked((int) 0x02f5254c), unchecked((int) 0xe54ffcd7), unchecked((int) 0x2ac5d7cb), unchecked((int) 0x35268044),
+ unchecked((int) 0x62b58fa3), unchecked((int) 0xb1de495a), unchecked((int) 0xba25671b), unchecked((int) 0xea45980e), unchecked((int) 0xfe5de1c0),
+ unchecked((int) 0x2fc30275), unchecked((int) 0x4c8112f0), unchecked((int) 0x468da397), unchecked((int) 0xd36bc6f9), unchecked((int) 0x8f03e75f),
+ unchecked((int) 0x9215959c), unchecked((int) 0x6dbfeb7a), unchecked((int) 0x5295da59), unchecked((int) 0xbed42d83), unchecked((int) 0x7458d321),
+ unchecked((int) 0xe0492969), unchecked((int) 0xc98e44c8), unchecked((int) 0xc2756a89), unchecked((int) 0x8ef47879), unchecked((int) 0x58996b3e),
+ unchecked((int) 0xb927dd71), unchecked((int) 0xe1beb64f), unchecked((int) 0x88f017ad), unchecked((int) 0x20c966ac), unchecked((int) 0xce7db43a),
+ unchecked((int) 0xdf63184a), unchecked((int) 0x1ae58231), unchecked((int) 0x51976033), unchecked((int) 0x5362457f), unchecked((int) 0x64b1e077),
+ unchecked((int) 0x6bbb84ae), unchecked((int) 0x81fe1ca0), unchecked((int) 0x08f9942b), unchecked((int) 0x48705868), unchecked((int) 0x458f19fd),
+ unchecked((int) 0xde94876c), unchecked((int) 0x7b52b7f8), unchecked((int) 0x73ab23d3), unchecked((int) 0x4b72e202), unchecked((int) 0x1fe3578f),
+ unchecked((int) 0x55662aab), unchecked((int) 0xebb20728), unchecked((int) 0xb52f03c2), unchecked((int) 0xc5869a7b), unchecked((int) 0x37d3a508),
+ unchecked((int) 0x2830f287), unchecked((int) 0xbf23b2a5), unchecked((int) 0x0302ba6a), unchecked((int) 0x16ed5c82), unchecked((int) 0xcf8a2b1c),
+ unchecked((int) 0x79a792b4), unchecked((int) 0x07f3f0f2), unchecked((int) 0x694ea1e2), unchecked((int) 0xda65cdf4), unchecked((int) 0x0506d5be),
+ unchecked((int) 0x34d11f62), unchecked((int) 0xa6c48afe), unchecked((int) 0x2e349d53), unchecked((int) 0xf3a2a055), unchecked((int) 0x8a0532e1),
+ unchecked((int) 0xf6a475eb), unchecked((int) 0x830b39ec), unchecked((int) 0x6040aaef), unchecked((int) 0x715e069f), unchecked((int) 0x6ebd5110),
+ unchecked((int) 0x213ef98a), unchecked((int) 0xdd963d06), unchecked((int) 0x3eddae05), unchecked((int) 0xe64d46bd), unchecked((int) 0x5491b58d),
+ unchecked((int) 0xc471055d), unchecked((int) 0x06046fd4), unchecked((int) 0x5060ff15), unchecked((int) 0x981924fb), unchecked((int) 0xbdd697e9),
+ unchecked((int) 0x4089cc43), unchecked((int) 0xd967779e), unchecked((int) 0xe8b0bd42), unchecked((int) 0x8907888b), unchecked((int) 0x19e7385b),
+ unchecked((int) 0xc879dbee), unchecked((int) 0x7ca1470a), unchecked((int) 0x427ce90f), unchecked((int) 0x84f8c91e), unchecked((int) 0x00000000),
+ unchecked((int) 0x80098386), unchecked((int) 0x2b3248ed), unchecked((int) 0x111eac70), unchecked((int) 0x5a6c4e72), unchecked((int) 0x0efdfbff),
+ unchecked((int) 0x850f5638), unchecked((int) 0xae3d1ed5), unchecked((int) 0x2d362739), unchecked((int) 0x0f0a64d9), unchecked((int) 0x5c6821a6),
+ unchecked((int) 0x5b9bd154), unchecked((int) 0x36243a2e), unchecked((int) 0x0a0cb167), unchecked((int) 0x57930fe7), unchecked((int) 0xeeb4d296),
+ unchecked((int) 0x9b1b9e91), unchecked((int) 0xc0804fc5), unchecked((int) 0xdc61a220), unchecked((int) 0x775a694b), unchecked((int) 0x121c161a),
+ unchecked((int) 0x93e20aba), unchecked((int) 0xa0c0e52a), unchecked((int) 0x223c43e0), unchecked((int) 0x1b121d17), unchecked((int) 0x090e0b0d),
+ unchecked((int) 0x8bf2adc7), unchecked((int) 0xb62db9a8), unchecked((int) 0x1e14c8a9), unchecked((int) 0xf1578519), unchecked((int) 0x75af4c07),
+ unchecked((int) 0x99eebbdd), unchecked((int) 0x7fa3fd60), unchecked((int) 0x01f79f26), unchecked((int) 0x725cbcf5), unchecked((int) 0x6644c53b),
+ unchecked((int) 0xfb5b347e), unchecked((int) 0x438b7629), unchecked((int) 0x23cbdcc6), unchecked((int) 0xedb668fc), unchecked((int) 0xe4b863f1),
+ unchecked((int) 0x31d7cadc), unchecked((int) 0x63421085), unchecked((int) 0x97134022), unchecked((int) 0xc6842011), unchecked((int) 0x4a857d24),
+ unchecked((int) 0xbbd2f83d), unchecked((int) 0xf9ae1132), unchecked((int) 0x29c76da1), unchecked((int) 0x9e1d4b2f), unchecked((int) 0xb2dcf330),
+ unchecked((int) 0x860dec52), unchecked((int) 0xc177d0e3), unchecked((int) 0xb32b6c16), unchecked((int) 0x70a999b9), unchecked((int) 0x9411fa48),
+ unchecked((int) 0xe9472264), unchecked((int) 0xfca8c48c), unchecked((int) 0xf0a01a3f), unchecked((int) 0x7d56d82c), unchecked((int) 0x3322ef90),
+ unchecked((int) 0x4987c74e), unchecked((int) 0x38d9c1d1), unchecked((int) 0xca8cfea2), unchecked((int) 0xd498360b), unchecked((int) 0xf5a6cf81),
+ unchecked((int) 0x7aa528de), unchecked((int) 0xb7da268e), unchecked((int) 0xad3fa4bf), unchecked((int) 0x3a2ce49d), unchecked((int) 0x78500d92),
+ unchecked((int) 0x5f6a9bcc), unchecked((int) 0x7e546246), unchecked((int) 0x8df6c213), unchecked((int) 0xd890e8b8), unchecked((int) 0x392e5ef7),
+ unchecked((int) 0xc382f5af), unchecked((int) 0x5d9fbe80), unchecked((int) 0xd0697c93), unchecked((int) 0xd56fa92d), unchecked((int) 0x25cfb312),
+ unchecked((int) 0xacc83b99), unchecked((int) 0x1810a77d), unchecked((int) 0x9ce86e63), unchecked((int) 0x3bdb7bbb), unchecked((int) 0x26cd0978),
+ unchecked((int) 0x596ef418), unchecked((int) 0x9aec01b7), unchecked((int) 0x4f83a89a), unchecked((int) 0x95e6656e), unchecked((int) 0xffaa7ee6),
+ unchecked((int) 0xbc2108cf), unchecked((int) 0x15efe6e8), unchecked((int) 0xe7bad99b), unchecked((int) 0x6f4ace36), unchecked((int) 0x9fead409),
+ unchecked((int) 0xb029d67c), unchecked((int) 0xa431afb2), unchecked((int) 0x3f2a3123), unchecked((int) 0xa5c63094), unchecked((int) 0xa235c066),
+ unchecked((int) 0x4e7437bc), unchecked((int) 0x82fca6ca), unchecked((int) 0x90e0b0d0), unchecked((int) 0xa73315d8), unchecked((int) 0x04f14a98),
+ unchecked((int) 0xec41f7da), unchecked((int) 0xcd7f0e50), unchecked((int) 0x91172ff6), unchecked((int) 0x4d768dd6), unchecked((int) 0xef434db0),
+ unchecked((int) 0xaacc544d), unchecked((int) 0x96e4df04), unchecked((int) 0xd19ee3b5), unchecked((int) 0x6a4c1b88), unchecked((int) 0x2cc1b81f),
+ unchecked((int) 0x65467f51), unchecked((int) 0x5e9d04ea), unchecked((int) 0x8c015d35), unchecked((int) 0x87fa7374), unchecked((int) 0x0bfb2e41),
+ unchecked((int) 0x67b35a1d), unchecked((int) 0xdb9252d2), unchecked((int) 0x10e93356), unchecked((int) 0xd66d1347), unchecked((int) 0xd79a8c61),
+ unchecked((int) 0xa1377a0c), unchecked((int) 0xf8598e14), unchecked((int) 0x13eb893c), unchecked((int) 0xa9ceee27), unchecked((int) 0x61b735c9),
+ unchecked((int) 0x1ce1ede5), unchecked((int) 0x477a3cb1), unchecked((int) 0xd29c59df), unchecked((int) 0xf2553f73), unchecked((int) 0x141879ce),
+ unchecked((int) 0xc773bf37), unchecked((int) 0xf753eacd), unchecked((int) 0xfd5f5baa), unchecked((int) 0x3ddf146f), unchecked((int) 0x447886db),
+ unchecked((int) 0xafca81f3), unchecked((int) 0x68b93ec4), unchecked((int) 0x24382c34), unchecked((int) 0xa3c25f40), unchecked((int) 0x1d1672c3),
+ unchecked((int) 0xe2bc0c25), unchecked((int) 0x3c288b49), unchecked((int) 0x0dff4195), unchecked((int) 0xa8397101), unchecked((int) 0x0c08deb3),
+ unchecked((int) 0xb4d89ce4), unchecked((int) 0x566490c1), unchecked((int) 0xcb7b6184), unchecked((int) 0x32d570b6), unchecked((int) 0x6c48745c),
+ unchecked((int) 0xb8d04257)};
+
+ private static readonly int[] Tinv3 =
+ {
+ unchecked((int) 0x5150a7f4), unchecked((int) 0x7e536541), unchecked((int) 0x1ac3a417), unchecked((int) 0x3a965e27), unchecked((int) 0x3bcb6bab),
+ unchecked((int) 0x1ff1459d), unchecked((int) 0xacab58fa), unchecked((int) 0x4b9303e3), unchecked((int) 0x2055fa30), unchecked((int) 0xadf66d76),
+ unchecked((int) 0x889176cc), unchecked((int) 0xf5254c02), unchecked((int) 0x4ffcd7e5), unchecked((int) 0xc5d7cb2a), unchecked((int) 0x26804435),
+ unchecked((int) 0xb58fa362), unchecked((int) 0xde495ab1), unchecked((int) 0x25671bba), unchecked((int) 0x45980eea), unchecked((int) 0x5de1c0fe),
+ unchecked((int) 0xc302752f), unchecked((int) 0x8112f04c), unchecked((int) 0x8da39746), unchecked((int) 0x6bc6f9d3), unchecked((int) 0x03e75f8f),
+ unchecked((int) 0x15959c92), unchecked((int) 0xbfeb7a6d), unchecked((int) 0x95da5952), unchecked((int) 0xd42d83be), unchecked((int) 0x58d32174),
+ unchecked((int) 0x492969e0), unchecked((int) 0x8e44c8c9), unchecked((int) 0x756a89c2), unchecked((int) 0xf478798e), unchecked((int) 0x996b3e58),
+ unchecked((int) 0x27dd71b9), unchecked((int) 0xbeb64fe1), unchecked((int) 0xf017ad88), unchecked((int) 0xc966ac20), unchecked((int) 0x7db43ace),
+ unchecked((int) 0x63184adf), unchecked((int) 0xe582311a), unchecked((int) 0x97603351), unchecked((int) 0x62457f53), unchecked((int) 0xb1e07764),
+ unchecked((int) 0xbb84ae6b), unchecked((int) 0xfe1ca081), unchecked((int) 0xf9942b08), unchecked((int) 0x70586848), unchecked((int) 0x8f19fd45),
+ unchecked((int) 0x94876cde), unchecked((int) 0x52b7f87b), unchecked((int) 0xab23d373), unchecked((int) 0x72e2024b), unchecked((int) 0xe3578f1f),
+ unchecked((int) 0x662aab55), unchecked((int) 0xb20728eb), unchecked((int) 0x2f03c2b5), unchecked((int) 0x869a7bc5), unchecked((int) 0xd3a50837),
+ unchecked((int) 0x30f28728), unchecked((int) 0x23b2a5bf), unchecked((int) 0x02ba6a03), unchecked((int) 0xed5c8216), unchecked((int) 0x8a2b1ccf),
+ unchecked((int) 0xa792b479), unchecked((int) 0xf3f0f207), unchecked((int) 0x4ea1e269), unchecked((int) 0x65cdf4da), unchecked((int) 0x06d5be05),
+ unchecked((int) 0xd11f6234), unchecked((int) 0xc48afea6), unchecked((int) 0x349d532e), unchecked((int) 0xa2a055f3), unchecked((int) 0x0532e18a),
+ unchecked((int) 0xa475ebf6), unchecked((int) 0x0b39ec83), unchecked((int) 0x40aaef60), unchecked((int) 0x5e069f71), unchecked((int) 0xbd51106e),
+ unchecked((int) 0x3ef98a21), unchecked((int) 0x963d06dd), unchecked((int) 0xddae053e), unchecked((int) 0x4d46bde6), unchecked((int) 0x91b58d54),
+ unchecked((int) 0x71055dc4), unchecked((int) 0x046fd406), unchecked((int) 0x60ff1550), unchecked((int) 0x1924fb98), unchecked((int) 0xd697e9bd),
+ unchecked((int) 0x89cc4340), unchecked((int) 0x67779ed9), unchecked((int) 0xb0bd42e8), unchecked((int) 0x07888b89), unchecked((int) 0xe7385b19),
+ unchecked((int) 0x79dbeec8), unchecked((int) 0xa1470a7c), unchecked((int) 0x7ce90f42), unchecked((int) 0xf8c91e84), unchecked((int) 0x00000000),
+ unchecked((int) 0x09838680), unchecked((int) 0x3248ed2b), unchecked((int) 0x1eac7011), unchecked((int) 0x6c4e725a), unchecked((int) 0xfdfbff0e),
+ unchecked((int) 0x0f563885), unchecked((int) 0x3d1ed5ae), unchecked((int) 0x3627392d), unchecked((int) 0x0a64d90f), unchecked((int) 0x6821a65c),
+ unchecked((int) 0x9bd1545b), unchecked((int) 0x243a2e36), unchecked((int) 0x0cb1670a), unchecked((int) 0x930fe757), unchecked((int) 0xb4d296ee),
+ unchecked((int) 0x1b9e919b), unchecked((int) 0x804fc5c0), unchecked((int) 0x61a220dc), unchecked((int) 0x5a694b77), unchecked((int) 0x1c161a12),
+ unchecked((int) 0xe20aba93), unchecked((int) 0xc0e52aa0), unchecked((int) 0x3c43e022), unchecked((int) 0x121d171b), unchecked((int) 0x0e0b0d09),
+ unchecked((int) 0xf2adc78b), unchecked((int) 0x2db9a8b6), unchecked((int) 0x14c8a91e), unchecked((int) 0x578519f1), unchecked((int) 0xaf4c0775),
+ unchecked((int) 0xeebbdd99), unchecked((int) 0xa3fd607f), unchecked((int) 0xf79f2601), unchecked((int) 0x5cbcf572), unchecked((int) 0x44c53b66),
+ unchecked((int) 0x5b347efb), unchecked((int) 0x8b762943), unchecked((int) 0xcbdcc623), unchecked((int) 0xb668fced), unchecked((int) 0xb863f1e4),
+ unchecked((int) 0xd7cadc31), unchecked((int) 0x42108563), unchecked((int) 0x13402297), unchecked((int) 0x842011c6), unchecked((int) 0x857d244a),
+ unchecked((int) 0xd2f83dbb), unchecked((int) 0xae1132f9), unchecked((int) 0xc76da129), unchecked((int) 0x1d4b2f9e), unchecked((int) 0xdcf330b2),
+ unchecked((int) 0x0dec5286), unchecked((int) 0x77d0e3c1), unchecked((int) 0x2b6c16b3), unchecked((int) 0xa999b970), unchecked((int) 0x11fa4894),
+ unchecked((int) 0x472264e9), unchecked((int) 0xa8c48cfc), unchecked((int) 0xa01a3ff0), unchecked((int) 0x56d82c7d), unchecked((int) 0x22ef9033),
+ unchecked((int) 0x87c74e49), unchecked((int) 0xd9c1d138), unchecked((int) 0x8cfea2ca), unchecked((int) 0x98360bd4), unchecked((int) 0xa6cf81f5),
+ unchecked((int) 0xa528de7a), unchecked((int) 0xda268eb7), unchecked((int) 0x3fa4bfad), unchecked((int) 0x2ce49d3a), unchecked((int) 0x500d9278),
+ unchecked((int) 0x6a9bcc5f), unchecked((int) 0x5462467e), unchecked((int) 0xf6c2138d), unchecked((int) 0x90e8b8d8), unchecked((int) 0x2e5ef739),
+ unchecked((int) 0x82f5afc3), unchecked((int) 0x9fbe805d), unchecked((int) 0x697c93d0), unchecked((int) 0x6fa92dd5), unchecked((int) 0xcfb31225),
+ unchecked((int) 0xc83b99ac), unchecked((int) 0x10a77d18), unchecked((int) 0xe86e639c), unchecked((int) 0xdb7bbb3b), unchecked((int) 0xcd097826),
+ unchecked((int) 0x6ef41859), unchecked((int) 0xec01b79a), unchecked((int) 0x83a89a4f), unchecked((int) 0xe6656e95), unchecked((int) 0xaa7ee6ff),
+ unchecked((int) 0x2108cfbc), unchecked((int) 0xefe6e815), unchecked((int) 0xbad99be7), unchecked((int) 0x4ace366f), unchecked((int) 0xead4099f),
+ unchecked((int) 0x29d67cb0), unchecked((int) 0x31afb2a4), unchecked((int) 0x2a31233f), unchecked((int) 0xc63094a5), unchecked((int) 0x35c066a2),
+ unchecked((int) 0x7437bc4e), unchecked((int) 0xfca6ca82), unchecked((int) 0xe0b0d090), unchecked((int) 0x3315d8a7), unchecked((int) 0xf14a9804),
+ unchecked((int) 0x41f7daec), unchecked((int) 0x7f0e50cd), unchecked((int) 0x172ff691), unchecked((int) 0x768dd64d), unchecked((int) 0x434db0ef),
+ unchecked((int) 0xcc544daa), unchecked((int) 0xe4df0496), unchecked((int) 0x9ee3b5d1), unchecked((int) 0x4c1b886a), unchecked((int) 0xc1b81f2c),
+ unchecked((int) 0x467f5165), unchecked((int) 0x9d04ea5e), unchecked((int) 0x015d358c), unchecked((int) 0xfa737487), unchecked((int) 0xfb2e410b),
+ unchecked((int) 0xb35a1d67), unchecked((int) 0x9252d2db), unchecked((int) 0xe9335610), unchecked((int) 0x6d1347d6), unchecked((int) 0x9a8c61d7),
+ unchecked((int) 0x377a0ca1), unchecked((int) 0x598e14f8), unchecked((int) 0xeb893c13), unchecked((int) 0xceee27a9), unchecked((int) 0xb735c961),
+ unchecked((int) 0xe1ede51c), unchecked((int) 0x7a3cb147), unchecked((int) 0x9c59dfd2), unchecked((int) 0x553f73f2), unchecked((int) 0x1879ce14),
+ unchecked((int) 0x73bf37c7), unchecked((int) 0x53eacdf7), unchecked((int) 0x5f5baafd), unchecked((int) 0xdf146f3d), unchecked((int) 0x7886db44),
+ unchecked((int) 0xca81f3af), unchecked((int) 0xb93ec468), unchecked((int) 0x382c3424), unchecked((int) 0xc25f40a3), unchecked((int) 0x1672c31d),
+ unchecked((int) 0xbc0c25e2), unchecked((int) 0x288b493c), unchecked((int) 0xff41950d), unchecked((int) 0x397101a8), unchecked((int) 0x08deb30c),
+ unchecked((int) 0xd89ce4b4), unchecked((int) 0x6490c156), unchecked((int) 0x7b6184cb), unchecked((int) 0xd570b632), unchecked((int) 0x48745c6c),
+ unchecked((int) 0xd04257b8)};
+
+ private int Shift(
+ int r,
+ int shift)
+ {
+ return ((int) ( ( (uint) r >> shift) |
+ (uint) (r << (32 - shift))
+ ));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const int m1 = unchecked((int) 0x80808080);
+ private const int m2 = unchecked((int) 0x7f7f7f7f);
+ private const int m3 = unchecked((int) 0x0000001b);
+ private int FFmulX(int x) {
+ return ( (int) ( ((x & m2) << 1) ^
+ (( (uint)(x & m1) >> 7) * m3)
+ ) );
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private int Inv_Mcol(int x) {
+ int f2 = FFmulX(x);
+ int f4 = FFmulX(f2);
+ int f8 = FFmulX(f4);
+ int f9 = x ^ f8;
+
+ return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+ }
+
+
+ private int SubWord(int x) {
+ return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private int[,] GenerateWorkingKey(
+ byte[] key,
+ bool forEncryption)
+ {
+ int KC = key.Length / 4; // key length in words
+ int t;
+
+ if ((KC != 4) && (KC != 6) && (KC != 8)) {
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+ }
+
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ int[,] W = new int[ROUNDS+1,4]; // 4 words in a block
+
+ //
+ // copy the key into the round key array
+ //
+
+ t = 0;
+ for (int i = 0; i < key.Length; t++)
+ {
+ W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+ i+=4;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (int i = KC; (i < k); i++)
+ {
+ int temp = W[(i-1)>>2,(i-1)&3];
+ if ((i % KC) == 0) {
+ temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
+ } else if ((KC > 6) && ((i % KC) == 4)) {
+ temp = SubWord(temp);
+ }
+
+ W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp;
+ }
+
+ if (!forEncryption) {
+ for (int j = 1; j < ROUNDS; j++) {
+ for (int i = 0; i < 4; i++){
+ W[j,i] = Inv_Mcol(W[j,i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private int[,] WorkingKey;
+ private int C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesFastEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
+
+ WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
+ this.forEncryption = forEncryption;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ {
+ throw new InvalidOperationException("AES engine not initialised");
+ }
+
+ if ((inOff + (32 / 2)) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (32 / 2)) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (forEncryption)
+ {
+ UnPackBlock(input, inOff);
+ EncryptBlock(WorkingKey);
+ PackBlock(output, outOff);
+ }
+ else
+ {
+ UnPackBlock(input, inOff);
+ DecryptBlock(WorkingKey);
+ PackBlock(output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ C0 = (bytes[index++] & 0xff);
+ C0 |= (bytes[index++] & 0xff) << 8;
+ C0 |= (bytes[index++] & 0xff) << 16;
+ C0 |= bytes[index++] << 24;
+
+ C1 = (bytes[index++] & 0xff);
+ C1 |= (bytes[index++] & 0xff) << 8;
+ C1 |= (bytes[index++] & 0xff) << 16;
+ C1 |= bytes[index++] << 24;
+
+ C2 = (bytes[index++] & 0xff);
+ C2 |= (bytes[index++] & 0xff) << 8;
+ C2 |= (bytes[index++] & 0xff) << 16;
+ C2 |= bytes[index++] << 24;
+
+ C3 = (bytes[index++] & 0xff);
+ C3 |= (bytes[index++] & 0xff) << 8;
+ C3 |= (bytes[index++] & 0xff) << 16;
+ C3 |= bytes[index++] << 24;
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ bytes[index++] = (byte)C0;
+ bytes[index++] = (byte)(C0 >> 8);
+ bytes[index++] = (byte)(C0 >> 16);
+ bytes[index++] = (byte)(C0 >> 24);
+
+ bytes[index++] = (byte)C1;
+ bytes[index++] = (byte)(C1 >> 8);
+ bytes[index++] = (byte)(C1 >> 16);
+ bytes[index++] = (byte)(C1 >> 24);
+
+ bytes[index++] = (byte)C2;
+ bytes[index++] = (byte)(C2 >> 8);
+ bytes[index++] = (byte)(C2 >> 16);
+ bytes[index++] = (byte)(C2 >> 24);
+
+ bytes[index++] = (byte)C3;
+ bytes[index++] = (byte)(C3 >> 8);
+ bytes[index++] = (byte)(C3 >> 16);
+ bytes[index++] = (byte)(C3 >> 24);
+ }
+
+ private void EncryptBlock(int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[0,0];
+ C1 ^= KW[0,1];
+ C2 ^= KW[0,2];
+ C3 ^= KW[0,3];
+
+ for (r = 1; r < ROUNDS - 1;) {
+ r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0];
+ r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1];
+ r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2];
+ r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3];
+ C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r,0];
+ C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r,1];
+ C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r,2];
+ C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++,3];
+ }
+
+ r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0];
+ r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1];
+ r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2];
+ r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3];
+
+ // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+ C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
+ C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
+ C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
+ C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
+
+ }
+
+ private void DecryptBlock(int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[ROUNDS,0];
+ C1 ^= KW[ROUNDS,1];
+ C2 ^= KW[ROUNDS,2];
+ C3 ^= KW[ROUNDS,3];
+
+ for (r = ROUNDS-1; r>1;) {
+ r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0];
+ r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1];
+ r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2];
+ r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--,3];
+ C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r,0];
+ C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r,1];
+ C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r,2];
+ C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--,3];
+ }
+
+ r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0];
+ r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1];
+ r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2];
+ r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r,3];
+
+ // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+ C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
+ C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
+ C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
+ C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/AesLightEngine.cs b/src/core/srcbc/crypto/engines/AesLightEngine.cs
new file mode 100644
index 0000000..57ec6f7
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/AesLightEngine.cs
@@ -0,0 +1,438 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values
+ * in each round.
+ *
+ *
+ * This file contains the slowest performance version with no static tables
+ * for round precomputation, but it has the smallest foot print.
+ *
+ */
+ public class AesLightEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S = {
+ (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+ (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+ (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
+ (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+ (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
+ (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
+ (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
+ (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
+ (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
+ (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
+ (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
+ (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
+ (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
+ (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
+ (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
+ (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
+ (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
+ (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
+ (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
+ (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
+ (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
+ (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+ (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
+ (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
+ (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
+ (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
+ (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
+ (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
+ (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+ (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
+ (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
+ (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si = {
+ (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
+ (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+ (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
+ (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+ (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
+ (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
+ (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
+ (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
+ (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
+ (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
+ (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+ (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+ (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
+ (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
+ (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
+ (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
+ (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
+ (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+ (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
+ (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
+ (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
+ (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
+ (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
+ (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
+ (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
+ (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
+ (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
+ (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+ (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
+ (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
+ (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
+ (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+ private int Shift(
+ int r,
+ int shift)
+ {
+ return ((int) ( ( (uint) r >> shift) |
+ (uint) (r << (32 - shift)) )
+ );
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const int m1 = unchecked((int) 0x80808080);
+ private const int m2 = unchecked((int) 0x7f7f7f7f);
+ private const int m3 = unchecked((int) 0x0000001b);
+
+ private int FFmulX(int x)
+ {
+ return ( (int) ( ((x & m2) << 1) ^
+ (( (uint)(x & m1) >> 7) * m3)
+ )
+ );
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private int Mcol(int x)
+ {
+ int f2 = FFmulX(x);
+ return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
+ }
+
+ private int Inv_Mcol(int x)
+ {
+ int f2 = FFmulX(x);
+ int f4 = FFmulX(f2);
+ int f8 = FFmulX(f4);
+ int f9 = x ^ f8;
+
+ return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+ }
+
+
+ private int SubWord(int x)
+ {
+ return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private int[,] GenerateWorkingKey(
+ byte[] key,
+ bool forEncryption)
+ {
+ int KC = key.Length / 4; // key length in words
+ int t;
+
+ if ((KC != 4) && (KC != 6) && (KC != 8)) {
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+ }
+
+ ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+ int[,] W = new int[ROUNDS+1,4]; // 4 words in a block
+
+ //
+ // copy the key into the round key array
+ //
+
+ t = 0;
+ for (int i = 0; i < key.Length; t++)
+ {
+ W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+ i+=4;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (int i = KC; (i < k); i++)
+ {
+ int temp = W[(i-1)>>2,(i-1)&3];
+ if ((i % KC) == 0) {
+ temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1];
+ } else if ((KC > 6) && ((i % KC) == 4)) {
+ temp = SubWord(temp);
+ }
+
+ W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp;
+ }
+
+ if (!forEncryption) {
+ for (int j = 1; j < ROUNDS; j++) {
+ for (int i = 0; i < 4; i++){
+ W[j,i] = Inv_Mcol(W[j,i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private int[,] WorkingKey;
+ private int C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesLightEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
+
+ WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
+ this.forEncryption = forEncryption;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ {
+ throw new InvalidOperationException("AES engine not initialised");
+ }
+
+ if ((inOff + (32 / 2)) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (32 / 2)) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (forEncryption)
+ {
+ UnPackBlock(input, inOff);
+ EncryptBlock(WorkingKey);
+ PackBlock(output, outOff);
+ }
+ else
+ {
+ UnPackBlock(input, inOff);
+ DecryptBlock(WorkingKey);
+ PackBlock(output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ C0 = (bytes[index++] & 0xff);
+ C0 |= (bytes[index++] & 0xff) << 8;
+ C0 |= (bytes[index++] & 0xff) << 16;
+ C0 |= bytes[index++] << 24;
+
+ C1 = (bytes[index++] & 0xff);
+ C1 |= (bytes[index++] & 0xff) << 8;
+ C1 |= (bytes[index++] & 0xff) << 16;
+ C1 |= bytes[index++] << 24;
+
+ C2 = (bytes[index++] & 0xff);
+ C2 |= (bytes[index++] & 0xff) << 8;
+ C2 |= (bytes[index++] & 0xff) << 16;
+ C2 |= bytes[index++] << 24;
+
+ C3 = (bytes[index++] & 0xff);
+ C3 |= (bytes[index++] & 0xff) << 8;
+ C3 |= (bytes[index++] & 0xff) << 16;
+ C3 |= bytes[index++] << 24;
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ bytes[index++] = (byte)C0;
+ bytes[index++] = (byte)(C0 >> 8);
+ bytes[index++] = (byte)(C0 >> 16);
+ bytes[index++] = (byte)(C0 >> 24);
+
+ bytes[index++] = (byte)C1;
+ bytes[index++] = (byte)(C1 >> 8);
+ bytes[index++] = (byte)(C1 >> 16);
+ bytes[index++] = (byte)(C1 >> 24);
+
+ bytes[index++] = (byte)C2;
+ bytes[index++] = (byte)(C2 >> 8);
+ bytes[index++] = (byte)(C2 >> 16);
+ bytes[index++] = (byte)(C2 >> 24);
+
+ bytes[index++] = (byte)C3;
+ bytes[index++] = (byte)(C3 >> 8);
+ bytes[index++] = (byte)(C3 >> 16);
+ bytes[index++] = (byte)(C3 >> 24);
+ }
+
+ private void EncryptBlock(int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[0,0];
+ C1 ^= KW[0,1];
+ C2 ^= KW[0,2];
+ C3 ^= KW[0,3];
+
+ for (r = 1; r < ROUNDS - 1;) {
+ r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0];
+ r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1];
+ r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2];
+ r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3];
+ C0 = Mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r,0];
+ C1 = Mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r,1];
+ C2 = Mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r,2];
+ C3 = Mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++,3];
+ }
+
+ r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0];
+ r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1];
+ r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2];
+ r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3];
+
+ // the final round is a simple function of S
+
+ C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0];
+ C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1];
+ C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2];
+ C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3];
+
+ }
+
+ private void DecryptBlock(int[,] KW)
+ {
+ int r, r0, r1, r2, r3;
+
+ C0 ^= KW[ROUNDS,0];
+ C1 ^= KW[ROUNDS,1];
+ C2 ^= KW[ROUNDS,2];
+ C3 ^= KW[ROUNDS,3];
+
+ for (r = ROUNDS-1; r>1;) {
+ r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0];
+ r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1];
+ r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2];
+ r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--,3];
+ C0 = Inv_Mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r,0];
+ C1 = Inv_Mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r,1];
+ C2 = Inv_Mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r,2];
+ C3 = Inv_Mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--,3];
+ }
+
+ r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0];
+ r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1];
+ r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2];
+ r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r,3];
+
+ // the final round's table is a simple function of Si
+
+ C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0];
+ C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1];
+ C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2];
+ C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3];
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/AesWrapEngine.cs b/src/core/srcbc/crypto/engines/AesWrapEngine.cs
new file mode 100644
index 0000000..bfba7cd
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/AesWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the AES Key Wrapper from the NIST Key Wrap Specification.
+ ///
+ /// For further details see: http://csrc.nist.gov/encryption/kms/key-wrap.pdf.
+ ///
+ public class AesWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public AesWrapEngine()
+ : base(new AesEngine())
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/BlowfishEngine.cs b/src/core/srcbc/crypto/engines/BlowfishEngine.cs
new file mode 100644
index 0000000..0bfdf70
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/BlowfishEngine.cs
@@ -0,0 +1,577 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides Blowfish key encryption operations,
+ * such as encoding data and generating keys.
+ * All the algorithms herein are from Applied Cryptography
+ * and implement a simplified cryptography interface.
+ */
+ public sealed class BlowfishEngine
+ : IBlockCipher
+ {
+ private readonly static int[]
+ KP = {
+ unchecked((int) 0x243F6A88), unchecked((int) 0x85A308D3), unchecked((int) 0x13198A2E), unchecked((int) 0x03707344),
+ unchecked((int) 0xA4093822), unchecked((int) 0x299F31D0), unchecked((int) 0x082EFA98), unchecked((int) 0xEC4E6C89),
+ unchecked((int) 0x452821E6), unchecked((int) 0x38D01377), unchecked((int) 0xBE5466CF), unchecked((int) 0x34E90C6C),
+ unchecked((int) 0xC0AC29B7), unchecked((int) 0xC97C50DD), unchecked((int) 0x3F84D5B5), unchecked((int) 0xB5470917),
+ unchecked((int) 0x9216D5D9), unchecked((int) 0x8979FB1B)
+ },
+
+ KS0 = {
+ unchecked((int) 0xD1310BA6), unchecked((int) 0x98DFB5AC), unchecked((int) 0x2FFD72DB), unchecked((int) 0xD01ADFB7),
+ unchecked((int) 0xB8E1AFED), unchecked((int) 0x6A267E96), unchecked((int) 0xBA7C9045), unchecked((int) 0xF12C7F99),
+ unchecked((int) 0x24A19947), unchecked((int) 0xB3916CF7), unchecked((int) 0x0801F2E2), unchecked((int) 0x858EFC16),
+ unchecked((int) 0x636920D8), unchecked((int) 0x71574E69), unchecked((int) 0xA458FEA3), unchecked((int) 0xF4933D7E),
+ unchecked((int) 0x0D95748F), unchecked((int) 0x728EB658), unchecked((int) 0x718BCD58), unchecked((int) 0x82154AEE),
+ unchecked((int) 0x7B54A41D), unchecked((int) 0xC25A59B5), unchecked((int) 0x9C30D539), unchecked((int) 0x2AF26013),
+ unchecked((int) 0xC5D1B023), unchecked((int) 0x286085F0), unchecked((int) 0xCA417918), unchecked((int) 0xB8DB38EF),
+ unchecked((int) 0x8E79DCB0), unchecked((int) 0x603A180E), unchecked((int) 0x6C9E0E8B), unchecked((int) 0xB01E8A3E),
+ unchecked((int) 0xD71577C1), unchecked((int) 0xBD314B27), unchecked((int) 0x78AF2FDA), unchecked((int) 0x55605C60),
+ unchecked((int) 0xE65525F3), unchecked((int) 0xAA55AB94), unchecked((int) 0x57489862), unchecked((int) 0x63E81440),
+ unchecked((int) 0x55CA396A), unchecked((int) 0x2AAB10B6), unchecked((int) 0xB4CC5C34), unchecked((int) 0x1141E8CE),
+ unchecked((int) 0xA15486AF), unchecked((int) 0x7C72E993), unchecked((int) 0xB3EE1411), unchecked((int) 0x636FBC2A),
+ unchecked((int) 0x2BA9C55D), unchecked((int) 0x741831F6), unchecked((int) 0xCE5C3E16), unchecked((int) 0x9B87931E),
+ unchecked((int) 0xAFD6BA33), unchecked((int) 0x6C24CF5C), unchecked((int) 0x7A325381), unchecked((int) 0x28958677),
+ unchecked((int) 0x3B8F4898), unchecked((int) 0x6B4BB9AF), unchecked((int) 0xC4BFE81B), unchecked((int) 0x66282193),
+ unchecked((int) 0x61D809CC), unchecked((int) 0xFB21A991), unchecked((int) 0x487CAC60), unchecked((int) 0x5DEC8032),
+ unchecked((int) 0xEF845D5D), unchecked((int) 0xE98575B1), unchecked((int) 0xDC262302), unchecked((int) 0xEB651B88),
+ unchecked((int) 0x23893E81), unchecked((int) 0xD396ACC5), unchecked((int) 0x0F6D6FF3), unchecked((int) 0x83F44239),
+ unchecked((int) 0x2E0B4482), unchecked((int) 0xA4842004), unchecked((int) 0x69C8F04A), unchecked((int) 0x9E1F9B5E),
+ unchecked((int) 0x21C66842), unchecked((int) 0xF6E96C9A), unchecked((int) 0x670C9C61), unchecked((int) 0xABD388F0),
+ unchecked((int) 0x6A51A0D2), unchecked((int) 0xD8542F68), unchecked((int) 0x960FA728), unchecked((int) 0xAB5133A3),
+ unchecked((int) 0x6EEF0B6C), unchecked((int) 0x137A3BE4), unchecked((int) 0xBA3BF050), unchecked((int) 0x7EFB2A98),
+ unchecked((int) 0xA1F1651D), unchecked((int) 0x39AF0176), unchecked((int) 0x66CA593E), unchecked((int) 0x82430E88),
+ unchecked((int) 0x8CEE8619), unchecked((int) 0x456F9FB4), unchecked((int) 0x7D84A5C3), unchecked((int) 0x3B8B5EBE),
+ unchecked((int) 0xE06F75D8), unchecked((int) 0x85C12073), unchecked((int) 0x401A449F), unchecked((int) 0x56C16AA6),
+ unchecked((int) 0x4ED3AA62), unchecked((int) 0x363F7706), unchecked((int) 0x1BFEDF72), unchecked((int) 0x429B023D),
+ unchecked((int) 0x37D0D724), unchecked((int) 0xD00A1248), unchecked((int) 0xDB0FEAD3), unchecked((int) 0x49F1C09B),
+ unchecked((int) 0x075372C9), unchecked((int) 0x80991B7B), unchecked((int) 0x25D479D8), unchecked((int) 0xF6E8DEF7),
+ unchecked((int) 0xE3FE501A), unchecked((int) 0xB6794C3B), unchecked((int) 0x976CE0BD), unchecked((int) 0x04C006BA),
+ unchecked((int) 0xC1A94FB6), unchecked((int) 0x409F60C4), unchecked((int) 0x5E5C9EC2), unchecked((int) 0x196A2463),
+ unchecked((int) 0x68FB6FAF), unchecked((int) 0x3E6C53B5), unchecked((int) 0x1339B2EB), unchecked((int) 0x3B52EC6F),
+ unchecked((int) 0x6DFC511F), unchecked((int) 0x9B30952C), unchecked((int) 0xCC814544), unchecked((int) 0xAF5EBD09),
+ unchecked((int) 0xBEE3D004), unchecked((int) 0xDE334AFD), unchecked((int) 0x660F2807), unchecked((int) 0x192E4BB3),
+ unchecked((int) 0xC0CBA857), unchecked((int) 0x45C8740F), unchecked((int) 0xD20B5F39), unchecked((int) 0xB9D3FBDB),
+ unchecked((int) 0x5579C0BD), unchecked((int) 0x1A60320A), unchecked((int) 0xD6A100C6), unchecked((int) 0x402C7279),
+ unchecked((int) 0x679F25FE), unchecked((int) 0xFB1FA3CC), unchecked((int) 0x8EA5E9F8), unchecked((int) 0xDB3222F8),
+ unchecked((int) 0x3C7516DF), unchecked((int) 0xFD616B15), unchecked((int) 0x2F501EC8), unchecked((int) 0xAD0552AB),
+ unchecked((int) 0x323DB5FA), unchecked((int) 0xFD238760), unchecked((int) 0x53317B48), unchecked((int) 0x3E00DF82),
+ unchecked((int) 0x9E5C57BB), unchecked((int) 0xCA6F8CA0), unchecked((int) 0x1A87562E), unchecked((int) 0xDF1769DB),
+ unchecked((int) 0xD542A8F6), unchecked((int) 0x287EFFC3), unchecked((int) 0xAC6732C6), unchecked((int) 0x8C4F5573),
+ unchecked((int) 0x695B27B0), unchecked((int) 0xBBCA58C8), unchecked((int) 0xE1FFA35D), unchecked((int) 0xB8F011A0),
+ unchecked((int) 0x10FA3D98), unchecked((int) 0xFD2183B8), unchecked((int) 0x4AFCB56C), unchecked((int) 0x2DD1D35B),
+ unchecked((int) 0x9A53E479), unchecked((int) 0xB6F84565), unchecked((int) 0xD28E49BC), unchecked((int) 0x4BFB9790),
+ unchecked((int) 0xE1DDF2DA), unchecked((int) 0xA4CB7E33), unchecked((int) 0x62FB1341), unchecked((int) 0xCEE4C6E8),
+ unchecked((int) 0xEF20CADA), unchecked((int) 0x36774C01), unchecked((int) 0xD07E9EFE), unchecked((int) 0x2BF11FB4),
+ unchecked((int) 0x95DBDA4D), unchecked((int) 0xAE909198), unchecked((int) 0xEAAD8E71), unchecked((int) 0x6B93D5A0),
+ unchecked((int) 0xD08ED1D0), unchecked((int) 0xAFC725E0), unchecked((int) 0x8E3C5B2F), unchecked((int) 0x8E7594B7),
+ unchecked((int) 0x8FF6E2FB), unchecked((int) 0xF2122B64), unchecked((int) 0x8888B812), unchecked((int) 0x900DF01C),
+ unchecked((int) 0x4FAD5EA0), unchecked((int) 0x688FC31C), unchecked((int) 0xD1CFF191), unchecked((int) 0xB3A8C1AD),
+ unchecked((int) 0x2F2F2218), unchecked((int) 0xBE0E1777), unchecked((int) 0xEA752DFE), unchecked((int) 0x8B021FA1),
+ unchecked((int) 0xE5A0CC0F), unchecked((int) 0xB56F74E8), unchecked((int) 0x18ACF3D6), unchecked((int) 0xCE89E299),
+ unchecked((int) 0xB4A84FE0), unchecked((int) 0xFD13E0B7), unchecked((int) 0x7CC43B81), unchecked((int) 0xD2ADA8D9),
+ unchecked((int) 0x165FA266), unchecked((int) 0x80957705), unchecked((int) 0x93CC7314), unchecked((int) 0x211A1477),
+ unchecked((int) 0xE6AD2065), unchecked((int) 0x77B5FA86), unchecked((int) 0xC75442F5), unchecked((int) 0xFB9D35CF),
+ unchecked((int) 0xEBCDAF0C), unchecked((int) 0x7B3E89A0), unchecked((int) 0xD6411BD3), unchecked((int) 0xAE1E7E49),
+ unchecked((int) 0x00250E2D), unchecked((int) 0x2071B35E), unchecked((int) 0x226800BB), unchecked((int) 0x57B8E0AF),
+ unchecked((int) 0x2464369B), unchecked((int) 0xF009B91E), unchecked((int) 0x5563911D), unchecked((int) 0x59DFA6AA),
+ unchecked((int) 0x78C14389), unchecked((int) 0xD95A537F), unchecked((int) 0x207D5BA2), unchecked((int) 0x02E5B9C5),
+ unchecked((int) 0x83260376), unchecked((int) 0x6295CFA9), unchecked((int) 0x11C81968), unchecked((int) 0x4E734A41),
+ unchecked((int) 0xB3472DCA), unchecked((int) 0x7B14A94A), unchecked((int) 0x1B510052), unchecked((int) 0x9A532915),
+ unchecked((int) 0xD60F573F), unchecked((int) 0xBC9BC6E4), unchecked((int) 0x2B60A476), unchecked((int) 0x81E67400),
+ unchecked((int) 0x08BA6FB5), unchecked((int) 0x571BE91F), unchecked((int) 0xF296EC6B), unchecked((int) 0x2A0DD915),
+ unchecked((int) 0xB6636521), unchecked((int) 0xE7B9F9B6), unchecked((int) 0xFF34052E), unchecked((int) 0xC5855664),
+ unchecked((int) 0x53B02D5D), unchecked((int) 0xA99F8FA1), unchecked((int) 0x08BA4799), unchecked((int) 0x6E85076A)
+ },
+
+ KS1 = {
+ unchecked((int) 0x4B7A70E9), unchecked((int) 0xB5B32944), unchecked((int) 0xDB75092E), unchecked((int) 0xC4192623),
+ unchecked((int) 0xAD6EA6B0), unchecked((int) 0x49A7DF7D), unchecked((int) 0x9CEE60B8), unchecked((int) 0x8FEDB266),
+ unchecked((int) 0xECAA8C71), unchecked((int) 0x699A17FF), unchecked((int) 0x5664526C), unchecked((int) 0xC2B19EE1),
+ unchecked((int) 0x193602A5), unchecked((int) 0x75094C29), unchecked((int) 0xA0591340), unchecked((int) 0xE4183A3E),
+ unchecked((int) 0x3F54989A), unchecked((int) 0x5B429D65), unchecked((int) 0x6B8FE4D6), unchecked((int) 0x99F73FD6),
+ unchecked((int) 0xA1D29C07), unchecked((int) 0xEFE830F5), unchecked((int) 0x4D2D38E6), unchecked((int) 0xF0255DC1),
+ unchecked((int) 0x4CDD2086), unchecked((int) 0x8470EB26), unchecked((int) 0x6382E9C6), unchecked((int) 0x021ECC5E),
+ unchecked((int) 0x09686B3F), unchecked((int) 0x3EBAEFC9), unchecked((int) 0x3C971814), unchecked((int) 0x6B6A70A1),
+ unchecked((int) 0x687F3584), unchecked((int) 0x52A0E286), unchecked((int) 0xB79C5305), unchecked((int) 0xAA500737),
+ unchecked((int) 0x3E07841C), unchecked((int) 0x7FDEAE5C), unchecked((int) 0x8E7D44EC), unchecked((int) 0x5716F2B8),
+ unchecked((int) 0xB03ADA37), unchecked((int) 0xF0500C0D), unchecked((int) 0xF01C1F04), unchecked((int) 0x0200B3FF),
+ unchecked((int) 0xAE0CF51A), unchecked((int) 0x3CB574B2), unchecked((int) 0x25837A58), unchecked((int) 0xDC0921BD),
+ unchecked((int) 0xD19113F9), unchecked((int) 0x7CA92FF6), unchecked((int) 0x94324773), unchecked((int) 0x22F54701),
+ unchecked((int) 0x3AE5E581), unchecked((int) 0x37C2DADC), unchecked((int) 0xC8B57634), unchecked((int) 0x9AF3DDA7),
+ unchecked((int) 0xA9446146), unchecked((int) 0x0FD0030E), unchecked((int) 0xECC8C73E), unchecked((int) 0xA4751E41),
+ unchecked((int) 0xE238CD99), unchecked((int) 0x3BEA0E2F), unchecked((int) 0x3280BBA1), unchecked((int) 0x183EB331),
+ unchecked((int) 0x4E548B38), unchecked((int) 0x4F6DB908), unchecked((int) 0x6F420D03), unchecked((int) 0xF60A04BF),
+ unchecked((int) 0x2CB81290), unchecked((int) 0x24977C79), unchecked((int) 0x5679B072), unchecked((int) 0xBCAF89AF),
+ unchecked((int) 0xDE9A771F), unchecked((int) 0xD9930810), unchecked((int) 0xB38BAE12), unchecked((int) 0xDCCF3F2E),
+ unchecked((int) 0x5512721F), unchecked((int) 0x2E6B7124), unchecked((int) 0x501ADDE6), unchecked((int) 0x9F84CD87),
+ unchecked((int) 0x7A584718), unchecked((int) 0x7408DA17), unchecked((int) 0xBC9F9ABC), unchecked((int) 0xE94B7D8C),
+ unchecked((int) 0xEC7AEC3A), unchecked((int) 0xDB851DFA), unchecked((int) 0x63094366), unchecked((int) 0xC464C3D2),
+ unchecked((int) 0xEF1C1847), unchecked((int) 0x3215D908), unchecked((int) 0xDD433B37), unchecked((int) 0x24C2BA16),
+ unchecked((int) 0x12A14D43), unchecked((int) 0x2A65C451), unchecked((int) 0x50940002), unchecked((int) 0x133AE4DD),
+ unchecked((int) 0x71DFF89E), unchecked((int) 0x10314E55), unchecked((int) 0x81AC77D6), unchecked((int) 0x5F11199B),
+ unchecked((int) 0x043556F1), unchecked((int) 0xD7A3C76B), unchecked((int) 0x3C11183B), unchecked((int) 0x5924A509),
+ unchecked((int) 0xF28FE6ED), unchecked((int) 0x97F1FBFA), unchecked((int) 0x9EBABF2C), unchecked((int) 0x1E153C6E),
+ unchecked((int) 0x86E34570), unchecked((int) 0xEAE96FB1), unchecked((int) 0x860E5E0A), unchecked((int) 0x5A3E2AB3),
+ unchecked((int) 0x771FE71C), unchecked((int) 0x4E3D06FA), unchecked((int) 0x2965DCB9), unchecked((int) 0x99E71D0F),
+ unchecked((int) 0x803E89D6), unchecked((int) 0x5266C825), unchecked((int) 0x2E4CC978), unchecked((int) 0x9C10B36A),
+ unchecked((int) 0xC6150EBA), unchecked((int) 0x94E2EA78), unchecked((int) 0xA5FC3C53), unchecked((int) 0x1E0A2DF4),
+ unchecked((int) 0xF2F74EA7), unchecked((int) 0x361D2B3D), unchecked((int) 0x1939260F), unchecked((int) 0x19C27960),
+ unchecked((int) 0x5223A708), unchecked((int) 0xF71312B6), unchecked((int) 0xEBADFE6E), unchecked((int) 0xEAC31F66),
+ unchecked((int) 0xE3BC4595), unchecked((int) 0xA67BC883), unchecked((int) 0xB17F37D1), unchecked((int) 0x018CFF28),
+ unchecked((int) 0xC332DDEF), unchecked((int) 0xBE6C5AA5), unchecked((int) 0x65582185), unchecked((int) 0x68AB9802),
+ unchecked((int) 0xEECEA50F), unchecked((int) 0xDB2F953B), unchecked((int) 0x2AEF7DAD), unchecked((int) 0x5B6E2F84),
+ unchecked((int) 0x1521B628), unchecked((int) 0x29076170), unchecked((int) 0xECDD4775), unchecked((int) 0x619F1510),
+ unchecked((int) 0x13CCA830), unchecked((int) 0xEB61BD96), unchecked((int) 0x0334FE1E), unchecked((int) 0xAA0363CF),
+ unchecked((int) 0xB5735C90), unchecked((int) 0x4C70A239), unchecked((int) 0xD59E9E0B), unchecked((int) 0xCBAADE14),
+ unchecked((int) 0xEECC86BC), unchecked((int) 0x60622CA7), unchecked((int) 0x9CAB5CAB), unchecked((int) 0xB2F3846E),
+ unchecked((int) 0x648B1EAF), unchecked((int) 0x19BDF0CA), unchecked((int) 0xA02369B9), unchecked((int) 0x655ABB50),
+ unchecked((int) 0x40685A32), unchecked((int) 0x3C2AB4B3), unchecked((int) 0x319EE9D5), unchecked((int) 0xC021B8F7),
+ unchecked((int) 0x9B540B19), unchecked((int) 0x875FA099), unchecked((int) 0x95F7997E), unchecked((int) 0x623D7DA8),
+ unchecked((int) 0xF837889A), unchecked((int) 0x97E32D77), unchecked((int) 0x11ED935F), unchecked((int) 0x16681281),
+ unchecked((int) 0x0E358829), unchecked((int) 0xC7E61FD6), unchecked((int) 0x96DEDFA1), unchecked((int) 0x7858BA99),
+ unchecked((int) 0x57F584A5), unchecked((int) 0x1B227263), unchecked((int) 0x9B83C3FF), unchecked((int) 0x1AC24696),
+ unchecked((int) 0xCDB30AEB), unchecked((int) 0x532E3054), unchecked((int) 0x8FD948E4), unchecked((int) 0x6DBC3128),
+ unchecked((int) 0x58EBF2EF), unchecked((int) 0x34C6FFEA), unchecked((int) 0xFE28ED61), unchecked((int) 0xEE7C3C73),
+ unchecked((int) 0x5D4A14D9), unchecked((int) 0xE864B7E3), unchecked((int) 0x42105D14), unchecked((int) 0x203E13E0),
+ unchecked((int) 0x45EEE2B6), unchecked((int) 0xA3AAABEA), unchecked((int) 0xDB6C4F15), unchecked((int) 0xFACB4FD0),
+ unchecked((int) 0xC742F442), unchecked((int) 0xEF6ABBB5), unchecked((int) 0x654F3B1D), unchecked((int) 0x41CD2105),
+ unchecked((int) 0xD81E799E), unchecked((int) 0x86854DC7), unchecked((int) 0xE44B476A), unchecked((int) 0x3D816250),
+ unchecked((int) 0xCF62A1F2), unchecked((int) 0x5B8D2646), unchecked((int) 0xFC8883A0), unchecked((int) 0xC1C7B6A3),
+ unchecked((int) 0x7F1524C3), unchecked((int) 0x69CB7492), unchecked((int) 0x47848A0B), unchecked((int) 0x5692B285),
+ unchecked((int) 0x095BBF00), unchecked((int) 0xAD19489D), unchecked((int) 0x1462B174), unchecked((int) 0x23820E00),
+ unchecked((int) 0x58428D2A), unchecked((int) 0x0C55F5EA), unchecked((int) 0x1DADF43E), unchecked((int) 0x233F7061),
+ unchecked((int) 0x3372F092), unchecked((int) 0x8D937E41), unchecked((int) 0xD65FECF1), unchecked((int) 0x6C223BDB),
+ unchecked((int) 0x7CDE3759), unchecked((int) 0xCBEE7460), unchecked((int) 0x4085F2A7), unchecked((int) 0xCE77326E),
+ unchecked((int) 0xA6078084), unchecked((int) 0x19F8509E), unchecked((int) 0xE8EFD855), unchecked((int) 0x61D99735),
+ unchecked((int) 0xA969A7AA), unchecked((int) 0xC50C06C2), unchecked((int) 0x5A04ABFC), unchecked((int) 0x800BCADC),
+ unchecked((int) 0x9E447A2E), unchecked((int) 0xC3453484), unchecked((int) 0xFDD56705), unchecked((int) 0x0E1E9EC9),
+ unchecked((int) 0xDB73DBD3), unchecked((int) 0x105588CD), unchecked((int) 0x675FDA79), unchecked((int) 0xE3674340),
+ unchecked((int) 0xC5C43465), unchecked((int) 0x713E38D8), unchecked((int) 0x3D28F89E), unchecked((int) 0xF16DFF20),
+ unchecked((int) 0x153E21E7), unchecked((int) 0x8FB03D4A), unchecked((int) 0xE6E39F2B), unchecked((int) 0xDB83ADF7)
+ },
+
+ KS2 = {
+ unchecked((int) 0xE93D5A68), unchecked((int) 0x948140F7), unchecked((int) 0xF64C261C), unchecked((int) 0x94692934),
+ unchecked((int) 0x411520F7), unchecked((int) 0x7602D4F7), unchecked((int) 0xBCF46B2E), unchecked((int) 0xD4A20068),
+ unchecked((int) 0xD4082471), unchecked((int) 0x3320F46A), unchecked((int) 0x43B7D4B7), unchecked((int) 0x500061AF),
+ unchecked((int) 0x1E39F62E), unchecked((int) 0x97244546), unchecked((int) 0x14214F74), unchecked((int) 0xBF8B8840),
+ unchecked((int) 0x4D95FC1D), unchecked((int) 0x96B591AF), unchecked((int) 0x70F4DDD3), unchecked((int) 0x66A02F45),
+ unchecked((int) 0xBFBC09EC), unchecked((int) 0x03BD9785), unchecked((int) 0x7FAC6DD0), unchecked((int) 0x31CB8504),
+ unchecked((int) 0x96EB27B3), unchecked((int) 0x55FD3941), unchecked((int) 0xDA2547E6), unchecked((int) 0xABCA0A9A),
+ unchecked((int) 0x28507825), unchecked((int) 0x530429F4), unchecked((int) 0x0A2C86DA), unchecked((int) 0xE9B66DFB),
+ unchecked((int) 0x68DC1462), unchecked((int) 0xD7486900), unchecked((int) 0x680EC0A4), unchecked((int) 0x27A18DEE),
+ unchecked((int) 0x4F3FFEA2), unchecked((int) 0xE887AD8C), unchecked((int) 0xB58CE006), unchecked((int) 0x7AF4D6B6),
+ unchecked((int) 0xAACE1E7C), unchecked((int) 0xD3375FEC), unchecked((int) 0xCE78A399), unchecked((int) 0x406B2A42),
+ unchecked((int) 0x20FE9E35), unchecked((int) 0xD9F385B9), unchecked((int) 0xEE39D7AB), unchecked((int) 0x3B124E8B),
+ unchecked((int) 0x1DC9FAF7), unchecked((int) 0x4B6D1856), unchecked((int) 0x26A36631), unchecked((int) 0xEAE397B2),
+ unchecked((int) 0x3A6EFA74), unchecked((int) 0xDD5B4332), unchecked((int) 0x6841E7F7), unchecked((int) 0xCA7820FB),
+ unchecked((int) 0xFB0AF54E), unchecked((int) 0xD8FEB397), unchecked((int) 0x454056AC), unchecked((int) 0xBA489527),
+ unchecked((int) 0x55533A3A), unchecked((int) 0x20838D87), unchecked((int) 0xFE6BA9B7), unchecked((int) 0xD096954B),
+ unchecked((int) 0x55A867BC), unchecked((int) 0xA1159A58), unchecked((int) 0xCCA92963), unchecked((int) 0x99E1DB33),
+ unchecked((int) 0xA62A4A56), unchecked((int) 0x3F3125F9), unchecked((int) 0x5EF47E1C), unchecked((int) 0x9029317C),
+ unchecked((int) 0xFDF8E802), unchecked((int) 0x04272F70), unchecked((int) 0x80BB155C), unchecked((int) 0x05282CE3),
+ unchecked((int) 0x95C11548), unchecked((int) 0xE4C66D22), unchecked((int) 0x48C1133F), unchecked((int) 0xC70F86DC),
+ unchecked((int) 0x07F9C9EE), unchecked((int) 0x41041F0F), unchecked((int) 0x404779A4), unchecked((int) 0x5D886E17),
+ unchecked((int) 0x325F51EB), unchecked((int) 0xD59BC0D1), unchecked((int) 0xF2BCC18F), unchecked((int) 0x41113564),
+ unchecked((int) 0x257B7834), unchecked((int) 0x602A9C60), unchecked((int) 0xDFF8E8A3), unchecked((int) 0x1F636C1B),
+ unchecked((int) 0x0E12B4C2), unchecked((int) 0x02E1329E), unchecked((int) 0xAF664FD1), unchecked((int) 0xCAD18115),
+ unchecked((int) 0x6B2395E0), unchecked((int) 0x333E92E1), unchecked((int) 0x3B240B62), unchecked((int) 0xEEBEB922),
+ unchecked((int) 0x85B2A20E), unchecked((int) 0xE6BA0D99), unchecked((int) 0xDE720C8C), unchecked((int) 0x2DA2F728),
+ unchecked((int) 0xD0127845), unchecked((int) 0x95B794FD), unchecked((int) 0x647D0862), unchecked((int) 0xE7CCF5F0),
+ unchecked((int) 0x5449A36F), unchecked((int) 0x877D48FA), unchecked((int) 0xC39DFD27), unchecked((int) 0xF33E8D1E),
+ unchecked((int) 0x0A476341), unchecked((int) 0x992EFF74), unchecked((int) 0x3A6F6EAB), unchecked((int) 0xF4F8FD37),
+ unchecked((int) 0xA812DC60), unchecked((int) 0xA1EBDDF8), unchecked((int) 0x991BE14C), unchecked((int) 0xDB6E6B0D),
+ unchecked((int) 0xC67B5510), unchecked((int) 0x6D672C37), unchecked((int) 0x2765D43B), unchecked((int) 0xDCD0E804),
+ unchecked((int) 0xF1290DC7), unchecked((int) 0xCC00FFA3), unchecked((int) 0xB5390F92), unchecked((int) 0x690FED0B),
+ unchecked((int) 0x667B9FFB), unchecked((int) 0xCEDB7D9C), unchecked((int) 0xA091CF0B), unchecked((int) 0xD9155EA3),
+ unchecked((int) 0xBB132F88), unchecked((int) 0x515BAD24), unchecked((int) 0x7B9479BF), unchecked((int) 0x763BD6EB),
+ unchecked((int) 0x37392EB3), unchecked((int) 0xCC115979), unchecked((int) 0x8026E297), unchecked((int) 0xF42E312D),
+ unchecked((int) 0x6842ADA7), unchecked((int) 0xC66A2B3B), unchecked((int) 0x12754CCC), unchecked((int) 0x782EF11C),
+ unchecked((int) 0x6A124237), unchecked((int) 0xB79251E7), unchecked((int) 0x06A1BBE6), unchecked((int) 0x4BFB6350),
+ unchecked((int) 0x1A6B1018), unchecked((int) 0x11CAEDFA), unchecked((int) 0x3D25BDD8), unchecked((int) 0xE2E1C3C9),
+ unchecked((int) 0x44421659), unchecked((int) 0x0A121386), unchecked((int) 0xD90CEC6E), unchecked((int) 0xD5ABEA2A),
+ unchecked((int) 0x64AF674E), unchecked((int) 0xDA86A85F), unchecked((int) 0xBEBFE988), unchecked((int) 0x64E4C3FE),
+ unchecked((int) 0x9DBC8057), unchecked((int) 0xF0F7C086), unchecked((int) 0x60787BF8), unchecked((int) 0x6003604D),
+ unchecked((int) 0xD1FD8346), unchecked((int) 0xF6381FB0), unchecked((int) 0x7745AE04), unchecked((int) 0xD736FCCC),
+ unchecked((int) 0x83426B33), unchecked((int) 0xF01EAB71), unchecked((int) 0xB0804187), unchecked((int) 0x3C005E5F),
+ unchecked((int) 0x77A057BE), unchecked((int) 0xBDE8AE24), unchecked((int) 0x55464299), unchecked((int) 0xBF582E61),
+ unchecked((int) 0x4E58F48F), unchecked((int) 0xF2DDFDA2), unchecked((int) 0xF474EF38), unchecked((int) 0x8789BDC2),
+ unchecked((int) 0x5366F9C3), unchecked((int) 0xC8B38E74), unchecked((int) 0xB475F255), unchecked((int) 0x46FCD9B9),
+ unchecked((int) 0x7AEB2661), unchecked((int) 0x8B1DDF84), unchecked((int) 0x846A0E79), unchecked((int) 0x915F95E2),
+ unchecked((int) 0x466E598E), unchecked((int) 0x20B45770), unchecked((int) 0x8CD55591), unchecked((int) 0xC902DE4C),
+ unchecked((int) 0xB90BACE1), unchecked((int) 0xBB8205D0), unchecked((int) 0x11A86248), unchecked((int) 0x7574A99E),
+ unchecked((int) 0xB77F19B6), unchecked((int) 0xE0A9DC09), unchecked((int) 0x662D09A1), unchecked((int) 0xC4324633),
+ unchecked((int) 0xE85A1F02), unchecked((int) 0x09F0BE8C), unchecked((int) 0x4A99A025), unchecked((int) 0x1D6EFE10),
+ unchecked((int) 0x1AB93D1D), unchecked((int) 0x0BA5A4DF), unchecked((int) 0xA186F20F), unchecked((int) 0x2868F169),
+ unchecked((int) 0xDCB7DA83), unchecked((int) 0x573906FE), unchecked((int) 0xA1E2CE9B), unchecked((int) 0x4FCD7F52),
+ unchecked((int) 0x50115E01), unchecked((int) 0xA70683FA), unchecked((int) 0xA002B5C4), unchecked((int) 0x0DE6D027),
+ unchecked((int) 0x9AF88C27), unchecked((int) 0x773F8641), unchecked((int) 0xC3604C06), unchecked((int) 0x61A806B5),
+ unchecked((int) 0xF0177A28), unchecked((int) 0xC0F586E0), unchecked((int) 0x006058AA), unchecked((int) 0x30DC7D62),
+ unchecked((int) 0x11E69ED7), unchecked((int) 0x2338EA63), unchecked((int) 0x53C2DD94), unchecked((int) 0xC2C21634),
+ unchecked((int) 0xBBCBEE56), unchecked((int) 0x90BCB6DE), unchecked((int) 0xEBFC7DA1), unchecked((int) 0xCE591D76),
+ unchecked((int) 0x6F05E409), unchecked((int) 0x4B7C0188), unchecked((int) 0x39720A3D), unchecked((int) 0x7C927C24),
+ unchecked((int) 0x86E3725F), unchecked((int) 0x724D9DB9), unchecked((int) 0x1AC15BB4), unchecked((int) 0xD39EB8FC),
+ unchecked((int) 0xED545578), unchecked((int) 0x08FCA5B5), unchecked((int) 0xD83D7CD3), unchecked((int) 0x4DAD0FC4),
+ unchecked((int) 0x1E50EF5E), unchecked((int) 0xB161E6F8), unchecked((int) 0xA28514D9), unchecked((int) 0x6C51133C),
+ unchecked((int) 0x6FD5C7E7), unchecked((int) 0x56E14EC4), unchecked((int) 0x362ABFCE), unchecked((int) 0xDDC6C837),
+ unchecked((int) 0xD79A3234), unchecked((int) 0x92638212), unchecked((int) 0x670EFA8E), unchecked((int) 0x406000E0)
+ },
+
+ KS3 = {
+ unchecked((int) 0x3A39CE37), unchecked((int) 0xD3FAF5CF), unchecked((int) 0xABC27737), unchecked((int) 0x5AC52D1B),
+ unchecked((int) 0x5CB0679E), unchecked((int) 0x4FA33742), unchecked((int) 0xD3822740), unchecked((int) 0x99BC9BBE),
+ unchecked((int) 0xD5118E9D), unchecked((int) 0xBF0F7315), unchecked((int) 0xD62D1C7E), unchecked((int) 0xC700C47B),
+ unchecked((int) 0xB78C1B6B), unchecked((int) 0x21A19045), unchecked((int) 0xB26EB1BE), unchecked((int) 0x6A366EB4),
+ unchecked((int) 0x5748AB2F), unchecked((int) 0xBC946E79), unchecked((int) 0xC6A376D2), unchecked((int) 0x6549C2C8),
+ unchecked((int) 0x530FF8EE), unchecked((int) 0x468DDE7D), unchecked((int) 0xD5730A1D), unchecked((int) 0x4CD04DC6),
+ unchecked((int) 0x2939BBDB), unchecked((int) 0xA9BA4650), unchecked((int) 0xAC9526E8), unchecked((int) 0xBE5EE304),
+ unchecked((int) 0xA1FAD5F0), unchecked((int) 0x6A2D519A), unchecked((int) 0x63EF8CE2), unchecked((int) 0x9A86EE22),
+ unchecked((int) 0xC089C2B8), unchecked((int) 0x43242EF6), unchecked((int) 0xA51E03AA), unchecked((int) 0x9CF2D0A4),
+ unchecked((int) 0x83C061BA), unchecked((int) 0x9BE96A4D), unchecked((int) 0x8FE51550), unchecked((int) 0xBA645BD6),
+ unchecked((int) 0x2826A2F9), unchecked((int) 0xA73A3AE1), unchecked((int) 0x4BA99586), unchecked((int) 0xEF5562E9),
+ unchecked((int) 0xC72FEFD3), unchecked((int) 0xF752F7DA), unchecked((int) 0x3F046F69), unchecked((int) 0x77FA0A59),
+ unchecked((int) 0x80E4A915), unchecked((int) 0x87B08601), unchecked((int) 0x9B09E6AD), unchecked((int) 0x3B3EE593),
+ unchecked((int) 0xE990FD5A), unchecked((int) 0x9E34D797), unchecked((int) 0x2CF0B7D9), unchecked((int) 0x022B8B51),
+ unchecked((int) 0x96D5AC3A), unchecked((int) 0x017DA67D), unchecked((int) 0xD1CF3ED6), unchecked((int) 0x7C7D2D28),
+ unchecked((int) 0x1F9F25CF), unchecked((int) 0xADF2B89B), unchecked((int) 0x5AD6B472), unchecked((int) 0x5A88F54C),
+ unchecked((int) 0xE029AC71), unchecked((int) 0xE019A5E6), unchecked((int) 0x47B0ACFD), unchecked((int) 0xED93FA9B),
+ unchecked((int) 0xE8D3C48D), unchecked((int) 0x283B57CC), unchecked((int) 0xF8D56629), unchecked((int) 0x79132E28),
+ unchecked((int) 0x785F0191), unchecked((int) 0xED756055), unchecked((int) 0xF7960E44), unchecked((int) 0xE3D35E8C),
+ unchecked((int) 0x15056DD4), unchecked((int) 0x88F46DBA), unchecked((int) 0x03A16125), unchecked((int) 0x0564F0BD),
+ unchecked((int) 0xC3EB9E15), unchecked((int) 0x3C9057A2), unchecked((int) 0x97271AEC), unchecked((int) 0xA93A072A),
+ unchecked((int) 0x1B3F6D9B), unchecked((int) 0x1E6321F5), unchecked((int) 0xF59C66FB), unchecked((int) 0x26DCF319),
+ unchecked((int) 0x7533D928), unchecked((int) 0xB155FDF5), unchecked((int) 0x03563482), unchecked((int) 0x8ABA3CBB),
+ unchecked((int) 0x28517711), unchecked((int) 0xC20AD9F8), unchecked((int) 0xABCC5167), unchecked((int) 0xCCAD925F),
+ unchecked((int) 0x4DE81751), unchecked((int) 0x3830DC8E), unchecked((int) 0x379D5862), unchecked((int) 0x9320F991),
+ unchecked((int) 0xEA7A90C2), unchecked((int) 0xFB3E7BCE), unchecked((int) 0x5121CE64), unchecked((int) 0x774FBE32),
+ unchecked((int) 0xA8B6E37E), unchecked((int) 0xC3293D46), unchecked((int) 0x48DE5369), unchecked((int) 0x6413E680),
+ unchecked((int) 0xA2AE0810), unchecked((int) 0xDD6DB224), unchecked((int) 0x69852DFD), unchecked((int) 0x09072166),
+ unchecked((int) 0xB39A460A), unchecked((int) 0x6445C0DD), unchecked((int) 0x586CDECF), unchecked((int) 0x1C20C8AE),
+ unchecked((int) 0x5BBEF7DD), unchecked((int) 0x1B588D40), unchecked((int) 0xCCD2017F), unchecked((int) 0x6BB4E3BB),
+ unchecked((int) 0xDDA26A7E), unchecked((int) 0x3A59FF45), unchecked((int) 0x3E350A44), unchecked((int) 0xBCB4CDD5),
+ unchecked((int) 0x72EACEA8), unchecked((int) 0xFA6484BB), unchecked((int) 0x8D6612AE), unchecked((int) 0xBF3C6F47),
+ unchecked((int) 0xD29BE463), unchecked((int) 0x542F5D9E), unchecked((int) 0xAEC2771B), unchecked((int) 0xF64E6370),
+ unchecked((int) 0x740E0D8D), unchecked((int) 0xE75B1357), unchecked((int) 0xF8721671), unchecked((int) 0xAF537D5D),
+ unchecked((int) 0x4040CB08), unchecked((int) 0x4EB4E2CC), unchecked((int) 0x34D2466A), unchecked((int) 0x0115AF84),
+ unchecked((int) 0xE1B00428), unchecked((int) 0x95983A1D), unchecked((int) 0x06B89FB4), unchecked((int) 0xCE6EA048),
+ unchecked((int) 0x6F3F3B82), unchecked((int) 0x3520AB82), unchecked((int) 0x011A1D4B), unchecked((int) 0x277227F8),
+ unchecked((int) 0x611560B1), unchecked((int) 0xE7933FDC), unchecked((int) 0xBB3A792B), unchecked((int) 0x344525BD),
+ unchecked((int) 0xA08839E1), unchecked((int) 0x51CE794B), unchecked((int) 0x2F32C9B7), unchecked((int) 0xA01FBAC9),
+ unchecked((int) 0xE01CC87E), unchecked((int) 0xBCC7D1F6), unchecked((int) 0xCF0111C3), unchecked((int) 0xA1E8AAC7),
+ unchecked((int) 0x1A908749), unchecked((int) 0xD44FBD9A), unchecked((int) 0xD0DADECB), unchecked((int) 0xD50ADA38),
+ unchecked((int) 0x0339C32A), unchecked((int) 0xC6913667), unchecked((int) 0x8DF9317C), unchecked((int) 0xE0B12B4F),
+ unchecked((int) 0xF79E59B7), unchecked((int) 0x43F5BB3A), unchecked((int) 0xF2D519FF), unchecked((int) 0x27D9459C),
+ unchecked((int) 0xBF97222C), unchecked((int) 0x15E6FC2A), unchecked((int) 0x0F91FC71), unchecked((int) 0x9B941525),
+ unchecked((int) 0xFAE59361), unchecked((int) 0xCEB69CEB), unchecked((int) 0xC2A86459), unchecked((int) 0x12BAA8D1),
+ unchecked((int) 0xB6C1075E), unchecked((int) 0xE3056A0C), unchecked((int) 0x10D25065), unchecked((int) 0xCB03A442),
+ unchecked((int) 0xE0EC6E0E), unchecked((int) 0x1698DB3B), unchecked((int) 0x4C98A0BE), unchecked((int) 0x3278E964),
+ unchecked((int) 0x9F1F9532), unchecked((int) 0xE0D392DF), unchecked((int) 0xD3A0342B), unchecked((int) 0x8971F21E),
+ unchecked((int) 0x1B0A7441), unchecked((int) 0x4BA3348C), unchecked((int) 0xC5BE7120), unchecked((int) 0xC37632D8),
+ unchecked((int) 0xDF359F8D), unchecked((int) 0x9B992F2E), unchecked((int) 0xE60B6F47), unchecked((int) 0x0FE3F11D),
+ unchecked((int) 0xE54CDA54), unchecked((int) 0x1EDAD891), unchecked((int) 0xCE6279CF), unchecked((int) 0xCD3E7E6F),
+ unchecked((int) 0x1618B166), unchecked((int) 0xFD2C1D05), unchecked((int) 0x848FD2C5), unchecked((int) 0xF6FB2299),
+ unchecked((int) 0xF523F357), unchecked((int) 0xA6327623), unchecked((int) 0x93A83531), unchecked((int) 0x56CCCD02),
+ unchecked((int) 0xACF08162), unchecked((int) 0x5A75EBB5), unchecked((int) 0x6E163697), unchecked((int) 0x88D273CC),
+ unchecked((int) 0xDE966292), unchecked((int) 0x81B949D0), unchecked((int) 0x4C50901B), unchecked((int) 0x71C65614),
+ unchecked((int) 0xE6C6C7BD), unchecked((int) 0x327A140A), unchecked((int) 0x45E1D006), unchecked((int) 0xC3F27B9A),
+ unchecked((int) 0xC9AA53FD), unchecked((int) 0x62A80F00), unchecked((int) 0xBB25BFE2), unchecked((int) 0x35BDD2F6),
+ unchecked((int) 0x71126905), unchecked((int) 0xB2040222), unchecked((int) 0xB6CBCF7C), unchecked((int) 0xCD769C2B),
+ unchecked((int) 0x53113EC0), unchecked((int) 0x1640E3D3), unchecked((int) 0x38ABBD60), unchecked((int) 0x2547ADF0),
+ unchecked((int) 0xBA38209C), unchecked((int) 0xF746CE76), unchecked((int) 0x77AFA1C5), unchecked((int) 0x20756060),
+ unchecked((int) 0x85CBFE4E), unchecked((int) 0x8AE88DD8), unchecked((int) 0x7AAAF9B0), unchecked((int) 0x4CF9AA7E),
+ unchecked((int) 0x1948C25C), unchecked((int) 0x02FB8A8C), unchecked((int) 0x01C36AE4), unchecked((int) 0xD6EBE1F9),
+ unchecked((int) 0x90D4F869), unchecked((int) 0xA65CDEA0), unchecked((int) 0x3F09252D), unchecked((int) 0xC208E69F),
+ unchecked((int) 0xB74E6132), unchecked((int) 0xCE77E25B), unchecked((int) 0x578FDFE3), unchecked((int) 0x3AC372E6)
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private static readonly int ROUNDS = 16;
+ private const int BLOCK_SIZE = 8; // bytes = 64 bits
+ private static readonly int SBOX_SK = 256;
+ private static readonly int P_SZ = ROUNDS+2;
+
+ private readonly int[] S0, S1, S2, S3; // the s-boxes
+ private readonly int[] P; // the p-array
+
+ private bool encrypting;
+
+ private byte[] workingKey;
+
+ public BlowfishEngine()
+ {
+ S0 = new int[SBOX_SK];
+ S1 = new int[SBOX_SK];
+ S2 = new int[SBOX_SK];
+ S3 = new int[SBOX_SK];
+ P = new int[P_SZ];
+ }
+
+ /**
+ * initialise a Blowfish cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to Blowfish init - " + parameters.GetType().ToString());
+
+ this.encrypting = forEncryption;
+ this.workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(this.workingKey);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Blowfish"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new InvalidOperationException("Blowfish not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private int F(int x)
+ {
+ return (( (S0[((uint) x >> 24)] + S1[((uint) x >> 16) & 0xff])
+ ^ S2[((uint) x >> 8) & 0xff]) + S3[x & 0xff]);
+ }
+
+ /**
+ * apply the encryption cycle to each value pair in the table.
+ */
+ private void ProcessTable(
+ int xl,
+ int xr,
+ int[] table)
+ {
+ int size = table.Length;
+
+ for (int s = 0; s < size; s += 2)
+ {
+ xl ^= P[0];
+
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i + 1];
+ }
+
+ xr ^= P[ROUNDS + 1];
+
+ table[s] = xr;
+ table[s + 1] = xl;
+
+ xr = xl; // end of cycle swap
+ xl = table[s];
+ }
+ }
+
+ private void SetKey(byte[] key)
+ {
+ /*
+ * - comments are from _Applied Crypto_, Schneier, p338
+ * please be careful comparing the two, AC numbers the
+ * arrays from 1, the enclosed code from 0.
+ *
+ * (1)
+ * Initialise the S-boxes and the P-array, with a fixed string
+ * This string contains the hexadecimal digits of pi (3.141...)
+ */
+ Array.Copy(KS0, 0, S0, 0, SBOX_SK);
+ Array.Copy(KS1, 0, S1, 0, SBOX_SK);
+ Array.Copy(KS2, 0, S2, 0, SBOX_SK);
+ Array.Copy(KS3, 0, S3, 0, SBOX_SK);
+
+ Array.Copy(KP, 0, P, 0, P_SZ);
+
+ /*
+ * (2)
+ * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
+ * second 32-bits of the key, and so on for all bits of the key
+ * (up to P[17]). Repeatedly cycle through the key bits until the
+ * entire P-array has been XOR-ed with the key bits
+ */
+ int keyLength = key.Length;
+ int keyIndex = 0;
+
+ for (int i=0; i < P_SZ; i++)
+ {
+ // Get the 32 bits of the key, in 4 * 8 bit chunks
+ int data = unchecked((int) 0x0000000);
+ for (int j=0; j < 4; j++)
+ {
+ // create a 32 bit block
+ data = (data << 8) | (key[keyIndex++] & 0xff);
+
+ // wrap when we Get to the end of the key
+ if (keyIndex >= keyLength)
+ {
+ keyIndex = 0;
+ }
+ }
+ // XOR the newly created 32 bit chunk onto the P-array
+ P[i] ^= data;
+ }
+
+ /*
+ * (3)
+ * Encrypt the all-zero string with the Blowfish algorithm, using
+ * the subkeys described in (1) and (2)
+ *
+ * (4)
+ * Replace P1 and P2 with the output of step (3)
+ *
+ * (5)
+ * Encrypt the output of step(3) using the Blowfish algorithm,
+ * with the modified subkeys.
+ *
+ * (6)
+ * Replace P3 and P4 with the output of step (5)
+ *
+ * (7)
+ * Continue the process, replacing all elements of the P-array
+ * and then all four S-boxes in order, with the output of the
+ * continuously changing Blowfish algorithm
+ */
+
+ ProcessTable(0, 0, P);
+ ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0);
+ ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
+ ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
+ ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
+ }
+
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void EncryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int xl = BytesTo32bits(src, srcIndex);
+ int xr = BytesTo32bits(src, srcIndex+4);
+
+ xl ^= P[0];
+
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i + 1];
+ }
+
+ xr ^= P[ROUNDS + 1];
+
+ Bits32ToBytes(xr, dst, dstIndex);
+ Bits32ToBytes(xl, dst, dstIndex + 4);
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void DecryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int xl = BytesTo32bits(src, srcIndex);
+ int xr = BytesTo32bits(src, srcIndex + 4);
+
+ xl ^= P[ROUNDS + 1];
+
+ for (int i = ROUNDS; i > 0 ; i -= 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i - 1];
+ }
+
+ xr ^= P[0];
+
+ Bits32ToBytes(xr, dst, dstIndex);
+ Bits32ToBytes(xl, dst, dstIndex+4);
+ }
+
+ private int BytesTo32bits(byte[] b, int i)
+ {
+ return ((b[i] & 0xff) << 24) |
+ ((b[i+1] & 0xff) << 16) |
+ ((b[i+2] & 0xff) << 8) |
+ ((b[i+3] & 0xff));
+ }
+
+ private void Bits32ToBytes(int inData, byte[] b, int offset)
+ {
+ b[offset + 3] = (byte)inData;
+ b[offset + 2] = (byte)(inData >> 8);
+ b[offset + 1] = (byte)(inData >> 16);
+ b[offset] = (byte)(inData >> 24);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/CamelliaEngine.cs b/src/core/srcbc/crypto/engines/CamelliaEngine.cs
new file mode 100644
index 0000000..6135375
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/CamelliaEngine.cs
@@ -0,0 +1,579 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Camellia - based on RFC 3713.
+ */
+ public class CamelliaEngine
+ : IBlockCipher
+ {
+ private bool initialised;
+ private bool _keyIs128;
+
+ private const int BLOCK_SIZE = 16;
+
+ private const long MASK8 = 0xff;
+ private const long MASK32 = 0xffffffffL;
+
+ private const long SIGMA1 = unchecked((long) 0xA09E667F3BCC908BL);
+ private const long SIGMA2 = unchecked((long) 0xB67AE8584CAA73B2L);
+ private const long SIGMA3 = unchecked((long) 0xC6EF372FE94F82BEL);
+ private const long SIGMA4 = unchecked((long) 0x54FF53A5F1D36F1CL);
+ private const long SIGMA5 = unchecked((long) 0x10E527FADE682D1DL);
+ private const long SIGMA6 = unchecked((long) 0xB05688C2B3E6C1FDL);
+
+ private long _kw1, _kw2, _kw3, _kw4;
+ private long _k1, _k2, _k3, _k4, _k5, _k6, _k7, _k8, _k9, _k10, _k11, _k12,
+ _k13, _k14, _k15, _k16, _k17, _k18, _k19, _k20, _k21, _k22, _k23, _k24;
+ private long _ke1, _ke2, _ke3, _ke4, _ke5, _ke6;
+
+ private readonly byte[] SBOX1 = {
+ (byte)112, (byte)130, (byte)44, (byte)236, (byte)179 , (byte)39, (byte)192, (byte)229, (byte)228, (byte)133 , (byte)87 , (byte)53, (byte)234 , (byte)12, (byte)174 , (byte)65,
+ (byte)35, (byte)239, (byte)107, (byte)147 , (byte)69 , (byte)25, (byte)165 , (byte)33, (byte)237 , (byte)14 , (byte)79 , (byte)78 , (byte)29, (byte)101, (byte)146, (byte)189,
+ (byte)134, (byte)184, (byte)175, (byte)143, (byte)124, (byte)235 , (byte)31, (byte)206 , (byte)62 , (byte)48, (byte)220 , (byte)95 , (byte)94, (byte)197 , (byte)11 , (byte)26,
+ (byte)166, (byte)225, (byte)57, (byte)202, (byte)213 , (byte)71 , (byte)93 , (byte)61, (byte)217 , (byte)1 , (byte)90, (byte)214 , (byte)81 , (byte)86, (byte)108 , (byte)77,
+ (byte)139, (byte)13, (byte)154, (byte)102, (byte)251, (byte)204, (byte)176 , (byte)45, (byte)116 , (byte)18 , (byte)43 , (byte)32, (byte)240, (byte)177, (byte)132, (byte)153,
+ (byte)223, (byte)76, (byte)203, (byte)194 , (byte)52, (byte)126, (byte)118 , (byte)5, (byte)109, (byte)183, (byte)169 , (byte)49, (byte)209 , (byte)23 , (byte)4, (byte)215,
+ (byte)20, (byte)88, (byte)58, (byte)97, (byte)222 , (byte)27 , (byte)17 , (byte)28 , (byte)50 , (byte)15, (byte)156 , (byte)22 , (byte)83 , (byte)24, (byte)242 , (byte)34,
+ (byte)254, (byte)68, (byte)207, (byte)178, (byte)195, (byte)181, (byte)122, (byte)145 , (byte)36 , (byte)8, (byte)232, (byte)168 , (byte)96, (byte)252, (byte)105 , (byte)80,
+ (byte)170, (byte)208, (byte)160, (byte)125, (byte)161, (byte)137 , (byte)98, (byte)151 , (byte)84 , (byte)91 , (byte)30, (byte)149, (byte)224, (byte)255, (byte)100, (byte)210,
+ (byte)16, (byte)196, (byte)0, (byte)72, (byte)163, (byte)247, (byte)117, (byte)219, (byte)138 , (byte)3, (byte)230, (byte)218 , (byte)9 , (byte)63, (byte)221, (byte)148,
+ (byte)135, (byte)92, (byte)131, (byte)2, (byte)205 , (byte)74, (byte)144 , (byte)51, (byte)115, (byte)103, (byte)246, (byte)243, (byte)157, (byte)127, (byte)191, (byte)226,
+ (byte)82, (byte)155, (byte)216 , (byte)38, (byte)200 , (byte)55, (byte)198 , (byte)59, (byte)129, (byte)150, (byte)111 , (byte)75 , (byte)19, (byte)190 , (byte)99 , (byte)46,
+ (byte)233, (byte)121, (byte)167, (byte)140, (byte)159, (byte)110, (byte)188, (byte)142 , (byte)41, (byte)245, (byte)249, (byte)182 , (byte)47, (byte)253, (byte)180 , (byte)89,
+ (byte)120, (byte)152, (byte)6, (byte)106, (byte)231 , (byte)70, (byte)113, (byte)186, (byte)212 , (byte)37, (byte)171 , (byte)66, (byte)136, (byte)162, (byte)141, (byte)250,
+ (byte)114, (byte)7, (byte)185 , (byte)85, (byte)248, (byte)238, (byte)172 , (byte)10 , (byte)54 , (byte)73 , (byte)42, (byte)104 , (byte)60 , (byte)56, (byte)241, (byte)164,
+ (byte)64, (byte)40, (byte)211, (byte)123, (byte)187, (byte)201 , (byte)67, (byte)193 , (byte)21, (byte)227, (byte)173, (byte)244, (byte)119, (byte)199, (byte)128, (byte)158
+ };
+
+ private readonly byte[] SBOX2 = new byte[256];
+ private readonly byte[] SBOX3 = new byte[256];
+ private readonly byte[] SBOX4 = new byte[256];
+
+
+ public CamelliaEngine()
+ {
+ for (int x = 0; x != 256; x++)
+ {
+ SBOX2[x] = lRot8(SBOX1[x], 1);
+ SBOX3[x] = lRot8(SBOX1[x], 7);
+ SBOX4[x] = SBOX1[lRot8((byte)x, 1) & 0xff];
+ }
+ }
+
+ private void setKey(
+ bool forEncryption,
+ byte[] key)
+ {
+ long klA, klB;
+ long krA, krB;
+
+ switch (key.Length)
+ {
+ case 16:
+ _keyIs128 = true;
+ klA = bytesToWord(key, 0);
+ klB = bytesToWord(key, 8);
+ krA = 0;
+ krB = 0;
+ break;
+ case 24:
+ klA = bytesToWord(key, 0);
+ klB = bytesToWord(key, 8);
+ krA = bytesToWord(key, 16);
+ krB = ~bytesToWord(key, 16);
+ _keyIs128 = false;
+ break;
+ case 32:
+ klA = bytesToWord(key, 0);
+ klB = bytesToWord(key, 8);
+ krA = bytesToWord(key, 16);
+ krB = bytesToWord(key, 24);
+ _keyIs128 = false;
+ break;
+ default:
+ throw new ArgumentException("only a key sizes of 128/192/256 are acceptable.");
+ }
+
+ long d1 = klA ^ krA;
+ long d2 = klB ^ krB;
+
+ d2 = d2 ^ f(d1, SIGMA1);
+ d1 = d1 ^ f(d2, SIGMA2);
+ d1 = d1 ^ klA;
+ d2 = d2 ^ klB;
+ d2 = d2 ^ f(d1, SIGMA3);
+ d1 = d1 ^ f(d2, SIGMA4);
+
+ long kaA = d1;
+ long kaB = d2;
+
+ if (_keyIs128)
+ {
+ if (forEncryption)
+ {
+ _kw1 = klA;
+ _kw2 = klB;
+ _kw3 = lRot128high(kaA, kaB, 111);
+ _kw4 = lRot128low(kaA, kaB, 111);
+ _k1 = kaA;
+ _k2 = kaB;
+ _k3 = lRot128high(klA, klB, 15);
+ _k4 = lRot128low(klA, klB, 15);
+ _k5 = lRot128high(kaA, kaB, 15);
+ _k6 = lRot128low(kaA, kaB, 15);
+ _k7 = lRot128high(klA, klB, 45);
+ _k8 = lRot128low(klA, klB, 45);
+ _k9 = lRot128high(kaA, kaB, 45);
+ _k10 = lRot128low(klA, klB, 60);
+ _k11 = lRot128high(kaA, kaB, 60);
+ _k12 = lRot128low(kaA, kaB, 60);
+ _k13 = lRot128high(klA, klB, 94);
+ _k14 = lRot128low(klA, klB, 94);
+ _k15 = lRot128high(kaA, kaB, 94);
+ _k16 = lRot128low(kaA, kaB, 94);
+ _k17 = lRot128high(klA, klB, 111);
+ _k18 = lRot128low(klA, klB, 111);
+ _ke1 = lRot128high(kaA, kaB, 30);
+ _ke2 = lRot128low(kaA, kaB, 30);
+ _ke3 = lRot128high(klA, klB, 77);
+ _ke4 = lRot128low(klA, klB, 77);
+ }
+ else
+ {
+ _kw3 = klA;
+ _kw4 = klB;
+ _kw1 = lRot128high(kaA, kaB, 111);
+ _kw2 = lRot128low(kaA, kaB, 111);
+ _k18 = kaA;
+ _k17 = kaB;
+ _k16 = lRot128high(klA, klB, 15);
+ _k15 = lRot128low(klA, klB, 15);
+ _k14 = lRot128high(kaA, kaB, 15);
+ _k13 = lRot128low(kaA, kaB, 15);
+ _k12 = lRot128high(klA, klB, 45);
+ _k11 = lRot128low(klA, klB, 45);
+ _k10 = lRot128high(kaA, kaB, 45);
+ _k9 = lRot128low(klA, klB, 60);
+ _k8 = lRot128high(kaA, kaB, 60);
+ _k7 = lRot128low(kaA, kaB, 60);
+ _k6 = lRot128high(klA, klB, 94);
+ _k5 = lRot128low(klA, klB, 94);
+ _k4 = lRot128high(kaA, kaB, 94);
+ _k3 = lRot128low(kaA, kaB, 94);
+ _k2 = lRot128high(klA, klB, 111);
+ _k1 = lRot128low(klA, klB, 111);
+ _ke4 = lRot128high(kaA, kaB, 30);
+ _ke3 = lRot128low(kaA, kaB, 30);
+ _ke2 = lRot128high(klA, klB, 77);
+ _ke1 = lRot128low(klA, klB, 77);
+ }
+ }
+ else
+ {
+ d1 = kaA ^ krA;
+ d2 = kaB ^ krB;
+ d2 = d2 ^ f(d1, SIGMA5);
+ d1 = d1 ^ f(d2, SIGMA6);
+
+ long kbA = d1;
+ long kbB = d2;
+
+ if (forEncryption)
+ {
+ _kw1 = klA;
+ _kw2 = klB;
+ _k1 = kbA;
+ _k2 = kbB;
+ _k3 = lRot128high(krA, krB, 15);
+ _k4 = lRot128low(krA, krB, 15);
+ _k5 = lRot128high(kaA, kaB, 15);
+ _k6 = lRot128low(kaA, kaB, 15);
+ _ke1 = lRot128high(krA, krB, 30);
+ _ke2 = lRot128low(krA, krB, 30);
+ _k7 = lRot128high(kbA, kbB, 30);
+ _k8 = lRot128low(kbA, kbB, 30);
+ _k9 = lRot128high(klA, klB, 45);
+ _k10 = lRot128low(klA, klB, 45);
+ _k11 = lRot128high(kaA, kaB, 45);
+ _k12 = lRot128low(kaA, kaB, 45);
+ _ke3 = lRot128high(klA, klB, 60);
+ _ke4 = lRot128low(klA, klB, 60);
+ _k13 = lRot128high(krA, krB, 60);
+ _k14 = lRot128low(krA, krB, 60);
+ _k15 = lRot128high(kbA, kbB, 60);
+ _k16 = lRot128low(kbA, kbB, 60);
+ _k17 = lRot128high(klA, klB, 77);
+ _k18 = lRot128low(klA, klB, 77);
+ _ke5 = lRot128high(kaA, kaB, 77);
+ _ke6 = lRot128low(kaA, kaB, 77);
+ _k19 = lRot128high(krA, krB, 94);
+ _k20 = lRot128low(krA, krB, 94);
+ _k21 = lRot128high(kaA, kaB, 94);
+ _k22 = lRot128low(kaA, kaB, 94);
+ _k23 = lRot128high(klA, klB, 111);
+ _k24 = lRot128low(klA, klB, 111);
+ _kw3 = lRot128high(kbA, kbB, 111);
+ _kw4 = lRot128low(kbA, kbB, 111);
+ }
+ else
+ {
+ _kw3 = klA;
+ _kw4 = klB;
+ _kw1 = lRot128high(kbA, kbB, 111);
+ _kw2 = lRot128low(kbA, kbB, 111);
+ _k24 = kbA;
+ _k23 = kbB;
+ _k22 = lRot128high(krA, krB, 15);
+ _k21 = lRot128low(krA, krB, 15);
+ _k20 = lRot128high(kaA, kaB, 15);
+ _k19 = lRot128low(kaA, kaB, 15);
+ _k18 = lRot128high(kbA, kbB, 30);
+ _k17 = lRot128low(kbA, kbB, 30);
+ _k16 = lRot128high(klA, klB, 45);
+ _k15 = lRot128low(klA, klB, 45);
+ _k14 = lRot128high(kaA, kaB, 45);
+ _k13 = lRot128low(kaA, kaB, 45);
+ _k12 = lRot128high(krA, krB, 60);
+ _k11 = lRot128low(krA, krB, 60);
+ _k10 = lRot128high(kbA, kbB, 60);
+ _k9 = lRot128low(kbA, kbB, 60);
+ _k8 = lRot128high(klA, klB, 77);
+ _k7 = lRot128low(klA, klB, 77);
+ _k6 = lRot128high(krA, krB, 94);
+ _k5 = lRot128low(krA, krB, 94);
+ _k4 = lRot128high(kaA, kaB, 94);
+ _k3 = lRot128low(kaA, kaB, 94);
+ _k2 = lRot128high(klA, klB, 111);
+ _k1 = lRot128low(klA, klB, 111);
+ _ke6 = lRot128high(krA, krB, 30);
+ _ke5 = lRot128low(krA, krB, 30);
+ _ke4 = lRot128high(klA, klB, 60);
+ _ke3 = lRot128low(klA, klB, 60);
+ _ke2 = lRot128high(kaA, kaB, 77);
+ _ke1 = lRot128low(kaA, kaB, 77);
+ }
+ }
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("only simple KeyParameter expected.");
+
+ setKey(forEncryption, ((KeyParameter)parameters).GetKey());
+
+ initialised = true;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Camellia"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Camellia engine not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (_keyIs128)
+ {
+ return processBlock128(input, inOff, output, outOff);
+ }
+ else
+ {
+ return processBlock192or256(input, inOff, output, outOff);
+ }
+ }
+
+ public void Reset()
+ {
+ // nothing
+ }
+
+ private byte lRot8(
+ byte value,
+ int rotation)
+ {
+// return (byte)((value << rotation) | ((value & 0xff) >>> (8 - rotation)));
+ return (byte)((value << rotation) | ((value & 0xff) >> (8 - rotation)));
+ }
+
+ private int lRot32(
+ int value,
+ int rotation)
+ {
+ uint uv = (uint) value;
+// return (value << rotation) | (value >>> (32 - rotation));
+ return (int)((uv << rotation) | (uv >> (32 - rotation)));
+ }
+
+ private long lRot128high(
+ long a,
+ long b,
+ int rotation)
+ {
+ ulong ua = (ulong) a, ub = (ulong) b;
+
+ if (rotation < 64)
+ {
+// a = (a << rotation) | (b >>> (64 - rotation));
+ ua = (ua << rotation) | (ub >> (64 - rotation));
+ }
+ else if (rotation == 64)
+ {
+ ua = ub;
+ }
+ else
+ {
+// a = (b << (rotation - 64)) | (a >>> (64 - (rotation - 64)));
+ ua = (ub << (rotation - 64)) | (ua >> (64 - (rotation - 64)));
+ }
+
+// return a;
+ return (long) ua;
+ }
+
+ private long lRot128low(
+ long a,
+ long b,
+ int rotation)
+ {
+ ulong ua = (ulong) a, ub = (ulong) b;
+
+ if (rotation < 64)
+ {
+// b = (b << rotation) | (a >>> (64 - rotation));
+ ub = (ub << rotation) | (ua >> (64 - rotation));
+ }
+ else if (rotation == 64)
+ {
+ ub = ua;
+ }
+ else
+ {
+// b = (a << (rotation - 64)) | (b >>> (64 - (rotation - 64)));
+ ub = (ua << (rotation - 64)) | (ub >> (64 - (rotation - 64)));
+ }
+
+// return b;
+ return (long) ub;
+ }
+
+ private long fl(
+ long input,
+ long ke)
+ {
+ int x1 = (int)(input >> 32);
+ int x2 = (int)input;
+ int k1 = (int)(ke >> 32);
+ int k2 = (int)ke;
+
+ x2 = x2 ^ lRot32((x1 & k1), 1);
+ x1 = x1 ^ (x2 | k2);
+
+ return ((long)x1 << 32) | (x2 & MASK32);
+ }
+
+ private long flInv(
+ long input,
+ long ke)
+ {
+ int y1 = (int)(input >> 32);
+ int y2 = (int)input;
+ int k1 = (int)(ke >> 32);
+ int k2 = (int)ke;
+
+ y1 = y1 ^ (y2 | k2);
+ y2 = y2 ^ lRot32((y1 & k1), 1);
+
+ return ((long)y1 << 32) | (y2 & MASK32);
+ }
+
+ private long f(
+ long input,
+ long ke)
+ {
+ long x;
+ int a, b;
+ int t1, t2, t3, t4, t5, t6, t7, t8;
+ int y1, y2, y3, y4, y5, y6, y7, y8;
+
+ x = input ^ ke;
+
+ a = (int)(x >> 32);
+ b = (int)x;
+
+ t1 = SBOX1[(a >> 24) & 0xff];
+ t2 = SBOX2[(a >> 16) & 0xff];
+ t3 = SBOX3[(a >> 8) & 0xff];
+ t4 = SBOX4[a & 0xff];
+ t5 = SBOX2[(b >> 24) & 0xff];
+ t6 = SBOX3[(b >> 16) & 0xff];
+ t7 = SBOX4[(b >> 8) & 0xff];
+ t8 = SBOX1[b & 0xff];
+
+ y1 = (t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8);
+ y2 = (t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8);
+ y3 = (t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8);
+ y4 = (t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7);
+ y5 = (t1 ^ t2 ^ t6 ^ t7 ^ t8);
+ y6 = (t2 ^ t3 ^ t5 ^ t7 ^ t8);
+ y7 = (t3 ^ t4 ^ t5 ^ t6 ^ t8);
+ y8 = (t1 ^ t4 ^ t5 ^ t6 ^ t7);
+
+ return ((long)y1 << 56) | (((long)y2 & MASK8) << 48) | (((long)y3 & MASK8) << 40)
+ | (((long)y4 & MASK8) << 32) | (((long)y5 & MASK8) << 24) | (((long)y6 & MASK8) << 16)
+ | (((long)y7 & MASK8) << 8) | ((long)y8 & MASK8);
+ }
+
+ private long bytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ long word = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ private void wordToBytes(
+ long word,
+ byte[] dst,
+ int dstOff)
+ {
+ ulong uw = (ulong) word;
+ for (int i = 0; i < 8; i++)
+ {
+// dst[(7 - i) + dstOff] = (byte)word;
+ dst[(7 - i) + dstOff] = (byte)uw;
+// word >>>= 8;
+ uw >>= 8;
+ }
+ }
+
+ private int processBlock128(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ long d1 = bytesToWord(inBytes, inOff);
+ long d2 = bytesToWord(inBytes, inOff + 8);
+
+ d1 = d1 ^ _kw1; // Prewhitening
+ d2 = d2 ^ _kw2;
+
+ d2 = d2 ^ f(d1, _k1); // Round 1
+ d1 = d1 ^ f(d2, _k2); // Round 2
+ d2 = d2 ^ f(d1, _k3); // Round 3
+ d1 = d1 ^ f(d2, _k4); // Round 4
+ d2 = d2 ^ f(d1, _k5); // Round 5
+ d1 = d1 ^ f(d2, _k6); // Round 6
+ d1 = fl (d1, _ke1); // FL
+ d2 = flInv(d2, _ke2); // FLINV
+ d2 = d2 ^ f(d1, _k7); // Round 7
+ d1 = d1 ^ f(d2, _k8); // Round 8
+ d2 = d2 ^ f(d1, _k9); // Round 9
+ d1 = d1 ^ f(d2, _k10); // Round 10
+ d2 = d2 ^ f(d1, _k11); // Round 11
+ d1 = d1 ^ f(d2, _k12); // Round 12
+ d1 = fl (d1, _ke3); // FL
+ d2 = flInv(d2, _ke4); // FLINV
+
+ d2 = d2 ^ f(d1, _k13); // Round 13
+ d1 = d1 ^ f(d2, _k14); // Round 14
+ d2 = d2 ^ f(d1, _k15); // Round 15
+ d1 = d1 ^ f(d2, _k16); // Round 16
+ d2 = d2 ^ f(d1, _k17); // Round 17
+ d1 = d1 ^ f(d2, _k18); // Round 18
+
+ d2 = d2 ^ _kw3; // Postwhitening
+ d1 = d1 ^ _kw4;
+
+ wordToBytes(d2, outBytes, outOff);
+ wordToBytes(d1, outBytes, outOff + 8);
+
+ return BLOCK_SIZE;
+ }
+
+ private int processBlock192or256(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ long d1 = bytesToWord(inBytes, inOff);
+ long d2 = bytesToWord(inBytes, inOff + 8);
+
+ d1 = d1 ^ _kw1; // Prewhitening
+ d2 = d2 ^ _kw2;
+
+ d2 = d2 ^ f(d1, _k1); // Round 1
+ d1 = d1 ^ f(d2, _k2); // Round 2
+ d2 = d2 ^ f(d1, _k3); // Round 3
+ d1 = d1 ^ f(d2, _k4); // Round 4
+ d2 = d2 ^ f(d1, _k5); // Round 5
+ d1 = d1 ^ f(d2, _k6); // Round 6
+ d1 = fl (d1, _ke1); // FL
+ d2 = flInv(d2, _ke2); // FLINV
+ d2 = d2 ^ f(d1, _k7); // Round 7
+ d1 = d1 ^ f(d2, _k8); // Round 8
+ d2 = d2 ^ f(d1, _k9); // Round 9
+ d1 = d1 ^ f(d2, _k10); // Round 10
+ d2 = d2 ^ f(d1, _k11); // Round 11
+ d1 = d1 ^ f(d2, _k12); // Round 12
+ d1 = fl (d1, _ke3); // FL
+ d2 = flInv(d2, _ke4); // FLINV
+ d2 = d2 ^ f(d1, _k13); // Round 13
+ d1 = d1 ^ f(d2, _k14); // Round 14
+ d2 = d2 ^ f(d1, _k15); // Round 15
+ d1 = d1 ^ f(d2, _k16); // Round 16
+ d2 = d2 ^ f(d1, _k17); // Round 17
+ d1 = d1 ^ f(d2, _k18); // Round 18
+ d1 = fl (d1, _ke5); // FL
+ d2 = flInv(d2, _ke6); // FLINV
+ d2 = d2 ^ f(d1, _k19); // Round 19
+ d1 = d1 ^ f(d2, _k20); // Round 20
+ d2 = d2 ^ f(d1, _k21); // Round 21
+ d1 = d1 ^ f(d2, _k22); // Round 22
+ d2 = d2 ^ f(d1, _k23); // Round 23
+ d1 = d1 ^ f(d2, _k24); // Round 24
+
+ d2 = d2 ^ _kw3; // Postwhitening
+ d1 = d1 ^ _kw4;
+
+ wordToBytes(d2, outBytes, outOff);
+ wordToBytes(d1, outBytes, outOff + 8);
+
+ return BLOCK_SIZE;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/CamelliaWrapEngine.cs b/src/core/srcbc/crypto/engines/CamelliaWrapEngine.cs
new file mode 100644
index 0000000..26e7602
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/CamelliaWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc3657.txt.
+ ///
+ public class CamelliaWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public CamelliaWrapEngine()
+ : base(new CamelliaEngine())
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/Cast5Engine.cs b/src/core/srcbc/crypto/engines/Cast5Engine.cs
new file mode 100644
index 0000000..56743b6
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/Cast5Engine.cs
@@ -0,0 +1,829 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides CAST key encryption operations,
+ * such as encoding data and generating keys.
+ *
+ * All the algorithms herein are from the Internet RFC's
+ *
+ * RFC2144 - Cast5 (64bit block, 40-128bit key)
+ * RFC2612 - CAST6 (128bit block, 128-256bit key)
+ *
+ * and implement a simplified cryptography interface.
+ */
+ public class Cast5Engine
+ : IBlockCipher
+ {
+ internal const int M32 = unchecked((int) 0xffffffff);
+
+ internal static readonly int[]
+ S1 = {
+ unchecked((int) 0x30fb40d4), unchecked((int) 0x9fa0ff0b), unchecked((int) 0x6beccd2f), unchecked((int) 0x3f258c7a), unchecked((int) 0x1e213f2f), unchecked((int) 0x9c004dd3), unchecked((int) 0x6003e540), unchecked((int) 0xcf9fc949),
+ unchecked((int) 0xbfd4af27), unchecked((int) 0x88bbbdb5), unchecked((int) 0xe2034090), unchecked((int) 0x98d09675), unchecked((int) 0x6e63a0e0), unchecked((int) 0x15c361d2), unchecked((int) 0xc2e7661d), unchecked((int) 0x22d4ff8e),
+ unchecked((int) 0x28683b6f), unchecked((int) 0xc07fd059), unchecked((int) 0xff2379c8), unchecked((int) 0x775f50e2), unchecked((int) 0x43c340d3), unchecked((int) 0xdf2f8656), unchecked((int) 0x887ca41a), unchecked((int) 0xa2d2bd2d),
+ unchecked((int) 0xa1c9e0d6), unchecked((int) 0x346c4819), unchecked((int) 0x61b76d87), unchecked((int) 0x22540f2f), unchecked((int) 0x2abe32e1), unchecked((int) 0xaa54166b), unchecked((int) 0x22568e3a), unchecked((int) 0xa2d341d0),
+ unchecked((int) 0x66db40c8), unchecked((int) 0xa784392f), unchecked((int) 0x004dff2f), unchecked((int) 0x2db9d2de), unchecked((int) 0x97943fac), unchecked((int) 0x4a97c1d8), unchecked((int) 0x527644b7), unchecked((int) 0xb5f437a7),
+ unchecked((int) 0xb82cbaef), unchecked((int) 0xd751d159), unchecked((int) 0x6ff7f0ed), unchecked((int) 0x5a097a1f), unchecked((int) 0x827b68d0), unchecked((int) 0x90ecf52e), unchecked((int) 0x22b0c054), unchecked((int) 0xbc8e5935),
+ unchecked((int) 0x4b6d2f7f), unchecked((int) 0x50bb64a2), unchecked((int) 0xd2664910), unchecked((int) 0xbee5812d), unchecked((int) 0xb7332290), unchecked((int) 0xe93b159f), unchecked((int) 0xb48ee411), unchecked((int) 0x4bff345d),
+ unchecked((int) 0xfd45c240), unchecked((int) 0xad31973f), unchecked((int) 0xc4f6d02e), unchecked((int) 0x55fc8165), unchecked((int) 0xd5b1caad), unchecked((int) 0xa1ac2dae), unchecked((int) 0xa2d4b76d), unchecked((int) 0xc19b0c50),
+ unchecked((int) 0x882240f2), unchecked((int) 0x0c6e4f38), unchecked((int) 0xa4e4bfd7), unchecked((int) 0x4f5ba272), unchecked((int) 0x564c1d2f), unchecked((int) 0xc59c5319), unchecked((int) 0xb949e354), unchecked((int) 0xb04669fe),
+ unchecked((int) 0xb1b6ab8a), unchecked((int) 0xc71358dd), unchecked((int) 0x6385c545), unchecked((int) 0x110f935d), unchecked((int) 0x57538ad5), unchecked((int) 0x6a390493), unchecked((int) 0xe63d37e0), unchecked((int) 0x2a54f6b3),
+ unchecked((int) 0x3a787d5f), unchecked((int) 0x6276a0b5), unchecked((int) 0x19a6fcdf), unchecked((int) 0x7a42206a), unchecked((int) 0x29f9d4d5), unchecked((int) 0xf61b1891), unchecked((int) 0xbb72275e), unchecked((int) 0xaa508167),
+ unchecked((int) 0x38901091), unchecked((int) 0xc6b505eb), unchecked((int) 0x84c7cb8c), unchecked((int) 0x2ad75a0f), unchecked((int) 0x874a1427), unchecked((int) 0xa2d1936b), unchecked((int) 0x2ad286af), unchecked((int) 0xaa56d291),
+ unchecked((int) 0xd7894360), unchecked((int) 0x425c750d), unchecked((int) 0x93b39e26), unchecked((int) 0x187184c9), unchecked((int) 0x6c00b32d), unchecked((int) 0x73e2bb14), unchecked((int) 0xa0bebc3c), unchecked((int) 0x54623779),
+ unchecked((int) 0x64459eab), unchecked((int) 0x3f328b82), unchecked((int) 0x7718cf82), unchecked((int) 0x59a2cea6), unchecked((int) 0x04ee002e), unchecked((int) 0x89fe78e6), unchecked((int) 0x3fab0950), unchecked((int) 0x325ff6c2),
+ unchecked((int) 0x81383f05), unchecked((int) 0x6963c5c8), unchecked((int) 0x76cb5ad6), unchecked((int) 0xd49974c9), unchecked((int) 0xca180dcf), unchecked((int) 0x380782d5), unchecked((int) 0xc7fa5cf6), unchecked((int) 0x8ac31511),
+ unchecked((int) 0x35e79e13), unchecked((int) 0x47da91d0), unchecked((int) 0xf40f9086), unchecked((int) 0xa7e2419e), unchecked((int) 0x31366241), unchecked((int) 0x051ef495), unchecked((int) 0xaa573b04), unchecked((int) 0x4a805d8d),
+ unchecked((int) 0x548300d0), unchecked((int) 0x00322a3c), unchecked((int) 0xbf64cddf), unchecked((int) 0xba57a68e), unchecked((int) 0x75c6372b), unchecked((int) 0x50afd341), unchecked((int) 0xa7c13275), unchecked((int) 0x915a0bf5),
+ unchecked((int) 0x6b54bfab), unchecked((int) 0x2b0b1426), unchecked((int) 0xab4cc9d7), unchecked((int) 0x449ccd82), unchecked((int) 0xf7fbf265), unchecked((int) 0xab85c5f3), unchecked((int) 0x1b55db94), unchecked((int) 0xaad4e324),
+ unchecked((int) 0xcfa4bd3f), unchecked((int) 0x2deaa3e2), unchecked((int) 0x9e204d02), unchecked((int) 0xc8bd25ac), unchecked((int) 0xeadf55b3), unchecked((int) 0xd5bd9e98), unchecked((int) 0xe31231b2), unchecked((int) 0x2ad5ad6c),
+ unchecked((int) 0x954329de), unchecked((int) 0xadbe4528), unchecked((int) 0xd8710f69), unchecked((int) 0xaa51c90f), unchecked((int) 0xaa786bf6), unchecked((int) 0x22513f1e), unchecked((int) 0xaa51a79b), unchecked((int) 0x2ad344cc),
+ unchecked((int) 0x7b5a41f0), unchecked((int) 0xd37cfbad), unchecked((int) 0x1b069505), unchecked((int) 0x41ece491), unchecked((int) 0xb4c332e6), unchecked((int) 0x032268d4), unchecked((int) 0xc9600acc), unchecked((int) 0xce387e6d),
+ unchecked((int) 0xbf6bb16c), unchecked((int) 0x6a70fb78), unchecked((int) 0x0d03d9c9), unchecked((int) 0xd4df39de), unchecked((int) 0xe01063da), unchecked((int) 0x4736f464), unchecked((int) 0x5ad328d8), unchecked((int) 0xb347cc96),
+ unchecked((int) 0x75bb0fc3), unchecked((int) 0x98511bfb), unchecked((int) 0x4ffbcc35), unchecked((int) 0xb58bcf6a), unchecked((int) 0xe11f0abc), unchecked((int) 0xbfc5fe4a), unchecked((int) 0xa70aec10), unchecked((int) 0xac39570a),
+ unchecked((int) 0x3f04442f), unchecked((int) 0x6188b153), unchecked((int) 0xe0397a2e), unchecked((int) 0x5727cb79), unchecked((int) 0x9ceb418f), unchecked((int) 0x1cacd68d), unchecked((int) 0x2ad37c96), unchecked((int) 0x0175cb9d),
+ unchecked((int) 0xc69dff09), unchecked((int) 0xc75b65f0), unchecked((int) 0xd9db40d8), unchecked((int) 0xec0e7779), unchecked((int) 0x4744ead4), unchecked((int) 0xb11c3274), unchecked((int) 0xdd24cb9e), unchecked((int) 0x7e1c54bd),
+ unchecked((int) 0xf01144f9), unchecked((int) 0xd2240eb1), unchecked((int) 0x9675b3fd), unchecked((int) 0xa3ac3755), unchecked((int) 0xd47c27af), unchecked((int) 0x51c85f4d), unchecked((int) 0x56907596), unchecked((int) 0xa5bb15e6),
+ unchecked((int) 0x580304f0), unchecked((int) 0xca042cf1), unchecked((int) 0x011a37ea), unchecked((int) 0x8dbfaadb), unchecked((int) 0x35ba3e4a), unchecked((int) 0x3526ffa0), unchecked((int) 0xc37b4d09), unchecked((int) 0xbc306ed9),
+ unchecked((int) 0x98a52666), unchecked((int) 0x5648f725), unchecked((int) 0xff5e569d), unchecked((int) 0x0ced63d0), unchecked((int) 0x7c63b2cf), unchecked((int) 0x700b45e1), unchecked((int) 0xd5ea50f1), unchecked((int) 0x85a92872),
+ unchecked((int) 0xaf1fbda7), unchecked((int) 0xd4234870), unchecked((int) 0xa7870bf3), unchecked((int) 0x2d3b4d79), unchecked((int) 0x42e04198), unchecked((int) 0x0cd0ede7), unchecked((int) 0x26470db8), unchecked((int) 0xf881814c),
+ unchecked((int) 0x474d6ad7), unchecked((int) 0x7c0c5e5c), unchecked((int) 0xd1231959), unchecked((int) 0x381b7298), unchecked((int) 0xf5d2f4db), unchecked((int) 0xab838653), unchecked((int) 0x6e2f1e23), unchecked((int) 0x83719c9e),
+ unchecked((int) 0xbd91e046), unchecked((int) 0x9a56456e), unchecked((int) 0xdc39200c), unchecked((int) 0x20c8c571), unchecked((int) 0x962bda1c), unchecked((int) 0xe1e696ff), unchecked((int) 0xb141ab08), unchecked((int) 0x7cca89b9),
+ unchecked((int) 0x1a69e783), unchecked((int) 0x02cc4843), unchecked((int) 0xa2f7c579), unchecked((int) 0x429ef47d), unchecked((int) 0x427b169c), unchecked((int) 0x5ac9f049), unchecked((int) 0xdd8f0f00), unchecked((int) 0x5c8165bf)
+ },
+ S2 =
+ {
+ unchecked((int) 0x1f201094), unchecked((int) 0xef0ba75b), unchecked((int) 0x69e3cf7e), unchecked((int) 0x393f4380), unchecked((int) 0xfe61cf7a), unchecked((int) 0xeec5207a), unchecked((int) 0x55889c94), unchecked((int) 0x72fc0651),
+ unchecked((int) 0xada7ef79), unchecked((int) 0x4e1d7235), unchecked((int) 0xd55a63ce), unchecked((int) 0xde0436ba), unchecked((int) 0x99c430ef), unchecked((int) 0x5f0c0794), unchecked((int) 0x18dcdb7d), unchecked((int) 0xa1d6eff3),
+ unchecked((int) 0xa0b52f7b), unchecked((int) 0x59e83605), unchecked((int) 0xee15b094), unchecked((int) 0xe9ffd909), unchecked((int) 0xdc440086), unchecked((int) 0xef944459), unchecked((int) 0xba83ccb3), unchecked((int) 0xe0c3cdfb),
+ unchecked((int) 0xd1da4181), unchecked((int) 0x3b092ab1), unchecked((int) 0xf997f1c1), unchecked((int) 0xa5e6cf7b), unchecked((int) 0x01420ddb), unchecked((int) 0xe4e7ef5b), unchecked((int) 0x25a1ff41), unchecked((int) 0xe180f806),
+ unchecked((int) 0x1fc41080), unchecked((int) 0x179bee7a), unchecked((int) 0xd37ac6a9), unchecked((int) 0xfe5830a4), unchecked((int) 0x98de8b7f), unchecked((int) 0x77e83f4e), unchecked((int) 0x79929269), unchecked((int) 0x24fa9f7b),
+ unchecked((int) 0xe113c85b), unchecked((int) 0xacc40083), unchecked((int) 0xd7503525), unchecked((int) 0xf7ea615f), unchecked((int) 0x62143154), unchecked((int) 0x0d554b63), unchecked((int) 0x5d681121), unchecked((int) 0xc866c359),
+ unchecked((int) 0x3d63cf73), unchecked((int) 0xcee234c0), unchecked((int) 0xd4d87e87), unchecked((int) 0x5c672b21), unchecked((int) 0x071f6181), unchecked((int) 0x39f7627f), unchecked((int) 0x361e3084), unchecked((int) 0xe4eb573b),
+ unchecked((int) 0x602f64a4), unchecked((int) 0xd63acd9c), unchecked((int) 0x1bbc4635), unchecked((int) 0x9e81032d), unchecked((int) 0x2701f50c), unchecked((int) 0x99847ab4), unchecked((int) 0xa0e3df79), unchecked((int) 0xba6cf38c),
+ unchecked((int) 0x10843094), unchecked((int) 0x2537a95e), unchecked((int) 0xf46f6ffe), unchecked((int) 0xa1ff3b1f), unchecked((int) 0x208cfb6a), unchecked((int) 0x8f458c74), unchecked((int) 0xd9e0a227), unchecked((int) 0x4ec73a34),
+ unchecked((int) 0xfc884f69), unchecked((int) 0x3e4de8df), unchecked((int) 0xef0e0088), unchecked((int) 0x3559648d), unchecked((int) 0x8a45388c), unchecked((int) 0x1d804366), unchecked((int) 0x721d9bfd), unchecked((int) 0xa58684bb),
+ unchecked((int) 0xe8256333), unchecked((int) 0x844e8212), unchecked((int) 0x128d8098), unchecked((int) 0xfed33fb4), unchecked((int) 0xce280ae1), unchecked((int) 0x27e19ba5), unchecked((int) 0xd5a6c252), unchecked((int) 0xe49754bd),
+ unchecked((int) 0xc5d655dd), unchecked((int) 0xeb667064), unchecked((int) 0x77840b4d), unchecked((int) 0xa1b6a801), unchecked((int) 0x84db26a9), unchecked((int) 0xe0b56714), unchecked((int) 0x21f043b7), unchecked((int) 0xe5d05860),
+ unchecked((int) 0x54f03084), unchecked((int) 0x066ff472), unchecked((int) 0xa31aa153), unchecked((int) 0xdadc4755), unchecked((int) 0xb5625dbf), unchecked((int) 0x68561be6), unchecked((int) 0x83ca6b94), unchecked((int) 0x2d6ed23b),
+ unchecked((int) 0xeccf01db), unchecked((int) 0xa6d3d0ba), unchecked((int) 0xb6803d5c), unchecked((int) 0xaf77a709), unchecked((int) 0x33b4a34c), unchecked((int) 0x397bc8d6), unchecked((int) 0x5ee22b95), unchecked((int) 0x5f0e5304),
+ unchecked((int) 0x81ed6f61), unchecked((int) 0x20e74364), unchecked((int) 0xb45e1378), unchecked((int) 0xde18639b), unchecked((int) 0x881ca122), unchecked((int) 0xb96726d1), unchecked((int) 0x8049a7e8), unchecked((int) 0x22b7da7b),
+ unchecked((int) 0x5e552d25), unchecked((int) 0x5272d237), unchecked((int) 0x79d2951c), unchecked((int) 0xc60d894c), unchecked((int) 0x488cb402), unchecked((int) 0x1ba4fe5b), unchecked((int) 0xa4b09f6b), unchecked((int) 0x1ca815cf),
+ unchecked((int) 0xa20c3005), unchecked((int) 0x8871df63), unchecked((int) 0xb9de2fcb), unchecked((int) 0x0cc6c9e9), unchecked((int) 0x0beeff53), unchecked((int) 0xe3214517), unchecked((int) 0xb4542835), unchecked((int) 0x9f63293c),
+ unchecked((int) 0xee41e729), unchecked((int) 0x6e1d2d7c), unchecked((int) 0x50045286), unchecked((int) 0x1e6685f3), unchecked((int) 0xf33401c6), unchecked((int) 0x30a22c95), unchecked((int) 0x31a70850), unchecked((int) 0x60930f13),
+ unchecked((int) 0x73f98417), unchecked((int) 0xa1269859), unchecked((int) 0xec645c44), unchecked((int) 0x52c877a9), unchecked((int) 0xcdff33a6), unchecked((int) 0xa02b1741), unchecked((int) 0x7cbad9a2), unchecked((int) 0x2180036f),
+ unchecked((int) 0x50d99c08), unchecked((int) 0xcb3f4861), unchecked((int) 0xc26bd765), unchecked((int) 0x64a3f6ab), unchecked((int) 0x80342676), unchecked((int) 0x25a75e7b), unchecked((int) 0xe4e6d1fc), unchecked((int) 0x20c710e6),
+ unchecked((int) 0xcdf0b680), unchecked((int) 0x17844d3b), unchecked((int) 0x31eef84d), unchecked((int) 0x7e0824e4), unchecked((int) 0x2ccb49eb), unchecked((int) 0x846a3bae), unchecked((int) 0x8ff77888), unchecked((int) 0xee5d60f6),
+ unchecked((int) 0x7af75673), unchecked((int) 0x2fdd5cdb), unchecked((int) 0xa11631c1), unchecked((int) 0x30f66f43), unchecked((int) 0xb3faec54), unchecked((int) 0x157fd7fa), unchecked((int) 0xef8579cc), unchecked((int) 0xd152de58),
+ unchecked((int) 0xdb2ffd5e), unchecked((int) 0x8f32ce19), unchecked((int) 0x306af97a), unchecked((int) 0x02f03ef8), unchecked((int) 0x99319ad5), unchecked((int) 0xc242fa0f), unchecked((int) 0xa7e3ebb0), unchecked((int) 0xc68e4906),
+ unchecked((int) 0xb8da230c), unchecked((int) 0x80823028), unchecked((int) 0xdcdef3c8), unchecked((int) 0xd35fb171), unchecked((int) 0x088a1bc8), unchecked((int) 0xbec0c560), unchecked((int) 0x61a3c9e8), unchecked((int) 0xbca8f54d),
+ unchecked((int) 0xc72feffa), unchecked((int) 0x22822e99), unchecked((int) 0x82c570b4), unchecked((int) 0xd8d94e89), unchecked((int) 0x8b1c34bc), unchecked((int) 0x301e16e6), unchecked((int) 0x273be979), unchecked((int) 0xb0ffeaa6),
+ unchecked((int) 0x61d9b8c6), unchecked((int) 0x00b24869), unchecked((int) 0xb7ffce3f), unchecked((int) 0x08dc283b), unchecked((int) 0x43daf65a), unchecked((int) 0xf7e19798), unchecked((int) 0x7619b72f), unchecked((int) 0x8f1c9ba4),
+ unchecked((int) 0xdc8637a0), unchecked((int) 0x16a7d3b1), unchecked((int) 0x9fc393b7), unchecked((int) 0xa7136eeb), unchecked((int) 0xc6bcc63e), unchecked((int) 0x1a513742), unchecked((int) 0xef6828bc), unchecked((int) 0x520365d6),
+ unchecked((int) 0x2d6a77ab), unchecked((int) 0x3527ed4b), unchecked((int) 0x821fd216), unchecked((int) 0x095c6e2e), unchecked((int) 0xdb92f2fb), unchecked((int) 0x5eea29cb), unchecked((int) 0x145892f5), unchecked((int) 0x91584f7f),
+ unchecked((int) 0x5483697b), unchecked((int) 0x2667a8cc), unchecked((int) 0x85196048), unchecked((int) 0x8c4bacea), unchecked((int) 0x833860d4), unchecked((int) 0x0d23e0f9), unchecked((int) 0x6c387e8a), unchecked((int) 0x0ae6d249),
+ unchecked((int) 0xb284600c), unchecked((int) 0xd835731d), unchecked((int) 0xdcb1c647), unchecked((int) 0xac4c56ea), unchecked((int) 0x3ebd81b3), unchecked((int) 0x230eabb0), unchecked((int) 0x6438bc87), unchecked((int) 0xf0b5b1fa),
+ unchecked((int) 0x8f5ea2b3), unchecked((int) 0xfc184642), unchecked((int) 0x0a036b7a), unchecked((int) 0x4fb089bd), unchecked((int) 0x649da589), unchecked((int) 0xa345415e), unchecked((int) 0x5c038323), unchecked((int) 0x3e5d3bb9),
+ unchecked((int) 0x43d79572), unchecked((int) 0x7e6dd07c), unchecked((int) 0x06dfdf1e), unchecked((int) 0x6c6cc4ef), unchecked((int) 0x7160a539), unchecked((int) 0x73bfbe70), unchecked((int) 0x83877605), unchecked((int) 0x4523ecf1)
+ },
+ S3 =
+ {
+ unchecked((int) 0x8defc240), unchecked((int) 0x25fa5d9f), unchecked((int) 0xeb903dbf), unchecked((int) 0xe810c907), unchecked((int) 0x47607fff), unchecked((int) 0x369fe44b), unchecked((int) 0x8c1fc644), unchecked((int) 0xaececa90),
+ unchecked((int) 0xbeb1f9bf), unchecked((int) 0xeefbcaea), unchecked((int) 0xe8cf1950), unchecked((int) 0x51df07ae), unchecked((int) 0x920e8806), unchecked((int) 0xf0ad0548), unchecked((int) 0xe13c8d83), unchecked((int) 0x927010d5),
+ unchecked((int) 0x11107d9f), unchecked((int) 0x07647db9), unchecked((int) 0xb2e3e4d4), unchecked((int) 0x3d4f285e), unchecked((int) 0xb9afa820), unchecked((int) 0xfade82e0), unchecked((int) 0xa067268b), unchecked((int) 0x8272792e),
+ unchecked((int) 0x553fb2c0), unchecked((int) 0x489ae22b), unchecked((int) 0xd4ef9794), unchecked((int) 0x125e3fbc), unchecked((int) 0x21fffcee), unchecked((int) 0x825b1bfd), unchecked((int) 0x9255c5ed), unchecked((int) 0x1257a240),
+ unchecked((int) 0x4e1a8302), unchecked((int) 0xbae07fff), unchecked((int) 0x528246e7), unchecked((int) 0x8e57140e), unchecked((int) 0x3373f7bf), unchecked((int) 0x8c9f8188), unchecked((int) 0xa6fc4ee8), unchecked((int) 0xc982b5a5),
+ unchecked((int) 0xa8c01db7), unchecked((int) 0x579fc264), unchecked((int) 0x67094f31), unchecked((int) 0xf2bd3f5f), unchecked((int) 0x40fff7c1), unchecked((int) 0x1fb78dfc), unchecked((int) 0x8e6bd2c1), unchecked((int) 0x437be59b),
+ unchecked((int) 0x99b03dbf), unchecked((int) 0xb5dbc64b), unchecked((int) 0x638dc0e6), unchecked((int) 0x55819d99), unchecked((int) 0xa197c81c), unchecked((int) 0x4a012d6e), unchecked((int) 0xc5884a28), unchecked((int) 0xccc36f71),
+ unchecked((int) 0xb843c213), unchecked((int) 0x6c0743f1), unchecked((int) 0x8309893c), unchecked((int) 0x0feddd5f), unchecked((int) 0x2f7fe850), unchecked((int) 0xd7c07f7e), unchecked((int) 0x02507fbf), unchecked((int) 0x5afb9a04),
+ unchecked((int) 0xa747d2d0), unchecked((int) 0x1651192e), unchecked((int) 0xaf70bf3e), unchecked((int) 0x58c31380), unchecked((int) 0x5f98302e), unchecked((int) 0x727cc3c4), unchecked((int) 0x0a0fb402), unchecked((int) 0x0f7fef82),
+ unchecked((int) 0x8c96fdad), unchecked((int) 0x5d2c2aae), unchecked((int) 0x8ee99a49), unchecked((int) 0x50da88b8), unchecked((int) 0x8427f4a0), unchecked((int) 0x1eac5790), unchecked((int) 0x796fb449), unchecked((int) 0x8252dc15),
+ unchecked((int) 0xefbd7d9b), unchecked((int) 0xa672597d), unchecked((int) 0xada840d8), unchecked((int) 0x45f54504), unchecked((int) 0xfa5d7403), unchecked((int) 0xe83ec305), unchecked((int) 0x4f91751a), unchecked((int) 0x925669c2),
+ unchecked((int) 0x23efe941), unchecked((int) 0xa903f12e), unchecked((int) 0x60270df2), unchecked((int) 0x0276e4b6), unchecked((int) 0x94fd6574), unchecked((int) 0x927985b2), unchecked((int) 0x8276dbcb), unchecked((int) 0x02778176),
+ unchecked((int) 0xf8af918d), unchecked((int) 0x4e48f79e), unchecked((int) 0x8f616ddf), unchecked((int) 0xe29d840e), unchecked((int) 0x842f7d83), unchecked((int) 0x340ce5c8), unchecked((int) 0x96bbb682), unchecked((int) 0x93b4b148),
+ unchecked((int) 0xef303cab), unchecked((int) 0x984faf28), unchecked((int) 0x779faf9b), unchecked((int) 0x92dc560d), unchecked((int) 0x224d1e20), unchecked((int) 0x8437aa88), unchecked((int) 0x7d29dc96), unchecked((int) 0x2756d3dc),
+ unchecked((int) 0x8b907cee), unchecked((int) 0xb51fd240), unchecked((int) 0xe7c07ce3), unchecked((int) 0xe566b4a1), unchecked((int) 0xc3e9615e), unchecked((int) 0x3cf8209d), unchecked((int) 0x6094d1e3), unchecked((int) 0xcd9ca341),
+ unchecked((int) 0x5c76460e), unchecked((int) 0x00ea983b), unchecked((int) 0xd4d67881), unchecked((int) 0xfd47572c), unchecked((int) 0xf76cedd9), unchecked((int) 0xbda8229c), unchecked((int) 0x127dadaa), unchecked((int) 0x438a074e),
+ unchecked((int) 0x1f97c090), unchecked((int) 0x081bdb8a), unchecked((int) 0x93a07ebe), unchecked((int) 0xb938ca15), unchecked((int) 0x97b03cff), unchecked((int) 0x3dc2c0f8), unchecked((int) 0x8d1ab2ec), unchecked((int) 0x64380e51),
+ unchecked((int) 0x68cc7bfb), unchecked((int) 0xd90f2788), unchecked((int) 0x12490181), unchecked((int) 0x5de5ffd4), unchecked((int) 0xdd7ef86a), unchecked((int) 0x76a2e214), unchecked((int) 0xb9a40368), unchecked((int) 0x925d958f),
+ unchecked((int) 0x4b39fffa), unchecked((int) 0xba39aee9), unchecked((int) 0xa4ffd30b), unchecked((int) 0xfaf7933b), unchecked((int) 0x6d498623), unchecked((int) 0x193cbcfa), unchecked((int) 0x27627545), unchecked((int) 0x825cf47a),
+ unchecked((int) 0x61bd8ba0), unchecked((int) 0xd11e42d1), unchecked((int) 0xcead04f4), unchecked((int) 0x127ea392), unchecked((int) 0x10428db7), unchecked((int) 0x8272a972), unchecked((int) 0x9270c4a8), unchecked((int) 0x127de50b),
+ unchecked((int) 0x285ba1c8), unchecked((int) 0x3c62f44f), unchecked((int) 0x35c0eaa5), unchecked((int) 0xe805d231), unchecked((int) 0x428929fb), unchecked((int) 0xb4fcdf82), unchecked((int) 0x4fb66a53), unchecked((int) 0x0e7dc15b),
+ unchecked((int) 0x1f081fab), unchecked((int) 0x108618ae), unchecked((int) 0xfcfd086d), unchecked((int) 0xf9ff2889), unchecked((int) 0x694bcc11), unchecked((int) 0x236a5cae), unchecked((int) 0x12deca4d), unchecked((int) 0x2c3f8cc5),
+ unchecked((int) 0xd2d02dfe), unchecked((int) 0xf8ef5896), unchecked((int) 0xe4cf52da), unchecked((int) 0x95155b67), unchecked((int) 0x494a488c), unchecked((int) 0xb9b6a80c), unchecked((int) 0x5c8f82bc), unchecked((int) 0x89d36b45),
+ unchecked((int) 0x3a609437), unchecked((int) 0xec00c9a9), unchecked((int) 0x44715253), unchecked((int) 0x0a874b49), unchecked((int) 0xd773bc40), unchecked((int) 0x7c34671c), unchecked((int) 0x02717ef6), unchecked((int) 0x4feb5536),
+ unchecked((int) 0xa2d02fff), unchecked((int) 0xd2bf60c4), unchecked((int) 0xd43f03c0), unchecked((int) 0x50b4ef6d), unchecked((int) 0x07478cd1), unchecked((int) 0x006e1888), unchecked((int) 0xa2e53f55), unchecked((int) 0xb9e6d4bc),
+ unchecked((int) 0xa2048016), unchecked((int) 0x97573833), unchecked((int) 0xd7207d67), unchecked((int) 0xde0f8f3d), unchecked((int) 0x72f87b33), unchecked((int) 0xabcc4f33), unchecked((int) 0x7688c55d), unchecked((int) 0x7b00a6b0),
+ unchecked((int) 0x947b0001), unchecked((int) 0x570075d2), unchecked((int) 0xf9bb88f8), unchecked((int) 0x8942019e), unchecked((int) 0x4264a5ff), unchecked((int) 0x856302e0), unchecked((int) 0x72dbd92b), unchecked((int) 0xee971b69),
+ unchecked((int) 0x6ea22fde), unchecked((int) 0x5f08ae2b), unchecked((int) 0xaf7a616d), unchecked((int) 0xe5c98767), unchecked((int) 0xcf1febd2), unchecked((int) 0x61efc8c2), unchecked((int) 0xf1ac2571), unchecked((int) 0xcc8239c2),
+ unchecked((int) 0x67214cb8), unchecked((int) 0xb1e583d1), unchecked((int) 0xb7dc3e62), unchecked((int) 0x7f10bdce), unchecked((int) 0xf90a5c38), unchecked((int) 0x0ff0443d), unchecked((int) 0x606e6dc6), unchecked((int) 0x60543a49),
+ unchecked((int) 0x5727c148), unchecked((int) 0x2be98a1d), unchecked((int) 0x8ab41738), unchecked((int) 0x20e1be24), unchecked((int) 0xaf96da0f), unchecked((int) 0x68458425), unchecked((int) 0x99833be5), unchecked((int) 0x600d457d),
+ unchecked((int) 0x282f9350), unchecked((int) 0x8334b362), unchecked((int) 0xd91d1120), unchecked((int) 0x2b6d8da0), unchecked((int) 0x642b1e31), unchecked((int) 0x9c305a00), unchecked((int) 0x52bce688), unchecked((int) 0x1b03588a),
+ unchecked((int) 0xf7baefd5), unchecked((int) 0x4142ed9c), unchecked((int) 0xa4315c11), unchecked((int) 0x83323ec5), unchecked((int) 0xdfef4636), unchecked((int) 0xa133c501), unchecked((int) 0xe9d3531c), unchecked((int) 0xee353783)
+ },
+ S4 =
+ {
+ unchecked((int) 0x9db30420), unchecked((int) 0x1fb6e9de), unchecked((int) 0xa7be7bef), unchecked((int) 0xd273a298), unchecked((int) 0x4a4f7bdb), unchecked((int) 0x64ad8c57), unchecked((int) 0x85510443), unchecked((int) 0xfa020ed1),
+ unchecked((int) 0x7e287aff), unchecked((int) 0xe60fb663), unchecked((int) 0x095f35a1), unchecked((int) 0x79ebf120), unchecked((int) 0xfd059d43), unchecked((int) 0x6497b7b1), unchecked((int) 0xf3641f63), unchecked((int) 0x241e4adf),
+ unchecked((int) 0x28147f5f), unchecked((int) 0x4fa2b8cd), unchecked((int) 0xc9430040), unchecked((int) 0x0cc32220), unchecked((int) 0xfdd30b30), unchecked((int) 0xc0a5374f), unchecked((int) 0x1d2d00d9), unchecked((int) 0x24147b15),
+ unchecked((int) 0xee4d111a), unchecked((int) 0x0fca5167), unchecked((int) 0x71ff904c), unchecked((int) 0x2d195ffe), unchecked((int) 0x1a05645f), unchecked((int) 0x0c13fefe), unchecked((int) 0x081b08ca), unchecked((int) 0x05170121),
+ unchecked((int) 0x80530100), unchecked((int) 0xe83e5efe), unchecked((int) 0xac9af4f8), unchecked((int) 0x7fe72701), unchecked((int) 0xd2b8ee5f), unchecked((int) 0x06df4261), unchecked((int) 0xbb9e9b8a), unchecked((int) 0x7293ea25),
+ unchecked((int) 0xce84ffdf), unchecked((int) 0xf5718801), unchecked((int) 0x3dd64b04), unchecked((int) 0xa26f263b), unchecked((int) 0x7ed48400), unchecked((int) 0x547eebe6), unchecked((int) 0x446d4ca0), unchecked((int) 0x6cf3d6f5),
+ unchecked((int) 0x2649abdf), unchecked((int) 0xaea0c7f5), unchecked((int) 0x36338cc1), unchecked((int) 0x503f7e93), unchecked((int) 0xd3772061), unchecked((int) 0x11b638e1), unchecked((int) 0x72500e03), unchecked((int) 0xf80eb2bb),
+ unchecked((int) 0xabe0502e), unchecked((int) 0xec8d77de), unchecked((int) 0x57971e81), unchecked((int) 0xe14f6746), unchecked((int) 0xc9335400), unchecked((int) 0x6920318f), unchecked((int) 0x081dbb99), unchecked((int) 0xffc304a5),
+ unchecked((int) 0x4d351805), unchecked((int) 0x7f3d5ce3), unchecked((int) 0xa6c866c6), unchecked((int) 0x5d5bcca9), unchecked((int) 0xdaec6fea), unchecked((int) 0x9f926f91), unchecked((int) 0x9f46222f), unchecked((int) 0x3991467d),
+ unchecked((int) 0xa5bf6d8e), unchecked((int) 0x1143c44f), unchecked((int) 0x43958302), unchecked((int) 0xd0214eeb), unchecked((int) 0x022083b8), unchecked((int) 0x3fb6180c), unchecked((int) 0x18f8931e), unchecked((int) 0x281658e6),
+ unchecked((int) 0x26486e3e), unchecked((int) 0x8bd78a70), unchecked((int) 0x7477e4c1), unchecked((int) 0xb506e07c), unchecked((int) 0xf32d0a25), unchecked((int) 0x79098b02), unchecked((int) 0xe4eabb81), unchecked((int) 0x28123b23),
+ unchecked((int) 0x69dead38), unchecked((int) 0x1574ca16), unchecked((int) 0xdf871b62), unchecked((int) 0x211c40b7), unchecked((int) 0xa51a9ef9), unchecked((int) 0x0014377b), unchecked((int) 0x041e8ac8), unchecked((int) 0x09114003),
+ unchecked((int) 0xbd59e4d2), unchecked((int) 0xe3d156d5), unchecked((int) 0x4fe876d5), unchecked((int) 0x2f91a340), unchecked((int) 0x557be8de), unchecked((int) 0x00eae4a7), unchecked((int) 0x0ce5c2ec), unchecked((int) 0x4db4bba6),
+ unchecked((int) 0xe756bdff), unchecked((int) 0xdd3369ac), unchecked((int) 0xec17b035), unchecked((int) 0x06572327), unchecked((int) 0x99afc8b0), unchecked((int) 0x56c8c391), unchecked((int) 0x6b65811c), unchecked((int) 0x5e146119),
+ unchecked((int) 0x6e85cb75), unchecked((int) 0xbe07c002), unchecked((int) 0xc2325577), unchecked((int) 0x893ff4ec), unchecked((int) 0x5bbfc92d), unchecked((int) 0xd0ec3b25), unchecked((int) 0xb7801ab7), unchecked((int) 0x8d6d3b24),
+ unchecked((int) 0x20c763ef), unchecked((int) 0xc366a5fc), unchecked((int) 0x9c382880), unchecked((int) 0x0ace3205), unchecked((int) 0xaac9548a), unchecked((int) 0xeca1d7c7), unchecked((int) 0x041afa32), unchecked((int) 0x1d16625a),
+ unchecked((int) 0x6701902c), unchecked((int) 0x9b757a54), unchecked((int) 0x31d477f7), unchecked((int) 0x9126b031), unchecked((int) 0x36cc6fdb), unchecked((int) 0xc70b8b46), unchecked((int) 0xd9e66a48), unchecked((int) 0x56e55a79),
+ unchecked((int) 0x026a4ceb), unchecked((int) 0x52437eff), unchecked((int) 0x2f8f76b4), unchecked((int) 0x0df980a5), unchecked((int) 0x8674cde3), unchecked((int) 0xedda04eb), unchecked((int) 0x17a9be04), unchecked((int) 0x2c18f4df),
+ unchecked((int) 0xb7747f9d), unchecked((int) 0xab2af7b4), unchecked((int) 0xefc34d20), unchecked((int) 0x2e096b7c), unchecked((int) 0x1741a254), unchecked((int) 0xe5b6a035), unchecked((int) 0x213d42f6), unchecked((int) 0x2c1c7c26),
+ unchecked((int) 0x61c2f50f), unchecked((int) 0x6552daf9), unchecked((int) 0xd2c231f8), unchecked((int) 0x25130f69), unchecked((int) 0xd8167fa2), unchecked((int) 0x0418f2c8), unchecked((int) 0x001a96a6), unchecked((int) 0x0d1526ab),
+ unchecked((int) 0x63315c21), unchecked((int) 0x5e0a72ec), unchecked((int) 0x49bafefd), unchecked((int) 0x187908d9), unchecked((int) 0x8d0dbd86), unchecked((int) 0x311170a7), unchecked((int) 0x3e9b640c), unchecked((int) 0xcc3e10d7),
+ unchecked((int) 0xd5cad3b6), unchecked((int) 0x0caec388), unchecked((int) 0xf73001e1), unchecked((int) 0x6c728aff), unchecked((int) 0x71eae2a1), unchecked((int) 0x1f9af36e), unchecked((int) 0xcfcbd12f), unchecked((int) 0xc1de8417),
+ unchecked((int) 0xac07be6b), unchecked((int) 0xcb44a1d8), unchecked((int) 0x8b9b0f56), unchecked((int) 0x013988c3), unchecked((int) 0xb1c52fca), unchecked((int) 0xb4be31cd), unchecked((int) 0xd8782806), unchecked((int) 0x12a3a4e2),
+ unchecked((int) 0x6f7de532), unchecked((int) 0x58fd7eb6), unchecked((int) 0xd01ee900), unchecked((int) 0x24adffc2), unchecked((int) 0xf4990fc5), unchecked((int) 0x9711aac5), unchecked((int) 0x001d7b95), unchecked((int) 0x82e5e7d2),
+ unchecked((int) 0x109873f6), unchecked((int) 0x00613096), unchecked((int) 0xc32d9521), unchecked((int) 0xada121ff), unchecked((int) 0x29908415), unchecked((int) 0x7fbb977f), unchecked((int) 0xaf9eb3db), unchecked((int) 0x29c9ed2a),
+ unchecked((int) 0x5ce2a465), unchecked((int) 0xa730f32c), unchecked((int) 0xd0aa3fe8), unchecked((int) 0x8a5cc091), unchecked((int) 0xd49e2ce7), unchecked((int) 0x0ce454a9), unchecked((int) 0xd60acd86), unchecked((int) 0x015f1919),
+ unchecked((int) 0x77079103), unchecked((int) 0xdea03af6), unchecked((int) 0x78a8565e), unchecked((int) 0xdee356df), unchecked((int) 0x21f05cbe), unchecked((int) 0x8b75e387), unchecked((int) 0xb3c50651), unchecked((int) 0xb8a5c3ef),
+ unchecked((int) 0xd8eeb6d2), unchecked((int) 0xe523be77), unchecked((int) 0xc2154529), unchecked((int) 0x2f69efdf), unchecked((int) 0xafe67afb), unchecked((int) 0xf470c4b2), unchecked((int) 0xf3e0eb5b), unchecked((int) 0xd6cc9876),
+ unchecked((int) 0x39e4460c), unchecked((int) 0x1fda8538), unchecked((int) 0x1987832f), unchecked((int) 0xca007367), unchecked((int) 0xa99144f8), unchecked((int) 0x296b299e), unchecked((int) 0x492fc295), unchecked((int) 0x9266beab),
+ unchecked((int) 0xb5676e69), unchecked((int) 0x9bd3ddda), unchecked((int) 0xdf7e052f), unchecked((int) 0xdb25701c), unchecked((int) 0x1b5e51ee), unchecked((int) 0xf65324e6), unchecked((int) 0x6afce36c), unchecked((int) 0x0316cc04),
+ unchecked((int) 0x8644213e), unchecked((int) 0xb7dc59d0), unchecked((int) 0x7965291f), unchecked((int) 0xccd6fd43), unchecked((int) 0x41823979), unchecked((int) 0x932bcdf6), unchecked((int) 0xb657c34d), unchecked((int) 0x4edfd282),
+ unchecked((int) 0x7ae5290c), unchecked((int) 0x3cb9536b), unchecked((int) 0x851e20fe), unchecked((int) 0x9833557e), unchecked((int) 0x13ecf0b0), unchecked((int) 0xd3ffb372), unchecked((int) 0x3f85c5c1), unchecked((int) 0x0aef7ed2)
+ },
+ S5 =
+ {
+ unchecked((int) 0x7ec90c04), unchecked((int) 0x2c6e74b9), unchecked((int) 0x9b0e66df), unchecked((int) 0xa6337911), unchecked((int) 0xb86a7fff), unchecked((int) 0x1dd358f5), unchecked((int) 0x44dd9d44), unchecked((int) 0x1731167f),
+ unchecked((int) 0x08fbf1fa), unchecked((int) 0xe7f511cc), unchecked((int) 0xd2051b00), unchecked((int) 0x735aba00), unchecked((int) 0x2ab722d8), unchecked((int) 0x386381cb), unchecked((int) 0xacf6243a), unchecked((int) 0x69befd7a),
+ unchecked((int) 0xe6a2e77f), unchecked((int) 0xf0c720cd), unchecked((int) 0xc4494816), unchecked((int) 0xccf5c180), unchecked((int) 0x38851640), unchecked((int) 0x15b0a848), unchecked((int) 0xe68b18cb), unchecked((int) 0x4caadeff),
+ unchecked((int) 0x5f480a01), unchecked((int) 0x0412b2aa), unchecked((int) 0x259814fc), unchecked((int) 0x41d0efe2), unchecked((int) 0x4e40b48d), unchecked((int) 0x248eb6fb), unchecked((int) 0x8dba1cfe), unchecked((int) 0x41a99b02),
+ unchecked((int) 0x1a550a04), unchecked((int) 0xba8f65cb), unchecked((int) 0x7251f4e7), unchecked((int) 0x95a51725), unchecked((int) 0xc106ecd7), unchecked((int) 0x97a5980a), unchecked((int) 0xc539b9aa), unchecked((int) 0x4d79fe6a),
+ unchecked((int) 0xf2f3f763), unchecked((int) 0x68af8040), unchecked((int) 0xed0c9e56), unchecked((int) 0x11b4958b), unchecked((int) 0xe1eb5a88), unchecked((int) 0x8709e6b0), unchecked((int) 0xd7e07156), unchecked((int) 0x4e29fea7),
+ unchecked((int) 0x6366e52d), unchecked((int) 0x02d1c000), unchecked((int) 0xc4ac8e05), unchecked((int) 0x9377f571), unchecked((int) 0x0c05372a), unchecked((int) 0x578535f2), unchecked((int) 0x2261be02), unchecked((int) 0xd642a0c9),
+ unchecked((int) 0xdf13a280), unchecked((int) 0x74b55bd2), unchecked((int) 0x682199c0), unchecked((int) 0xd421e5ec), unchecked((int) 0x53fb3ce8), unchecked((int) 0xc8adedb3), unchecked((int) 0x28a87fc9), unchecked((int) 0x3d959981),
+ unchecked((int) 0x5c1ff900), unchecked((int) 0xfe38d399), unchecked((int) 0x0c4eff0b), unchecked((int) 0x062407ea), unchecked((int) 0xaa2f4fb1), unchecked((int) 0x4fb96976), unchecked((int) 0x90c79505), unchecked((int) 0xb0a8a774),
+ unchecked((int) 0xef55a1ff), unchecked((int) 0xe59ca2c2), unchecked((int) 0xa6b62d27), unchecked((int) 0xe66a4263), unchecked((int) 0xdf65001f), unchecked((int) 0x0ec50966), unchecked((int) 0xdfdd55bc), unchecked((int) 0x29de0655),
+ unchecked((int) 0x911e739a), unchecked((int) 0x17af8975), unchecked((int) 0x32c7911c), unchecked((int) 0x89f89468), unchecked((int) 0x0d01e980), unchecked((int) 0x524755f4), unchecked((int) 0x03b63cc9), unchecked((int) 0x0cc844b2),
+ unchecked((int) 0xbcf3f0aa), unchecked((int) 0x87ac36e9), unchecked((int) 0xe53a7426), unchecked((int) 0x01b3d82b), unchecked((int) 0x1a9e7449), unchecked((int) 0x64ee2d7e), unchecked((int) 0xcddbb1da), unchecked((int) 0x01c94910),
+ unchecked((int) 0xb868bf80), unchecked((int) 0x0d26f3fd), unchecked((int) 0x9342ede7), unchecked((int) 0x04a5c284), unchecked((int) 0x636737b6), unchecked((int) 0x50f5b616), unchecked((int) 0xf24766e3), unchecked((int) 0x8eca36c1),
+ unchecked((int) 0x136e05db), unchecked((int) 0xfef18391), unchecked((int) 0xfb887a37), unchecked((int) 0xd6e7f7d4), unchecked((int) 0xc7fb7dc9), unchecked((int) 0x3063fcdf), unchecked((int) 0xb6f589de), unchecked((int) 0xec2941da),
+ unchecked((int) 0x26e46695), unchecked((int) 0xb7566419), unchecked((int) 0xf654efc5), unchecked((int) 0xd08d58b7), unchecked((int) 0x48925401), unchecked((int) 0xc1bacb7f), unchecked((int) 0xe5ff550f), unchecked((int) 0xb6083049),
+ unchecked((int) 0x5bb5d0e8), unchecked((int) 0x87d72e5a), unchecked((int) 0xab6a6ee1), unchecked((int) 0x223a66ce), unchecked((int) 0xc62bf3cd), unchecked((int) 0x9e0885f9), unchecked((int) 0x68cb3e47), unchecked((int) 0x086c010f),
+ unchecked((int) 0xa21de820), unchecked((int) 0xd18b69de), unchecked((int) 0xf3f65777), unchecked((int) 0xfa02c3f6), unchecked((int) 0x407edac3), unchecked((int) 0xcbb3d550), unchecked((int) 0x1793084d), unchecked((int) 0xb0d70eba),
+ unchecked((int) 0x0ab378d5), unchecked((int) 0xd951fb0c), unchecked((int) 0xded7da56), unchecked((int) 0x4124bbe4), unchecked((int) 0x94ca0b56), unchecked((int) 0x0f5755d1), unchecked((int) 0xe0e1e56e), unchecked((int) 0x6184b5be),
+ unchecked((int) 0x580a249f), unchecked((int) 0x94f74bc0), unchecked((int) 0xe327888e), unchecked((int) 0x9f7b5561), unchecked((int) 0xc3dc0280), unchecked((int) 0x05687715), unchecked((int) 0x646c6bd7), unchecked((int) 0x44904db3),
+ unchecked((int) 0x66b4f0a3), unchecked((int) 0xc0f1648a), unchecked((int) 0x697ed5af), unchecked((int) 0x49e92ff6), unchecked((int) 0x309e374f), unchecked((int) 0x2cb6356a), unchecked((int) 0x85808573), unchecked((int) 0x4991f840),
+ unchecked((int) 0x76f0ae02), unchecked((int) 0x083be84d), unchecked((int) 0x28421c9a), unchecked((int) 0x44489406), unchecked((int) 0x736e4cb8), unchecked((int) 0xc1092910), unchecked((int) 0x8bc95fc6), unchecked((int) 0x7d869cf4),
+ unchecked((int) 0x134f616f), unchecked((int) 0x2e77118d), unchecked((int) 0xb31b2be1), unchecked((int) 0xaa90b472), unchecked((int) 0x3ca5d717), unchecked((int) 0x7d161bba), unchecked((int) 0x9cad9010), unchecked((int) 0xaf462ba2),
+ unchecked((int) 0x9fe459d2), unchecked((int) 0x45d34559), unchecked((int) 0xd9f2da13), unchecked((int) 0xdbc65487), unchecked((int) 0xf3e4f94e), unchecked((int) 0x176d486f), unchecked((int) 0x097c13ea), unchecked((int) 0x631da5c7),
+ unchecked((int) 0x445f7382), unchecked((int) 0x175683f4), unchecked((int) 0xcdc66a97), unchecked((int) 0x70be0288), unchecked((int) 0xb3cdcf72), unchecked((int) 0x6e5dd2f3), unchecked((int) 0x20936079), unchecked((int) 0x459b80a5),
+ unchecked((int) 0xbe60e2db), unchecked((int) 0xa9c23101), unchecked((int) 0xeba5315c), unchecked((int) 0x224e42f2), unchecked((int) 0x1c5c1572), unchecked((int) 0xf6721b2c), unchecked((int) 0x1ad2fff3), unchecked((int) 0x8c25404e),
+ unchecked((int) 0x324ed72f), unchecked((int) 0x4067b7fd), unchecked((int) 0x0523138e), unchecked((int) 0x5ca3bc78), unchecked((int) 0xdc0fd66e), unchecked((int) 0x75922283), unchecked((int) 0x784d6b17), unchecked((int) 0x58ebb16e),
+ unchecked((int) 0x44094f85), unchecked((int) 0x3f481d87), unchecked((int) 0xfcfeae7b), unchecked((int) 0x77b5ff76), unchecked((int) 0x8c2302bf), unchecked((int) 0xaaf47556), unchecked((int) 0x5f46b02a), unchecked((int) 0x2b092801),
+ unchecked((int) 0x3d38f5f7), unchecked((int) 0x0ca81f36), unchecked((int) 0x52af4a8a), unchecked((int) 0x66d5e7c0), unchecked((int) 0xdf3b0874), unchecked((int) 0x95055110), unchecked((int) 0x1b5ad7a8), unchecked((int) 0xf61ed5ad),
+ unchecked((int) 0x6cf6e479), unchecked((int) 0x20758184), unchecked((int) 0xd0cefa65), unchecked((int) 0x88f7be58), unchecked((int) 0x4a046826), unchecked((int) 0x0ff6f8f3), unchecked((int) 0xa09c7f70), unchecked((int) 0x5346aba0),
+ unchecked((int) 0x5ce96c28), unchecked((int) 0xe176eda3), unchecked((int) 0x6bac307f), unchecked((int) 0x376829d2), unchecked((int) 0x85360fa9), unchecked((int) 0x17e3fe2a), unchecked((int) 0x24b79767), unchecked((int) 0xf5a96b20),
+ unchecked((int) 0xd6cd2595), unchecked((int) 0x68ff1ebf), unchecked((int) 0x7555442c), unchecked((int) 0xf19f06be), unchecked((int) 0xf9e0659a), unchecked((int) 0xeeb9491d), unchecked((int) 0x34010718), unchecked((int) 0xbb30cab8),
+ unchecked((int) 0xe822fe15), unchecked((int) 0x88570983), unchecked((int) 0x750e6249), unchecked((int) 0xda627e55), unchecked((int) 0x5e76ffa8), unchecked((int) 0xb1534546), unchecked((int) 0x6d47de08), unchecked((int) 0xefe9e7d4)
+ },
+ S6 =
+ {
+ unchecked((int) 0xf6fa8f9d), unchecked((int) 0x2cac6ce1), unchecked((int) 0x4ca34867), unchecked((int) 0xe2337f7c), unchecked((int) 0x95db08e7), unchecked((int) 0x016843b4), unchecked((int) 0xeced5cbc), unchecked((int) 0x325553ac),
+ unchecked((int) 0xbf9f0960), unchecked((int) 0xdfa1e2ed), unchecked((int) 0x83f0579d), unchecked((int) 0x63ed86b9), unchecked((int) 0x1ab6a6b8), unchecked((int) 0xde5ebe39), unchecked((int) 0xf38ff732), unchecked((int) 0x8989b138),
+ unchecked((int) 0x33f14961), unchecked((int) 0xc01937bd), unchecked((int) 0xf506c6da), unchecked((int) 0xe4625e7e), unchecked((int) 0xa308ea99), unchecked((int) 0x4e23e33c), unchecked((int) 0x79cbd7cc), unchecked((int) 0x48a14367),
+ unchecked((int) 0xa3149619), unchecked((int) 0xfec94bd5), unchecked((int) 0xa114174a), unchecked((int) 0xeaa01866), unchecked((int) 0xa084db2d), unchecked((int) 0x09a8486f), unchecked((int) 0xa888614a), unchecked((int) 0x2900af98),
+ unchecked((int) 0x01665991), unchecked((int) 0xe1992863), unchecked((int) 0xc8f30c60), unchecked((int) 0x2e78ef3c), unchecked((int) 0xd0d51932), unchecked((int) 0xcf0fec14), unchecked((int) 0xf7ca07d2), unchecked((int) 0xd0a82072),
+ unchecked((int) 0xfd41197e), unchecked((int) 0x9305a6b0), unchecked((int) 0xe86be3da), unchecked((int) 0x74bed3cd), unchecked((int) 0x372da53c), unchecked((int) 0x4c7f4448), unchecked((int) 0xdab5d440), unchecked((int) 0x6dba0ec3),
+ unchecked((int) 0x083919a7), unchecked((int) 0x9fbaeed9), unchecked((int) 0x49dbcfb0), unchecked((int) 0x4e670c53), unchecked((int) 0x5c3d9c01), unchecked((int) 0x64bdb941), unchecked((int) 0x2c0e636a), unchecked((int) 0xba7dd9cd),
+ unchecked((int) 0xea6f7388), unchecked((int) 0xe70bc762), unchecked((int) 0x35f29adb), unchecked((int) 0x5c4cdd8d), unchecked((int) 0xf0d48d8c), unchecked((int) 0xb88153e2), unchecked((int) 0x08a19866), unchecked((int) 0x1ae2eac8),
+ unchecked((int) 0x284caf89), unchecked((int) 0xaa928223), unchecked((int) 0x9334be53), unchecked((int) 0x3b3a21bf), unchecked((int) 0x16434be3), unchecked((int) 0x9aea3906), unchecked((int) 0xefe8c36e), unchecked((int) 0xf890cdd9),
+ unchecked((int) 0x80226dae), unchecked((int) 0xc340a4a3), unchecked((int) 0xdf7e9c09), unchecked((int) 0xa694a807), unchecked((int) 0x5b7c5ecc), unchecked((int) 0x221db3a6), unchecked((int) 0x9a69a02f), unchecked((int) 0x68818a54),
+ unchecked((int) 0xceb2296f), unchecked((int) 0x53c0843a), unchecked((int) 0xfe893655), unchecked((int) 0x25bfe68a), unchecked((int) 0xb4628abc), unchecked((int) 0xcf222ebf), unchecked((int) 0x25ac6f48), unchecked((int) 0xa9a99387),
+ unchecked((int) 0x53bddb65), unchecked((int) 0xe76ffbe7), unchecked((int) 0xe967fd78), unchecked((int) 0x0ba93563), unchecked((int) 0x8e342bc1), unchecked((int) 0xe8a11be9), unchecked((int) 0x4980740d), unchecked((int) 0xc8087dfc),
+ unchecked((int) 0x8de4bf99), unchecked((int) 0xa11101a0), unchecked((int) 0x7fd37975), unchecked((int) 0xda5a26c0), unchecked((int) 0xe81f994f), unchecked((int) 0x9528cd89), unchecked((int) 0xfd339fed), unchecked((int) 0xb87834bf),
+ unchecked((int) 0x5f04456d), unchecked((int) 0x22258698), unchecked((int) 0xc9c4c83b), unchecked((int) 0x2dc156be), unchecked((int) 0x4f628daa), unchecked((int) 0x57f55ec5), unchecked((int) 0xe2220abe), unchecked((int) 0xd2916ebf),
+ unchecked((int) 0x4ec75b95), unchecked((int) 0x24f2c3c0), unchecked((int) 0x42d15d99), unchecked((int) 0xcd0d7fa0), unchecked((int) 0x7b6e27ff), unchecked((int) 0xa8dc8af0), unchecked((int) 0x7345c106), unchecked((int) 0xf41e232f),
+ unchecked((int) 0x35162386), unchecked((int) 0xe6ea8926), unchecked((int) 0x3333b094), unchecked((int) 0x157ec6f2), unchecked((int) 0x372b74af), unchecked((int) 0x692573e4), unchecked((int) 0xe9a9d848), unchecked((int) 0xf3160289),
+ unchecked((int) 0x3a62ef1d), unchecked((int) 0xa787e238), unchecked((int) 0xf3a5f676), unchecked((int) 0x74364853), unchecked((int) 0x20951063), unchecked((int) 0x4576698d), unchecked((int) 0xb6fad407), unchecked((int) 0x592af950),
+ unchecked((int) 0x36f73523), unchecked((int) 0x4cfb6e87), unchecked((int) 0x7da4cec0), unchecked((int) 0x6c152daa), unchecked((int) 0xcb0396a8), unchecked((int) 0xc50dfe5d), unchecked((int) 0xfcd707ab), unchecked((int) 0x0921c42f),
+ unchecked((int) 0x89dff0bb), unchecked((int) 0x5fe2be78), unchecked((int) 0x448f4f33), unchecked((int) 0x754613c9), unchecked((int) 0x2b05d08d), unchecked((int) 0x48b9d585), unchecked((int) 0xdc049441), unchecked((int) 0xc8098f9b),
+ unchecked((int) 0x7dede786), unchecked((int) 0xc39a3373), unchecked((int) 0x42410005), unchecked((int) 0x6a091751), unchecked((int) 0x0ef3c8a6), unchecked((int) 0x890072d6), unchecked((int) 0x28207682), unchecked((int) 0xa9a9f7be),
+ unchecked((int) 0xbf32679d), unchecked((int) 0xd45b5b75), unchecked((int) 0xb353fd00), unchecked((int) 0xcbb0e358), unchecked((int) 0x830f220a), unchecked((int) 0x1f8fb214), unchecked((int) 0xd372cf08), unchecked((int) 0xcc3c4a13),
+ unchecked((int) 0x8cf63166), unchecked((int) 0x061c87be), unchecked((int) 0x88c98f88), unchecked((int) 0x6062e397), unchecked((int) 0x47cf8e7a), unchecked((int) 0xb6c85283), unchecked((int) 0x3cc2acfb), unchecked((int) 0x3fc06976),
+ unchecked((int) 0x4e8f0252), unchecked((int) 0x64d8314d), unchecked((int) 0xda3870e3), unchecked((int) 0x1e665459), unchecked((int) 0xc10908f0), unchecked((int) 0x513021a5), unchecked((int) 0x6c5b68b7), unchecked((int) 0x822f8aa0),
+ unchecked((int) 0x3007cd3e), unchecked((int) 0x74719eef), unchecked((int) 0xdc872681), unchecked((int) 0x073340d4), unchecked((int) 0x7e432fd9), unchecked((int) 0x0c5ec241), unchecked((int) 0x8809286c), unchecked((int) 0xf592d891),
+ unchecked((int) 0x08a930f6), unchecked((int) 0x957ef305), unchecked((int) 0xb7fbffbd), unchecked((int) 0xc266e96f), unchecked((int) 0x6fe4ac98), unchecked((int) 0xb173ecc0), unchecked((int) 0xbc60b42a), unchecked((int) 0x953498da),
+ unchecked((int) 0xfba1ae12), unchecked((int) 0x2d4bd736), unchecked((int) 0x0f25faab), unchecked((int) 0xa4f3fceb), unchecked((int) 0xe2969123), unchecked((int) 0x257f0c3d), unchecked((int) 0x9348af49), unchecked((int) 0x361400bc),
+ unchecked((int) 0xe8816f4a), unchecked((int) 0x3814f200), unchecked((int) 0xa3f94043), unchecked((int) 0x9c7a54c2), unchecked((int) 0xbc704f57), unchecked((int) 0xda41e7f9), unchecked((int) 0xc25ad33a), unchecked((int) 0x54f4a084),
+ unchecked((int) 0xb17f5505), unchecked((int) 0x59357cbe), unchecked((int) 0xedbd15c8), unchecked((int) 0x7f97c5ab), unchecked((int) 0xba5ac7b5), unchecked((int) 0xb6f6deaf), unchecked((int) 0x3a479c3a), unchecked((int) 0x5302da25),
+ unchecked((int) 0x653d7e6a), unchecked((int) 0x54268d49), unchecked((int) 0x51a477ea), unchecked((int) 0x5017d55b), unchecked((int) 0xd7d25d88), unchecked((int) 0x44136c76), unchecked((int) 0x0404a8c8), unchecked((int) 0xb8e5a121),
+ unchecked((int) 0xb81a928a), unchecked((int) 0x60ed5869), unchecked((int) 0x97c55b96), unchecked((int) 0xeaec991b), unchecked((int) 0x29935913), unchecked((int) 0x01fdb7f1), unchecked((int) 0x088e8dfa), unchecked((int) 0x9ab6f6f5),
+ unchecked((int) 0x3b4cbf9f), unchecked((int) 0x4a5de3ab), unchecked((int) 0xe6051d35), unchecked((int) 0xa0e1d855), unchecked((int) 0xd36b4cf1), unchecked((int) 0xf544edeb), unchecked((int) 0xb0e93524), unchecked((int) 0xbebb8fbd),
+ unchecked((int) 0xa2d762cf), unchecked((int) 0x49c92f54), unchecked((int) 0x38b5f331), unchecked((int) 0x7128a454), unchecked((int) 0x48392905), unchecked((int) 0xa65b1db8), unchecked((int) 0x851c97bd), unchecked((int) 0xd675cf2f)
+ },
+ S7 =
+ {
+ unchecked((int) 0x85e04019), unchecked((int) 0x332bf567), unchecked((int) 0x662dbfff), unchecked((int) 0xcfc65693), unchecked((int) 0x2a8d7f6f), unchecked((int) 0xab9bc912), unchecked((int) 0xde6008a1), unchecked((int) 0x2028da1f),
+ unchecked((int) 0x0227bce7), unchecked((int) 0x4d642916), unchecked((int) 0x18fac300), unchecked((int) 0x50f18b82), unchecked((int) 0x2cb2cb11), unchecked((int) 0xb232e75c), unchecked((int) 0x4b3695f2), unchecked((int) 0xb28707de),
+ unchecked((int) 0xa05fbcf6), unchecked((int) 0xcd4181e9), unchecked((int) 0xe150210c), unchecked((int) 0xe24ef1bd), unchecked((int) 0xb168c381), unchecked((int) 0xfde4e789), unchecked((int) 0x5c79b0d8), unchecked((int) 0x1e8bfd43),
+ unchecked((int) 0x4d495001), unchecked((int) 0x38be4341), unchecked((int) 0x913cee1d), unchecked((int) 0x92a79c3f), unchecked((int) 0x089766be), unchecked((int) 0xbaeeadf4), unchecked((int) 0x1286becf), unchecked((int) 0xb6eacb19),
+ unchecked((int) 0x2660c200), unchecked((int) 0x7565bde4), unchecked((int) 0x64241f7a), unchecked((int) 0x8248dca9), unchecked((int) 0xc3b3ad66), unchecked((int) 0x28136086), unchecked((int) 0x0bd8dfa8), unchecked((int) 0x356d1cf2),
+ unchecked((int) 0x107789be), unchecked((int) 0xb3b2e9ce), unchecked((int) 0x0502aa8f), unchecked((int) 0x0bc0351e), unchecked((int) 0x166bf52a), unchecked((int) 0xeb12ff82), unchecked((int) 0xe3486911), unchecked((int) 0xd34d7516),
+ unchecked((int) 0x4e7b3aff), unchecked((int) 0x5f43671b), unchecked((int) 0x9cf6e037), unchecked((int) 0x4981ac83), unchecked((int) 0x334266ce), unchecked((int) 0x8c9341b7), unchecked((int) 0xd0d854c0), unchecked((int) 0xcb3a6c88),
+ unchecked((int) 0x47bc2829), unchecked((int) 0x4725ba37), unchecked((int) 0xa66ad22b), unchecked((int) 0x7ad61f1e), unchecked((int) 0x0c5cbafa), unchecked((int) 0x4437f107), unchecked((int) 0xb6e79962), unchecked((int) 0x42d2d816),
+ unchecked((int) 0x0a961288), unchecked((int) 0xe1a5c06e), unchecked((int) 0x13749e67), unchecked((int) 0x72fc081a), unchecked((int) 0xb1d139f7), unchecked((int) 0xf9583745), unchecked((int) 0xcf19df58), unchecked((int) 0xbec3f756),
+ unchecked((int) 0xc06eba30), unchecked((int) 0x07211b24), unchecked((int) 0x45c28829), unchecked((int) 0xc95e317f), unchecked((int) 0xbc8ec511), unchecked((int) 0x38bc46e9), unchecked((int) 0xc6e6fa14), unchecked((int) 0xbae8584a),
+ unchecked((int) 0xad4ebc46), unchecked((int) 0x468f508b), unchecked((int) 0x7829435f), unchecked((int) 0xf124183b), unchecked((int) 0x821dba9f), unchecked((int) 0xaff60ff4), unchecked((int) 0xea2c4e6d), unchecked((int) 0x16e39264),
+ unchecked((int) 0x92544a8b), unchecked((int) 0x009b4fc3), unchecked((int) 0xaba68ced), unchecked((int) 0x9ac96f78), unchecked((int) 0x06a5b79a), unchecked((int) 0xb2856e6e), unchecked((int) 0x1aec3ca9), unchecked((int) 0xbe838688),
+ unchecked((int) 0x0e0804e9), unchecked((int) 0x55f1be56), unchecked((int) 0xe7e5363b), unchecked((int) 0xb3a1f25d), unchecked((int) 0xf7debb85), unchecked((int) 0x61fe033c), unchecked((int) 0x16746233), unchecked((int) 0x3c034c28),
+ unchecked((int) 0xda6d0c74), unchecked((int) 0x79aac56c), unchecked((int) 0x3ce4e1ad), unchecked((int) 0x51f0c802), unchecked((int) 0x98f8f35a), unchecked((int) 0x1626a49f), unchecked((int) 0xeed82b29), unchecked((int) 0x1d382fe3),
+ unchecked((int) 0x0c4fb99a), unchecked((int) 0xbb325778), unchecked((int) 0x3ec6d97b), unchecked((int) 0x6e77a6a9), unchecked((int) 0xcb658b5c), unchecked((int) 0xd45230c7), unchecked((int) 0x2bd1408b), unchecked((int) 0x60c03eb7),
+ unchecked((int) 0xb9068d78), unchecked((int) 0xa33754f4), unchecked((int) 0xf430c87d), unchecked((int) 0xc8a71302), unchecked((int) 0xb96d8c32), unchecked((int) 0xebd4e7be), unchecked((int) 0xbe8b9d2d), unchecked((int) 0x7979fb06),
+ unchecked((int) 0xe7225308), unchecked((int) 0x8b75cf77), unchecked((int) 0x11ef8da4), unchecked((int) 0xe083c858), unchecked((int) 0x8d6b786f), unchecked((int) 0x5a6317a6), unchecked((int) 0xfa5cf7a0), unchecked((int) 0x5dda0033),
+ unchecked((int) 0xf28ebfb0), unchecked((int) 0xf5b9c310), unchecked((int) 0xa0eac280), unchecked((int) 0x08b9767a), unchecked((int) 0xa3d9d2b0), unchecked((int) 0x79d34217), unchecked((int) 0x021a718d), unchecked((int) 0x9ac6336a),
+ unchecked((int) 0x2711fd60), unchecked((int) 0x438050e3), unchecked((int) 0x069908a8), unchecked((int) 0x3d7fedc4), unchecked((int) 0x826d2bef), unchecked((int) 0x4eeb8476), unchecked((int) 0x488dcf25), unchecked((int) 0x36c9d566),
+ unchecked((int) 0x28e74e41), unchecked((int) 0xc2610aca), unchecked((int) 0x3d49a9cf), unchecked((int) 0xbae3b9df), unchecked((int) 0xb65f8de6), unchecked((int) 0x92aeaf64), unchecked((int) 0x3ac7d5e6), unchecked((int) 0x9ea80509),
+ unchecked((int) 0xf22b017d), unchecked((int) 0xa4173f70), unchecked((int) 0xdd1e16c3), unchecked((int) 0x15e0d7f9), unchecked((int) 0x50b1b887), unchecked((int) 0x2b9f4fd5), unchecked((int) 0x625aba82), unchecked((int) 0x6a017962),
+ unchecked((int) 0x2ec01b9c), unchecked((int) 0x15488aa9), unchecked((int) 0xd716e740), unchecked((int) 0x40055a2c), unchecked((int) 0x93d29a22), unchecked((int) 0xe32dbf9a), unchecked((int) 0x058745b9), unchecked((int) 0x3453dc1e),
+ unchecked((int) 0xd699296e), unchecked((int) 0x496cff6f), unchecked((int) 0x1c9f4986), unchecked((int) 0xdfe2ed07), unchecked((int) 0xb87242d1), unchecked((int) 0x19de7eae), unchecked((int) 0x053e561a), unchecked((int) 0x15ad6f8c),
+ unchecked((int) 0x66626c1c), unchecked((int) 0x7154c24c), unchecked((int) 0xea082b2a), unchecked((int) 0x93eb2939), unchecked((int) 0x17dcb0f0), unchecked((int) 0x58d4f2ae), unchecked((int) 0x9ea294fb), unchecked((int) 0x52cf564c),
+ unchecked((int) 0x9883fe66), unchecked((int) 0x2ec40581), unchecked((int) 0x763953c3), unchecked((int) 0x01d6692e), unchecked((int) 0xd3a0c108), unchecked((int) 0xa1e7160e), unchecked((int) 0xe4f2dfa6), unchecked((int) 0x693ed285),
+ unchecked((int) 0x74904698), unchecked((int) 0x4c2b0edd), unchecked((int) 0x4f757656), unchecked((int) 0x5d393378), unchecked((int) 0xa132234f), unchecked((int) 0x3d321c5d), unchecked((int) 0xc3f5e194), unchecked((int) 0x4b269301),
+ unchecked((int) 0xc79f022f), unchecked((int) 0x3c997e7e), unchecked((int) 0x5e4f9504), unchecked((int) 0x3ffafbbd), unchecked((int) 0x76f7ad0e), unchecked((int) 0x296693f4), unchecked((int) 0x3d1fce6f), unchecked((int) 0xc61e45be),
+ unchecked((int) 0xd3b5ab34), unchecked((int) 0xf72bf9b7), unchecked((int) 0x1b0434c0), unchecked((int) 0x4e72b567), unchecked((int) 0x5592a33d), unchecked((int) 0xb5229301), unchecked((int) 0xcfd2a87f), unchecked((int) 0x60aeb767),
+ unchecked((int) 0x1814386b), unchecked((int) 0x30bcc33d), unchecked((int) 0x38a0c07d), unchecked((int) 0xfd1606f2), unchecked((int) 0xc363519b), unchecked((int) 0x589dd390), unchecked((int) 0x5479f8e6), unchecked((int) 0x1cb8d647),
+ unchecked((int) 0x97fd61a9), unchecked((int) 0xea7759f4), unchecked((int) 0x2d57539d), unchecked((int) 0x569a58cf), unchecked((int) 0xe84e63ad), unchecked((int) 0x462e1b78), unchecked((int) 0x6580f87e), unchecked((int) 0xf3817914),
+ unchecked((int) 0x91da55f4), unchecked((int) 0x40a230f3), unchecked((int) 0xd1988f35), unchecked((int) 0xb6e318d2), unchecked((int) 0x3ffa50bc), unchecked((int) 0x3d40f021), unchecked((int) 0xc3c0bdae), unchecked((int) 0x4958c24c),
+ unchecked((int) 0x518f36b2), unchecked((int) 0x84b1d370), unchecked((int) 0x0fedce83), unchecked((int) 0x878ddada), unchecked((int) 0xf2a279c7), unchecked((int) 0x94e01be8), unchecked((int) 0x90716f4b), unchecked((int) 0x954b8aa3)
+ },
+ S8 =
+ {
+ unchecked((int) 0xe216300d), unchecked((int) 0xbbddfffc), unchecked((int) 0xa7ebdabd), unchecked((int) 0x35648095), unchecked((int) 0x7789f8b7), unchecked((int) 0xe6c1121b), unchecked((int) 0x0e241600), unchecked((int) 0x052ce8b5),
+ unchecked((int) 0x11a9cfb0), unchecked((int) 0xe5952f11), unchecked((int) 0xece7990a), unchecked((int) 0x9386d174), unchecked((int) 0x2a42931c), unchecked((int) 0x76e38111), unchecked((int) 0xb12def3a), unchecked((int) 0x37ddddfc),
+ unchecked((int) 0xde9adeb1), unchecked((int) 0x0a0cc32c), unchecked((int) 0xbe197029), unchecked((int) 0x84a00940), unchecked((int) 0xbb243a0f), unchecked((int) 0xb4d137cf), unchecked((int) 0xb44e79f0), unchecked((int) 0x049eedfd),
+ unchecked((int) 0x0b15a15d), unchecked((int) 0x480d3168), unchecked((int) 0x8bbbde5a), unchecked((int) 0x669ded42), unchecked((int) 0xc7ece831), unchecked((int) 0x3f8f95e7), unchecked((int) 0x72df191b), unchecked((int) 0x7580330d),
+ unchecked((int) 0x94074251), unchecked((int) 0x5c7dcdfa), unchecked((int) 0xabbe6d63), unchecked((int) 0xaa402164), unchecked((int) 0xb301d40a), unchecked((int) 0x02e7d1ca), unchecked((int) 0x53571dae), unchecked((int) 0x7a3182a2),
+ unchecked((int) 0x12a8ddec), unchecked((int) 0xfdaa335d), unchecked((int) 0x176f43e8), unchecked((int) 0x71fb46d4), unchecked((int) 0x38129022), unchecked((int) 0xce949ad4), unchecked((int) 0xb84769ad), unchecked((int) 0x965bd862),
+ unchecked((int) 0x82f3d055), unchecked((int) 0x66fb9767), unchecked((int) 0x15b80b4e), unchecked((int) 0x1d5b47a0), unchecked((int) 0x4cfde06f), unchecked((int) 0xc28ec4b8), unchecked((int) 0x57e8726e), unchecked((int) 0x647a78fc),
+ unchecked((int) 0x99865d44), unchecked((int) 0x608bd593), unchecked((int) 0x6c200e03), unchecked((int) 0x39dc5ff6), unchecked((int) 0x5d0b00a3), unchecked((int) 0xae63aff2), unchecked((int) 0x7e8bd632), unchecked((int) 0x70108c0c),
+ unchecked((int) 0xbbd35049), unchecked((int) 0x2998df04), unchecked((int) 0x980cf42a), unchecked((int) 0x9b6df491), unchecked((int) 0x9e7edd53), unchecked((int) 0x06918548), unchecked((int) 0x58cb7e07), unchecked((int) 0x3b74ef2e),
+ unchecked((int) 0x522fffb1), unchecked((int) 0xd24708cc), unchecked((int) 0x1c7e27cd), unchecked((int) 0xa4eb215b), unchecked((int) 0x3cf1d2e2), unchecked((int) 0x19b47a38), unchecked((int) 0x424f7618), unchecked((int) 0x35856039),
+ unchecked((int) 0x9d17dee7), unchecked((int) 0x27eb35e6), unchecked((int) 0xc9aff67b), unchecked((int) 0x36baf5b8), unchecked((int) 0x09c467cd), unchecked((int) 0xc18910b1), unchecked((int) 0xe11dbf7b), unchecked((int) 0x06cd1af8),
+ unchecked((int) 0x7170c608), unchecked((int) 0x2d5e3354), unchecked((int) 0xd4de495a), unchecked((int) 0x64c6d006), unchecked((int) 0xbcc0c62c), unchecked((int) 0x3dd00db3), unchecked((int) 0x708f8f34), unchecked((int) 0x77d51b42),
+ unchecked((int) 0x264f620f), unchecked((int) 0x24b8d2bf), unchecked((int) 0x15c1b79e), unchecked((int) 0x46a52564), unchecked((int) 0xf8d7e54e), unchecked((int) 0x3e378160), unchecked((int) 0x7895cda5), unchecked((int) 0x859c15a5),
+ unchecked((int) 0xe6459788), unchecked((int) 0xc37bc75f), unchecked((int) 0xdb07ba0c), unchecked((int) 0x0676a3ab), unchecked((int) 0x7f229b1e), unchecked((int) 0x31842e7b), unchecked((int) 0x24259fd7), unchecked((int) 0xf8bef472),
+ unchecked((int) 0x835ffcb8), unchecked((int) 0x6df4c1f2), unchecked((int) 0x96f5b195), unchecked((int) 0xfd0af0fc), unchecked((int) 0xb0fe134c), unchecked((int) 0xe2506d3d), unchecked((int) 0x4f9b12ea), unchecked((int) 0xf215f225),
+ unchecked((int) 0xa223736f), unchecked((int) 0x9fb4c428), unchecked((int) 0x25d04979), unchecked((int) 0x34c713f8), unchecked((int) 0xc4618187), unchecked((int) 0xea7a6e98), unchecked((int) 0x7cd16efc), unchecked((int) 0x1436876c),
+ unchecked((int) 0xf1544107), unchecked((int) 0xbedeee14), unchecked((int) 0x56e9af27), unchecked((int) 0xa04aa441), unchecked((int) 0x3cf7c899), unchecked((int) 0x92ecbae6), unchecked((int) 0xdd67016d), unchecked((int) 0x151682eb),
+ unchecked((int) 0xa842eedf), unchecked((int) 0xfdba60b4), unchecked((int) 0xf1907b75), unchecked((int) 0x20e3030f), unchecked((int) 0x24d8c29e), unchecked((int) 0xe139673b), unchecked((int) 0xefa63fb8), unchecked((int) 0x71873054),
+ unchecked((int) 0xb6f2cf3b), unchecked((int) 0x9f326442), unchecked((int) 0xcb15a4cc), unchecked((int) 0xb01a4504), unchecked((int) 0xf1e47d8d), unchecked((int) 0x844a1be5), unchecked((int) 0xbae7dfdc), unchecked((int) 0x42cbda70),
+ unchecked((int) 0xcd7dae0a), unchecked((int) 0x57e85b7a), unchecked((int) 0xd53f5af6), unchecked((int) 0x20cf4d8c), unchecked((int) 0xcea4d428), unchecked((int) 0x79d130a4), unchecked((int) 0x3486ebfb), unchecked((int) 0x33d3cddc),
+ unchecked((int) 0x77853b53), unchecked((int) 0x37effcb5), unchecked((int) 0xc5068778), unchecked((int) 0xe580b3e6), unchecked((int) 0x4e68b8f4), unchecked((int) 0xc5c8b37e), unchecked((int) 0x0d809ea2), unchecked((int) 0x398feb7c),
+ unchecked((int) 0x132a4f94), unchecked((int) 0x43b7950e), unchecked((int) 0x2fee7d1c), unchecked((int) 0x223613bd), unchecked((int) 0xdd06caa2), unchecked((int) 0x37df932b), unchecked((int) 0xc4248289), unchecked((int) 0xacf3ebc3),
+ unchecked((int) 0x5715f6b7), unchecked((int) 0xef3478dd), unchecked((int) 0xf267616f), unchecked((int) 0xc148cbe4), unchecked((int) 0x9052815e), unchecked((int) 0x5e410fab), unchecked((int) 0xb48a2465), unchecked((int) 0x2eda7fa4),
+ unchecked((int) 0xe87b40e4), unchecked((int) 0xe98ea084), unchecked((int) 0x5889e9e1), unchecked((int) 0xefd390fc), unchecked((int) 0xdd07d35b), unchecked((int) 0xdb485694), unchecked((int) 0x38d7e5b2), unchecked((int) 0x57720101),
+ unchecked((int) 0x730edebc), unchecked((int) 0x5b643113), unchecked((int) 0x94917e4f), unchecked((int) 0x503c2fba), unchecked((int) 0x646f1282), unchecked((int) 0x7523d24a), unchecked((int) 0xe0779695), unchecked((int) 0xf9c17a8f),
+ unchecked((int) 0x7a5b2121), unchecked((int) 0xd187b896), unchecked((int) 0x29263a4d), unchecked((int) 0xba510cdf), unchecked((int) 0x81f47c9f), unchecked((int) 0xad1163ed), unchecked((int) 0xea7b5965), unchecked((int) 0x1a00726e),
+ unchecked((int) 0x11403092), unchecked((int) 0x00da6d77), unchecked((int) 0x4a0cdd61), unchecked((int) 0xad1f4603), unchecked((int) 0x605bdfb0), unchecked((int) 0x9eedc364), unchecked((int) 0x22ebe6a8), unchecked((int) 0xcee7d28a),
+ unchecked((int) 0xa0e736a0), unchecked((int) 0x5564a6b9), unchecked((int) 0x10853209), unchecked((int) 0xc7eb8f37), unchecked((int) 0x2de705ca), unchecked((int) 0x8951570f), unchecked((int) 0xdf09822b), unchecked((int) 0xbd691a6c),
+ unchecked((int) 0xaa12e4f2), unchecked((int) 0x87451c0f), unchecked((int) 0xe0f6a27a), unchecked((int) 0x3ada4819), unchecked((int) 0x4cf1764f), unchecked((int) 0x0d771c2b), unchecked((int) 0x67cdb156), unchecked((int) 0x350d8384),
+ unchecked((int) 0x5938fa0f), unchecked((int) 0x42399ef3), unchecked((int) 0x36997b07), unchecked((int) 0x0e84093d), unchecked((int) 0x4aa93e61), unchecked((int) 0x8360d87b), unchecked((int) 0x1fa98b0c), unchecked((int) 0x1149382c),
+ unchecked((int) 0xe97625a5), unchecked((int) 0x0614d1b7), unchecked((int) 0x0e25244b), unchecked((int) 0x0c768347), unchecked((int) 0x589e8d82), unchecked((int) 0x0d2059d1), unchecked((int) 0xa466bb1e), unchecked((int) 0xf8da0a82),
+ unchecked((int) 0x04f19130), unchecked((int) 0xba6e4ec0), unchecked((int) 0x99265164), unchecked((int) 0x1ee7230d), unchecked((int) 0x50b2ad80), unchecked((int) 0xeaee6801), unchecked((int) 0x8db2a283), unchecked((int) 0xea8bf59e)
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ internal static readonly int MAX_ROUNDS = 16;
+ internal static readonly int RED_ROUNDS = 12;
+
+ private const int BLOCK_SIZE = 8; // bytes = 64 bits
+
+ private int [] _Kr = new int[17]; // the rotating round key
+ private int [] _Km = new int[17]; // the masking round key
+
+ private bool _encrypting;
+
+ private byte[] _workingKey;
+ private int _rounds = MAX_ROUNDS;
+
+ public Cast5Engine()
+ {
+ }
+
+ /**
+ * initialise a CAST cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + parameters.GetType().ToString());
+
+ _encrypting = forEncryption;
+ _workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(_workingKey);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "CAST5"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = GetBlockSize();
+ if (_workingKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + blockSize) > input.Length)
+ throw new DataLengthException("Input buffer too short");
+ if ((outOff + blockSize) > output.Length)
+ throw new DataLengthException("Output buffer too short");
+
+ if (_encrypting)
+ {
+ return EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ return DecryptBlock(input, inOff, output, outOff);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ /*
+ * Creates the subkeys using the same nomenclature
+ * as described in RFC2144.
+ *
+ * See section 2.4
+ */
+ internal virtual void SetKey(byte[] key)
+ {
+ /*
+ * Determine the key size here, if required
+ *
+ * if keysize <= 80bits, use 12 rounds instead of 16
+ * if keysize < 128bits, pad with 0
+ *
+ * Typical key sizes => 40, 64, 80, 128
+ */
+
+ if (key.Length < 11)
+ {
+ _rounds = RED_ROUNDS;
+ }
+
+ int [] z = new int[16];
+ int [] x = new int[16];
+
+ int z03, z47, z8B, zCF;
+ int x03, x47, x8B, xCF;
+
+ /* copy the key into x */
+ for (int i=0; i< key.Length; i++)
+ {
+ x[i] = (int)(key[i] & 0xff);
+ }
+
+ /*
+ * This will look different because the selection of
+ * bytes from the input key I've already chosen the
+ * correct int.
+ */
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
+ _Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
+ _Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
+ _Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
+ _Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
+ _Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
+ _Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
+ _Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
+ _Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
+ _Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
+ _Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
+ _Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
+ _Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Kr[ 1]=(S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f;
+ _Kr[ 2]=(S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f;
+ _Kr[ 3]=(S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f;
+ _Kr[ 4]=(S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f;
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Kr[ 5]=(S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f;
+ _Kr[ 6]=(S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f;
+ _Kr[ 7]=(S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f;
+ _Kr[ 8]=(S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f;
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Kr[ 9]=(S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f;
+ _Kr[10]=(S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f;
+ _Kr[11]=(S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f;
+ _Kr[12]=(S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f;
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Kr[13]=(S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f;
+ _Kr[14]=(S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f;
+ _Kr[15]=(S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f;
+ _Kr[16]=(S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f;
+ }
+
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param src The plaintext buffer
+ * @param srcIndex An offset into src
+ * @param dst The ciphertext buffer
+ * @param dstIndex An offset into dst
+ */
+ internal virtual int EncryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int [] result = new int[2];
+
+ // process the input block
+ // batch the units up into a 32 bit chunk and go for it
+ // the array is in bytes, the increment is 8x8 bits = 64
+
+ int L0 = BytesTo32bits(src, srcIndex);
+ int R0 = BytesTo32bits(src, srcIndex + 4);
+
+ CAST_Encipher(L0, R0, result);
+
+ // now stuff them into the destination block
+ Bits32ToBytes(result[0], dst, dstIndex);
+ Bits32ToBytes(result[1], dst, dstIndex + 4);
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param src The plaintext buffer
+ * @param srcIndex An offset into src
+ * @param dst The ciphertext buffer
+ * @param dstIndex An offset into dst
+ */
+ internal virtual int DecryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int [] result = new int[2];
+
+ // process the input block
+ // batch the units up into a 32 bit chunk and go for it
+ // the array is in bytes, the increment is 8x8 bits = 64
+ int L16 = BytesTo32bits(src, srcIndex);
+ int R16 = BytesTo32bits(src, srcIndex+4);
+
+ CAST_Decipher(L16, R16, result);
+
+ // now stuff them into the destination block
+ Bits32ToBytes(result[0], dst, dstIndex);
+ Bits32ToBytes(result[1], dst, dstIndex+4);
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * The first of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static int F1(int D, int Kmi, int Kri)
+ {
+ int I = Kmi + D;
+ I = I << Kri | (int) ((uint) I >> (32-Kri));
+ return ((S1[((uint) I >>24)&0xff]^S2[((uint)I>>16)&0xff])-S3[((uint)I>> 8)&0xff])+
+ S4[(I )&0xff];
+ }
+
+ /**
+ * The second of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static int F2(int D, int Kmi, int Kri)
+ {
+ int I = Kmi ^ D;
+ I = I << Kri | (int) ((uint)I >> (32-Kri));
+ return ((S1[((uint)I>>24)&0xff]-S2[((uint)I>>16)&0xff])+S3[((uint)I>> 8)&0xff])^
+ S4[(I )&0xff];
+ }
+
+ /**
+ * The third of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static int F3(int D, int Kmi, int Kri)
+ {
+ int I = Kmi - D;
+ I = I << Kri | (int) ((uint)I >> (32-Kri));
+ return ((S1[((uint)I>>24)&0xff]+S2[((uint)I>>16)&0xff])^S3[((uint)I>> 8)&0xff])-
+ S4[(I )&0xff];
+ }
+
+ /**
+ * Does the 16 rounds to encrypt the block.
+ *
+ * @param L0 the LH-32bits of the plaintext block
+ * @param R0 the RH-32bits of the plaintext block
+ */
+ internal void CAST_Encipher(int L0, int R0, int [] result)
+ {
+ int Lp = L0; // the previous value, equiv to L[i-1]
+ int Rp = R0; // equivalent to R[i-1]
+
+ /*
+ * numbering consistent with paper to make
+ * checking and validating easier
+ */
+ int Li = L0, Ri = R0;
+
+ for (int i = 1; i<=_rounds ; i++)
+ {
+ Lp = Li;
+ Rp = Ri;
+
+ Li = Rp;
+ switch (i)
+ {
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ case 13:
+ case 16:
+ Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+ break;
+ case 2:
+ case 5:
+ case 8:
+ case 11:
+ case 14:
+ Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+ break;
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+ break;
+ }
+ }
+
+ result[0] = Ri;
+ result[1] = Li;
+
+ return;
+ }
+
+ internal void CAST_Decipher(int L16, int R16, int [] result)
+ {
+ int Lp = L16; // the previous value, equiv to L[i-1]
+ int Rp = R16; // equivalent to R[i-1]
+
+ /*
+ * numbering consistent with paper to make
+ * checking and validating easier
+ */
+ int Li = L16, Ri = R16;
+
+ for (int i = _rounds; i > 0; i--)
+ {
+ Lp = Li;
+ Rp = Ri;
+
+ Li = Rp;
+ switch (i)
+ {
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ case 13:
+ case 16:
+ Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+ break;
+ case 2:
+ case 5:
+ case 8:
+ case 11:
+ case 14:
+ Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+ break;
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+ break;
+ }
+ }
+
+ result[0] = Ri;
+ result[1] = Li;
+
+ return;
+ }
+
+ internal static void Bits32ToInts(int inData, int[] b, int offset)
+ {
+ b[offset + 3] = (inData & 0xff);
+ b[offset + 2] = (int) (((uint) inData >> 8) & 0xff);
+ b[offset + 1] = (int) (((uint)inData >> 16) & 0xff);
+ b[offset] = (int) (((uint)inData >> 24) & 0xff);
+ }
+
+ internal static int IntsTo32bits(int[] b, int i)
+ {
+ int rv = 0;
+
+ rv = ((b[i] & 0xff) << 24) |
+ ((b[i+1] & 0xff) << 16) |
+ ((b[i+2] & 0xff) << 8) |
+ ((b[i+3] & 0xff));
+
+ return rv;
+ }
+
+ internal static void Bits32ToBytes(int inData, byte[] b, int offset)
+ {
+ b[offset + 3] = (byte)inData;
+ b[offset + 2] = (byte)((uint)inData >> 8);
+ b[offset + 1] = (byte)((uint)inData >> 16);
+ b[offset] = (byte)((uint)inData >> 24);
+ }
+
+ internal static int BytesTo32bits(byte[] b, int i)
+ {
+ return ((b[i] & 0xff) << 24) |
+ ((b[i+1] & 0xff) << 16) |
+ ((b[i+2] & 0xff) << 8) |
+ ((b[i+3] & 0xff));
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/Cast6Engine.cs b/src/core/srcbc/crypto/engines/Cast6Engine.cs
new file mode 100644
index 0000000..0ed331a
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/Cast6Engine.cs
@@ -0,0 +1,277 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides CAST6 key encryption operations,
+ * such as encoding data and generating keys.
+ *
+ * All the algorithms herein are from the Internet RFC
+ *
+ * RFC2612 - CAST6 (128bit block, 128-256bit key)
+ *
+ * and implement a simplified cryptography interface.
+ */
+ public sealed class Cast6Engine
+ : Cast5Engine
+ {
+ //====================================
+ // Useful constants
+ //====================================
+ private const int ROUNDS = 12;
+ private const int BLOCK_SIZE = 16; // bytes = 128 bits
+
+ /*
+ * Put the round and mask keys into an array.
+ * Kr0[i] => _Kr[i*4 + 0]
+ */
+ private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s)
+ private int []_Km = new int[ROUNDS*4]; // the masking round key(s)
+
+ /*
+ * Key setup
+ */
+ private int []_Tr = new int[24 * 8];
+ private int []_Tm = new int[24 * 8];
+ private int[] _workingKey = new int[8];
+
+ public Cast6Engine()
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "CAST6"; }
+ }
+
+ public override void Reset()
+ {
+ }
+
+ public override int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+ /*
+ * Creates the subkeys using the same nomenclature
+ * as described in RFC2612.
+ *
+ * See section 2.4
+ */
+ internal override void SetKey(
+ byte[] key)
+ {
+ int Cm = 0x5a827999;
+ int Mm = 0x6ed9eba1;
+ int Cr = 19;
+ int Mr = 17;
+ /*
+ * Determine the key size here, if required
+ *
+ * if keysize < 256 bytes, pad with 0
+ *
+ * Typical key sizes => 128, 160, 192, 224, 256
+ */
+ for (int i=0; i< 24; i++)
+ {
+ for (int j=0; j< 8; j++)
+ {
+ _Tm[i*8 + j] = Cm;
+ Cm += Mm; //mod 2^32;
+ _Tr[i*8 + j] = Cr;
+ Cr = (Cr + Mr) & 0x1f; // mod 32
+ }
+ }
+
+ byte[] tmpKey = new byte[64];
+ key.CopyTo(tmpKey, 0);
+
+ // now create ABCDEFGH
+ for (int i = 0; i < 8; i++)
+ {
+ _workingKey[i] = BytesTo32bits(tmpKey, i*4);
+ }
+
+ // Generate the key schedule
+ for (int i = 0; i < 12; i++)
+ {
+ // KAPPA <- W2i(KAPPA)
+ int i2 = i*2 *8;
+ _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+ _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+ _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+ _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+ _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+ _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+ _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+ _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+ // KAPPA <- W2i+1(KAPPA)
+ i2 = (i*2 + 1)*8;
+ _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+ _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+ _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+ _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+ _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+ _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+ _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+ _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+ // Kr_(i) <- KAPPA
+ _Kr[i*4] = _workingKey[0] & 0x1f;
+ _Kr[i*4 + 1] = _workingKey[2] & 0x1f;
+ _Kr[i*4 + 2] = _workingKey[4] & 0x1f;
+ _Kr[i*4 + 3] = _workingKey[6] & 0x1f;
+ // Km_(i) <- KAPPA
+ _Km[i*4] = _workingKey[7];
+ _Km[i*4 + 1] = _workingKey[5];
+ _Km[i*4 + 2] = _workingKey[3];
+ _Km[i*4 + 3] = _workingKey[1];
+ }
+ }
+
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param src The plaintext buffer
+ * @param srcIndex An offset into src
+ * @param dst The ciphertext buffer
+ * @param dstIndex An offset into dst
+ */
+ internal override int EncryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int[] result = new int[4];
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ int A = BytesTo32bits(src, srcIndex);
+ int B = BytesTo32bits(src, srcIndex + 4);
+ int C = BytesTo32bits(src, srcIndex + 8);
+ int D = BytesTo32bits(src, srcIndex + 12);
+ CAST_Encipher(A, B, C, D, result);
+ // now stuff them into the destination block
+ Bits32ToBytes(result[0], dst, dstIndex);
+ Bits32ToBytes(result[1], dst, dstIndex + 4);
+ Bits32ToBytes(result[2], dst, dstIndex + 8);
+ Bits32ToBytes(result[3], dst, dstIndex + 12);
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param src The plaintext buffer
+ * @param srcIndex An offset into src
+ * @param dst The ciphertext buffer
+ * @param dstIndex An offset into dst
+ */
+ internal override int DecryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int[] result = new int[4];
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ int A = BytesTo32bits(src, srcIndex);
+ int B = BytesTo32bits(src, srcIndex + 4);
+ int C = BytesTo32bits(src, srcIndex + 8);
+ int D = BytesTo32bits(src, srcIndex + 12);
+ CAST_Decipher(A, B, C, D, result);
+ // now stuff them into the destination block
+ Bits32ToBytes(result[0], dst, dstIndex);
+ Bits32ToBytes(result[1], dst, dstIndex + 4);
+ Bits32ToBytes(result[2], dst, dstIndex + 8);
+ Bits32ToBytes(result[3], dst, dstIndex + 12);
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * Does the 12 quad rounds rounds to encrypt the block.
+ *
+ * @param A the 00-31 bits of the plaintext block
+ * @param B the 32-63 bits of the plaintext block
+ * @param C the 64-95 bits of the plaintext block
+ * @param D the 96-127 bits of the plaintext block
+ * @param result the resulting ciphertext
+ */
+ private void CAST_Encipher(
+ int A,
+ int B,
+ int C,
+ int D,
+ int[] result)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ int x = i*4;
+ // BETA <- Qi(BETA)
+ C ^= F1(D, _Km[x], _Kr[x]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ }
+ for (int i = 6; i < 12; i++)
+ {
+ int x = i*4;
+ // BETA <- QBARi(BETA)
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ C ^= F1(D, _Km[x], _Kr[x]);
+ }
+ result[0] = A;
+ result[1] = B;
+ result[2] = C;
+ result[3] = D;
+ }
+
+ /**
+ * Does the 12 quad rounds rounds to decrypt the block.
+ *
+ * @param A the 00-31 bits of the ciphertext block
+ * @param B the 32-63 bits of the ciphertext block
+ * @param C the 64-95 bits of the ciphertext block
+ * @param D the 96-127 bits of the ciphertext block
+ * @param result the resulting plaintext
+ */
+ private void CAST_Decipher(
+ int A,
+ int B,
+ int C,
+ int D,
+ int[] result)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ int x = (11-i)*4;
+ // BETA <- Qi(BETA)
+ C ^= F1(D, _Km[x], _Kr[x]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ }
+ for (int i=6; i<12; i++)
+ {
+ int x = (11-i)*4;
+ // BETA <- QBARi(BETA)
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ C ^= F1(D, _Km[x], _Kr[x]);
+ }
+ result[0] = A;
+ result[1] = B;
+ result[2] = C;
+ result[3] = D;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/DesEdeEngine.cs b/src/core/srcbc/crypto/engines/DesEdeEngine.cs
new file mode 100644
index 0000000..455a3a7
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/DesEdeEngine.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /// A class that provides a basic DESede (or Triple DES) engine.
+ public class DesEdeEngine
+ : DesEngine
+ {
+ private int[] workingKey1, workingKey2, workingKey3;
+ private bool forEncryption;
+
+ /**
+ * initialise a DESede cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ {
+ throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString());
+ }
+
+ byte[] keyMaster = ((KeyParameter)parameters).GetKey();
+ byte[] key1 = new byte[8], key2 = new byte[8], key3 = new byte[8];
+ this.forEncryption = forEncryption;
+ if (keyMaster.Length == 24)
+ {
+ Array.Copy(keyMaster, 0, key1, 0, key1.Length);
+ Array.Copy(keyMaster, 8, key2, 0, key2.Length);
+ Array.Copy(keyMaster, 16, key3, 0, key3.Length);
+ workingKey1 = GenerateWorkingKey(forEncryption, key1);
+ workingKey2 = GenerateWorkingKey(!forEncryption, key2);
+ workingKey3 = GenerateWorkingKey(forEncryption, key3);
+ }
+ else // 16 byte key
+ {
+ Array.Copy(keyMaster, 0, key1, 0, key1.Length);
+ Array.Copy(keyMaster, 8, key2, 0, key2.Length);
+ workingKey1 = GenerateWorkingKey(forEncryption, key1);
+ workingKey2 = GenerateWorkingKey(!forEncryption, key2);
+ workingKey3 = workingKey1;
+ }
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "DESede"; }
+ }
+
+ public override int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public override int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey1 == null)
+ throw new InvalidOperationException("DESede engine not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (forEncryption)
+ {
+ DesFunc(workingKey1, input, inOff, output, outOff);
+ DesFunc(workingKey2, output, outOff, output, outOff);
+ DesFunc(workingKey3, output, outOff, output, outOff);
+ }
+ else
+ {
+ DesFunc(workingKey3, input, inOff, output, outOff);
+ DesFunc(workingKey2, output, outOff, output, outOff);
+ DesFunc(workingKey1, output, outOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public override void Reset()
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/DesEdeWrapEngine.cs b/src/core/srcbc/crypto/engines/DesEdeWrapEngine.cs
new file mode 100644
index 0000000..348a523
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/DesEdeWrapEngine.cs
@@ -0,0 +1,299 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Wrap keys according to
+ *
+ * draft-ietf-smime-key-wrap-01.txt.
+ *
+ * Note:
+ *
+ * - this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
+ * - if you are using this to wrap triple-des keys you need to set the
+ * parity bits on the key and, if it's a two-key triple-des key, pad it
+ * yourself.
+ *
+ *
+ */
+ public class DesEdeWrapEngine
+ : IWrapper
+ {
+ /** Field engine */
+ private CbcBlockCipher engine;
+ /** Field param */
+ private KeyParameter param;
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+ /** Field iv */
+ private byte[] iv;
+ /** Field forWrapping */
+ private bool forWrapping;
+ /** Field IV2 */
+ private static readonly byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05 };
+
+ //
+ // checksum digest
+ //
+ private readonly IDigest sha1 = new Sha1Digest();
+ private readonly byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+ this.engine = new CbcBlockCipher(new DesEdeEngine());
+
+ SecureRandom sr;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom pr = (ParametersWithRandom) parameters;
+ parameters = pr.Parameters;
+ sr = pr.Random;
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (parameters is KeyParameter)
+ {
+ this.param = (KeyParameter) parameters;
+ if (this.forWrapping)
+ {
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+ sr.NextBytes(iv);
+
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ }
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ if (!forWrapping)
+ throw new ArgumentException("You should not supply an IV for unwrapping");
+
+ this.paramPlusIV = (ParametersWithIV) parameters;
+ this.iv = this.paramPlusIV.GetIV();
+ this.param = (KeyParameter) this.paramPlusIV.Parameters;
+
+ if (this.iv.Length != 8)
+ throw new ArgumentException("IV is not 8 octets", "parameters");
+ }
+ }
+
+ /**
+ * Method GetAlgorithmName
+ *
+ * @return
+ */
+ public string AlgorithmName
+ {
+ get { return "DESede"; }
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ */
+ public byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("Not initialized for wrapping");
+ }
+
+ byte[] keyToBeWrapped = new byte[length];
+ Array.Copy(input, inOff, keyToBeWrapped, 0, length);
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
+ Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+ Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+ byte [] TEMP1 = new byte[WKCKS.Length];
+ Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
+ int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
+ int extraBytes = WKCKS.Length % engine.GetBlockSize();
+ if (extraBytes != 0) {
+ throw new InvalidOperationException("Not multiple of block length");
+ }
+ engine.Init(true, paramPlusIV);
+ for (int i = 0; i < noOfBlocks; i++) {
+ int currentBytePos = i * engine.GetBlockSize();
+ engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+ }
+ // Left TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
+ Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+ Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = new byte[TEMP2.Length];
+ for (int i = 0; i < TEMP2.Length; i++) {
+ TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
+ }
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+ this.engine.Init(true, param2);
+ for (int i = 0; i < noOfBlocks + 1; i++) {
+ int currentBytePos = i * engine.GetBlockSize();
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ * @throws InvalidCipherTextException
+ */
+ public byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("Not set for unwrapping");
+ }
+ if (input == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+ if (length % engine.GetBlockSize() != 0)
+ {
+ throw new InvalidCipherTextException(
+ "Ciphertext not multiple of " + engine.GetBlockSize());
+ }
+
+ /*
+ // Check if the length of the cipher text is reasonable given the key
+ // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+ // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+ // or inconsistent with the algorithm for which the key is intended,
+ // return error.
+ //
+ // we do not accept 168 bit keys. it has to be 192 bit.
+ int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ int lengthB = estimatedKeyLengthInBit % 8;
+ if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
+ throw new XMLSecurityException("empty");
+ }
+ */
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+ this.engine.Init(false, param2);
+ byte [] TEMP3 = new byte[length];
+ Array.Copy(input, inOff, TEMP3, 0, length);
+ for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++) {
+ int currentBytePos = i * engine.GetBlockSize();
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = new byte[TEMP3.Length];
+ for (int i = 0; i < TEMP3.Length; i++) {
+ TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
+ }
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+ this.iv = new byte[8];
+ byte[] TEMP1 = new byte[TEMP2.Length - 8];
+ Array.Copy(TEMP2, 0, this.iv, 0, 8);
+ Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ this.engine.Init(false, this.paramPlusIV);
+ byte[] WKCKS = new byte[TEMP1.Length];
+ Array.Copy(TEMP1, 0, WKCKS, 0, TEMP1.Length);
+ for (int i = 0; i < (WKCKS.Length / engine.GetBlockSize()); i++) {
+ int currentBytePos = i * engine.GetBlockSize();
+ engine.ProcessBlock(WKCKS, currentBytePos, WKCKS, currentBytePos);
+ }
+ // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
+ byte[] result = new byte[WKCKS.Length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+ Array.Copy(WKCKS, 0, result, 0, WKCKS.Length - 8);
+ Array.Copy(WKCKS, WKCKS.Length - 8, CKStoBeVerified, 0, 8);
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!CheckCmsKeyChecksum(result, CKStoBeVerified)) {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+ // WK is the wrapped key, now extracted for use in data decryption.
+ return result;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+ * - Use the first 8 octets of this hash as the checksum value.
+ *
+ * @param key
+ * @return
+ * @throws Exception
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] CalculateCmsKeyChecksum(
+ byte[] key)
+ {
+ byte[] result = new byte[8];
+
+ sha1.BlockUpdate(key, 0, key.Length);
+ sha1.DoFinal(digest, 0);
+
+ Array.Copy(digest, 0, result, 0, 8);
+
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private bool CheckCmsKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/DesEngine.cs b/src/core/srcbc/crypto/engines/DesEngine.cs
new file mode 100644
index 0000000..05368d2
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/DesEngine.cs
@@ -0,0 +1,493 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /// A class that provides a basic DES engine.
+ public class DesEngine
+ : IBlockCipher
+ {
+ internal const int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+
+ public virtual int[] GetWorkingKey()
+ {
+ return workingKey;
+ }
+
+ /**
+ * initialise a DES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to DES init - " + parameters.GetType().ToString());
+
+ workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "DES"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("DES engine not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ DesFunc(workingKey, input, inOff, output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * what follows is mainly taken from "Applied Cryptography", by
+ * Bruce Schneier, however it also bears great resemblance to Richard
+ * Outerbridge's D3DES...
+ */
+
+ private static readonly short[] Df_Key =
+ {
+ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+ 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+ 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
+ };
+
+ private static readonly short[] bytebit =
+ {
+ 128, 64, 32, 16, 8, 4, 2, 1
+ };
+
+ private static readonly int[] bigbyte =
+ {
+ 0x800000, 0x400000, 0x200000, 0x100000,
+ 0x80000, 0x40000, 0x20000, 0x10000,
+ 0x8000, 0x4000, 0x2000, 0x1000,
+ 0x800, 0x400, 0x200, 0x100,
+ 0x80, 0x40, 0x20, 0x10,
+ 0x8, 0x4, 0x2, 0x1
+ };
+
+ /*
+ * Use the key schedule specified in the Standard (ANSI X3.92-1981).
+ */
+ private static readonly byte[] pc1 =
+ {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ };
+
+ private static readonly byte[] totrot =
+ {
+ 1, 2, 4, 6, 8, 10, 12, 14,
+ 15, 17, 19, 21, 23, 25, 27, 28
+ };
+
+ private static readonly byte[] pc2 =
+ {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+ };
+
+ private static readonly int[] SP1 =
+ {
+ unchecked((int) 0x01010400), unchecked((int) 0x00000000), unchecked((int) 0x00010000), unchecked((int) 0x01010404),
+ unchecked((int) 0x01010004), unchecked((int) 0x00010404), unchecked((int) 0x00000004), unchecked((int) 0x00010000),
+ unchecked((int) 0x00000400), unchecked((int) 0x01010400), unchecked((int) 0x01010404), unchecked((int) 0x00000400),
+ unchecked((int) 0x01000404), unchecked((int) 0x01010004), unchecked((int) 0x01000000), unchecked((int) 0x00000004),
+ unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00010400),
+ unchecked((int) 0x00010400), unchecked((int) 0x01010000), unchecked((int) 0x01010000), unchecked((int) 0x01000404),
+ unchecked((int) 0x00010004), unchecked((int) 0x01000004), unchecked((int) 0x01000004), unchecked((int) 0x00010004),
+ unchecked((int) 0x00000000), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01000000),
+ unchecked((int) 0x00010000), unchecked((int) 0x01010404), unchecked((int) 0x00000004), unchecked((int) 0x01010000),
+ unchecked((int) 0x01010400), unchecked((int) 0x01000000), unchecked((int) 0x01000000), unchecked((int) 0x00000400),
+ unchecked((int) 0x01010004), unchecked((int) 0x00010000), unchecked((int) 0x00010400), unchecked((int) 0x01000004),
+ unchecked((int) 0x00000400), unchecked((int) 0x00000004), unchecked((int) 0x01000404), unchecked((int) 0x00010404),
+ unchecked((int) 0x01010404), unchecked((int) 0x00010004), unchecked((int) 0x01010000), unchecked((int) 0x01000404),
+ unchecked((int) 0x01000004), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01010400),
+ unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00000000),
+ unchecked((int) 0x00010004), unchecked((int) 0x00010400), unchecked((int) 0x00000000), unchecked((int) 0x01010004)
+ };
+
+ private static readonly int[] SP2 =
+ {
+ unchecked((int) 0x80108020), unchecked((int) 0x80008000), unchecked((int) 0x00008000), unchecked((int) 0x00108020),
+ unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020), unchecked((int) 0x80008020),
+ unchecked((int) 0x80000020), unchecked((int) 0x80108020), unchecked((int) 0x80108000), unchecked((int) 0x80000000),
+ unchecked((int) 0x80008000), unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020),
+ unchecked((int) 0x00108000), unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x00000000),
+ unchecked((int) 0x80000000), unchecked((int) 0x00008000), unchecked((int) 0x00108020), unchecked((int) 0x80100000),
+ unchecked((int) 0x00100020), unchecked((int) 0x80000020), unchecked((int) 0x00000000), unchecked((int) 0x00108000),
+ unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x80100000), unchecked((int) 0x00008020),
+ unchecked((int) 0x00000000), unchecked((int) 0x00108020), unchecked((int) 0x80100020), unchecked((int) 0x00100000),
+ unchecked((int) 0x80008020), unchecked((int) 0x80100000), unchecked((int) 0x80108000), unchecked((int) 0x00008000),
+ unchecked((int) 0x80100000), unchecked((int) 0x80008000), unchecked((int) 0x00000020), unchecked((int) 0x80108020),
+ unchecked((int) 0x00108020), unchecked((int) 0x00000020), unchecked((int) 0x00008000), unchecked((int) 0x80000000),
+ unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x00100000), unchecked((int) 0x80000020),
+ unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x80000020), unchecked((int) 0x00100020),
+ unchecked((int) 0x00108000), unchecked((int) 0x00000000), unchecked((int) 0x80008000), unchecked((int) 0x00008020),
+ unchecked((int) 0x80000000), unchecked((int) 0x80100020), unchecked((int) 0x80108020), unchecked((int) 0x00108000)
+ };
+
+ private static readonly int[] SP3 =
+ {
+ unchecked((int) 0x00000208), unchecked((int) 0x08020200), unchecked((int) 0x00000000), unchecked((int) 0x08020008),
+ unchecked((int) 0x08000200), unchecked((int) 0x00000000), unchecked((int) 0x00020208), unchecked((int) 0x08000200),
+ unchecked((int) 0x00020008), unchecked((int) 0x08000008), unchecked((int) 0x08000008), unchecked((int) 0x00020000),
+ unchecked((int) 0x08020208), unchecked((int) 0x00020008), unchecked((int) 0x08020000), unchecked((int) 0x00000208),
+ unchecked((int) 0x08000000), unchecked((int) 0x00000008), unchecked((int) 0x08020200), unchecked((int) 0x00000200),
+ unchecked((int) 0x00020200), unchecked((int) 0x08020000), unchecked((int) 0x08020008), unchecked((int) 0x00020208),
+ unchecked((int) 0x08000208), unchecked((int) 0x00020200), unchecked((int) 0x00020000), unchecked((int) 0x08000208),
+ unchecked((int) 0x00000008), unchecked((int) 0x08020208), unchecked((int) 0x00000200), unchecked((int) 0x08000000),
+ unchecked((int) 0x08020200), unchecked((int) 0x08000000), unchecked((int) 0x00020008), unchecked((int) 0x00000208),
+ unchecked((int) 0x00020000), unchecked((int) 0x08020200), unchecked((int) 0x08000200), unchecked((int) 0x00000000),
+ unchecked((int) 0x00000200), unchecked((int) 0x00020008), unchecked((int) 0x08020208), unchecked((int) 0x08000200),
+ unchecked((int) 0x08000008), unchecked((int) 0x00000200), unchecked((int) 0x00000000), unchecked((int) 0x08020008),
+ unchecked((int) 0x08000208), unchecked((int) 0x00020000), unchecked((int) 0x08000000), unchecked((int) 0x08020208),
+ unchecked((int) 0x00000008), unchecked((int) 0x00020208), unchecked((int) 0x00020200), unchecked((int) 0x08000008),
+ unchecked((int) 0x08020000), unchecked((int) 0x08000208), unchecked((int) 0x00000208), unchecked((int) 0x08020000),
+ unchecked((int) 0x00020208), unchecked((int) 0x00000008), unchecked((int) 0x08020008), unchecked((int) 0x00020200)
+ };
+
+ private static readonly int[] SP4 =
+ {
+ unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080),
+ unchecked((int) 0x00802080), unchecked((int) 0x00800081), unchecked((int) 0x00800001), unchecked((int) 0x00002001),
+ unchecked((int) 0x00000000), unchecked((int) 0x00802000), unchecked((int) 0x00802000), unchecked((int) 0x00802081),
+ unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00800080), unchecked((int) 0x00800001),
+ unchecked((int) 0x00000001), unchecked((int) 0x00002000), unchecked((int) 0x00800000), unchecked((int) 0x00802001),
+ unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002001), unchecked((int) 0x00002080),
+ unchecked((int) 0x00800081), unchecked((int) 0x00000001), unchecked((int) 0x00002080), unchecked((int) 0x00800080),
+ unchecked((int) 0x00002000), unchecked((int) 0x00802080), unchecked((int) 0x00802081), unchecked((int) 0x00000081),
+ unchecked((int) 0x00800080), unchecked((int) 0x00800001), unchecked((int) 0x00802000), unchecked((int) 0x00802081),
+ unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x00802000),
+ unchecked((int) 0x00002080), unchecked((int) 0x00800080), unchecked((int) 0x00800081), unchecked((int) 0x00000001),
+ unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080),
+ unchecked((int) 0x00802081), unchecked((int) 0x00000081), unchecked((int) 0x00000001), unchecked((int) 0x00002000),
+ unchecked((int) 0x00800001), unchecked((int) 0x00002001), unchecked((int) 0x00802080), unchecked((int) 0x00800081),
+ unchecked((int) 0x00002001), unchecked((int) 0x00002080), unchecked((int) 0x00800000), unchecked((int) 0x00802001),
+ unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002000), unchecked((int) 0x00802080)
+ };
+
+ private static readonly int[] SP5 =
+ {
+ unchecked((int) 0x00000100), unchecked((int) 0x02080100), unchecked((int) 0x02080000), unchecked((int) 0x42000100),
+ unchecked((int) 0x00080000), unchecked((int) 0x00000100), unchecked((int) 0x40000000), unchecked((int) 0x02080000),
+ unchecked((int) 0x40080100), unchecked((int) 0x00080000), unchecked((int) 0x02000100), unchecked((int) 0x40080100),
+ unchecked((int) 0x42000100), unchecked((int) 0x42080000), unchecked((int) 0x00080100), unchecked((int) 0x40000000),
+ unchecked((int) 0x02000000), unchecked((int) 0x40080000), unchecked((int) 0x40080000), unchecked((int) 0x00000000),
+ unchecked((int) 0x40000100), unchecked((int) 0x42080100), unchecked((int) 0x42080100), unchecked((int) 0x02000100),
+ unchecked((int) 0x42080000), unchecked((int) 0x40000100), unchecked((int) 0x00000000), unchecked((int) 0x42000000),
+ unchecked((int) 0x02080100), unchecked((int) 0x02000000), unchecked((int) 0x42000000), unchecked((int) 0x00080100),
+ unchecked((int) 0x00080000), unchecked((int) 0x42000100), unchecked((int) 0x00000100), unchecked((int) 0x02000000),
+ unchecked((int) 0x40000000), unchecked((int) 0x02080000), unchecked((int) 0x42000100), unchecked((int) 0x40080100),
+ unchecked((int) 0x02000100), unchecked((int) 0x40000000), unchecked((int) 0x42080000), unchecked((int) 0x02080100),
+ unchecked((int) 0x40080100), unchecked((int) 0x00000100), unchecked((int) 0x02000000), unchecked((int) 0x42080000),
+ unchecked((int) 0x42080100), unchecked((int) 0x00080100), unchecked((int) 0x42000000), unchecked((int) 0x42080100),
+ unchecked((int) 0x02080000), unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x42000000),
+ unchecked((int) 0x00080100), unchecked((int) 0x02000100), unchecked((int) 0x40000100), unchecked((int) 0x00080000),
+ unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x02080100), unchecked((int) 0x40000100)
+ };
+
+ private static readonly int[] SP6 =
+ {
+ unchecked((int) 0x20000010), unchecked((int) 0x20400000), unchecked((int) 0x00004000), unchecked((int) 0x20404010),
+ unchecked((int) 0x20400000), unchecked((int) 0x00000010), unchecked((int) 0x20404010), unchecked((int) 0x00400000),
+ unchecked((int) 0x20004000), unchecked((int) 0x00404010), unchecked((int) 0x00400000), unchecked((int) 0x20000010),
+ unchecked((int) 0x00400010), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010),
+ unchecked((int) 0x00000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00004000),
+ unchecked((int) 0x00404000), unchecked((int) 0x20004010), unchecked((int) 0x00000010), unchecked((int) 0x20400010),
+ unchecked((int) 0x20400010), unchecked((int) 0x00000000), unchecked((int) 0x00404010), unchecked((int) 0x20404000),
+ unchecked((int) 0x00004010), unchecked((int) 0x00404000), unchecked((int) 0x20404000), unchecked((int) 0x20000000),
+ unchecked((int) 0x20004000), unchecked((int) 0x00000010), unchecked((int) 0x20400010), unchecked((int) 0x00404000),
+ unchecked((int) 0x20404010), unchecked((int) 0x00400000), unchecked((int) 0x00004010), unchecked((int) 0x20000010),
+ unchecked((int) 0x00400000), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010),
+ unchecked((int) 0x20000010), unchecked((int) 0x20404010), unchecked((int) 0x00404000), unchecked((int) 0x20400000),
+ unchecked((int) 0x00404010), unchecked((int) 0x20404000), unchecked((int) 0x00000000), unchecked((int) 0x20400010),
+ unchecked((int) 0x00000010), unchecked((int) 0x00004000), unchecked((int) 0x20400000), unchecked((int) 0x00404010),
+ unchecked((int) 0x00004000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00000000),
+ unchecked((int) 0x20404000), unchecked((int) 0x20000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010)
+ };
+
+ private static readonly int[] SP7 =
+ {
+ unchecked((int) 0x00200000), unchecked((int) 0x04200002), unchecked((int) 0x04000802), unchecked((int) 0x00000000),
+ unchecked((int) 0x00000800), unchecked((int) 0x04000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800),
+ unchecked((int) 0x04200802), unchecked((int) 0x00200000), unchecked((int) 0x00000000), unchecked((int) 0x04000002),
+ unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x04200002), unchecked((int) 0x00000802),
+ unchecked((int) 0x04000800), unchecked((int) 0x00200802), unchecked((int) 0x00200002), unchecked((int) 0x04000800),
+ unchecked((int) 0x04000002), unchecked((int) 0x04200000), unchecked((int) 0x04200800), unchecked((int) 0x00200002),
+ unchecked((int) 0x04200000), unchecked((int) 0x00000800), unchecked((int) 0x00000802), unchecked((int) 0x04200802),
+ unchecked((int) 0x00200800), unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x00200800),
+ unchecked((int) 0x04000000), unchecked((int) 0x00200800), unchecked((int) 0x00200000), unchecked((int) 0x04000802),
+ unchecked((int) 0x04000802), unchecked((int) 0x04200002), unchecked((int) 0x04200002), unchecked((int) 0x00000002),
+ unchecked((int) 0x00200002), unchecked((int) 0x04000000), unchecked((int) 0x04000800), unchecked((int) 0x00200000),
+ unchecked((int) 0x04200800), unchecked((int) 0x00000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800),
+ unchecked((int) 0x00000802), unchecked((int) 0x04000002), unchecked((int) 0x04200802), unchecked((int) 0x04200000),
+ unchecked((int) 0x00200800), unchecked((int) 0x00000000), unchecked((int) 0x00000002), unchecked((int) 0x04200802),
+ unchecked((int) 0x00000000), unchecked((int) 0x00200802), unchecked((int) 0x04200000), unchecked((int) 0x00000800),
+ unchecked((int) 0x04000002), unchecked((int) 0x04000800), unchecked((int) 0x00000800), unchecked((int) 0x00200002)
+ };
+
+ private static readonly int[] SP8 =
+ {
+ unchecked((int) 0x10001040), unchecked((int) 0x00001000), unchecked((int) 0x00040000), unchecked((int) 0x10041040),
+ unchecked((int) 0x10000000), unchecked((int) 0x10001040), unchecked((int) 0x00000040), unchecked((int) 0x10000000),
+ unchecked((int) 0x00040040), unchecked((int) 0x10040000), unchecked((int) 0x10041040), unchecked((int) 0x00041000),
+ unchecked((int) 0x10041000), unchecked((int) 0x00041040), unchecked((int) 0x00001000), unchecked((int) 0x00000040),
+ unchecked((int) 0x10040000), unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00001040),
+ unchecked((int) 0x00041000), unchecked((int) 0x00040040), unchecked((int) 0x10040040), unchecked((int) 0x10041000),
+ unchecked((int) 0x00001040), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x10040040),
+ unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00041040), unchecked((int) 0x00040000),
+ unchecked((int) 0x00041040), unchecked((int) 0x00040000), unchecked((int) 0x10041000), unchecked((int) 0x00001000),
+ unchecked((int) 0x00000040), unchecked((int) 0x10040040), unchecked((int) 0x00001000), unchecked((int) 0x00041040),
+ unchecked((int) 0x10001000), unchecked((int) 0x00000040), unchecked((int) 0x10000040), unchecked((int) 0x10040000),
+ unchecked((int) 0x10040040), unchecked((int) 0x10000000), unchecked((int) 0x00040000), unchecked((int) 0x10001040),
+ unchecked((int) 0x00000000), unchecked((int) 0x10041040), unchecked((int) 0x00040040), unchecked((int) 0x10000040),
+ unchecked((int) 0x10040000), unchecked((int) 0x10001000), unchecked((int) 0x10001040), unchecked((int) 0x00000000),
+ unchecked((int) 0x10041040), unchecked((int) 0x00041000), unchecked((int) 0x00041000), unchecked((int) 0x00001040),
+ unchecked((int) 0x00001040), unchecked((int) 0x00040040), unchecked((int) 0x10000000), unchecked((int) 0x10041000)
+ };
+
+ /**
+ * Generate an integer based working key based on our secret key
+ * and what we processing we are planning to do.
+ *
+ * Acknowledgements for this routine go to James Gillogly and Phil Karn.
+ * (whoever, and wherever they are!).
+ */
+ protected static int[] GenerateWorkingKey(
+ bool encrypting,
+ byte[] key)
+ {
+ int[] newKey = new int[32];
+ bool[] pc1m = new bool[56];
+ bool[] pcr = new bool[56];
+
+ for (int j = 0; j < 56; j++ )
+ {
+ int l = pc1[j];
+
+ pc1m[j] = ((key[(uint) l >> 3] & bytebit[l & 07]) != 0);
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ int l, m, n;
+
+ if (encrypting)
+ {
+ m = i << 1;
+ }
+ else
+ {
+ m = (15 - i) << 1;
+ }
+
+ n = m + 1;
+ newKey[m] = newKey[n] = 0;
+
+ for (int j = 0; j < 28; j++)
+ {
+ l = j + totrot[i];
+ if ( l < 28 )
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 28; j < 56; j++)
+ {
+ l = j + totrot[i];
+ if (l < 56 )
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 0; j < 24; j++)
+ {
+ if (pcr[pc2[j]])
+ {
+ newKey[m] |= bigbyte[j];
+ }
+
+ if (pcr[pc2[j + 24]])
+ {
+ newKey[n] |= bigbyte[j];
+ }
+ }
+ }
+
+ //
+ // store the processed key
+ //
+ for (int i = 0; i != 32; i += 2)
+ {
+ int i1, i2;
+
+ i1 = newKey[i];
+ i2 = newKey[i + 1];
+
+ newKey[i] = (int) ( (uint) ((i1 & 0x00fc0000) << 6) |
+ (uint) ((i1 & 0x00000fc0) << 10) |
+ ((uint) (i2 & 0x00fc0000) >> 10) |
+ ((uint) (i2 & 0x00000fc0) >> 6));
+
+ newKey[i + 1] = (int) ( (uint) ((i1 & 0x0003f000) << 12) |
+ (uint) ((i1 & 0x0000003f) << 16) |
+ ((uint) (i2 & 0x0003f000) >> 4) |
+ (uint) (i2 & 0x0000003f));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * the DES engine.
+ */
+ internal static void DesFunc(
+ int[] wKey,
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int work, right, left;
+
+ left = (input[inOff + 0] & 0xff) << 24;
+ left |= (input[inOff + 1] & 0xff) << 16;
+ left |= (input[inOff + 2] & 0xff) << 8;
+ left |= (input[inOff + 3] & 0xff);
+
+ right = (input[inOff + 4] & 0xff) << 24;
+ right |= (input[inOff + 5] & 0xff) << 16;
+ right |= (input[inOff + 6] & 0xff) << 8;
+ right |= (input[inOff + 7] & 0xff);
+
+ work = (int) (((uint) left >> 4) ^ right) & unchecked((int) 0x0f0f0f0f);
+ right ^= work;
+ left ^= (work << 4);
+ work = (int) (((uint) left >> 16) ^ right) & unchecked((int) 0x0000ffff);
+ right ^= work;
+ left ^= (work << 16);
+ work = (int) (((uint) right >> 2) ^ left) & unchecked((int) 0x33333333);
+ left ^= work;
+ right ^= (work << 2);
+ work = (int) (((uint) right >> 8) ^ left) & unchecked((int) 0x00ff00ff);
+ left ^= work;
+ right ^= (work << 8);
+ right = (int) ( (uint) (right << 1) |
+ ( ((uint) right >> 31) & 1 )
+ ) &
+ unchecked((int) 0xffffffff);
+ work = (left ^ right) & unchecked((int) 0xaaaaaaaa);
+ left ^= work;
+ right ^= work;
+ left = (int) ( (uint) (left << 1) |
+ ( ((uint) left >> 31) & 1)) &
+ unchecked((int) 0xffffffff);
+
+ for (int round = 0; round < 8; round++)
+ {
+ int fval;
+
+ work = (int) ((uint) (right << 28) | ((uint) right >> 4));
+ work ^= wKey[round * 4 + 0];
+ fval = SP7[ work & 0x3f];
+ fval |= SP5[((uint) work >> 8) & 0x3f];
+ fval |= SP3[((uint) work >> 16) & 0x3f];
+ fval |= SP1[((uint) work >> 24) & 0x3f];
+ work = right ^ wKey[round * 4 + 1];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[((uint) work >> 8) & 0x3f];
+ fval |= SP4[((uint) work >> 16) & 0x3f];
+ fval |= SP2[((uint) work >> 24) & 0x3f];
+ left ^= fval;
+ work = (int) ((uint) (left << 28) | ((uint) left >> 4));
+ work ^= wKey[round * 4 + 2];
+ fval = SP7[ work & 0x3f];
+ fval |= SP5[((uint) work >> 8) & 0x3f];
+ fval |= SP3[((uint) work >> 16) & 0x3f];
+ fval |= SP1[((uint) work >> 24) & 0x3f];
+ work = left ^ wKey[round * 4 + 3];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[((uint) work >> 8) & 0x3f];
+ fval |= SP4[((uint) work >> 16) & 0x3f];
+ fval |= SP2[((uint) work >> 24) & 0x3f];
+ right ^= fval;
+ }
+
+ right = (int) ((uint) (right << 31) | ((uint) right >> 1));
+ work = (left ^ right) & unchecked((int) 0xaaaaaaaa);
+ left ^= work;
+ right ^= work;
+ left = (int) ((uint) (left << 31) | ((uint) left >> 1));
+ work = (int) ((((uint) left >> 8) ^ right) & 0x00ff00ff);
+ right ^= work;
+ left ^= (work << 8);
+ work = (int) ((((uint) left >> 2) ^ right) & 0x33333333);
+ right ^= work;
+ left ^= (work << 2);
+ work = (int) ((((uint) right >> 16) ^ left) & 0x0000ffff);
+ left ^= work;
+ right ^= (work << 16);
+ work = (int) ((((uint) right >> 4) ^ left) & 0x0f0f0f0f);
+ left ^= work;
+ right ^= (work << 4);
+
+ outBytes[outOff + 0] = (byte)(((uint) right >> 24) & 0xff);
+ outBytes[outOff + 1] = (byte)(((uint) right >> 16) & 0xff);
+ outBytes[outOff + 2] = (byte)(((uint) right >> 8) & 0xff);
+ outBytes[outOff + 3] = (byte)( right & 0xff);
+ outBytes[outOff + 4] = (byte)(((uint) left >> 24) & 0xff);
+ outBytes[outOff + 5] = (byte)(((uint) left >> 16) & 0xff);
+ outBytes[outOff + 6] = (byte)(((uint) left >> 8) & 0xff);
+ outBytes[outOff + 7] = (byte)( left & 0xff);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/ElGamalEngine.cs b/src/core/srcbc/crypto/engines/ElGamalEngine.cs
new file mode 100644
index 0000000..012f4af
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/ElGamalEngine.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic ElGamal algorithm.
+ */
+ public class ElGamalEngine
+ : IAsymmetricBlockCipher
+ {
+ private ElGamalKeyParameters key;
+ private SecureRandom random;
+ private bool forEncryption;
+ private int bitSize;
+
+ public string AlgorithmName
+ {
+ get { return "ElGamal"; }
+ }
+
+ /**
+ * initialise the ElGamal engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary ElGamal key parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ this.key = (ElGamalKeyParameters) p.Parameters;
+ this.random = p.Random;
+ }
+ else
+ {
+ this.key = (ElGamalKeyParameters) parameters;
+ this.random = new SecureRandom();
+ }
+
+ this.forEncryption = forEncryption;
+ this.bitSize = key.Parameters.P.BitLength;
+
+ if (forEncryption)
+ {
+ if (!(key is ElGamalPublicKeyParameters))
+ {
+ throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption.");
+ }
+ }
+ else
+ {
+ if (!(key is ElGamalPrivateKeyParameters))
+ {
+ throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption.");
+ }
+ }
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For ElGamal this is always one byte less than the size of P on
+ * encryption, and twice the length as the size of P on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize - 1) / 8;
+ }
+
+ return 2 * ((bitSize + 7) / 8);
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For ElGamal this is always one byte less than the size of P on
+ * decryption, and twice the length as the size of P on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return 2 * ((bitSize + 7) / 8);
+ }
+
+ return (bitSize - 1) / 8;
+ }
+
+ /**
+ * Process a single block using the basic ElGamal algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param length the length of the data to be processed.
+ * @return the result of the ElGamal process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (key == null)
+ throw new InvalidOperationException("ElGamal engine not initialised");
+
+ int maxLength = forEncryption
+ ? (bitSize - 1 + 7) / 8
+ : GetInputBlockSize();
+
+ if (length > maxLength)
+ throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+ BigInteger p = key.Parameters.P;
+
+ byte[] output;
+ if (key is ElGamalPrivateKeyParameters) // decryption
+ {
+ int halfLength = length / 2;
+ BigInteger gamma = new BigInteger(1, input, inOff, halfLength);
+ BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength);
+
+ ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key;
+
+ // a shortcut, which generally relies on p being prime amongst other things.
+ // if a problem with this shows up, check the p and g values!
+ BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p);
+
+ output = m.ToByteArrayUnsigned();
+ }
+ else // encryption
+ {
+ BigInteger tmp = new BigInteger(1, input, inOff, length);
+
+ if (tmp.BitLength >= p.BitLength)
+ throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+
+ ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key;
+
+ BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+ // TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated
+ BigInteger k;
+ do
+ {
+ k = new BigInteger(p.BitLength, random);
+ }
+ while (k.SignValue == 0 || k.CompareTo(pSub2) > 0);
+
+ BigInteger g = key.Parameters.G;
+ BigInteger gamma = g.ModPow(k, p);
+ BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p);
+
+ output = new byte[this.GetOutputBlockSize()];
+
+ // TODO Add methods to allow writing BigInteger to existing byte array?
+ byte[] out1 = gamma.ToByteArrayUnsigned();
+ byte[] out2 = phi.ToByteArrayUnsigned();
+ out1.CopyTo(output, output.Length / 2 - out1.Length);
+ out2.CopyTo(output, output.Length - out2.Length);
+ }
+
+ return output;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/GOST28147Engine.cs b/src/core/srcbc/crypto/engines/GOST28147Engine.cs
new file mode 100644
index 0000000..585db4a
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/GOST28147Engine.cs
@@ -0,0 +1,364 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * implementation of GOST 28147-89
+ */
+ public class Gost28147Engine
+ : IBlockCipher
+ {
+ private const int BlockSize = 8;
+ private int[] workingKey = null;
+ private bool forEncryption;
+
+ // these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
+ // This is default S-box!
+ private readonly byte[] S = {
+ 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+ 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+ 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+ 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+ 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+ 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+ 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+ 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+ };
+
+ /*
+ * class content S-box parameters for encrypting
+ * getting from, see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
+ * http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-02.txt
+ */
+ private static readonly byte[] ESbox_Test = {
+ 0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6,
+ 0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5,
+ 0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB,
+ 0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8,
+ 0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4,
+ 0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4,
+ 0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD,
+ 0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8
+ };
+
+ private static readonly byte[] ESbox_A = {
+ 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
+ 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
+ 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
+ 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
+ 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
+ 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
+ 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
+ 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
+ };
+
+ private static readonly byte[] ESbox_B = {
+ 0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF,
+ 0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE,
+ 0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4,
+ 0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8,
+ 0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3,
+ 0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5,
+ 0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE,
+ 0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC
+ };
+
+ private static readonly byte[] ESbox_C = {
+ 0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3,
+ 0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3,
+ 0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB,
+ 0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4,
+ 0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7,
+ 0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD,
+ 0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7,
+ 0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8
+ };
+
+ private static readonly byte[] ESbox_D = {
+ 0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3,
+ 0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1,
+ 0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2,
+ 0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8,
+ 0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1,
+ 0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6,
+ 0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7,
+ 0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE
+ };
+
+ //S-box for digest
+ private static readonly byte[] DSbox_Test = {
+ 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+ 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+ 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+ 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+ 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+ 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+ 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+ 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+ };
+
+ private static readonly byte[] DSbox_A = {
+ 0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF,
+ 0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8,
+ 0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD,
+ 0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3,
+ 0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5,
+ 0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3,
+ 0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB,
+ 0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC
+ };
+
+ //
+ // pre-defined sbox table
+ //
+ private static readonly Hashtable sBoxes = new Hashtable();
+
+ static Gost28147Engine()
+ {
+ sBoxes.Add("E-TEST", ESbox_Test);
+ sBoxes.Add("E-A", ESbox_A);
+ sBoxes.Add("E-B", ESbox_B);
+ sBoxes.Add("E-C", ESbox_C);
+ sBoxes.Add("E-D", ESbox_D);
+ sBoxes.Add("D-TEST", DSbox_Test);
+ sBoxes.Add("D-A", DSbox_A);
+ }
+
+ /**
+ * standard constructor.
+ */
+ public Gost28147Engine()
+ {
+ }
+
+ /**
+ * initialise an Gost28147 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithSBox)
+ {
+ ParametersWithSBox param = (ParametersWithSBox)parameters;
+
+ //
+ // Set the S-Box
+ //
+ Array.Copy(param.GetSBox(), 0, this.S, 0, param.GetSBox().Length);
+
+ //
+ // set key if there is one
+ //
+ if (param.Parameters != null)
+ {
+ workingKey = generateWorkingKey(forEncryption,
+ ((KeyParameter)param.Parameters).GetKey());
+ }
+ }
+ else if (parameters is KeyParameter)
+ {
+ workingKey = generateWorkingKey(forEncryption,
+ ((KeyParameter)parameters).GetKey());
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to Gost28147 init - " + parameters.GetType().Name);
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Gost28147"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new InvalidOperationException("Gost28147 engine not initialised");
+ }
+
+ if ((inOff + BlockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BlockSize) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ Gost28147Func(workingKey, input, inOff, output, outOff);
+
+ return BlockSize;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private int[] generateWorkingKey(
+ bool forEncryption,
+ byte[] userKey)
+ {
+ this.forEncryption = forEncryption;
+
+ if (userKey.Length != 32)
+ {
+ throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
+ }
+
+ int[] key = new int[8];
+ for(int i=0; i!=8; i++)
+ {
+ key[i] = bytesToint(userKey,i*4);
+ }
+
+ return key;
+ }
+
+ private int Gost28147_mainStep(int n1, int key)
+ {
+ int cm = (key + n1); // CM1
+
+ // S-box replacing
+
+ int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
+ om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
+ om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
+ om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
+ om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
+ om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
+ om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
+ om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
+
+// return om << 11 | om >>> (32-11); // 11-leftshift
+ int omLeft = om << 11;
+ int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
+
+ return omLeft | omRight;
+ }
+
+ private void Gost28147Func(
+ int[] workingKey,
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int N1, N2, tmp; //tmp -> for saving N1
+ N1 = bytesToint(inBytes, inOff);
+ N2 = bytesToint(inBytes, inOff + 4);
+
+ if (this.forEncryption)
+ {
+ for(int k = 0; k < 3; k++) // 1-24 steps
+ {
+ for(int j = 0; j < 8; j++)
+ {
+ tmp = N1;
+ int step = Gost28147_mainStep(N1, workingKey[j]);
+ N1 = N2 ^ step; // CM2
+ N2 = tmp;
+ }
+ }
+ for(int j = 7; j > 0; j--) // 25-31 steps
+ {
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+ else //decrypt
+ {
+ for(int j = 0; j < 8; j++) // 1-8 steps
+ {
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ for(int k = 0; k < 3; k++) //9-31 steps
+ {
+ for(int j = 7; j >= 0; j--)
+ {
+ if ((k == 2) && (j==0))
+ {
+ break; // break 32 step
+ }
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+ }
+
+ N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1)
+
+ intTobytes(N1, outBytes, outOff);
+ intTobytes(N2, outBytes, outOff + 4);
+ }
+
+ //array of bytes to type int
+ private static int bytesToint(
+ byte[] inBytes,
+ int inOff)
+ {
+ return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
+ ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
+ }
+
+ //int to array of bytes
+ private static void intTobytes(
+ int num,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff + 3] = (byte)(num >> 24);
+ outBytes[outOff + 2] = (byte)(num >> 16);
+ outBytes[outOff + 1] = (byte)(num >> 8);
+ outBytes[outOff] = (byte)num;
+ }
+
+ /**
+ * Return the S-Box associated with SBoxName
+ * @param sBoxName name of the S-Box
+ * @return byte array representing the S-Box
+ */
+ public static byte[] GetSBox(
+ string sBoxName)
+ {
+ byte[] namedSBox = (byte[])sBoxes[sBoxName.ToUpper(CultureInfo.InvariantCulture)];
+
+ if (namedSBox == null)
+ {
+ throw new ArgumentException("Unknown S-Box - possible types: "
+ + "\"E-Test\", \"E-A\", \"E-B\", \"E-C\", \"E-D\", \"D-Test\", \"D-A\".");
+ }
+
+ return (byte[]) namedSBox.Clone();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/HC128Engine.cs b/src/core/srcbc/crypto/engines/HC128Engine.cs
new file mode 100644
index 0000000..0a8d214
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/HC128Engine.cs
@@ -0,0 +1,241 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * HC-128 is a software-efficient stream cipher created by Hongjun Wu. It
+ * generates keystream from a 128-bit secret key and a 128-bit initialization
+ * vector.
+ *
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+ *
+ * It is a third phase candidate in the eStream contest, and is patent-free.
+ * No attacks are known as of today (April 2007). See
+ *
+ * http://www.ecrypt.eu.org/stream/hcp3.html
+ *
+ */
+ public class HC128Engine
+ : IStreamCipher
+ {
+ private uint[] p = new uint[512];
+ private uint[] q = new uint[512];
+ private uint cnt = 0;
+
+ private static uint F1(uint x)
+ {
+ return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
+ }
+
+ private static uint F2(uint x)
+ {
+ return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
+ }
+
+ private uint G1(uint x, uint y, uint z)
+ {
+ return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8);
+ }
+
+ private uint G2(uint x, uint y, uint z)
+ {
+ return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8);
+ }
+
+ private static uint RotateLeft(uint x, int bits)
+ {
+ return (x << bits) | (x >> -bits);
+ }
+
+ private static uint RotateRight(uint x, int bits)
+ {
+ return (x >> bits) | (x << -bits);
+ }
+
+ private uint H1(uint x)
+ {
+ return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256];
+ }
+
+ private uint H2(uint x)
+ {
+ return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256];
+ }
+
+ private static uint Mod1024(uint x)
+ {
+ return x & 0x3FF;
+ }
+
+ private static uint Mod512(uint x)
+ {
+ return x & 0x1FF;
+ }
+
+ private static uint Dim(uint x, uint y)
+ {
+ return Mod512(x - y);
+ }
+
+ private uint Step()
+ {
+ uint j = Mod512(cnt);
+ uint ret;
+ if (cnt < 512)
+ {
+ p[j] += G1(p[Dim(j, 3)], p[Dim(j, 10)], p[Dim(j, 511)]);
+ ret = H1(p[Dim(j, 12)]) ^ p[j];
+ }
+ else
+ {
+ q[j] += G2(q[Dim(j, 3)], q[Dim(j, 10)], q[Dim(j, 511)]);
+ ret = H2(q[Dim(j, 12)]) ^ q[j];
+ }
+ cnt = Mod1024(cnt + 1);
+ return ret;
+ }
+
+ private byte[] key, iv;
+ private bool initialised;
+
+ private void Init()
+ {
+ if (key.Length != 16)
+ throw new ArgumentException("The key must be 128 bit long");
+
+ cnt = 0;
+
+ uint[] w = new uint[1280];
+
+ for (int i = 0; i < 16; i++)
+ {
+ w[i >> 3] |= ((uint)key[i] << (i & 0x7));
+ }
+ Array.Copy(w, 0, w, 4, 4);
+
+ for (int i = 0; i < iv.Length && i < 16; i++)
+ {
+ w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7));
+ }
+ Array.Copy(w, 8, w, 12, 4);
+
+ for (uint i = 16; i < 1280; i++)
+ {
+ w[i] = F2(w[i - 2]) + w[i - 7] + F1(w[i - 15]) + w[i - 16] + i;
+ }
+
+ Array.Copy(w, 256, p, 0, 512);
+ Array.Copy(w, 768, q, 0, 512);
+
+ for (int i = 0; i < 512; i++)
+ {
+ p[i] = Step();
+ }
+ for (int i = 0; i < 512; i++)
+ {
+ q[i] = Step();
+ }
+
+ cnt = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "HC-128"; }
+ }
+
+ /**
+ * Initialise a HC-128 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption. Irrelevant, as
+ * encryption and decryption are the same.
+ * @param params the parameters required to set up the cipher.
+ * @throws ArgumentException if the params argument is
+ * inappropriate (ie. the key is not 128 bit long).
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ ICipherParameters keyParam = parameters;
+
+ if (parameters is ParametersWithIV)
+ {
+ iv = ((ParametersWithIV)parameters).GetIV();
+ keyParam = ((ParametersWithIV)parameters).Parameters;
+ }
+ else
+ {
+ iv = new byte[0];
+ }
+
+ if (keyParam is KeyParameter)
+ {
+ key = ((KeyParameter)keyParam).GetKey();
+ Init();
+ }
+ else
+ {
+ throw new ArgumentException(
+ "Invalid parameter passed to HC128 init - " + parameters.GetType().Name,
+ "parameters");
+ }
+
+ initialised = true;
+ }
+
+ private byte[] buf = new byte[4];
+ private int idx = 0;
+
+ private byte GetByte()
+ {
+ if (idx == 0)
+ {
+ uint step = Step();
+ buf[3] = (byte)step;
+ step >>= 8;
+ buf[2] = (byte)step;
+ step >>= 8;
+ buf[1] = (byte)step;
+ step >>= 8;
+ buf[0] = (byte)step;
+ }
+ byte ret = buf[idx];
+ idx = idx + 1 & 0x3;
+ return ret;
+ }
+
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + len) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + len) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+ }
+ }
+
+ public void Reset()
+ {
+ idx = 0;
+ Init();
+ }
+
+ public byte ReturnByte(byte input)
+ {
+ return (byte)(input ^ GetByte());
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/HC256Engine.cs b/src/core/srcbc/crypto/engines/HC256Engine.cs
new file mode 100644
index 0000000..eff3ebc
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/HC256Engine.cs
@@ -0,0 +1,207 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * HC-256 is a software-efficient stream cipher created by Hongjun Wu. It
+ * generates keystream from a 256-bit secret key and a 256-bit initialization
+ * vector.
+ *
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+ *
+ * Its brother, HC-128, is a third phase candidate in the eStream contest.
+ * The algorithm is patent-free. No attacks are known as of today (April 2007).
+ * See
+ *
+ * http://www.ecrypt.eu.org/stream/hcp3.html
+ *
+ */
+ public class HC256Engine
+ : IStreamCipher
+ {
+ private uint[] p = new uint[1024];
+ private uint[] q = new uint[1024];
+ private uint cnt = 0;
+
+ private uint Step()
+ {
+ uint j = cnt & 0x3FF;
+ uint ret;
+ if (cnt < 1024)
+ {
+ uint x = p[(j - 3 & 0x3FF)];
+ uint y = p[(j - 1023 & 0x3FF)];
+ p[j] += p[(j - 10 & 0x3FF)]
+ + (RotateRight(x, 10) ^ RotateRight(y, 23))
+ + q[((x ^ y) & 0x3FF)];
+
+ x = p[(j - 12 & 0x3FF)];
+ ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
+ + q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
+ ^ p[j];
+ }
+ else
+ {
+ uint x = q[(j - 3 & 0x3FF)];
+ uint y = q[(j - 1023 & 0x3FF)];
+ q[j] += q[(j - 10 & 0x3FF)]
+ + (RotateRight(x, 10) ^ RotateRight(y, 23))
+ + p[((x ^ y) & 0x3FF)];
+
+ x = q[(j - 12 & 0x3FF)];
+ ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
+ + p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
+ ^ q[j];
+ }
+ cnt = cnt + 1 & 0x7FF;
+ return ret;
+ }
+
+ private byte[] key, iv;
+ private bool initialised;
+
+ private void Init()
+ {
+ if (key.Length != 32)
+ throw new ArgumentException("The key must be 256 bit long");
+
+ cnt = 0;
+
+ uint[] w = new uint[2560];
+
+ for (int i = 0; i < 32; i++)
+ {
+ w[i >> 3] |= ((uint)key[i] << (i & 0x7));
+ }
+
+ for (int i = 0; i < iv.Length && i < 32; i++)
+ {
+ w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7));
+ }
+
+ for (uint i = 16; i < 2560; i++)
+ {
+ uint x = w[i - 2];
+ uint y = w[i - 15];
+ w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10))
+ + w[i - 7]
+ + (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3))
+ + w[i - 16] + i;
+ }
+
+ Array.Copy(w, 512, p, 0, 1024);
+ Array.Copy(w, 1536, q, 0, 1024);
+
+ for (int i = 0; i < 4096; i++)
+ {
+ Step();
+ }
+
+ cnt = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "HC-256"; }
+ }
+
+ /**
+ * Initialise a HC-256 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption. Irrelevant, as
+ * encryption and decryption are the same.
+ * @param params the parameters required to set up the cipher.
+ * @throws ArgumentException if the params argument is
+ * inappropriate (ie. the key is not 256 bit long).
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ ICipherParameters keyParam = parameters;
+
+ if (parameters is ParametersWithIV)
+ {
+ iv = ((ParametersWithIV)parameters).GetIV();
+ keyParam = ((ParametersWithIV)parameters).Parameters;
+ }
+ else
+ {
+ iv = new byte[0];
+ }
+
+ if (keyParam is KeyParameter)
+ {
+ key = ((KeyParameter)keyParam).GetKey();
+ Init();
+ }
+ else
+ {
+ throw new ArgumentException(
+ "Invalid parameter passed to HC256 init - " + parameters.GetType().Name,
+ "parameters");
+ }
+
+ initialised = true;
+ }
+
+ private byte[] buf = new byte[4];
+ private int idx = 0;
+
+ private byte GetByte()
+ {
+ if (idx == 0)
+ {
+ uint step = Step();
+ buf[3] = (byte)step;
+ step >>= 8;
+ buf[2] = (byte)step;
+ step >>= 8;
+ buf[1] = (byte)step;
+ step >>= 8;
+ buf[0] = (byte)step;
+ }
+ byte ret = buf[idx];
+ idx = idx + 1 & 0x3;
+ return ret;
+ }
+
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + len) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + len) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+ }
+ }
+
+ public void Reset()
+ {
+ idx = 0;
+ Init();
+ }
+
+ public byte ReturnByte(byte input)
+ {
+ return (byte)(input ^ GetByte());
+ }
+
+ private static uint RotateRight(uint x, int bits)
+ {
+ return (x >> bits) | (x << -bits);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/ISAACEngine.cs b/src/core/srcbc/crypto/engines/ISAACEngine.cs
new file mode 100644
index 0000000..50e9def
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/ISAACEngine.cs
@@ -0,0 +1,252 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+ * see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+ */
+ public class IsaacEngine
+ : IStreamCipher
+ {
+ // Constants
+ private static readonly int sizeL = 8,
+ stateArraySize = sizeL<<5; // 256
+
+ // Cipher's internal state
+ private uint[] engineState = null, // mm
+ results = null; // randrsl
+ private uint a = 0, b = 0, c = 0;
+
+ // Engine state
+ private int index = 0;
+ private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes
+ workingKey = null;
+ private bool initialised = false;
+
+ /**
+ * initialise an ISAAC cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException(
+ "invalid parameter passed to ISAAC Init - " + parameters.GetType().Name,
+ "parameters");
+
+ /*
+ * ISAAC encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ KeyParameter p = (KeyParameter) parameters;
+ setKey(p.GetKey());
+ }
+
+ public byte ReturnByte(
+ byte input)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = intToByteLittle(results);
+ }
+
+ byte output = (byte)(keyStream[index]^input);
+ index = (index + 1) & 1023;
+
+ return output;
+ }
+
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + len) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + len) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = intToByteLittle(results);
+ }
+ output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]);
+ index = (index + 1) & 1023;
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "ISAAC"; }
+ }
+
+ public void Reset()
+ {
+ setKey(workingKey);
+ }
+
+ // Private implementation
+ private void setKey(
+ byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ if (engineState == null)
+ {
+ engineState = new uint[stateArraySize];
+ }
+
+ if (results == null)
+ {
+ results = new uint[stateArraySize];
+ }
+
+ int i, j, k;
+
+ // Reset state
+ for (i = 0; i < stateArraySize; i++)
+ {
+ engineState[i] = results[i] = 0;
+ }
+ a = b = c = 0;
+
+ // Reset index counter for output
+ index = 0;
+
+ // Convert the key bytes to ints and put them into results[] for initialization
+ byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)];
+ Array.Copy(keyBytes, 0, t, 0, keyBytes.Length);
+ for (i = 0; i < t.Length; i+=4)
+ {
+ results[i>>2] = byteToIntLittle(t, i);
+ }
+
+ // It has begun?
+ uint[] abcdefgh = new uint[sizeL];
+
+ for (i = 0; i < sizeL; i++)
+ {
+ abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ mix(abcdefgh);
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < stateArraySize; j+=sizeL)
+ {
+ for (k = 0; k < sizeL; k++)
+ {
+ abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
+ }
+
+ mix(abcdefgh);
+
+ for (k = 0; k < sizeL; k++)
+ {
+ engineState[j+k] = abcdefgh[k];
+ }
+ }
+ }
+
+ isaac();
+
+ initialised = true;
+ }
+
+ private void isaac()
+ {
+ uint x, y;
+
+ b += ++c;
+ for (int i = 0; i < stateArraySize; i++)
+ {
+ x = engineState[i];
+ switch (i & 3)
+ {
+ case 0: a ^= (a << 13); break;
+ case 1: a ^= (a >> 6); break;
+ case 2: a ^= (a << 2); break;
+ case 3: a ^= (a >> 16); break;
+ }
+ a += engineState[(i+128) & 0xFF];
+ engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b;
+ results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x;
+ }
+ }
+
+ private void mix(uint[] x)
+ {
+// x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
+// x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3];
+// x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
+// x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5];
+// x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
+// x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7];
+// x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
+// x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1];
+ x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
+ x[1]^=x[2]>> 2; x[4]+=x[1]; x[2]+=x[3];
+ x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
+ x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5];
+ x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
+ x[5]^=x[6]>> 4; x[0]+=x[5]; x[6]+=x[7];
+ x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
+ x[7]^=x[0]>> 9; x[2]+=x[7]; x[0]+=x[1];
+ }
+
+ private uint byteToIntLittle(
+ byte[] x,
+ int offset)
+ {
+ uint result = (byte) x[offset + 3];
+ result = (result << 8) | x[offset + 2];
+ result = (result << 8) | x[offset + 1];
+ result = (result << 8) | x[offset + 0];
+ return result;
+ }
+
+ private byte[] intToByteLittle(
+ uint x)
+ {
+ byte[] output = new byte[4];
+ output[3] = (byte)x;
+ output[2] = (byte)(x >> 8);
+ output[1] = (byte)(x >> 16);
+ output[0] = (byte)(x >> 24);
+ return output;
+ }
+
+ private byte[] intToByteLittle(
+ uint[] x)
+ {
+ byte[] output = new byte[4*x.Length];
+ for (int i = 0, j = 0; i < x.Length; i++,j+=4)
+ {
+ Array.Copy(intToByteLittle(x[i]), 0, output, j, 4);
+ }
+ return output;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/IdeaEngine.cs b/src/core/srcbc/crypto/engines/IdeaEngine.cs
new file mode 100644
index 0000000..247b91a
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/IdeaEngine.cs
@@ -0,0 +1,333 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
+ *
+ * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
+ * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
+ * end of the mulinv function!).
+ *
+ *
+ * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
+ *
+ *
+ * Note: This algorithm is patented in the USA, Japan, and Europe including
+ * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
+ * and the United Kingdom. Non-commercial use is free, however any commercial
+ * products are liable for royalties. Please see
+ * www.mediacrypt.com for
+ * further details. This announcement has been included at the request of
+ * the patent holders.
+ *
+ */
+ public class IdeaEngine
+ : IBlockCipher
+ {
+ private const int BLOCK_SIZE = 8;
+ private int[] workingKey;
+ /**
+ * standard constructor.
+ */
+ public IdeaEngine()
+ {
+ }
+ /**
+ * initialise an IDEA cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString());
+
+ workingKey = GenerateWorkingKey(forEncryption,
+ ((KeyParameter)parameters).GetKey());
+ }
+
+ public string AlgorithmName
+ {
+ get { return "IDEA"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new InvalidOperationException("IDEA engine not initialised");
+ }
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ IdeaFunc(workingKey, input, inOff, output, outOff);
+ return BLOCK_SIZE;
+ }
+ public void Reset()
+ {
+ }
+ private static readonly int MASK = 0xffff;
+ private static readonly int BASE = 0x10001;
+ private int BytesToWord(
+ byte[] input,
+ int inOff)
+ {
+ return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff);
+ }
+ private void WordToBytes(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)((uint) word >> 8);
+ outBytes[outOff + 1] = (byte)word;
+ }
+ /**
+ * return x = x * y where the multiplication is done modulo
+ * 65537 (0x10001) (as defined in the IDEA specification) and
+ * a zero input is taken to be 65536 (0x10000).
+ *
+ * @param x the x value
+ * @param y the y value
+ * @return x = x * y
+ */
+ private int Mul(
+ int x,
+ int y)
+ {
+ if (x == 0)
+ {
+ x = (BASE - y);
+ }
+ else if (y == 0)
+ {
+ x = (BASE - x);
+ }
+ else
+ {
+ int p = x * y;
+ y = p & MASK;
+ x = (int) ((uint) p >> 16);
+ x = y - x + ((y < x) ? 1 : 0);
+ }
+ return x & MASK;
+ }
+ private void IdeaFunc(
+ int[] workingKey,
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int x0, x1, x2, x3, t0, t1;
+ int keyOff = 0;
+ x0 = BytesToWord(input, inOff);
+ x1 = BytesToWord(input, inOff + 2);
+ x2 = BytesToWord(input, inOff + 4);
+ x3 = BytesToWord(input, inOff + 6);
+ for (int round = 0; round < 8; round++)
+ {
+ x0 = Mul(x0, workingKey[keyOff++]);
+ x1 += workingKey[keyOff++];
+ x1 &= MASK;
+ x2 += workingKey[keyOff++];
+ x2 &= MASK;
+ x3 = Mul(x3, workingKey[keyOff++]);
+ t0 = x1;
+ t1 = x2;
+ x2 ^= x0;
+ x1 ^= x3;
+ x2 = Mul(x2, workingKey[keyOff++]);
+ x1 += x2;
+ x1 &= MASK;
+ x1 = Mul(x1, workingKey[keyOff++]);
+ x2 += x1;
+ x2 &= MASK;
+ x0 ^= x1;
+ x3 ^= x2;
+ x1 ^= t1;
+ x2 ^= t0;
+ }
+ WordToBytes(Mul(x0, workingKey[keyOff++]), outBytes, outOff);
+ WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2); /* NB: Order */
+ WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
+ WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
+ }
+ /**
+ * The following function is used to expand the user key to the encryption
+ * subkey. The first 16 bytes are the user key, and the rest of the subkey
+ * is calculated by rotating the previous 16 bytes by 25 bits to the left,
+ * and so on until the subkey is completed.
+ */
+ private int[] ExpandKey(
+ byte[] uKey)
+ {
+ int[] key = new int[52];
+ if (uKey.Length < 16)
+ {
+ byte[] tmp = new byte[16];
+ Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length);
+ uKey = tmp;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ key[i] = BytesToWord(uKey, i * 2);
+ }
+ for (int i = 8; i < 52; i++)
+ {
+ if ((i & 7) < 6)
+ {
+ key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK;
+ }
+ else if ((i & 7) == 6)
+ {
+ key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK;
+ }
+ else
+ {
+ key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK;
+ }
+ }
+ return key;
+ }
+ /**
+ * This function computes multiplicative inverse using Euclid's Greatest
+ * Common Divisor algorithm. Zero and one are self inverse.
+ *
+ * i.e. x * MulInv(x) == 1 (modulo BASE)
+ *
+ */
+ private int MulInv(
+ int x)
+ {
+ int t0, t1, q, y;
+
+ if (x < 2)
+ {
+ return x;
+ }
+ t0 = 1;
+ t1 = BASE / x;
+ y = BASE % x;
+ while (y != 1)
+ {
+ q = x / y;
+ x = x % y;
+ t0 = (t0 + (t1 * q)) & MASK;
+ if (x == 1)
+ {
+ return t0;
+ }
+ q = y / x;
+ y = y % x;
+ t1 = (t1 + (t0 * q)) & MASK;
+ }
+ return (1 - t1) & MASK;
+ }
+ /**
+ * Return the additive inverse of x.
+ *
+ * i.e. x + AddInv(x) == 0
+ *
+ */
+ int AddInv(
+ int x)
+ {
+ return (0 - x) & MASK;
+ }
+
+ /**
+ * The function to invert the encryption subkey to the decryption subkey.
+ * It also involves the multiplicative inverse and the additive inverse functions.
+ */
+ private int[] InvertKey(
+ int[] inKey)
+ {
+ int t1, t2, t3, t4;
+ int p = 52; /* We work backwards */
+ int[] key = new int[52];
+ int inOff = 0;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+
+ for (int round = 1; round < 8; round++)
+ {
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t2; /* NB: Order */
+ key[--p] = t3;
+ key[--p] = t1;
+ }
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+ return key;
+ }
+
+ private int[] GenerateWorkingKey(
+ bool forEncryption,
+ byte[] userKey)
+ {
+ if (forEncryption)
+ {
+ return ExpandKey(userKey);
+ }
+ else
+ {
+ return InvertKey(ExpandKey(userKey));
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/IesEngine.cs b/src/core/srcbc/crypto/engines/IesEngine.cs
new file mode 100644
index 0000000..9282770
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/IesEngine.cs
@@ -0,0 +1,236 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * support class for constructing intergrated encryption ciphers
+ * for doing basic message exchanges on top of key agreement ciphers
+ */
+ public class IesEngine
+ {
+ private readonly IBasicAgreement agree;
+ private readonly IDerivationFunction kdf;
+ private readonly IMac mac;
+ private readonly BufferedBlockCipher cipher;
+ private readonly byte[] macBuf;
+
+ private bool forEncryption;
+ private ICipherParameters privParam, pubParam;
+ private IesParameters param;
+
+ /**
+ * set up for use with stream mode, where the key derivation function
+ * is used to provide a stream of bytes to xor with the message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ */
+ public IesEngine(
+ IBasicAgreement agree,
+ IDerivationFunction kdf,
+ IMac mac)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.GetMacSize()];
+// this.cipher = null;
+ }
+
+ /**
+ * set up for use in conjunction with a block cipher to handle the
+ * message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ * @param cipher the cipher to used for encrypting the message
+ */
+ public IesEngine(
+ IBasicAgreement agree,
+ IDerivationFunction kdf,
+ IMac mac,
+ BufferedBlockCipher cipher)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.GetMacSize()];
+ this.cipher = cipher;
+ }
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param forEncryption whether or not this is encryption/decryption.
+ * @param privParam our private key parameters
+ * @param pubParam the recipient's/sender's public key parameters
+ * @param param encoding and derivation parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters privParameters,
+ ICipherParameters pubParameters,
+ ICipherParameters iesParameters)
+ {
+ this.forEncryption = forEncryption;
+ this.privParam = privParameters;
+ this.pubParam = pubParameters;
+ this.param = (IesParameters)iesParameters;
+ }
+
+ private byte[] DecryptBlock(
+ byte[] in_enc,
+ int inOff,
+ int inLen,
+ byte[] z)
+ {
+ byte[] M = null;
+ KeyParameter macKey = null;
+ KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
+ int macKeySize = param.MacKeySize;
+
+ kdf.Init(kParam);
+
+ inLen -= mac.GetMacSize();
+
+ if (cipher == null) // stream mode
+ {
+ byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+ M = new byte[inLen];
+
+ for (int i = 0; i != inLen; i++)
+ {
+ M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]);
+ }
+
+ macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+ }
+ else
+ {
+ int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+ byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+
+ cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
+
+ M = cipher.DoFinal(in_enc, inOff, inLen);
+
+ macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+ }
+
+ byte[] macIV = param.GetEncodingV();
+
+ mac.Init(macKey);
+ mac.BlockUpdate(in_enc, inOff, inLen);
+ mac.BlockUpdate(macIV, 0, macIV.Length);
+ mac.DoFinal(macBuf, 0);
+
+ inOff += inLen;
+
+ for (int t = 0; t < macBuf.Length; t++)
+ {
+ if (macBuf[t] != in_enc[inOff + t])
+ {
+ throw (new InvalidCipherTextException("IMac codes failed to equal."));
+ }
+ }
+
+ return M;
+ }
+
+ private byte[] EncryptBlock(
+ byte[] input,
+ int inOff,
+ int inLen,
+ byte[] z)
+ {
+ byte[] C = null;
+ KeyParameter macKey = null;
+ KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
+ int c_text_length = 0;
+ int macKeySize = param.MacKeySize;
+
+ if (cipher == null) // stream mode
+ {
+ byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+ C = new byte[inLen + mac.GetMacSize()];
+ c_text_length = inLen;
+
+ for (int i = 0; i != inLen; i++)
+ {
+ C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
+ }
+
+ macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+ }
+ else
+ {
+ int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+ byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+
+ cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
+
+ c_text_length = cipher.GetOutputSize(inLen);
+ byte[] tmp = new byte[c_text_length];
+
+ int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
+ len += cipher.DoFinal(tmp, len);
+
+ C = new byte[len + mac.GetMacSize()];
+ c_text_length = len;
+
+ Array.Copy(tmp, 0, C, 0, len);
+
+ macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+ }
+
+ byte[] macIV = param.GetEncodingV();
+
+ mac.Init(macKey);
+ mac.BlockUpdate(C, 0, c_text_length);
+ mac.BlockUpdate(macIV, 0, macIV.Length);
+ //
+ // return the message and it's MAC
+ //
+ mac.DoFinal(C, c_text_length);
+ return C;
+ }
+
+ private byte[] GenerateKdfBytes(
+ KdfParameters kParam,
+ int length)
+ {
+ byte[] buf = new byte[length];
+
+ kdf.Init(kParam);
+
+ kdf.GenerateBytes(buf, 0, buf.Length);
+
+ return buf;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ agree.Init(privParam);
+
+ BigInteger z = agree.CalculateAgreement(pubParam);
+
+ // TODO Check that this is right (...Unsigned? Check length?)
+ byte[] zBytes = z.ToByteArray();
+
+ return forEncryption
+ ? EncryptBlock(input, inOff, inLen, zBytes)
+ : DecryptBlock(input, inOff, inLen, zBytes);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/NaccacheSternEngine.cs b/src/core/srcbc/crypto/engines/NaccacheSternEngine.cs
new file mode 100644
index 0000000..94355e2
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/NaccacheSternEngine.cs
@@ -0,0 +1,432 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * NaccacheStern Engine. For details on this cipher, please see
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternEngine
+ : IAsymmetricBlockCipher
+ {
+ private bool forEncryption;
+
+ private NaccacheSternKeyParameters key;
+
+ private ArrayList[] lookup = null;
+
+ private bool debug = false;
+
+ public string AlgorithmName
+ {
+ get { return "NaccacheStern"; }
+ }
+
+ /**
+ * Initializes this algorithm. Must be called before all other Functions.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
+ * org.bouncycastle.crypto.CipherParameters)
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ key = (NaccacheSternKeyParameters)parameters;
+
+ // construct lookup table for faster decryption if necessary
+ if (!this.forEncryption)
+ {
+ if (debug)
+ {
+ Console.WriteLine("Constructing lookup Array");
+ }
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ ArrayList primes = priv.SmallPrimes;
+ lookup = new ArrayList[primes.Count];
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger actualPrime = (BigInteger) primes[i];
+ int actualPrimeValue = actualPrime.IntValue;
+
+ lookup[i] = new ArrayList(actualPrimeValue);
+ lookup[i].Add(BigInteger.One);
+
+ if (debug)
+ {
+ Console.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue);
+ }
+
+ BigInteger accJ = BigInteger.Zero;
+
+ for (int j = 1; j < actualPrimeValue; j++)
+ {
+// BigInteger bigJ = BigInteger.ValueOf(j);
+// accJ = priv.PhiN.Multiply(bigJ);
+ accJ = accJ.Add(priv.PhiN);
+ BigInteger comp = accJ.Divide(actualPrime);
+ lookup[i].Add(priv.G.ModPow(comp, priv.Modulus));
+ }
+ }
+ }
+ }
+
+ public bool Debug
+ {
+ set { this.debug = value; }
+ }
+
+ /**
+ * Returns the input block size of this algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
+ */
+ public int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // We can only encrypt values up to lowerSigmaBound
+ return (key.LowerSigmaBound + 7) / 8 - 1;
+ }
+ else
+ {
+ // We pad to modulus-size bytes for easier decryption.
+// return key.Modulus.ToByteArray().Length;
+ return key.Modulus.BitLength / 8 + 1;
+ }
+ }
+
+ /**
+ * Returns the output block size of this algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
+ */
+ public int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // encrypted Data is always padded up to modulus size
+// return key.Modulus.ToByteArray().Length;
+ return key.Modulus.BitLength / 8 + 1;
+ }
+ else
+ {
+ // decrypted Data has upper limit lowerSigmaBound
+ return (key.LowerSigmaBound + 7) / 8 - 1;
+ }
+ }
+
+ /**
+ * Process a single Block using the Naccache-Stern algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
+ * int, int)
+ */
+ public byte[] ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ int length)
+ {
+ if (key == null)
+ throw new InvalidOperationException("NaccacheStern engine not initialised");
+ if (length > (GetInputBlockSize() + 1))
+ throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
+
+ if (!forEncryption)
+ {
+ // At decryption make sure that we receive padded data blocks
+ if (length < GetInputBlockSize())
+ {
+ throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
+ }
+ }
+
+ // transform input into BigInteger
+ BigInteger input = new BigInteger(1, inBytes, inOff, length);
+
+ if (debug)
+ {
+ Console.WriteLine("input as BigInteger: " + input);
+ }
+
+ byte[] output;
+ if (forEncryption)
+ {
+ output = Encrypt(input);
+ }
+ else
+ {
+ ArrayList plain = new ArrayList();
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ ArrayList primes = priv.SmallPrimes;
+ // Get Chinese Remainders of CipherText
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus);
+ ArrayList al = lookup[i];
+ if (lookup[i].Count != ((BigInteger)primes[i]).IntValue)
+ {
+ if (debug)
+ {
+ Console.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count);
+ }
+ throw new InvalidCipherTextException("Error in lookup Array for "
+ + ((BigInteger)primes[i]).IntValue
+ + ": Size mismatch. Expected ArrayList with length "
+ + ((BigInteger)primes[i]).IntValue + " but found ArrayList of length "
+ + lookup[i].Count);
+ }
+ int lookedup = al.IndexOf(exp);
+
+ if (lookedup == -1)
+ {
+ if (debug)
+ {
+ Console.WriteLine("Actual prime is " + primes[i]);
+ Console.WriteLine("Decrypted value is " + exp);
+
+ Console.WriteLine("LookupList for " + primes[i] + " with size " + lookup[i].Count
+ + " is: ");
+ for (int j = 0; j < lookup[i].Count; j++)
+ {
+ Console.WriteLine(lookup[i][j]);
+ }
+ }
+ throw new InvalidCipherTextException("Lookup failed");
+ }
+ plain.Add(BigInteger.ValueOf(lookedup));
+ }
+ BigInteger test = chineseRemainder(plain, primes);
+
+ // Should not be used as an oracle, so reencrypt output to see
+ // if it corresponds to input
+
+ // this breaks probabilisic encryption, so disable it. Anyway, we do
+ // use the first n primes for key generation, so it is pretty easy
+ // to guess them. But as stated in the paper, this is not a security
+ // breach. So we can just work with the correct sigma.
+
+ // if (debug) {
+ // Console.WriteLine("Decryption is " + test);
+ // }
+ // if ((key.G.ModPow(test, key.Modulus)).Equals(input)) {
+ // output = test.ToByteArray();
+ // } else {
+ // if(debug){
+ // Console.WriteLine("Engine seems to be used as an oracle,
+ // returning null");
+ // }
+ // output = null;
+ // }
+
+ output = test.ToByteArray();
+ }
+
+ return output;
+ }
+
+ /**
+ * Encrypts a BigInteger aka Plaintext with the public key.
+ *
+ * @param plain
+ * The BigInteger to encrypt
+ * @return The byte[] representation of the encrypted BigInteger (i.e.
+ * crypted.toByteArray())
+ */
+ public byte[] Encrypt(
+ BigInteger plain)
+ {
+ // Always return modulus size values 0-padded at the beginning
+ // 0-padding at the beginning is correctly parsed by BigInteger :)
+// byte[] output = key.Modulus.ToByteArray();
+// Array.Clear(output, 0, output.Length);
+ byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+ byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray();
+ Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
+ if (debug)
+ {
+ Console.WriteLine("Encrypted value is: " + new BigInteger(output));
+ }
+ return output;
+ }
+
+ /**
+ * Adds the contents of two encrypted blocks mod sigma
+ *
+ * @param block1
+ * the first encrypted block
+ * @param block2
+ * the second encrypted block
+ * @return encrypt((block1 + block2) mod sigma)
+ * @throws InvalidCipherTextException
+ */
+ public byte[] AddCryptedBlocks(
+ byte[] block1,
+ byte[] block2)
+ {
+ // check for correct blocksize
+ if (forEncryption)
+ {
+ if ((block1.Length > GetOutputBlockSize())
+ || (block2.Length > GetOutputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+ else
+ {
+ if ((block1.Length > GetInputBlockSize())
+ || (block2.Length > GetInputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+
+ // calculate resulting block
+ BigInteger m1Crypt = new BigInteger(1, block1);
+ BigInteger m2Crypt = new BigInteger(1, block2);
+ BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt);
+ m1m2Crypt = m1m2Crypt.Mod(key.Modulus);
+ if (debug)
+ {
+ Console.WriteLine("c(m1) as BigInteger:....... " + m1Crypt);
+ Console.WriteLine("c(m2) as BigInteger:....... " + m2Crypt);
+ Console.WriteLine("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt);
+ }
+
+ //byte[] output = key.Modulus.ToByteArray();
+ //Array.Clear(output, 0, output.Length);
+ byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+ byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray();
+ Array.Copy(m1m2CryptBytes, 0, output,
+ output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length);
+
+ return output;
+ }
+
+ /**
+ * Convenience Method for data exchange with the cipher.
+ *
+ * Determines blocksize and splits data to blocksize.
+ *
+ * @param data the data to be processed
+ * @return the data after it went through the NaccacheSternEngine.
+ * @throws InvalidCipherTextException
+ */
+ public byte[] ProcessData(
+ byte[] data)
+ {
+ if (debug)
+ {
+ Console.WriteLine();
+ }
+ if (data.Length > GetInputBlockSize())
+ {
+ int inBlocksize = GetInputBlockSize();
+ int outBlocksize = GetOutputBlockSize();
+ if (debug)
+ {
+ Console.WriteLine("Input blocksize is: " + inBlocksize + " bytes");
+ Console.WriteLine("Output blocksize is: " + outBlocksize + " bytes");
+ Console.WriteLine("Data has length:.... " + data.Length + " bytes");
+ }
+ int datapos = 0;
+ int retpos = 0;
+ byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize];
+ while (datapos < data.Length)
+ {
+ byte[] tmp;
+ if (datapos + inBlocksize < data.Length)
+ {
+ tmp = ProcessBlock(data, datapos, inBlocksize);
+ datapos += inBlocksize;
+ }
+ else
+ {
+ tmp = ProcessBlock(data, datapos, data.Length - datapos);
+ datapos += data.Length - datapos;
+ }
+ if (debug)
+ {
+ Console.WriteLine("new datapos is " + datapos);
+ }
+ if (tmp != null)
+ {
+ tmp.CopyTo(retval, retpos);
+ retpos += tmp.Length;
+ }
+ else
+ {
+ if (debug)
+ {
+ Console.WriteLine("cipher returned null");
+ }
+ throw new InvalidCipherTextException("cipher returned null");
+ }
+ }
+ byte[] ret = new byte[retpos];
+ Array.Copy(retval, 0, ret, 0, retpos);
+ if (debug)
+ {
+ Console.WriteLine("returning " + ret.Length + " bytes");
+ }
+ return ret;
+ }
+ else
+ {
+ if (debug)
+ {
+ Console.WriteLine("data size is less then input block size, processing directly");
+ }
+ return ProcessBlock(data, 0, data.Length);
+ }
+ }
+
+ /**
+ * Computes the integer x that is expressed through the given primes and the
+ * congruences with the chinese remainder theorem (CRT).
+ *
+ * @param congruences
+ * the congruences c_i
+ * @param primes
+ * the primes p_i
+ * @return an integer x for that x % p_i == c_i
+ */
+ private static BigInteger chineseRemainder(ArrayList congruences, ArrayList primes)
+ {
+ BigInteger retval = BigInteger.Zero;
+ BigInteger all = BigInteger.One;
+ for (int i = 0; i < primes.Count; i++)
+ {
+ all = all.Multiply((BigInteger)primes[i]);
+ }
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger a = (BigInteger)primes[i];
+ BigInteger b = all.Divide(a);
+ BigInteger b_ = b.ModInverse(a);
+ BigInteger tmp = b.Multiply(b_);
+ tmp = tmp.Multiply((BigInteger)congruences[i]);
+ retval = retval.Add(tmp);
+ }
+
+ return retval.Mod(all);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/NoekeonEngine.cs b/src/core/srcbc/crypto/engines/NoekeonEngine.cs
new file mode 100644
index 0000000..618007f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/NoekeonEngine.cs
@@ -0,0 +1,256 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A Noekeon engine, using direct-key mode.
+ */
+ public class NoekeonEngine
+ : IBlockCipher
+ {
+ private const int GenericSize = 16; // Block and key size, as well as the amount of rounds.
+
+ private static readonly uint[] nullVector =
+ {
+ 0x00, 0x00, 0x00, 0x00 // Used in decryption
+ };
+
+ private static readonly uint[] roundConstants =
+ {
+ 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4
+ };
+
+ private uint[] state = new uint[4], // a
+ subKeys = new uint[4], // k
+ decryptKeys = new uint[4];
+
+ private bool _initialised, _forEncryption;
+
+ /**
+ * Create an instance of the Noekeon encryption algorithm
+ * and set some defaults
+ */
+ public NoekeonEngine()
+ {
+ _initialised = false;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Noekeon"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return GenericSize;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters");
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + GenericSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + GenericSize) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ return _forEncryption
+ ? encryptBlock(input, inOff, output, outOff)
+ : decryptBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ // TODO This should do something in case the encryption is aborted
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(byte[] key)
+ {
+ subKeys[0] = bytesToIntBig(key, 0);
+ subKeys[1] = bytesToIntBig(key, 4);
+ subKeys[2] = bytesToIntBig(key, 8);
+ subKeys[3] = bytesToIntBig(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = bytesToIntBig(input, inOff);
+ state[1] = bytesToIntBig(input, inOff+4);
+ state[2] = bytesToIntBig(input, inOff+8);
+ state[3] = bytesToIntBig(input, inOff+12);
+
+ int i;
+ for (i = 0; i < GenericSize; i++)
+ {
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+
+ intToBytesBig(state[0], output, outOff);
+ intToBytesBig(state[1], output, outOff+4);
+ intToBytesBig(state[2], output, outOff+8);
+ intToBytesBig(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private int decryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = bytesToIntBig(input, inOff);
+ state[1] = bytesToIntBig(input, inOff+4);
+ state[2] = bytesToIntBig(input, inOff+8);
+ state[3] = bytesToIntBig(input, inOff+12);
+
+ Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length);
+ theta(decryptKeys, nullVector);
+
+ int i;
+ for (i = GenericSize; i > 0; i--)
+ {
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+
+ intToBytesBig(state[0], output, outOff);
+ intToBytesBig(state[1], output, outOff+4);
+ intToBytesBig(state[2], output, outOff+8);
+ intToBytesBig(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private void gamma(uint[] a)
+ {
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+
+ uint tmp = a[3];
+ a[3] = a[0];
+ a[0] = tmp;
+ a[2] ^= a[0]^a[1]^a[3];
+
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+ }
+
+ private void theta(uint[] a, uint[] k)
+ {
+ uint tmp;
+ tmp = a[0]^a[2];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[1] ^= tmp;
+ a[3] ^= tmp;
+
+ for (int i = 0; i < 4; i++)
+ {
+ a[i] ^= k[i];
+ }
+
+ tmp = a[1]^a[3];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[0] ^= tmp;
+ a[2] ^= tmp;
+ }
+
+ private void pi1(uint[] a)
+ {
+ a[1] = rotl(a[1], 1);
+ a[2] = rotl(a[2], 5);
+ a[3] = rotl(a[3], 2);
+ }
+
+ private void pi2(uint[] a)
+ {
+ a[1] = rotl(a[1], 31);
+ a[2] = rotl(a[2], 27);
+ a[3] = rotl(a[3], 30);
+ }
+
+ // Helpers
+
+ private uint bytesToIntBig(byte[] input, int off)
+ {
+ int result = ((input[off++]) << 24) |
+ ((input[off++] & 0xff) << 16) |
+ ((input[off++] & 0xff) << 8) |
+ (input[off ] & 0xff);
+ return (uint) result;
+ }
+
+ private void intToBytesBig(uint x, byte[] output, int off)
+ {
+ output[off++] = (byte)(x >> 24);
+ output[off++] = (byte)(x >> 16);
+ output[off++] = (byte)(x >> 8);
+ output[off ] = (byte)x;
+ }
+
+ private uint rotl(uint x, int y)
+ {
+ return (x << y) | (x >> (32-y));
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/NullEngine.cs b/src/core/srcbc/crypto/engines/NullEngine.cs
new file mode 100644
index 0000000..22a4e4c
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/NullEngine.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+ * Provided for the sake of completeness.
+ */
+ public class NullEngine
+ : IBlockCipher
+ {
+ private bool initialised;
+ private const int BlockSize = 1;
+
+ public NullEngine()
+ {
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ // we don't mind any parameters that may come in
+ initialised = true;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Null"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Null engine not initialised");
+ if ((inOff + BlockSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BlockSize) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ for (int i = 0; i < BlockSize; ++i)
+ {
+ output[outOff + i] = input[inOff + i];
+ }
+
+ return BlockSize;
+ }
+
+ public void Reset()
+ {
+ // nothing needs to be done
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RC2Engine.cs b/src/core/srcbc/crypto/engines/RC2Engine.cs
new file mode 100644
index 0000000..3f3a513
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC2Engine.cs
@@ -0,0 +1,312 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of RC2 as described in RFC 2268
+ * "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+ */
+ public class RC2Engine
+ : IBlockCipher
+ {
+ //
+ // the values we use for key expansion (based on the digits of PI)
+ //
+ private static readonly byte[] piTable =
+ {
+ (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed,
+ (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d,
+ (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e,
+ (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2,
+ (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13,
+ (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32,
+ (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb,
+ (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82,
+ (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c,
+ (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc,
+ (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1,
+ (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26,
+ (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57,
+ (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3,
+ (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7,
+ (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7,
+ (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7,
+ (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a,
+ (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74,
+ (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec,
+ (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc,
+ (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39,
+ (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a,
+ (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31,
+ (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae,
+ (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9,
+ (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c,
+ (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9,
+ (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0,
+ (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e,
+ (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77,
+ (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad
+ };
+
+ private const int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+ private bool encrypting;
+
+ private int[] GenerateWorkingKey(
+ byte[] key,
+ int bits)
+ {
+ int x;
+ int[] xKey = new int[128];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ xKey[i] = key[i] & 0xff;
+ }
+
+ // Phase 1: Expand input key to 128 bytes
+ int len = key.Length;
+
+ if (len < 128)
+ {
+ int index = 0;
+
+ x = xKey[len - 1];
+
+ do
+ {
+ x = piTable[(x + xKey[index++]) & 255] & 0xff;
+ xKey[len++] = x;
+ }
+ while (len < 128);
+ }
+
+ // Phase 2 - reduce effective key size to "bits"
+ len = (bits + 7) >> 3;
+ x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
+ xKey[128 - len] = x;
+
+ for (int i = 128 - len - 1; i >= 0; i--)
+ {
+ x = piTable[x ^ xKey[i + len]] & 0xff;
+ xKey[i] = x;
+ }
+
+ // Phase 3 - copy to newKey in little-endian order
+ int[] newKey = new int[64];
+
+ for (int i = 0; i != newKey.Length; i++)
+ {
+ newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * initialise a RC2 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.encrypting = forEncryption;
+
+ if (parameters is RC2Parameters)
+ {
+ RC2Parameters param = (RC2Parameters) parameters;
+
+ workingKey = GenerateWorkingKey(param.GetKey(), param.EffectiveKeyBits);
+ }
+ else if (parameters is KeyParameter)
+ {
+ KeyParameter param = (KeyParameter) parameters;
+ byte[] key = param.GetKey();
+
+ workingKey = GenerateWorkingKey(key, key.Length * 8);
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to RC2 init - " + parameters.GetType().Name);
+ }
+ }
+
+ public void Reset()
+ {
+ }
+
+ public string AlgorithmName
+ {
+ get { return "RC2"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("RC2 engine not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * return the result rotating the 16 bit number in x left by y
+ */
+ private int RotateWordLeft(
+ int x,
+ int y)
+ {
+ x &= 0xffff;
+ return (x << y) | (x >> (16 - y));
+ }
+
+ private void EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+ x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+ x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+ x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff);
+
+ for (int i = 0; i <= 16; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 20; i <= 40; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 44; i < 64; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ outBytes[outOff + 0] = (byte)x10;
+ outBytes[outOff + 1] = (byte)(x10 >> 8);
+ outBytes[outOff + 2] = (byte)x32;
+ outBytes[outOff + 3] = (byte)(x32 >> 8);
+ outBytes[outOff + 4] = (byte)x54;
+ outBytes[outOff + 5] = (byte)(x54 >> 8);
+ outBytes[outOff + 6] = (byte)x76;
+ outBytes[outOff + 7] = (byte)(x76 >> 8);
+ }
+
+ private void DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+ x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+ x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+ x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff);
+
+ for (int i = 60; i >= 44; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 40; i >= 20; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 16; i >= 0; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ outBytes[outOff + 0] = (byte)x10;
+ outBytes[outOff + 1] = (byte)(x10 >> 8);
+ outBytes[outOff + 2] = (byte)x32;
+ outBytes[outOff + 3] = (byte)(x32 >> 8);
+ outBytes[outOff + 4] = (byte)x54;
+ outBytes[outOff + 5] = (byte)(x54 >> 8);
+ outBytes[outOff + 6] = (byte)x76;
+ outBytes[outOff + 7] = (byte)(x76 >> 8);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RC2WrapEngine.cs b/src/core/srcbc/crypto/engines/RC2WrapEngine.cs
new file mode 100644
index 0000000..722f91f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC2WrapEngine.cs
@@ -0,0 +1,372 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Wrap keys according to RFC 3217 - RC2 mechanism
+ */
+ public class RC2WrapEngine
+ : IWrapper
+ {
+ /** Field engine */
+ private CbcBlockCipher engine;
+
+ /** Field param */
+ private ICipherParameters parameters;
+
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+
+ /** Field iv */
+ private byte[] iv;
+
+ /** Field forWrapping */
+ private bool forWrapping;
+
+ private SecureRandom sr;
+
+ /** Field IV2 */
+ private static readonly byte[] IV2 =
+ {
+ (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05
+ };
+
+ //
+ // checksum digest
+ //
+ IDigest sha1 = new Sha1Digest();
+ byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+ this.engine = new CbcBlockCipher(new RC2Engine());
+
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom pWithR = (ParametersWithRandom)parameters;
+ sr = pWithR.Random;
+ parameters = pWithR.Parameters;
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (parameters is ParametersWithIV)
+ {
+ if (!forWrapping)
+ throw new ArgumentException("You should not supply an IV for unwrapping");
+
+ this.paramPlusIV = (ParametersWithIV)parameters;
+ this.iv = this.paramPlusIV.GetIV();
+ this.parameters = this.paramPlusIV.Parameters;
+
+ if (this.iv.Length != 8)
+ throw new ArgumentException("IV is not 8 octets");
+ }
+ else
+ {
+ this.parameters = parameters;
+
+ if (this.forWrapping)
+ {
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+ sr.NextBytes(iv);
+ this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+ }
+ }
+ }
+
+ /**
+ * Method GetAlgorithmName
+ *
+ * @return
+ */
+ public string AlgorithmName
+ {
+ get { return "RC2"; }
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ */
+ public byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("Not initialized for wrapping");
+ }
+
+ int len = length + 1;
+ if ((len % 8) != 0)
+ {
+ len += 8 - (len % 8);
+ }
+
+ byte [] keyToBeWrapped = new byte[len];
+
+ keyToBeWrapped[0] = (byte)length;
+ Array.Copy(input, inOff, keyToBeWrapped, 1, length);
+
+ byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
+
+ if (pad.Length > 0)
+ {
+ sr.NextBytes(pad);
+ Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
+ }
+
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
+
+ Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+ Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
+
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+ byte [] TEMP1 = new byte[WKCKS.Length];
+
+ Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
+
+ int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
+ int extraBytes = WKCKS.Length % engine.GetBlockSize();
+
+ if (extraBytes != 0)
+ {
+ throw new InvalidOperationException("Not multiple of block length");
+ }
+
+ engine.Init(true, paramPlusIV);
+
+ for (int i = 0; i < noOfBlocks; i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+ }
+
+ // Left TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
+
+ Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+ Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
+
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = new byte[TEMP2.Length];
+
+ for (int i = 0; i < TEMP2.Length; i++)
+ {
+ TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
+ }
+
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
+
+ this.engine.Init(true, param2);
+
+ for (int i = 0; i < noOfBlocks + 1; i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ * @throws InvalidCipherTextException
+ */
+ public byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("Not set for unwrapping");
+ }
+
+ if (input == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+
+ if (length % engine.GetBlockSize() != 0)
+ {
+ throw new InvalidCipherTextException("Ciphertext not multiple of "
+ + engine.GetBlockSize());
+ }
+
+ /*
+ // Check if the length of the cipher text is reasonable given the key
+ // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+ // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+ // or inconsistent with the algorithm for which the key is intended,
+ // return error.
+ //
+ // we do not accept 168 bit keys. it has to be 192 bit.
+ int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ int lengthB = estimatedKeyLengthInBit % 8;
+
+ if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
+ throw new XMLSecurityException("empty");
+ }
+ */
+
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
+
+ this.engine.Init(false, param2);
+
+ byte [] TEMP3 = new byte[length];
+
+ Array.Copy(input, inOff, TEMP3, 0, length);
+
+ for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = new byte[TEMP3.Length];
+
+ for (int i = 0; i < TEMP3.Length; i++)
+ {
+ TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
+ }
+
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+ this.iv = new byte[8];
+
+ byte[] TEMP1 = new byte[TEMP2.Length - 8];
+
+ Array.Copy(TEMP2, 0, this.iv, 0, 8);
+ Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+
+ this.engine.Init(false, this.paramPlusIV);
+
+ byte[] LCEKPADICV = new byte[TEMP1.Length];
+
+ Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+
+ for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
+ }
+
+ // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
+ byte[] result = new byte[LCEKPADICV.Length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+
+ Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
+ Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
+
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
+ {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+
+ if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
+ {
+ throw new InvalidCipherTextException(
+ "too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
+ }
+
+ // CEK is the wrapped key, now extracted for use in data decryption.
+ byte[] CEK = new byte[result[0]];
+ Array.Copy(result, 1, CEK, 0, CEK.Length);
+ return CEK;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+ * - Use the first 8 octets of this hash as the checksum value.
+ *
+ * @param key
+ * @return
+ * @throws Exception
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] CalculateCmsKeyChecksum(
+ byte[] key)
+ {
+ byte[] result = new byte[8];
+
+ sha1.BlockUpdate(key, 0, key.Length);
+ sha1.DoFinal(digest, 0);
+
+ Array.Copy(digest, 0, result, 0, 8);
+
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private bool CheckCmsKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RC4Engine.cs b/src/core/srcbc/crypto/engines/RC4Engine.cs
new file mode 100644
index 0000000..76bae34
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC4Engine.cs
@@ -0,0 +1,147 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class RC4Engine
+ : IStreamCipher
+ {
+ private readonly static int STATE_LENGTH = 256;
+
+ /*
+ * variables to hold the state of the RC4 engine
+ * during encryption and decryption
+ */
+
+ private byte[] engineState;
+ private int x;
+ private int y;
+ private byte[] workingKey;
+
+ /**
+ * initialise a RC4 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ /*
+ * RC4 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(workingKey);
+
+ return;
+ }
+
+ throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
+ }
+
+ public string AlgorithmName
+ {
+ get { return "RC4"; }
+ }
+
+ public byte ReturnByte(
+ byte input)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff
+ )
+ {
+ if ((inOff + length) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + length) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < length ; i++)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ output[i+outOff] = (byte)(input[i + inOff]
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+ }
+
+ public void Reset()
+ {
+ SetKey(workingKey);
+ }
+
+ // Private implementation
+
+ private void SetKey(
+ byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ // System.out.println("the key length is ; "+ workingKey.Length);
+
+ x = 0;
+ y = 0;
+
+ if (engineState == null)
+ {
+ engineState = new byte[STATE_LENGTH];
+ }
+
+ // reset the state of the engine
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ engineState[i] = (byte)i;
+ }
+
+ int i1 = 0;
+ int i2 = 0;
+
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
+ // do the byte-swap inline
+ byte tmp = engineState[i];
+ engineState[i] = engineState[i2];
+ engineState[i2] = tmp;
+ i1 = (i1+1) % keyBytes.Length;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RC532Engine.cs b/src/core/srcbc/crypto/engines/RC532Engine.cs
new file mode 100644
index 0000000..3f34031
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC532Engine.cs
@@ -0,0 +1,294 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes.
+ *
+ * This implementation has a word size of 32 bits.
+ */
+ public class RC532Engine
+ : IBlockCipher
+ {
+ /*
+ * the number of rounds to perform
+ */
+ private int _noRounds;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private int [] _S;
+
+ /*
+ * our "magic constants" for 32 32
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly int P32 = unchecked((int) 0xb7e15163);
+ private static readonly int Q32 = unchecked((int) 0x9e3779b9);
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC5 encryption algorithm
+ * and set some defaults
+ */
+ public RC532Engine()
+ {
+ _noRounds = 12; // the default
+// _S = null;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "RC5-32"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return 2 * 4;
+ }
+
+ /**
+ * initialise a RC5-32 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (typeof(RC5Parameters).IsInstanceOfType(parameters))
+ {
+ RC5Parameters p = (RC5Parameters)parameters;
+
+ _noRounds = p.Rounds;
+
+ SetKey(p.GetKey());
+ }
+ else if (typeof(KeyParameter).IsInstanceOfType(parameters))
+ {
+ KeyParameter p = (KeyParameter)parameters;
+
+ SetKey(p.GetKey());
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to RC532 init - " + parameters.GetType().ToString());
+ }
+
+ this.forEncryption = forEncryption;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (forEncryption)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = 32/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // of K. Any unfilled byte positions in L are zeroed. In the
+ // case that b = c = 0, set c = 1 and L[0] = 0.
+ //
+ int[] L = new int[(key.Length + (4 - 1)) / 4];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ L[i / 4] += (key[i] & 0xff) << (8 * (i % 4));
+ }
+
+ //
+ // Phase 2:
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new int[2*(_noRounds + 1)];
+
+ _S[0] = P32;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q32);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ int A = 0, B = 0;
+ int ii = 0, jj = 0;
+
+ for (int k = 0; k < iter; k++)
+ {
+ A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ ii = (ii+1) % _S.Length;
+ jj = (jj+1) % L.Length;
+ }
+ }
+
+ /**
+ * Encrypt the given block starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param in in byte buffer containing data to encrypt
+ * @param inOff offset into src buffer
+ * @param out out buffer where encrypted data is written
+ * @param outOff offset into out buffer
+ */
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int A = BytesToWord(input, inOff) + _S[0];
+ int B = BytesToWord(input, inOff + 4) + _S[1];
+
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ A = RotateLeft(A ^ B, B) + _S[2*i];
+ B = RotateLeft(B ^ A, A) + _S[2*i+1];
+ }
+
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + 4);
+
+ return 2 * 4;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int A = BytesToWord(input, inOff);
+ int B = BytesToWord(input, inOff + 4);
+
+ for (int i = _noRounds; i >= 1; i--)
+ {
+ B = RotateRight(B - _S[2*i+1], A) ^ A;
+ A = RotateRight(A - _S[2*i], B) ^ B;
+ }
+
+ WordToBytes(A - _S[0], outBytes, outOff);
+ WordToBytes(B - _S[1], outBytes, outOff + 4);
+
+ return 2 * 4;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(32) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % 32
+ */
+ private int RotateLeft(int x, int y) {
+ return ((int) ( (uint) (x << (y & (32-1))) |
+ ((uint) x >> (32 - (y & (32-1)))) )
+ );
+ }
+
+ /**
+ * Perform a right "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(32) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % 32
+ */
+ private int RotateRight(int x, int y) {
+ return ((int) ( ((uint) x >> (y & (32-1))) |
+ (uint) (x << (32 - (y & (32-1)))) )
+ );
+ }
+
+ private int BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
+ | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
+ }
+
+ private void WordToBytes(
+ int word,
+ byte[] dst,
+ int dstOff)
+ {
+ dst[dstOff] = (byte)word;
+ dst[dstOff + 1] = (byte)(word >> 8);
+ dst[dstOff + 2] = (byte)(word >> 16);
+ dst[dstOff + 3] = (byte)(word >> 24);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RC564Engine.cs b/src/core/srcbc/crypto/engines/RC564Engine.cs
new file mode 100644
index 0000000..7aee798
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC564Engine.cs
@@ -0,0 +1,295 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes.
+ *
+ * This implementation is set to work with a 64 bit word size.
+ */
+ public class RC564Engine
+ : IBlockCipher
+ {
+ private static readonly int wordSize = 64;
+ private static readonly int bytesPerWord = wordSize / 8;
+
+ /*
+ * the number of rounds to perform
+ */
+ private int _noRounds;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private long [] _S;
+
+ /*
+ * our "magic constants" for wordSize 62
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly long P64 = unchecked( (long) 0xb7e151628aed2a6bL);
+ private static readonly long Q64 = unchecked( (long) 0x9e3779b97f4a7c15L);
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC5 encryption algorithm
+ * and set some defaults
+ */
+ public RC564Engine()
+ {
+ _noRounds = 12;
+// _S = null;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "RC5-64"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return 2 * bytesPerWord;
+ }
+
+ /**
+ * initialise a RC5-64 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
+ {
+ throw new ArgumentException("invalid parameter passed to RC564 init - " + parameters.GetType().ToString());
+ }
+
+ RC5Parameters p = (RC5Parameters)parameters;
+
+ this.forEncryption = forEncryption;
+
+ _noRounds = p.Rounds;
+
+ SetKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (forEncryption) ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = wordSize/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // of K. Any unfilled byte positions in L are zeroed. In the
+ // case that b = c = 0, set c = 1 and L[0] = 0.
+ //
+ long[] L = new long[(key.Length + (bytesPerWord - 1)) / bytesPerWord];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord));
+ }
+
+ //
+ // Phase 2:
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new long[2*(_noRounds + 1)];
+
+ _S[0] = P64;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q64);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ long A = 0, B = 0;
+ int ii = 0, jj = 0;
+
+ for (int k = 0; k < iter; k++)
+ {
+ A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ ii = (ii+1) % _S.Length;
+ jj = (jj+1) % L.Length;
+ }
+ }
+
+ /**
+ * Encrypt the given block starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ *
+ * @param in in byte buffer containing data to encrypt
+ * @param inOff offset into src buffer
+ * @param out out buffer where encrypted data is written
+ * @param outOff offset into out buffer
+ */
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ long A = BytesToWord(input, inOff) + _S[0];
+ long B = BytesToWord(input, inOff + bytesPerWord) + _S[1];
+
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ A = RotateLeft(A ^ B, B) + _S[2*i];
+ B = RotateLeft(B ^ A, A) + _S[2*i+1];
+ }
+
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + bytesPerWord);
+
+ return 2 * bytesPerWord;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ long A = BytesToWord(input, inOff);
+ long B = BytesToWord(input, inOff + bytesPerWord);
+
+ for (int i = _noRounds; i >= 1; i--)
+ {
+ B = RotateRight(B - _S[2*i+1], A) ^ A;
+ A = RotateRight(A - _S[2*i], B) ^ B;
+ }
+
+ WordToBytes(A - _S[0], outBytes, outOff);
+ WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord);
+
+ return 2 * bytesPerWord;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % wordSize
+ */
+ private long RotateLeft(long x, long y) {
+ return ((long) ( (ulong) (x << (int) (y & (wordSize-1))) |
+ ((ulong) x >> (int) (wordSize - (y & (wordSize-1)))))
+ );
+ }
+
+ /**
+ * Perform a right "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % wordSize
+ */
+ private long RotateRight(long x, long y) {
+ return ((long) ( ((ulong) x >> (int) (y & (wordSize-1))) |
+ (ulong) (x << (int) (wordSize - (y & (wordSize-1)))))
+ );
+ }
+
+ private long BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ long word = 0;
+
+ for (int i = bytesPerWord - 1; i >= 0; i--)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ private void WordToBytes(
+ long word,
+ byte[] dst,
+ int dstOff)
+ {
+ for (int i = 0; i < bytesPerWord; i++)
+ {
+ dst[i + dstOff] = (byte)word;
+ word = (long) ((ulong) word >> 8);
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RC6Engine.cs b/src/core/srcbc/crypto/engines/RC6Engine.cs
new file mode 100644
index 0000000..c1c23e0
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RC6Engine.cs
@@ -0,0 +1,362 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An RC6 engine.
+ */
+ public class RC6Engine
+ : IBlockCipher
+ {
+ private static readonly int wordSize = 32;
+ private static readonly int bytesPerWord = wordSize / 8;
+
+ /*
+ * the number of rounds to perform
+ */
+ private static readonly int _noRounds = 20;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private int [] _S;
+
+ /*
+ * our "magic constants" for wordSize 32
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly int P32 = unchecked((int) 0xb7e15163);
+ private static readonly int Q32 = unchecked((int) 0x9e3779b9);
+
+ private static readonly int LGW = 5; // log2(32)
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC6 encryption algorithm
+ * and set some defaults
+ */
+ public RC6Engine()
+ {
+// _S = null;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "RC6"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return 4 * bytesPerWord;
+ }
+
+ /**
+ * initialise a RC5-32 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to RC6 init - " + parameters.GetType().ToString());
+
+ this.forEncryption = forEncryption;
+
+ KeyParameter p = (KeyParameter)parameters;
+ SetKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = GetBlockSize();
+ if (_S == null)
+ throw new InvalidOperationException("RC6 engine not initialised");
+ if ((inOff + blockSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + blockSize) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ return (forEncryption)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param inKey the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = wordSize/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // of K. Any unfilled byte positions in L are zeroed. In the
+ // case that b = c = 0, set c = 1 and L[0] = 0.
+ //
+ // compute number of dwords
+ int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord;
+ if (c == 0)
+ {
+ c = 1;
+ }
+ int[] L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord];
+
+ // load all key bytes into array of key dwords
+ for (int i = key.Length - 1; i >= 0; i--)
+ {
+ L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff);
+ }
+
+ //
+ // Phase 2:
+ // Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords.
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new int[2+2*_noRounds+2];
+
+ _S[0] = P32;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q32);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ int A = 0;
+ int B = 0;
+ int ii = 0, jj = 0;
+
+ for (int k = 0; k < iter; k++)
+ {
+ A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ ii = (ii+1) % _S.Length;
+ jj = (jj+1) % L.Length;
+ }
+ }
+
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // load A,B,C and D registers from in.
+ int A = BytesToWord(input, inOff);
+ int B = BytesToWord(input, inOff + bytesPerWord);
+ int C = BytesToWord(input, inOff + bytesPerWord*2);
+ int D = BytesToWord(input, inOff + bytesPerWord*3);
+
+ // Do pseudo-round #0: pre-whitening of B and D
+ B += _S[0];
+ D += _S[1];
+
+ // perform round #1,#2 ... #ROUNDS of encryption
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ int t = 0,u = 0;
+
+ t = B*(2*B+1);
+ t = RotateLeft(t,5);
+
+ u = D*(2*D+1);
+ u = RotateLeft(u,5);
+
+ A ^= t;
+ A = RotateLeft(A,u);
+ A += _S[2*i];
+
+ C ^= u;
+ C = RotateLeft(C,t);
+ C += _S[2*i+1];
+
+ int temp = A;
+ A = B;
+ B = C;
+ C = D;
+ D = temp;
+ }
+ // do pseudo-round #(ROUNDS+1) : post-whitening of A and C
+ A += _S[2*_noRounds+2];
+ C += _S[2*_noRounds+3];
+
+ // store A, B, C and D registers to out
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + bytesPerWord);
+ WordToBytes(C, outBytes, outOff + bytesPerWord*2);
+ WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+
+ return 4 * bytesPerWord;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // load A,B,C and D registers from out.
+ int A = BytesToWord(input, inOff);
+ int B = BytesToWord(input, inOff + bytesPerWord);
+ int C = BytesToWord(input, inOff + bytesPerWord*2);
+ int D = BytesToWord(input, inOff + bytesPerWord*3);
+
+ // Undo pseudo-round #(ROUNDS+1) : post whitening of A and C
+ C -= _S[2*_noRounds+3];
+ A -= _S[2*_noRounds+2];
+
+ // Undo round #ROUNDS, .., #2,#1 of encryption
+ for (int i = _noRounds; i >= 1; i--)
+ {
+ int t=0,u = 0;
+
+ int temp = D;
+ D = C;
+ C = B;
+ B = A;
+ A = temp;
+
+ t = B*(2*B+1);
+ t = RotateLeft(t, LGW);
+
+ u = D*(2*D+1);
+ u = RotateLeft(u, LGW);
+
+ C -= _S[2*i+1];
+ C = RotateRight(C,t);
+ C ^= u;
+
+ A -= _S[2*i];
+ A = RotateRight(A,u);
+ A ^= t;
+
+ }
+ // Undo pseudo-round #0: pre-whitening of B and D
+ D -= _S[1];
+ B -= _S[0];
+
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + bytesPerWord);
+ WordToBytes(C, outBytes, outOff + bytesPerWord*2);
+ WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+
+ return 4 * bytesPerWord;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % wordSize
+ */
+ private int RotateLeft(int x, int y)
+ {
+ return ((int)((uint)(x << (y & (wordSize-1)))
+ | ((uint) x >> (wordSize - (y & (wordSize-1))))));
+ }
+
+ /**
+ * Perform a right "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * are used to determine the rotation amount. Here it is
+ * assumed that the wordsize used is a power of 2.
+ *
+ * @param x word to rotate
+ * @param y number of bits to rotate % wordSize
+ */
+ private int RotateRight(int x, int y)
+ {
+ return ((int)(((uint) x >> (y & (wordSize-1)))
+ | (uint)(x << (wordSize - (y & (wordSize-1))))));
+ }
+
+ private int BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ int word = 0;
+
+ for (int i = bytesPerWord - 1; i >= 0; i--)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ private void WordToBytes(
+ int word,
+ byte[] dst,
+ int dstOff)
+ {
+ for (int i = 0; i < bytesPerWord; i++)
+ {
+ dst[i + dstOff] = (byte)word;
+ word = (int) ((uint) word >> 8);
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RFC3211WrapEngine.cs b/src/core/srcbc/crypto/engines/RFC3211WrapEngine.cs
new file mode 100644
index 0000000..0b537a1
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RFC3211WrapEngine.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the RFC 3211 Key Wrap
+ * Specification.
+ */
+ public class Rfc3211WrapEngine
+ : IWrapper
+ {
+ private CbcBlockCipher engine;
+ private ParametersWithIV param;
+ private bool forWrapping;
+ private SecureRandom rand;
+
+ public Rfc3211WrapEngine(
+ IBlockCipher engine)
+ {
+ this.engine = new CbcBlockCipher(engine);
+ }
+
+ public void Init(
+ bool forWrapping,
+ ICipherParameters param)
+ {
+ this.forWrapping = forWrapping;
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) param;
+
+ this.rand = p.Random;
+ this.param = (ParametersWithIV) p.Parameters;
+ }
+ else
+ {
+ if (forWrapping)
+ {
+ rand = new SecureRandom();
+ }
+
+ this.param = (ParametersWithIV) param;
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
+ }
+
+ public byte[] Wrap(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("not set for wrapping");
+ }
+
+ engine.Init(true, param);
+
+ int blockSize = engine.GetBlockSize();
+ byte[] cekBlock;
+
+ if (inLen + 4 < blockSize * 2)
+ {
+ cekBlock = new byte[blockSize * 2];
+ }
+ else
+ {
+ cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
+ }
+
+ cekBlock[0] = (byte)inLen;
+ cekBlock[1] = (byte)~inBytes[inOff];
+ cekBlock[2] = (byte)~inBytes[inOff + 1];
+ cekBlock[3] = (byte)~inBytes[inOff + 2];
+
+ Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
+
+ rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ return cekBlock;
+ }
+
+ public byte[] Unwrap(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("not set for unwrapping");
+ }
+
+ int blockSize = engine.GetBlockSize();
+
+ if (inLen < 2 * blockSize)
+ {
+ throw new InvalidCipherTextException("input too short");
+ }
+
+ byte[] cekBlock = new byte[inLen];
+ byte[] iv = new byte[blockSize];
+
+ Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
+ Array.Copy(inBytes, inOff, iv, 0, iv.Length);
+
+ engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+ for (int i = blockSize; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
+
+ engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+ engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
+
+ engine.Init(false, param);
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
+ {
+ throw new InvalidCipherTextException("wrapped key corrupted");
+ }
+
+ byte[] key = new byte[cekBlock[0] & 0xff];
+
+ Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
+
+ for (int i = 0; i != 3; i++)
+ {
+ byte check = (byte)~cekBlock[1 + i];
+ if (check != key[i])
+ {
+ throw new InvalidCipherTextException("wrapped key fails checksum");
+ }
+ }
+
+ return key;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RFC3394WrapEngine.cs b/src/core/srcbc/crypto/engines/RFC3394WrapEngine.cs
new file mode 100644
index 0000000..b40efec
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RFC3394WrapEngine.cs
@@ -0,0 +1,181 @@
+using System;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the AES Key Wrapper from the NIST Key Wrap
+ /// Specification as described in RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc3394.txt
+ /// and http://csrc.nist.gov/encryption/kms/key-wrap.pdf.
+ ///
+ public class Rfc3394WrapEngine
+ : IWrapper
+ {
+ private readonly IBlockCipher engine;
+
+ private KeyParameter param;
+ private bool forWrapping;
+
+ private byte[] iv =
+ {
+ 0xa6, 0xa6, 0xa6, 0xa6,
+ 0xa6, 0xa6, 0xa6, 0xa6
+ };
+
+ public Rfc3394WrapEngine(
+ IBlockCipher engine)
+ {
+ this.engine = engine;
+ }
+
+ public void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (parameters is KeyParameter)
+ {
+ this.param = (KeyParameter) parameters;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV pIV = (ParametersWithIV) parameters;
+ byte[] iv = pIV.GetIV();
+
+ if (iv.Length != 8)
+ throw new ArgumentException("IV length not equal to 8", "parameters");
+
+ this.iv = iv;
+ this.param = (KeyParameter) pIV.Parameters;
+ }
+ else
+ {
+ // TODO Throw an exception for bad parameters?
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName; }
+ }
+
+ public byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("not set for wrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen + iv.Length];
+ byte[] buf = new byte[8 + iv.Length];
+
+ Array.Copy(iv, 0, block, 0, iv.Length);
+ Array.Copy(input, 0, block, iv.Length, inLen);
+
+ engine.Init(true, param);
+
+ for (int j = 0; j != 6; j++)
+ {
+ for (int i = 1; i <= n; i++)
+ {
+ Array.Copy(block, 0, buf, 0, iv.Length);
+ Array.Copy(block, 8 * i, buf, iv.Length, 8);
+ engine.ProcessBlock(buf, 0, buf, 0);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.Length - k] ^= v;
+ t = (int) ((uint)t >> 8);
+ }
+
+ Array.Copy(buf, 0, block, 0, 8);
+ Array.Copy(buf, 8, block, 8 * i, 8);
+ }
+ }
+
+ return block;
+ }
+
+ public byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("not set for unwrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen - iv.Length];
+ byte[] a = new byte[iv.Length];
+ byte[] buf = new byte[8 + iv.Length];
+
+ Array.Copy(input, 0, a, 0, iv.Length);
+ Array.Copy(input, iv.Length, block, 0, inLen - iv.Length);
+
+ engine.Init(false, param);
+
+ n = n - 1;
+
+ for (int j = 5; j >= 0; j--)
+ {
+ for (int i = n; i >= 1; i--)
+ {
+ Array.Copy(a, 0, buf, 0, iv.Length);
+ Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.Length - k] ^= v;
+ t = (int) ((uint)t >> 8);
+ }
+
+ engine.ProcessBlock(buf, 0, buf, 0);
+ Array.Copy(buf, 0, a, 0, 8);
+ Array.Copy(buf, 8, block, 8 * (i - 1), 8);
+ }
+ }
+
+ for (int i = 0; i != iv.Length; i++)
+ {
+ if (a[i] != iv[i])
+ {
+ throw new InvalidCipherTextException("checksum failed");
+ }
+ }
+
+ return block;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RSABlindedEngine.cs b/src/core/srcbc/crypto/engines/RSABlindedEngine.cs
new file mode 100644
index 0000000..1dbbe4f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RSABlindedEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm with blinding
+ */
+ public class RsaBlindedEngine
+ : IAsymmetricBlockCipher
+ {
+ private readonly RsaCoreEngine core = new RsaCoreEngine();
+ private RsaKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ core.Init(forEncryption, param);
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param inBuf the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ if (key == null)
+ throw new InvalidOperationException("RSA engine not initialised");
+
+ BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
+
+ BigInteger result;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
+ if (k.PublicExponent != null) // can't do blinding without a public exponent
+ {
+ BigInteger m = k.Modulus;
+ BigInteger r = calculateR(m);
+
+ BigInteger blindedInput = r.ModPow(k.PublicExponent, m).Multiply(input).Mod(m);
+ BigInteger blindedResult = core.ProcessBlock(blindedInput);
+
+ result = blindedResult.Multiply(r.ModInverse(m)).Mod(m);
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+
+ return core.ConvertOutput(result);
+ }
+
+ /*
+ * calculate a random mess-with-their-heads value.
+ */
+ private BigInteger calculateR(
+ BigInteger m)
+ {
+ int max = m.BitLength - 1; // must be less than m.BitLength
+ int min = max / 2;
+ int length = ((random.NextInt() & 0xff) * ((max - min) / 0xff)) + min;
+ BigInteger factor = new BigInteger(length, random);
+
+ while (factor.SignValue == 0)
+ {
+ factor = new BigInteger(length, random);
+ }
+
+ return factor;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RSABlindingEngine.cs b/src/core/srcbc/crypto/engines/RSABlindingEngine.cs
new file mode 100644
index 0000000..22cec15
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RSABlindingEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * This does your basic RSA Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475. You need to use this if you are
+ * trying to get another party to generate signatures without them being aware
+ * of the message they are signing.
+ */
+ public class RsaBlindingEngine
+ : IAsymmetricBlockCipher
+ {
+ private readonly RsaCoreEngine core = new RsaCoreEngine();
+
+ private RsaKeyParameters key;
+ private BigInteger blindingFactor;
+
+ private bool forEncryption;
+
+ public string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * Initialise the blinding engine.
+ *
+ * @param forEncryption true if we are encrypting (blinding), false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ RsaBlindingParameters p;
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ p = (RsaBlindingParameters)rParam.Parameters;
+ }
+ else
+ {
+ p = (RsaBlindingParameters)param;
+ }
+
+ core.Init(forEncryption, p.PublicKey);
+
+ this.forEncryption = forEncryption;
+ this.key = p.PublicKey;
+ this.blindingFactor = p.BlindingFactor;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the RSA blinding algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @throws DataLengthException the input block is too large.
+ */
+ public byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ BigInteger msg = core.ConvertInput(inBuf, inOff, inLen);
+
+ if (forEncryption)
+ {
+ msg = BlindMessage(msg);
+ }
+ else
+ {
+ msg = UnblindMessage(msg);
+ }
+
+ return core.ConvertOutput(msg);
+ }
+
+ /*
+ * Blind message with the blind factor.
+ */
+ private BigInteger BlindMessage(
+ BigInteger msg)
+ {
+ BigInteger blindMsg = blindingFactor;
+ blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus));
+ blindMsg = blindMsg.Mod(key.Modulus);
+
+ return blindMsg;
+ }
+
+ /*
+ * Unblind the message blinded with the blind factor.
+ */
+ private BigInteger UnblindMessage(
+ BigInteger blindedMsg)
+ {
+ BigInteger m = key.Modulus;
+ BigInteger msg = blindedMsg;
+ BigInteger blindFactorInverse = blindingFactor.ModInverse(m);
+ msg = msg.Multiply(blindFactorInverse);
+ msg = msg.Mod(m);
+
+ return msg;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RSACoreEngine.cs b/src/core/srcbc/crypto/engines/RSACoreEngine.cs
new file mode 100644
index 0000000..fe13387
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RSACoreEngine.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm.
+ */
+ class RsaCoreEngine
+ {
+ private RsaKeyParameters key;
+ private bool forEncryption;
+ private int bitSize;
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (!(parameters is RsaKeyParameters))
+ throw new InvalidKeyException("Not an RSA key");
+
+ this.key = (RsaKeyParameters) parameters;
+ this.forEncryption = forEncryption;
+ this.bitSize = key.Modulus.BitLength;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize - 1) / 8;
+ }
+
+ return (bitSize + 7) / 8;
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize + 7) / 8;
+ }
+
+ return (bitSize - 1) / 8;
+ }
+
+ public BigInteger ConvertInput(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ int maxLength = (bitSize + 7) / 8;
+
+ if (inLen > maxLength)
+ throw new DataLengthException("input too large for RSA cipher.");
+
+ BigInteger input = new BigInteger(1, inBuf, inOff, inLen);
+
+ if (input.CompareTo(key.Modulus) >= 0)
+ throw new DataLengthException("input too large for RSA cipher.");
+
+ return input;
+ }
+
+ public byte[] ConvertOutput(
+ BigInteger result)
+ {
+ byte[] output = result.ToByteArrayUnsigned();
+
+ if (forEncryption)
+ {
+ int outSize = GetOutputBlockSize();
+
+ // TODO To avoid this, create version of BigInteger.ToByteArray that
+ // writes to an existing array
+ if (output.Length < outSize) // have ended up with less bytes than normal, lengthen
+ {
+ byte[] tmp = new byte[outSize];
+ output.CopyTo(tmp, tmp.Length - output.Length);
+ output = tmp;
+ }
+ }
+
+ return output;
+ }
+
+ public BigInteger ProcessBlock(
+ BigInteger input)
+ {
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
+
+ BigInteger p = crtKey.P;;
+ BigInteger q = crtKey.Q;
+ BigInteger dP = crtKey.DP;
+ BigInteger dQ = crtKey.DQ;
+ BigInteger qInv = crtKey.QInv;
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input Mod p) ^ dP)) Mod p
+ mP = (input.Remainder(p)).ModPow(dP, p);
+
+ // mQ = ((input Mod q) ^ dQ)) Mod q
+ mQ = (input.Remainder(q)).ModPow(dQ, q);
+
+ // h = qInv * (mP - mQ) Mod p
+ h = mP.Subtract(mQ);
+ h = h.Multiply(qInv);
+ h = h.Mod(p); // Mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.Multiply(q);
+ m = m.Add(mQ);
+
+ return m;
+ }
+
+ return input.ModPow(key.Exponent, key.Modulus);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/RijndaelEngine.cs b/src/core/srcbc/crypto/engines/RijndaelEngine.cs
new file mode 100644
index 0000000..08c890a
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RijndaelEngine.cs
@@ -0,0 +1,740 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of Rijndael, based on the documentation and reference implementation
+ * by Paulo Barreto, Vincent Rijmen, for v2.0 August '99.
+ *
+ * Note: this implementation is based on information prior to readonly NIST publication.
+ *
+ */
+ public class RijndaelEngine
+ : IBlockCipher
+ {
+ private static readonly int MAXROUNDS = 14;
+
+ private static readonly int MAXKC = (256/4);
+
+ private static readonly byte[] Logtable = {
+ (byte)0, (byte)0, (byte)25, (byte)1, (byte)50, (byte)2, (byte)26, (byte)198,
+ (byte)75, (byte)199, (byte)27, (byte)104, (byte)51, (byte)238, (byte)223, (byte)3,
+ (byte)100, (byte)4, (byte)224, (byte)14, (byte)52, (byte)141, (byte)129, (byte)239,
+ (byte)76, (byte)113, (byte)8, (byte)200, (byte)248, (byte)105, (byte)28, (byte)193,
+ (byte)125, (byte)194, (byte)29, (byte)181, (byte)249, (byte)185, (byte)39, (byte)106,
+ (byte)77, (byte)228, (byte)166, (byte)114, (byte)154, (byte)201, (byte)9, (byte)120,
+ (byte)101, (byte)47, (byte)138, (byte)5, (byte)33, (byte)15, (byte)225, (byte)36,
+ (byte)18, (byte)240, (byte)130, (byte)69, (byte)53, (byte)147, (byte)218, (byte)142,
+ (byte)150, (byte)143, (byte)219, (byte)189, (byte)54, (byte)208, (byte)206, (byte)148,
+ (byte)19, (byte)92, (byte)210, (byte)241, (byte)64, (byte)70, (byte)131, (byte)56,
+ (byte)102, (byte)221, (byte)253, (byte)48, (byte)191, (byte)6, (byte)139, (byte)98,
+ (byte)179, (byte)37, (byte)226, (byte)152, (byte)34, (byte)136, (byte)145, (byte)16,
+ (byte)126, (byte)110, (byte)72, (byte)195, (byte)163, (byte)182, (byte)30, (byte)66,
+ (byte)58, (byte)107, (byte)40, (byte)84, (byte)250, (byte)133, (byte)61, (byte)186,
+ (byte)43, (byte)121, (byte)10, (byte)21, (byte)155, (byte)159, (byte)94, (byte)202,
+ (byte)78, (byte)212, (byte)172, (byte)229, (byte)243, (byte)115, (byte)167, (byte)87,
+ (byte)175, (byte)88, (byte)168, (byte)80, (byte)244, (byte)234, (byte)214, (byte)116,
+ (byte)79, (byte)174, (byte)233, (byte)213, (byte)231, (byte)230, (byte)173, (byte)232,
+ (byte)44, (byte)215, (byte)117, (byte)122, (byte)235, (byte)22, (byte)11, (byte)245,
+ (byte)89, (byte)203, (byte)95, (byte)176, (byte)156, (byte)169, (byte)81, (byte)160,
+ (byte)127, (byte)12, (byte)246, (byte)111, (byte)23, (byte)196, (byte)73, (byte)236,
+ (byte)216, (byte)67, (byte)31, (byte)45, (byte)164, (byte)118, (byte)123, (byte)183,
+ (byte)204, (byte)187, (byte)62, (byte)90, (byte)251, (byte)96, (byte)177, (byte)134,
+ (byte)59, (byte)82, (byte)161, (byte)108, (byte)170, (byte)85, (byte)41, (byte)157,
+ (byte)151, (byte)178, (byte)135, (byte)144, (byte)97, (byte)190, (byte)220, (byte)252,
+ (byte)188, (byte)149, (byte)207, (byte)205, (byte)55, (byte)63, (byte)91, (byte)209,
+ (byte)83, (byte)57, (byte)132, (byte)60, (byte)65, (byte)162, (byte)109, (byte)71,
+ (byte)20, (byte)42, (byte)158, (byte)93, (byte)86, (byte)242, (byte)211, (byte)171,
+ (byte)68, (byte)17, (byte)146, (byte)217, (byte)35, (byte)32, (byte)46, (byte)137,
+ (byte)180, (byte)124, (byte)184, (byte)38, (byte)119, (byte)153, (byte)227, (byte)165,
+ (byte)103, (byte)74, (byte)237, (byte)222, (byte)197, (byte)49, (byte)254, (byte)24,
+ (byte)13, (byte)99, (byte)140, (byte)128, (byte)192, (byte)247, (byte)112, (byte)7
+ };
+
+ private static readonly byte[] Alogtable = {
+ (byte)0, (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
+ (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
+ (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
+ (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
+ (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
+ (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
+ (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
+ (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
+ (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
+ (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
+ (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
+ (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
+ (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
+ (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
+ (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
+ (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
+ (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
+ (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
+ (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
+ (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
+ (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
+ (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
+ (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
+ (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
+ (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
+ (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
+ (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
+ (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
+ (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
+ (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
+ (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
+ (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
+ };
+
+ private static readonly byte[] S = {
+ (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+ (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+ (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
+ (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
+ (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
+ (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
+ (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
+ (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
+ (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
+ (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
+ (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+ (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
+ (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
+ (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
+ (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
+ (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
+ };
+
+ private static readonly byte[] Si = {
+ (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+ (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+ (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
+ (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
+ (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
+ (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+ (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
+ (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
+ (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+ (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
+ (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
+ (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
+ (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
+ (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+ (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
+ (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
+ };
+
+ private static readonly int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+ static readonly byte[][] shifts0 = new byte [][]
+ {
+ new byte [] { 0, 8, 16, 24 },
+ new byte [] { 0, 8, 16, 24 },
+ new byte [] { 0, 8, 16, 24 },
+ new byte [] { 0, 8, 16, 32 },
+ new byte [] { 0, 8, 24, 32 }
+ };
+
+ static readonly byte[][] shifts1 =
+ {
+ new byte [] { 0, 24, 16, 8 },
+ new byte [] { 0, 32, 24, 16 },
+ new byte [] { 0, 40, 32, 24 },
+ new byte [] { 0, 48, 40, 24 },
+ new byte [] { 0, 56, 40, 32 }
+ };
+
+ /**
+ * multiply two elements of GF(2^m)
+ * needed for MixColumn and InvMixColumn
+ */
+ private byte Mul0x2(
+ int b)
+ {
+ if (b != 0)
+ {
+ return Alogtable[25 + (Logtable[b] & 0xff)];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private byte Mul0x3(
+ int b)
+ {
+ if (b != 0)
+ {
+ return Alogtable[1 + (Logtable[b] & 0xff)];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private byte Mul0x9(
+ int b)
+ {
+ if (b >= 0)
+ {
+ return Alogtable[199 + b];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private byte Mul0xb(
+ int b)
+ {
+ if (b >= 0)
+ {
+ return Alogtable[104 + b];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private byte Mul0xd(
+ int b)
+ {
+ if (b >= 0)
+ {
+ return Alogtable[238 + b];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private byte Mul0xe(
+ int b)
+ {
+ if (b >= 0)
+ {
+ return Alogtable[223 + b];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * xor corresponding text input and round key input bytes
+ */
+ private void KeyAddition(
+ long[] rk)
+ {
+ A0 ^= rk[0];
+ A1 ^= rk[1];
+ A2 ^= rk[2];
+ A3 ^= rk[3];
+ }
+
+ private long Shift(
+ long r,
+ int shift)
+ {
+ //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK;
+
+ ulong temp = (ulong) r >> shift;
+
+ // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17)
+ if (shift > 31)
+ {
+ temp &= 0xFFFFFFFFUL;
+ }
+
+ return ((long) temp | (r << (BC - shift))) & BC_MASK;
+ }
+
+ /**
+ * Row 0 remains unchanged
+ * The other three rows are shifted a variable amount
+ */
+ private void ShiftRow(
+ byte[] shiftsSC)
+ {
+ A1 = Shift(A1, shiftsSC[1]);
+ A2 = Shift(A2, shiftsSC[2]);
+ A3 = Shift(A3, shiftsSC[3]);
+ }
+
+ private long ApplyS(
+ long r,
+ byte[] box)
+ {
+ long res = 0;
+
+ for (int j = 0; j < BC; j += 8)
+ {
+ res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j;
+ }
+
+ return res;
+ }
+
+ /**
+ * Replace every byte of the input by the byte at that place
+ * in the nonlinear S-box
+ */
+ private void Substitution(
+ byte[] box)
+ {
+ A0 = ApplyS(A0, box);
+ A1 = ApplyS(A1, box);
+ A2 = ApplyS(A2, box);
+ A3 = ApplyS(A3, box);
+ }
+
+ /**
+ * Mix the bytes of every column in a linear way
+ */
+ private void MixColumn()
+ {
+ long r0, r1, r2, r3;
+
+ r0 = r1 = r2 = r3 = 0;
+
+ for (int j = 0; j < BC; j += 8)
+ {
+ int a0 = (int)((A0 >> j) & 0xff);
+ int a1 = (int)((A1 >> j) & 0xff);
+ int a2 = (int)((A2 >> j) & 0xff);
+ int a3 = (int)((A3 >> j) & 0xff);
+
+ r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j;
+
+ r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j;
+
+ r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j;
+
+ r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j;
+ }
+
+ A0 = r0;
+ A1 = r1;
+ A2 = r2;
+ A3 = r3;
+ }
+
+ /**
+ * Mix the bytes of every column in a linear way
+ * This is the opposite operation of Mixcolumn
+ */
+ private void InvMixColumn()
+ {
+ long r0, r1, r2, r3;
+
+ r0 = r1 = r2 = r3 = 0;
+ for (int j = 0; j < BC; j += 8)
+ {
+ int a0 = (int)((A0 >> j) & 0xff);
+ int a1 = (int)((A1 >> j) & 0xff);
+ int a2 = (int)((A2 >> j) & 0xff);
+ int a3 = (int)((A3 >> j) & 0xff);
+
+ //
+ // pre-lookup the log table
+ //
+ a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1;
+ a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1;
+ a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1;
+ a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1;
+
+ r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j;
+
+ r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j;
+
+ r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j;
+
+ r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j;
+ }
+
+ A0 = r0;
+ A1 = r1;
+ A2 = r2;
+ A3 = r3;
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on keyBits and blockBits
+ */
+ private long[][] GenerateWorkingKey(
+ byte[] key)
+ {
+ int KC;
+ int t, rconpointer = 0;
+ int keyBits = key.Length * 8;
+ byte[,] tk = new byte[4,MAXKC];
+ //long[,] W = new long[MAXROUNDS+1,4];
+ long[][] W = new long[MAXROUNDS+1][];
+
+ for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4];
+
+ switch (keyBits)
+ {
+ case 128:
+ KC = 4;
+ break;
+ case 160:
+ KC = 5;
+ break;
+ case 192:
+ KC = 6;
+ break;
+ case 224:
+ KC = 7;
+ break;
+ case 256:
+ KC = 8;
+ break;
+ default :
+ throw new ArgumentException("Key length not 128/160/192/224/256 bits.");
+ }
+
+ if (keyBits >= blockBits)
+ {
+ ROUNDS = KC + 6;
+ }
+ else
+ {
+ ROUNDS = (BC / 8) + 6;
+ }
+
+ //
+ // copy the key into the processing area
+ //
+ int index = 0;
+
+ for (int i = 0; i < key.Length; i++)
+ {
+ tk[i % 4,i / 4] = key[index++];
+ }
+
+ t = 0;
+
+ //
+ // copy values into round key array
+ //
+ for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC);
+ }
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ while (t < (ROUNDS+1)*(BC/8))
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff];
+ }
+ tk[0,0] ^= (byte) rcon[rconpointer++];
+
+ if (KC <= 6)
+ {
+ for (int j = 1; j < KC; j++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ tk[i,j] ^= tk[i,j-1];
+ }
+ }
+ }
+ else
+ {
+ for (int j = 1; j < 4; j++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ tk[i,j] ^= tk[i,j-1];
+ }
+ }
+ for (int i = 0; i < 4; i++)
+ {
+ tk[i,4] ^= S[tk[i,3] & 0xff];
+ }
+ for (int j = 5; j < KC; j++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ tk[i,j] ^= tk[i,j-1];
+ }
+ }
+ }
+
+ //
+ // copy values into round key array
+ //
+ for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC));
+ }
+ }
+ }
+ return W;
+ }
+
+ private int BC;
+ private long BC_MASK;
+ private int ROUNDS;
+ private int blockBits;
+ private long[][] workingKey;
+ private long A0, A1, A2, A3;
+ private bool forEncryption;
+ private byte[] shifts0SC;
+ private byte[] shifts1SC;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public RijndaelEngine() : this(128) {}
+
+ /**
+ * basic constructor - set the cipher up for a given blocksize
+ *
+ * @param blocksize the blocksize in bits, must be 128, 192, or 256.
+ */
+ public RijndaelEngine(
+ int blockBits)
+ {
+ switch (blockBits)
+ {
+ case 128:
+ BC = 32;
+ BC_MASK = 0xffffffffL;
+ shifts0SC = shifts0[0];
+ shifts1SC = shifts1[0];
+ break;
+ case 160:
+ BC = 40;
+ BC_MASK = 0xffffffffffL;
+ shifts0SC = shifts0[1];
+ shifts1SC = shifts1[1];
+ break;
+ case 192:
+ BC = 48;
+ BC_MASK = 0xffffffffffffL;
+ shifts0SC = shifts0[2];
+ shifts1SC = shifts1[2];
+ break;
+ case 224:
+ BC = 56;
+ BC_MASK = 0xffffffffffffffL;
+ shifts0SC = shifts0[3];
+ shifts1SC = shifts1[3];
+ break;
+ case 256:
+ BC = 64;
+ BC_MASK = unchecked( (long)0xffffffffffffffffL);
+ shifts0SC = shifts0[4];
+ shifts1SC = shifts1[4];
+ break;
+ default:
+ throw new ArgumentException("unknown blocksize to Rijndael");
+ }
+
+ this.blockBits = blockBits;
+ }
+
+ /**
+ * initialise a Rijndael cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (typeof(KeyParameter).IsInstanceOfType(parameters))
+ {
+ workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
+ this.forEncryption = forEncryption;
+ return;
+ }
+
+ throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Rijndael"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BC / 2;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new InvalidOperationException("Rijndael engine not initialised");
+ }
+
+ if ((inOff + (BC / 2)) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (BC / 2)) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(workingKey);
+ }
+ else
+ {
+ DecryptBlock(workingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BC / 2;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ A0 = (long)(bytes[index++] & 0xff);
+ A1 = (long)(bytes[index++] & 0xff);
+ A2 = (long)(bytes[index++] & 0xff);
+ A3 = (long)(bytes[index++] & 0xff);
+
+ for (int j = 8; j != BC; j += 8)
+ {
+ A0 |= (long)(bytes[index++] & 0xff) << j;
+ A1 |= (long)(bytes[index++] & 0xff) << j;
+ A2 |= (long)(bytes[index++] & 0xff) << j;
+ A3 |= (long)(bytes[index++] & 0xff) << j;
+ }
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ int index = off;
+
+ for (int j = 0; j != BC; j += 8)
+ {
+ bytes[index++] = (byte)(A0 >> j);
+ bytes[index++] = (byte)(A1 >> j);
+ bytes[index++] = (byte)(A2 >> j);
+ bytes[index++] = (byte)(A3 >> j);
+ }
+ }
+
+ private void EncryptBlock(
+ long[][] rk)
+ {
+ int r;
+
+ //
+ // begin with a key addition
+ //
+ KeyAddition(rk[0]);
+
+ //
+ // ROUNDS-1 ordinary rounds
+ //
+ for (r = 1; r < ROUNDS; r++)
+ {
+ Substitution(S);
+ ShiftRow(shifts0SC);
+ MixColumn();
+ KeyAddition(rk[r]);
+ }
+
+ //
+ // Last round is special: there is no MixColumn
+ //
+ Substitution(S);
+ ShiftRow(shifts0SC);
+ KeyAddition(rk[ROUNDS]);
+ }
+
+ private void DecryptBlock(
+ long[][] rk)
+ {
+ int r;
+
+ // To decrypt: apply the inverse operations of the encrypt routine,
+ // in opposite order
+ //
+ // (KeyAddition is an involution: it 's equal to its inverse)
+ // (the inverse of Substitution with table S is Substitution with the inverse table of S)
+ // (the inverse of Shiftrow is Shiftrow over a suitable distance)
+ //
+
+ // First the special round:
+ // without InvMixColumn
+ // with extra KeyAddition
+ //
+ KeyAddition(rk[ROUNDS]);
+ Substitution(Si);
+ ShiftRow(shifts1SC);
+
+ //
+ // ROUNDS-1 ordinary rounds
+ //
+ for (r = ROUNDS-1; r > 0; r--)
+ {
+ KeyAddition(rk[r]);
+ InvMixColumn();
+ Substitution(Si);
+ ShiftRow(shifts1SC);
+ }
+
+ //
+ // End with the extra key addition
+ //
+ KeyAddition(rk[0]);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/RsaEngine.cs b/src/core/srcbc/crypto/engines/RsaEngine.cs
new file mode 100644
index 0000000..91fae9f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/RsaEngine.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm.
+ */
+ public class RsaEngine
+ : IAsymmetricBlockCipher
+ {
+ private RsaCoreEngine core;
+
+ public string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (core == null)
+ core = new RsaCoreEngine();
+
+ core.Init(forEncryption, parameters);
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param inBuf the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ if (core == null)
+ throw new InvalidOperationException("RSA engine not initialised");
+
+ return core.ConvertOutput(core.ProcessBlock(core.ConvertInput(inBuf, inOff, inLen)));
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/SEEDEngine.cs b/src/core/srcbc/crypto/engines/SEEDEngine.cs
new file mode 100644
index 0000000..6e66dbb
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/SEEDEngine.cs
@@ -0,0 +1,361 @@
+using System;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Implementation of the SEED algorithm as described in RFC 4009
+ */
+ public class SeedEngine
+ : IBlockCipher
+ {
+ private const int BlockSize = 16;
+
+ private static readonly uint[] SS0 =
+ {
+ 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
+ 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
+ 0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
+ 0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
+ 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
+ 0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
+ 0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
+ 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
+ 0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
+ 0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
+ 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
+ 0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
+ 0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
+ 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
+ 0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
+ 0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
+ 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
+ 0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
+ 0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038,
+ 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
+ 0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
+ 0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
+ 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
+ 0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
+ 0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
+ 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
+ 0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
+ 0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
+ 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
+ 0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
+ 0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330,
+ 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
+ };
+
+ private static readonly uint[] SS1 =
+ {
+ 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
+ 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
+ 0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
+ 0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
+ 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
+ 0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
+ 0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
+ 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
+ 0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
+ 0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
+ 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
+ 0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
+ 0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
+ 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171,
+ 0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
+ 0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
+ 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
+ 0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
+ 0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
+ 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
+ 0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
+ 0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
+ 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
+ 0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
+ 0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
+ 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
+ 0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
+ 0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
+ 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
+ 0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
+ 0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
+ 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
+ };
+
+ private static readonly uint[] SS2 =
+ {
+
+ 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
+ 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
+ 0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
+ 0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
+ 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
+ 0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
+ 0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
+ 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
+ 0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
+ 0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
+ 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
+ 0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
+ 0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
+ 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
+ 0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
+ 0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
+ 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
+ 0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
+ 0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808,
+ 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
+ 0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
+ 0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
+ 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
+ 0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
+ 0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
+ 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
+ 0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
+ 0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
+ 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
+ 0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
+ 0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303,
+ 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
+ };
+
+ private static readonly uint[] SS3 =
+ {
+
+ 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
+ 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
+ 0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
+ 0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
+ 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
+ 0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
+ 0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
+ 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
+ 0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
+ 0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
+ 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
+ 0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
+ 0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
+ 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031,
+ 0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
+ 0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
+ 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
+ 0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
+ 0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
+ 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
+ 0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
+ 0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
+ 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
+ 0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
+ 0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
+ 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
+ 0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
+ 0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
+ 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
+ 0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
+ 0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
+ 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
+ };
+
+ private static readonly uint[] KC =
+ {
+ 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc,
+ 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf,
+ 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1,
+ 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b
+ };
+
+ private int[] wKey;
+ private bool forEncryption;
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+
+ public string AlgorithmName
+ {
+ get { return "SEED"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public int ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ byte[] outBuf,
+ int outOff)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException("SEED engine not initialised");
+ if (inOff + BlockSize > inBuf.Length)
+ throw new DataLengthException("input buffer too short");
+ if (outOff + BlockSize > outBuf.Length)
+ throw new DataLengthException("output buffer too short");
+
+ long l = bytesToLong(inBuf, inOff + 0);
+ long r = bytesToLong(inBuf, inOff + 8);
+
+ if (forEncryption)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ long nl = r;
+
+ r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+ l = nl;
+ }
+ }
+ else
+ {
+ for (int i = 15; i >= 0; i--)
+ {
+ long nl = r;
+
+ r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+ l = nl;
+ }
+ }
+
+ longToBytes(outBuf, outOff + 0, r);
+ longToBytes(outBuf, outOff + 8, l);
+
+ return BlockSize;
+ }
+
+ public void Reset()
+ {
+ }
+
+ private int[] createWorkingKey(
+ byte[] inKey)
+ {
+ int[] key = new int[32];
+ long lower = bytesToLong(inKey, 0);
+ long upper = bytesToLong(inKey, 8);
+
+ int key0 = extractW0(lower);
+ int key1 = extractW1(lower);
+ int key2 = extractW0(upper);
+ int key3 = extractW1(upper);
+
+ for (int i = 0; i < 16; i++)
+ {
+ key[2 * i] = G(key0 + key2 - (int)KC[i]);
+ key[2 * i + 1] = G(key1 - key3 + (int)KC[i]);
+
+ if (i % 2 == 0)
+ {
+ lower = rotateRight8(lower);
+ key0 = extractW0(lower);
+ key1 = extractW1(lower);
+ }
+ else
+ {
+ upper = rotateLeft8(upper);
+ key2 = extractW0(upper);
+ key3 = extractW1(upper);
+ }
+ }
+
+ return key;
+ }
+
+ private int extractW1(
+ long lVal)
+ {
+ return (int)lVal;
+ }
+
+ private int extractW0(
+ long lVal)
+ {
+ return (int)(lVal >> 32);
+ }
+
+ private long rotateLeft8(
+ long x)
+ {
+ return (x << 8) | ((long)((ulong) x >> 56));
+ }
+
+ private long rotateRight8(
+ long x)
+ {
+ return ((long)((ulong) x >> 8)) | (x << 56);
+ }
+
+ private long bytesToLong(
+ byte[] src,
+ int srcOff)
+ {
+ long word = 0;
+
+ for (int i = 0; i <= 7; i++)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ private void longToBytes(
+ byte[] dest,
+ int destOff,
+ long value)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ dest[i + destOff] = (byte)(value >> ((7 - i) * 8));
+ }
+ }
+
+ private int G(
+ int x)
+ {
+ return (int)(SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]);
+ }
+
+ private long F(
+ int ki0,
+ int ki1,
+ long r)
+ {
+ int r0 = (int)(r >> 32);
+ int r1 = (int)r;
+ int rd1 = phaseCalc2(r0, ki0, r1, ki1);
+ int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1);
+
+ return ((long)rd0 << 32) | (rd1 & 0xffffffffL);
+ }
+
+ private int phaseCalc1(
+ int r0,
+ int ki0,
+ int r1,
+ int ki1)
+ {
+ return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0));
+ }
+
+ private int phaseCalc2(
+ int r0,
+ int ki0,
+ int r1,
+ int ki1)
+ {
+ return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1)));
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/SEEDWrapEngine.cs b/src/core/srcbc/crypto/engines/SEEDWrapEngine.cs
new file mode 100644
index 0000000..7b2ca9f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/SEEDWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the SEED key wrapper based on RFC 4010/RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc4010.txt.
+ ///
+ public class SeedWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public SeedWrapEngine()
+ : base(new SeedEngine())
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/Salsa20Engine.cs b/src/core/srcbc/crypto/engines/Salsa20Engine.cs
new file mode 100644
index 0000000..c4ea809
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/Salsa20Engine.cs
@@ -0,0 +1,363 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+ */
+ public class Salsa20Engine
+ : IStreamCipher
+ {
+ /** Constants */
+ private const int stateSize = 16; // 16, 32 bit ints = 64 bytes
+
+ private readonly static byte[]
+ sigma = Encoding.ASCII.GetBytes("expand 32-byte k"),
+ tau = Encoding.ASCII.GetBytes("expand 16-byte k");
+
+ /*
+ * variables to hold the state of the engine
+ * during encryption and decryption
+ */
+ private int index = 0;
+ private int[] engineState = new int[stateSize]; // state
+ private int[] x = new int[stateSize] ; // internal buffer
+ private byte[] keyStream = new byte[stateSize * 4], // expanded state, 64 bytes
+ workingKey = null,
+ workingIV = null;
+ private bool initialised = false;
+
+ /*
+ * internal counter
+ */
+ private int cW0, cW1, cW2;
+
+ /**
+ * initialise a Salsa20 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ /*
+ * Salsa20 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant. (Like 90% of stream ciphers)
+ */
+
+ ParametersWithIV ivParams = parameters as ParametersWithIV;
+
+ if (ivParams == null)
+ throw new ArgumentException("Salsa20 Init requires an IV", "parameters");
+
+ byte[] iv = ivParams.GetIV();
+
+ if (iv == null || iv.Length != 8)
+ throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV");
+
+ KeyParameter key = ivParams.Parameters as KeyParameter;
+
+ if (key == null)
+ throw new ArgumentException("Salsa20 Init requires a key", "parameters");
+
+ workingKey = key.GetKey();
+ workingIV = iv;
+
+ setKey(workingKey, workingIV);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Salsa20"; }
+ }
+
+ public byte ReturnByte(
+ byte input)
+ {
+ if (limitExceeded())
+ {
+ throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV");
+ }
+
+ if (index == 0)
+ {
+ salsa20WordToByte(engineState, keyStream);
+ engineState[8]++;
+ if (engineState[8] == 0)
+ {
+ engineState[9]++;
+ }
+ }
+ byte output = (byte)(keyStream[index]^input);
+ index = (index + 1) & 63;
+
+ return output;
+ }
+
+ public void ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!initialised)
+ {
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ }
+
+ if ((inOff + len) > inBytes.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (limitExceeded(len))
+ {
+ throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ if (index == 0)
+ {
+ salsa20WordToByte(engineState, keyStream);
+ engineState[8]++;
+ if (engineState[8] == 0)
+ {
+ engineState[9]++;
+ }
+ }
+ outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]);
+ index = (index + 1) & 63;
+ }
+ }
+
+ public void Reset()
+ {
+ setKey(workingKey, workingIV);
+ }
+
+ // Private implementation
+
+ private void setKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ workingKey = keyBytes;
+ workingIV = ivBytes;
+
+ index = 0;
+ resetCounter();
+ int offset = 0;
+ byte[] constants;
+
+ // Key
+ engineState[1] = byteToIntLittle(workingKey, 0);
+ engineState[2] = byteToIntLittle(workingKey, 4);
+ engineState[3] = byteToIntLittle(workingKey, 8);
+ engineState[4] = byteToIntLittle(workingKey, 12);
+
+ if (workingKey.Length == 32)
+ {
+ constants = sigma;
+ offset = 16;
+ }
+ else
+ {
+ constants = tau;
+ }
+
+ engineState[11] = byteToIntLittle(workingKey, offset);
+ engineState[12] = byteToIntLittle(workingKey, offset+4);
+ engineState[13] = byteToIntLittle(workingKey, offset+8);
+ engineState[14] = byteToIntLittle(workingKey, offset+12);
+ engineState[0 ] = byteToIntLittle(constants, 0);
+ engineState[5 ] = byteToIntLittle(constants, 4);
+ engineState[10] = byteToIntLittle(constants, 8);
+ engineState[15] = byteToIntLittle(constants, 12);
+
+ // IV
+ engineState[6] = byteToIntLittle(workingIV, 0);
+ engineState[7] = byteToIntLittle(workingIV, 4);
+ engineState[8] = engineState[9] = 0;
+
+ initialised = true;
+ }
+
+ /**
+ * Salsa20 function
+ *
+ * @param input input data
+ *
+ * @return keystream
+ */
+ private void salsa20WordToByte(
+ int[] input,
+ byte[] output)
+ {
+ Array.Copy(input, 0, x, 0, input.Length);
+
+ for (int i = 0; i < 10; i++)
+ {
+ x[ 4] ^= rotl((x[ 0]+x[12]), 7);
+ x[ 8] ^= rotl((x[ 4]+x[ 0]), 9);
+ x[12] ^= rotl((x[ 8]+x[ 4]),13);
+ x[ 0] ^= rotl((x[12]+x[ 8]),18);
+ x[ 9] ^= rotl((x[ 5]+x[ 1]), 7);
+ x[13] ^= rotl((x[ 9]+x[ 5]), 9);
+ x[ 1] ^= rotl((x[13]+x[ 9]),13);
+ x[ 5] ^= rotl((x[ 1]+x[13]),18);
+ x[14] ^= rotl((x[10]+x[ 6]), 7);
+ x[ 2] ^= rotl((x[14]+x[10]), 9);
+ x[ 6] ^= rotl((x[ 2]+x[14]),13);
+ x[10] ^= rotl((x[ 6]+x[ 2]),18);
+ x[ 3] ^= rotl((x[15]+x[11]), 7);
+ x[ 7] ^= rotl((x[ 3]+x[15]), 9);
+ x[11] ^= rotl((x[ 7]+x[ 3]),13);
+ x[15] ^= rotl((x[11]+x[ 7]),18);
+ x[ 1] ^= rotl((x[ 0]+x[ 3]), 7);
+ x[ 2] ^= rotl((x[ 1]+x[ 0]), 9);
+ x[ 3] ^= rotl((x[ 2]+x[ 1]),13);
+ x[ 0] ^= rotl((x[ 3]+x[ 2]),18);
+ x[ 6] ^= rotl((x[ 5]+x[ 4]), 7);
+ x[ 7] ^= rotl((x[ 6]+x[ 5]), 9);
+ x[ 4] ^= rotl((x[ 7]+x[ 6]),13);
+ x[ 5] ^= rotl((x[ 4]+x[ 7]),18);
+ x[11] ^= rotl((x[10]+x[ 9]), 7);
+ x[ 8] ^= rotl((x[11]+x[10]), 9);
+ x[ 9] ^= rotl((x[ 8]+x[11]),13);
+ x[10] ^= rotl((x[ 9]+x[ 8]),18);
+ x[12] ^= rotl((x[15]+x[14]), 7);
+ x[13] ^= rotl((x[12]+x[15]), 9);
+ x[14] ^= rotl((x[13]+x[12]),13);
+ x[15] ^= rotl((x[14]+x[13]),18);
+ }
+
+ int offset = 0;
+ for (int i = 0; i < stateSize; i++)
+ {
+ intToByteLittle(x[i] + input[i], output, offset);
+ offset += 4;
+ }
+
+ for (int i = stateSize; i < x.Length; i++)
+ {
+ intToByteLittle(x[i], output, offset);
+ offset += 4;
+ }
+ }
+
+ /**
+ * 32 bit word to 4 byte array in little endian order
+ *
+ * @param x value to 'unpack'
+ *
+ * @return value of x expressed as a byte[] array in little endian order
+ */
+ private byte[] intToByteLittle(
+ int x,
+ byte[] bs,
+ int off)
+ {
+ bs[off] = (byte)x;
+ bs[off + 1] = (byte)(x >> 8);
+ bs[off + 2] = (byte)(x >> 16);
+ bs[off + 3] = (byte)(x >> 24);
+ return bs;
+ }
+
+ /**
+ * Rotate left
+ *
+ * @param x value to rotate
+ * @param y amount to rotate x
+ *
+ * @return rotated x
+ */
+ private int rotl(
+ int x,
+ int y)
+ {
+ return (x << y) | ((int)((uint) x >> -y));
+ }
+
+ /**
+ * Pack byte[] array into an int in little endian order
+ *
+ * @param x byte array to 'pack'
+ * @param offset only x[offset]..x[offset+3] will be packed
+ *
+ * @return x[offset]..x[offset+3] 'packed' into an int in little-endian order
+ */
+ private int byteToIntLittle(
+ byte[] x,
+ int offset)
+ {
+ return ((x[offset] & 255)) |
+ ((x[offset + 1] & 255) << 8) |
+ ((x[offset + 2] & 255) << 16) |
+ (x[offset + 3] << 24);
+ }
+
+ private void resetCounter()
+ {
+ cW0 = 0;
+ cW1 = 0;
+ cW2 = 0;
+ }
+
+ private bool limitExceeded()
+ {
+ cW0++;
+ if (cW0 == 0)
+ {
+ cW1++;
+ if (cW1 == 0)
+ {
+ cW2++;
+ return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ * this relies on the fact len will always be positive.
+ */
+ private bool limitExceeded(
+ int len)
+ {
+ if (cW0 >= 0)
+ {
+ cW0 += len;
+ }
+ else
+ {
+ cW0 += len;
+ if (cW0 >= 0)
+ {
+ cW1++;
+ if (cW1 == 0)
+ {
+ cW2++;
+ return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/SerpentEngine.cs b/src/core/srcbc/crypto/engines/SerpentEngine.cs
new file mode 100644
index 0000000..5b63b38
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/SerpentEngine.cs
@@ -0,0 +1,779 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Serpent is a 128-bit 32-round block cipher with variable key lengths,
+ * including 128, 192 and 256 bit keys conjectured to be at least as
+ * secure as three-key triple-DES.
+ *
+ * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+ * candidate algorithm for the NIST AES Quest.>
+ *
+ *
+ * For full details see the The Serpent home page
+ *
+ */
+ public class SerpentEngine
+ : IBlockCipher
+ {
+ private const int BLOCK_SIZE = 16;
+
+ static readonly int ROUNDS = 32;
+ static readonly int PHI = unchecked((int)0x9E3779B9); // (Sqrt(5) - 1) * 2**31
+
+ private bool encrypting;
+ private int[] wKey;
+
+ private int X0, X1, X2, X3; // registers
+
+ /**
+ * initialise a Serpent cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to Serpent init - " + parameters.GetType().ToString());
+
+ this.encrypting = forEncryption;
+ this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Serpent"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException("Serpent not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Expand a user-supplied key material into a session key.
+ *
+ * @param key The user-key bytes (multiples of 4) to use.
+ * @exception ArgumentException
+ */
+ private int[] MakeWorkingKey(
+ byte[] key)
+ {
+ //
+ // pad key to 256 bits
+ //
+ int[] kPad = new int[16];
+ int off = 0;
+ int length = 0;
+
+ for (off = key.Length - 4; off > 0; off -= 4)
+ {
+ kPad[length++] = BytesToWord(key, off);
+ }
+
+ if (off == 0)
+ {
+ kPad[length++] = BytesToWord(key, 0);
+ if (length < 8)
+ {
+ kPad[length] = 1;
+ }
+ }
+ else
+ {
+ throw new ArgumentException("key must be a multiple of 4 bytes");
+ }
+
+ //
+ // expand the padded key up to 33 x 128 bits of key material
+ //
+ int amount = (ROUNDS + 1) * 4;
+ int[] w = new int[amount];
+
+ //
+ // compute w0 to w7 from w-8 to w-1
+ //
+ for (int i = 8; i < 16; i++)
+ {
+ kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
+ }
+
+ Array.Copy(kPad, 8, w, 0, 8);
+
+ //
+ // compute w8 to w136
+ //
+ for (int i = 8; i < amount; i++)
+ {
+ w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+ }
+
+ //
+ // create the working keys by processing w with the Sbox and IP
+ //
+ Sb3(w[0], w[1], w[2], w[3]);
+ w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
+ Sb2(w[4], w[5], w[6], w[7]);
+ w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
+ Sb1(w[8], w[9], w[10], w[11]);
+ w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
+ Sb0(w[12], w[13], w[14], w[15]);
+ w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
+ Sb7(w[16], w[17], w[18], w[19]);
+ w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
+ Sb6(w[20], w[21], w[22], w[23]);
+ w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
+ Sb5(w[24], w[25], w[26], w[27]);
+ w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
+ Sb4(w[28], w[29], w[30], w[31]);
+ w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
+ Sb3(w[32], w[33], w[34], w[35]);
+ w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
+ Sb2(w[36], w[37], w[38], w[39]);
+ w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
+ Sb1(w[40], w[41], w[42], w[43]);
+ w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
+ Sb0(w[44], w[45], w[46], w[47]);
+ w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
+ Sb7(w[48], w[49], w[50], w[51]);
+ w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
+ Sb6(w[52], w[53], w[54], w[55]);
+ w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
+ Sb5(w[56], w[57], w[58], w[59]);
+ w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
+ Sb4(w[60], w[61], w[62], w[63]);
+ w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
+ Sb3(w[64], w[65], w[66], w[67]);
+ w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
+ Sb2(w[68], w[69], w[70], w[71]);
+ w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
+ Sb1(w[72], w[73], w[74], w[75]);
+ w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
+ Sb0(w[76], w[77], w[78], w[79]);
+ w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
+ Sb7(w[80], w[81], w[82], w[83]);
+ w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
+ Sb6(w[84], w[85], w[86], w[87]);
+ w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
+ Sb5(w[88], w[89], w[90], w[91]);
+ w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
+ Sb4(w[92], w[93], w[94], w[95]);
+ w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
+ Sb3(w[96], w[97], w[98], w[99]);
+ w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
+ Sb2(w[100], w[101], w[102], w[103]);
+ w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
+ Sb1(w[104], w[105], w[106], w[107]);
+ w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
+ Sb0(w[108], w[109], w[110], w[111]);
+ w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
+ Sb7(w[112], w[113], w[114], w[115]);
+ w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
+ Sb6(w[116], w[117], w[118], w[119]);
+ w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
+ Sb5(w[120], w[121], w[122], w[123]);
+ w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
+ Sb4(w[124], w[125], w[126], w[127]);
+ w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
+ Sb3(w[128], w[129], w[130], w[131]);
+ w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
+
+ return w;
+ }
+
+ private int RotateLeft(
+ int x,
+ int bits)
+ {
+ return ((x << bits) | (int) ((uint)x >> (32 - bits)));
+ }
+
+ private int RotateRight(
+ int x,
+ int bits)
+ {
+ return ( (int)((uint)x >> bits) | (x << (32 - bits)));
+ }
+
+ private int BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) |
+ ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff)));
+ }
+
+ private void WordToBytes(
+ int word,
+ byte[] dst,
+ int dstOff)
+ {
+ dst[dstOff + 3] = (byte)(word);
+ dst[dstOff + 2] = (byte)((uint)word >> 8);
+ dst[dstOff + 1] = (byte)((uint)word >> 16);
+ dst[dstOff] = (byte)((uint)word >> 24);
+ }
+
+ /**
+ * Encrypt one block of plaintext.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ */
+ private void EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ X3 = BytesToWord(input, inOff);
+ X2 = BytesToWord(input, inOff + 4);
+ X1 = BytesToWord(input, inOff + 8);
+ X0 = BytesToWord(input, inOff + 12);
+
+ Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
+ Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
+ Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
+ Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
+ Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
+ Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
+ Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
+ Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
+ Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
+ Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
+ Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
+ Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
+ Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
+ Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
+ Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
+ Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
+ Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
+ Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
+ Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
+ Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
+ Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
+ Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
+ Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
+ Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
+ Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
+ Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
+ Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
+ Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
+ Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
+ Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
+ Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
+ Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
+
+ WordToBytes(wKey[131] ^ X3, outBytes, outOff);
+ WordToBytes(wKey[130] ^ X2, outBytes, outOff + 4);
+ WordToBytes(wKey[129] ^ X1, outBytes, outOff + 8);
+ WordToBytes(wKey[128] ^ X0, outBytes, outOff + 12);
+ }
+
+ /**
+ * Decrypt one block of ciphertext.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ */
+ private void DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ X3 = wKey[131] ^ BytesToWord(input, inOff);
+ X2 = wKey[130] ^ BytesToWord(input, inOff + 4);
+ X1 = wKey[129] ^ BytesToWord(input, inOff + 8);
+ X0 = wKey[128] ^ BytesToWord(input, inOff + 12);
+
+ Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+
+ WordToBytes(X3 ^ wKey[3], outBytes, outOff);
+ WordToBytes(X2 ^ wKey[2], outBytes, outOff + 4);
+ WordToBytes(X1 ^ wKey[1], outBytes, outOff + 8);
+ WordToBytes(X0 ^ wKey[0], outBytes, outOff + 12);
+ }
+
+ /*
+ * The sboxes below are based on the work of Brian Gladman and
+ * Sam Simpson, whose original notice appears below.
+ *
+ * For further details see:
+ * http://fp.gladman.plus.com/cryptography_technology/serpent/
+ *
+ */
+
+ /* Partially optimised Serpent S Box bool functions derived */
+ /* using a recursive descent analyser but without a full search */
+ /* of all subtrees. This set of S boxes is the result of work */
+ /* by Sam Simpson and Brian Gladman using the spare time on a */
+ /* cluster of high capacity servers to search for S boxes with */
+ /* this customised search engine. There are now an average of */
+ /* 15.375 terms per S box. */
+ /* */
+ /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */
+ /* and Sam Simpson (s.simpson@mia.co.uk) */
+ /* 17th December 1998 */
+ /* */
+ /* We hereby give permission for information in this file to be */
+ /* used freely subject only to acknowledgement of its origin. */
+
+ /**
+ * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+ */
+ private void Sb0(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t3 = c ^ t1;
+ int t4 = b ^ t3;
+ X3 = (a & d) ^ t4;
+ int t7 = a ^ (b & t1);
+ X2 = t4 ^ (c | t7);
+ int t12 = X3 & (t3 ^ t7);
+ X1 = (~t3) ^ t12;
+ X0 = t12 ^ (~t7);
+ }
+
+ /**
+ * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+ */
+ private void Ib0(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t4 = d ^ (t1 | t2);
+ int t5 = c ^ t4;
+ X2 = t2 ^ t5;
+ int t8 = t1 ^ (d & t2);
+ X1 = t4 ^ (X2 & t8);
+ X3 = (a & t4) ^ (t5 | X1);
+ X0 = X3 ^ (t5 ^ t8);
+ }
+
+ /**
+ * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+ */
+ private void Sb1(int a, int b, int c, int d)
+ {
+ int t2 = b ^ (~a);
+ int t5 = c ^ (a | t2);
+ X2 = d ^ t5;
+ int t7 = b ^ (d | t2);
+ int t8 = t2 ^ X2;
+ X3 = t8 ^ (t5 & t7);
+ int t11 = t5 ^ t7;
+ X1 = X3 ^ t11;
+ X0 = t5 ^ (t8 & t11);
+ }
+
+ /**
+ * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+ */
+ private void Ib1(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t3 = a ^ (b & t1);
+ int t4 = t1 ^ t3;
+ X3 = c ^ t4;
+ int t7 = b ^ (t1 & t3);
+ int t8 = X3 | t7;
+ X1 = t3 ^ t8;
+ int t10 = ~X1;
+ int t11 = X3 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = t4 ^ (t10 | t11);
+ }
+
+ /**
+ * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+ */
+ private void Sb2(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = b ^ d;
+ int t3 = c & t1;
+ X0 = t2 ^ t3;
+ int t5 = c ^ t1;
+ int t6 = c ^ X0;
+ int t7 = b & t6;
+ X3 = t5 ^ t7;
+ X2 = a ^ ((d | t7) & (X0 | t5));
+ X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
+ }
+
+ /**
+ * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+ */
+ private void Ib2(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t2 = ~t1;
+ int t3 = a ^ c;
+ int t4 = c ^ t1;
+ int t5 = b & t4;
+ X0 = t3 ^ t5;
+ int t7 = a | t2;
+ int t8 = d ^ t7;
+ int t9 = t3 | t8;
+ X3 = t1 ^ t9;
+ int t11 = ~t4;
+ int t12 = X0 | X3;
+ X1 = t11 ^ t12;
+ X2 = (d & t11) ^ (t3 ^ t12);
+ }
+
+ /**
+ * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+ */
+ private void Sb3(int a, int b, int c, int d)
+ {
+ int t1 = a ^ b;
+ int t2 = a & c;
+ int t3 = a | d;
+ int t4 = c ^ d;
+ int t5 = t1 & t3;
+ int t6 = t2 | t5;
+ X2 = t4 ^ t6;
+ int t8 = b ^ t3;
+ int t9 = t6 ^ t8;
+ int t10 = t4 & t9;
+ X0 = t1 ^ t10;
+ int t12 = X2 & X0;
+ X1 = t9 ^ t12;
+ X3 = (b | d) ^ (t4 ^ t12);
+ }
+
+ /**
+ * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+ */
+ private void Ib3(int a, int b, int c, int d)
+ {
+ int t1 = a | b;
+ int t2 = b ^ c;
+ int t3 = b & t2;
+ int t4 = a ^ t3;
+ int t5 = c ^ t4;
+ int t6 = d | t4;
+ X0 = t2 ^ t6;
+ int t8 = t2 | t6;
+ int t9 = d ^ t8;
+ X2 = t5 ^ t9;
+ int t11 = t1 ^ t9;
+ int t12 = X0 & t11;
+ X3 = t4 ^ t12;
+ X1 = X3 ^ (X0 ^ t11);
+ }
+
+ /**
+ * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+ */
+ private void Sb4(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t2 = d & t1;
+ int t3 = c ^ t2;
+ int t4 = b | t3;
+ X3 = t1 ^ t4;
+ int t6 = ~b;
+ int t7 = t1 | t6;
+ X0 = t3 ^ t7;
+ int t9 = a & X0;
+ int t10 = t1 ^ t6;
+ int t11 = t4 & t10;
+ X2 = t9 ^ t11;
+ X1 = (a ^ t3) ^ (t10 & X2);
+ }
+
+ /**
+ * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+ */
+ private void Ib4(int a, int b, int c, int d)
+ {
+ int t1 = c | d;
+ int t2 = a & t1;
+ int t3 = b ^ t2;
+ int t4 = a & t3;
+ int t5 = c ^ t4;
+ X1 = d ^ t5;
+ int t7 = ~a;
+ int t8 = t5 & X1;
+ X3 = t3 ^ t8;
+ int t10 = X1 | t7;
+ int t11 = d ^ t10;
+ X0 = X3 ^ t11;
+ X2 = (t3 & t11) ^ (X1 ^ t7);
+ }
+
+ /**
+ * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+ */
+ private void Sb5(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = a ^ d;
+ int t4 = c ^ t1;
+ int t5 = t2 | t3;
+ X0 = t4 ^ t5;
+ int t7 = d & X0;
+ int t8 = t2 ^ X0;
+ X1 = t7 ^ t8;
+ int t10 = t1 | X0;
+ int t11 = t2 | t7;
+ int t12 = t3 ^ t10;
+ X2 = t11 ^ t12;
+ X3 = (b ^ t7) ^ (X1 & t12);
+ }
+
+ /**
+ * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+ */
+ private void Ib5(int a, int b, int c, int d)
+ {
+ int t1 = ~c;
+ int t2 = b & t1;
+ int t3 = d ^ t2;
+ int t4 = a & t3;
+ int t5 = b ^ t1;
+ X3 = t4 ^ t5;
+ int t7 = b | X3;
+ int t8 = a & t7;
+ X1 = t3 ^ t8;
+ int t10 = a | d;
+ int t11 = t1 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = (b & t10) ^ (t4 | (a ^ c));
+ }
+
+ /**
+ * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+ */
+ private void Sb6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ d;
+ int t3 = b ^ t2;
+ int t4 = t1 | t2;
+ int t5 = c ^ t4;
+ X1 = b ^ t5;
+ int t7 = t2 | X1;
+ int t8 = d ^ t7;
+ int t9 = t5 & t8;
+ X2 = t3 ^ t9;
+ int t11 = t5 ^ t8;
+ X0 = X2 ^ t11;
+ X3 = (~t5) ^ (t3 & t11);
+ }
+
+ /**
+ * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+ */
+ private void Ib6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = c ^ t2;
+ int t4 = c | t1;
+ int t5 = d ^ t4;
+ X1 = t3 ^ t5;
+ int t7 = t3 & t5;
+ int t8 = t2 ^ t7;
+ int t9 = b | t8;
+ X3 = t5 ^ t9;
+ int t11 = b | X3;
+ X0 = t8 ^ t11;
+ X2 = (d & t1) ^ (t3 ^ t11);
+ }
+
+ /**
+ * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+ */
+ private void Sb7(int a, int b, int c, int d)
+ {
+ int t1 = b ^ c;
+ int t2 = c & t1;
+ int t3 = d ^ t2;
+ int t4 = a ^ t3;
+ int t5 = d | t1;
+ int t6 = t4 & t5;
+ X1 = b ^ t6;
+ int t8 = t3 | X1;
+ int t9 = a & t4;
+ X3 = t1 ^ t9;
+ int t11 = t4 ^ t8;
+ int t12 = X3 & t11;
+ X2 = t3 ^ t12;
+ X0 = (~t11) ^ (X3 & X2);
+ }
+
+ /**
+ * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+ */
+ private void Ib7(int a, int b, int c, int d)
+ {
+ int t3 = c | (a & b);
+ int t4 = d & (a | b);
+ X3 = t3 ^ t4;
+ int t6 = ~d;
+ int t7 = b ^ t4;
+ int t9 = t7 | (X3 ^ t6);
+ X1 = a ^ t9;
+ X0 = (c ^ t7) ^ (d | X1);
+ X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
+ }
+
+ /**
+ * Apply the linear transformation to the register set.
+ */
+ private void LT()
+ {
+ int x0 = RotateLeft(X0, 13);
+ int x2 = RotateLeft(X2, 3);
+ int x1 = X1 ^ x0 ^ x2 ;
+ int x3 = X3 ^ x2 ^ x0 << 3;
+
+ X1 = RotateLeft(x1, 1);
+ X3 = RotateLeft(x3, 7);
+ X0 = RotateLeft(x0 ^ X1 ^ X3, 5);
+ X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
+ }
+
+ /**
+ * Apply the inverse of the linear transformation to the register set.
+ */
+ private void InverseLT()
+ {
+ int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
+ int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
+ int x3 = RotateRight(X3, 7);
+ int x1 = RotateRight(X1, 1);
+ X3 = x3 ^ x2 ^ x0 << 3;
+ X1 = x1 ^ x0 ^ x2;
+ X2 = RotateRight(x2, 3);
+ X0 = RotateRight(x0, 13);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/SkipjackEngine.cs b/src/core/srcbc/crypto/engines/SkipjackEngine.cs
new file mode 100644
index 0000000..12b848e
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/SkipjackEngine.cs
@@ -0,0 +1,255 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * a class that provides a basic SKIPJACK engine.
+ */
+ public class SkipjackEngine
+ : IBlockCipher
+ {
+ const int BLOCK_SIZE = 8;
+
+ static readonly short [] ftable =
+ {
+ 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
+ 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
+ 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
+ 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
+ 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
+ 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
+ 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
+ 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
+ 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
+ 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
+ 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
+ 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
+ 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
+ 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
+ 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
+ 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
+ };
+
+ private int[] key0, key1, key2, key3;
+ private bool encrypting;
+
+ /**
+ * initialise a SKIPJACK cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + parameters.GetType().ToString());
+
+ byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+
+ this.encrypting = forEncryption;
+ this.key0 = new int[32];
+ this.key1 = new int[32];
+ this.key2 = new int[32];
+ this.key3 = new int[32];
+
+ //
+ // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply
+ // and an addition).
+ //
+ for (int i = 0; i < 32; i ++)
+ {
+ key0[i] = keyBytes[(i * 4) % 10] & 0xff;
+ key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff;
+ key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff;
+ key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff;
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "SKIPJACK"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (key1 == null)
+ throw new InvalidOperationException("SKIPJACK engine not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * The G permutation
+ */
+ private int G(
+ int k,
+ int w)
+ {
+ int g1, g2, g3, g4, g5, g6;
+
+ g1 = (w >> 8) & 0xff;
+ g2 = w & 0xff;
+
+ g3 = ftable[g2 ^ key0[k]] ^ g1;
+ g4 = ftable[g3 ^ key1[k]] ^ g2;
+ g5 = ftable[g4 ^ key2[k]] ^ g3;
+ g6 = ftable[g5 ^ key3[k]] ^ g4;
+
+ return ((g5 << 8) + g6);
+ }
+
+ public int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
+ int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
+ int w3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+ int w4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
+
+ int k = 0;
+
+ for (int t = 0; t < 2; t++)
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w2;
+ w2 = G(k, w1);
+ w1 = w2 ^ tmp ^ (k + 1);
+ k++;
+ }
+
+ for(int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w1 ^ w2 ^ (k + 1);
+ w2 = G(k, w1);
+ w1 = tmp;
+ k++;
+ }
+ }
+
+ outBytes[outOff + 0] = (byte)((w1 >> 8));
+ outBytes[outOff + 1] = (byte)(w1);
+ outBytes[outOff + 2] = (byte)((w2 >> 8));
+ outBytes[outOff + 3] = (byte)(w2);
+ outBytes[outOff + 4] = (byte)((w3 >> 8));
+ outBytes[outOff + 5] = (byte)(w3);
+ outBytes[outOff + 6] = (byte)((w4 >> 8));
+ outBytes[outOff + 7] = (byte)(w4);
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * the inverse of the G permutation.
+ */
+ private int H(
+ int k,
+ int w)
+ {
+ int h1, h2, h3, h4, h5, h6;
+
+ h1 = w & 0xff;
+ h2 = (w >> 8) & 0xff;
+
+ h3 = ftable[h2 ^ key3[k]] ^ h1;
+ h4 = ftable[h3 ^ key2[k]] ^ h2;
+ h5 = ftable[h4 ^ key1[k]] ^ h3;
+ h6 = ftable[h5 ^ key0[k]] ^ h4;
+
+ return ((h6 << 8) + h5);
+ }
+
+ public int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
+ int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
+ int w4 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+ int w3 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
+
+ int k = 31;
+
+ for (int t = 0; t < 2; t++)
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w2;
+ w2 = H(k, w1);
+ w1 = w2 ^ tmp ^ (k + 1);
+ k--;
+ }
+
+ for(int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w1 ^ w2 ^ (k + 1);
+ w2 = H(k, w1);
+ w1 = tmp;
+ k--;
+ }
+ }
+
+ outBytes[outOff + 0] = (byte)((w2 >> 8));
+ outBytes[outOff + 1] = (byte)(w2);
+ outBytes[outOff + 2] = (byte)((w1 >> 8));
+ outBytes[outOff + 3] = (byte)(w1);
+ outBytes[outOff + 4] = (byte)((w4 >> 8));
+ outBytes[outOff + 5] = (byte)(w4);
+ outBytes[outOff + 6] = (byte)((w3 >> 8));
+ outBytes[outOff + 7] = (byte)(w3);
+
+ return BLOCK_SIZE;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/TEAEngine.cs b/src/core/srcbc/crypto/engines/TEAEngine.cs
new file mode 100644
index 0000000..4733282
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/TEAEngine.cs
@@ -0,0 +1,191 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An TEA engine.
+ */
+ public class TeaEngine
+ : IBlockCipher
+ {
+ private const int
+ rounds = 32,
+ block_size = 8,
+ key_size = 16,
+ delta = unchecked((int) 0x9E3779B9),
+ d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt
+
+ /*
+ * the expanded key array of 4 subkeys
+ */
+ private int _a, _b, _c, _d;
+ private bool _initialised;
+ private bool _forEncryption;
+
+ /**
+ * Create an instance of the TEA encryption algorithm
+ * and set some defaults
+ */
+ public TeaEngine()
+ {
+ _initialised = false;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "TEA"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return block_size;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ {
+ throw new ArgumentException("invalid parameter passed to TEA init - "
+ + parameters.GetType().FullName);
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ if ((inOff + block_size) > inBytes.Length)
+ throw new DataLengthException("input buffer too short");
+
+ if ((outOff + block_size) > outBytes.Length)
+ throw new DataLengthException("output buffer too short");
+
+ return _forEncryption
+ ? encryptBlock(inBytes, inOff, outBytes, outOff)
+ : decryptBlock(inBytes, inOff, outBytes, outOff);
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ _a = bytesToInt(key, 0);
+ _b = bytesToInt(key, 4);
+ _c = bytesToInt(key, 8);
+ _d = bytesToInt(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(inBytes, inOff);
+ int v1 = bytesToInt(inBytes, inOff + 4);
+
+ int sum = 0;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ sum += delta;
+// v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
+ v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b);
+// v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
+ v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d);
+ }
+
+ unpackInt(v0, outBytes, outOff);
+ unpackInt(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(inBytes, inOff);
+ int v1 = bytesToInt(inBytes, inOff + 4);
+
+ int sum = d_sum;
+
+ for (int i = 0; i != rounds; i++)
+ {
+// v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
+ v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d);
+// v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
+ v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b);
+ sum -= delta;
+ }
+
+ unpackInt(v0, outBytes, outOff);
+ unpackInt(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int bytesToInt(
+ byte[] b,
+ int inOff)
+ {
+ return ((b[inOff++]) << 24)
+ | ((b[inOff++] & 255) << 16)
+ | ((b[inOff++] & 255) << 8)
+ | ((b[inOff] & 255));
+ }
+
+ private void unpackInt(
+ int v,
+ byte[] b,
+ int outOff)
+ {
+ uint uv = (uint) v;
+ b[outOff++] = (byte)(uv >> 24);
+ b[outOff++] = (byte)(uv >> 16);
+ b[outOff++] = (byte)(uv >> 8);
+ b[outOff ] = (byte)uv;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/TwofishEngine.cs b/src/core/srcbc/crypto/engines/TwofishEngine.cs
new file mode 100644
index 0000000..617b0a3
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/TwofishEngine.cs
@@ -0,0 +1,673 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides Twofish encryption operations.
+ *
+ * This Java implementation is based on the Java reference
+ * implementation provided by Bruce Schneier and developed
+ * by Raif S. Naffah.
+ */
+ public sealed class TwofishEngine
+ : IBlockCipher
+ {
+ private static readonly byte[,] P = {
+ { // p0
+ (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+ (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+ (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+ (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+ (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+ (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+ (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+ (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+ (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+ (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+ (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+ (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+ (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+ (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+ (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+ (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+ (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+ (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+ (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+ (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+ (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+ (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+ (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+ (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+ (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+ (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+ (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+ (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+ (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+ (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+ (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+ (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+ (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+ (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+ (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+ (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+ (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+ (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+ (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+ (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+ (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+ (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+ (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+ (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+ (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+ (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+ (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+ (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+ (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+ (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+ (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+ (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+ (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+ (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+ (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+ (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+ (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+ (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+ (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+ (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+ (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
+ { // p1
+ (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+ (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+ (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+ (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+ (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+ (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+ (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+ (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+ (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+ (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+ (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+ (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+ (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+ (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+ (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+ (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+ (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+ (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+ (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+ (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+ (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+ (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+ (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+ (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+ (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+ (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+ (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+ (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+ (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+ (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+ (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+ (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+ (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+ (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+ (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+ (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+ (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+ (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+ (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+ (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+ (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+ (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+ (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+ (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+ (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+ (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+ (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+ (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+ (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+ (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+ (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+ (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+ (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+ (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+ (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+ (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+ (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+ (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+ (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+ (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
+ };
+
+ /**
+ * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+ * By changing the following constant definitions, the S-boxes will
+ * automatically Get changed in the Twofish engine.
+ */
+ private const int P_00 = 1;
+ private const int P_01 = 0;
+ private const int P_02 = 0;
+ private const int P_03 = P_01 ^ 1;
+ private const int P_04 = 1;
+
+ private const int P_10 = 0;
+ private const int P_11 = 0;
+ private const int P_12 = 1;
+ private const int P_13 = P_11 ^ 1;
+ private const int P_14 = 0;
+
+ private const int P_20 = 1;
+ private const int P_21 = 1;
+ private const int P_22 = 0;
+ private const int P_23 = P_21 ^ 1;
+ private const int P_24 = 0;
+
+ private const int P_30 = 0;
+ private const int P_31 = 1;
+ private const int P_32 = 1;
+ private const int P_33 = P_31 ^ 1;
+ private const int P_34 = 1;
+
+ /* Primitive polynomial for GF(256) */
+ private const int GF256_FDBK = 0x169;
+ private const int GF256_FDBK_2 = GF256_FDBK / 2;
+ private const int GF256_FDBK_4 = GF256_FDBK / 4;
+
+ private const int RS_GF_FDBK = 0x14D; // field generator
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private const int ROUNDS = 16;
+ private const int MAX_ROUNDS = 16; // bytes = 128 bits
+ private const int BLOCK_SIZE = 16; // bytes = 128 bits
+ private const int MAX_KEY_BITS = 256;
+
+ private const int INPUT_WHITEN=0;
+ private const int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+ private const int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+ private const int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+ private const int SK_STEP = 0x02020202;
+ private const int SK_BUMP = 0x01010101;
+ private const int SK_ROTL = 9;
+
+ private bool encrypting;
+
+ private int[] gMDS0 = new int[MAX_KEY_BITS];
+ private int[] gMDS1 = new int[MAX_KEY_BITS];
+ private int[] gMDS2 = new int[MAX_KEY_BITS];
+ private int[] gMDS3 = new int[MAX_KEY_BITS];
+
+ /**
+ * gSubKeys[] and gSBox[] are eventually used in the
+ * encryption and decryption methods.
+ */
+ private int[] gSubKeys;
+ private int[] gSBox;
+
+ private int k64Cnt;
+
+ private byte[] workingKey;
+
+ public TwofishEngine()
+ {
+ // calculate the MDS matrix
+ int[] m1 = new int[2];
+ int[] mX = new int[2];
+ int[] mY = new int[2];
+ int j;
+
+ for (int i=0; i< MAX_KEY_BITS ; i++)
+ {
+ j = P[0,i] & 0xff;
+ m1[0] = j;
+ mX[0] = Mx_X(j) & 0xff;
+ mY[0] = Mx_Y(j) & 0xff;
+
+ j = P[1,i] & 0xff;
+ m1[1] = j;
+ mX[1] = Mx_X(j) & 0xff;
+ mY[1] = Mx_Y(j) & 0xff;
+
+ gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
+ mY[P_00] << 16 | mY[P_00] << 24;
+
+ gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
+ mX[P_10] << 16 | m1[P_10] << 24;
+
+ gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
+ m1[P_20] << 16 | mY[P_20] << 24;
+
+ gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
+ mY[P_30] << 16 | mX[P_30] << 24;
+ }
+ }
+
+ /**
+ * initialise a Twofish cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param parameters the parameters required to set up the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to Twofish init - " + parameters.GetType().ToString());
+
+ this.encrypting = forEncryption;
+ this.workingKey = ((KeyParameter)parameters).GetKey();
+ this.k64Cnt = (this.workingKey.Length / 8); // pre-padded ?
+ SetKey(this.workingKey);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Twofish"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Twofish not initialised");
+ if ((inOff + BLOCK_SIZE) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + BLOCK_SIZE) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ if (this.workingKey != null)
+ {
+ SetKey(this.workingKey);
+ }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private void SetKey(byte[] key)
+ {
+ int[] k32e = new int[MAX_KEY_BITS/64]; // 4
+ int[] k32o = new int[MAX_KEY_BITS/64]; // 4
+
+ int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
+ gSubKeys = new int[TOTAL_SUBKEYS];
+
+ if (k64Cnt < 1)
+ {
+ throw new ArgumentException("Key size less than 64 bits");
+ }
+
+ if (k64Cnt > 4)
+ {
+ throw new ArgumentException("Key size larger than 256 bits");
+ }
+
+ /*
+ * k64Cnt is the number of 8 byte blocks (64 chunks)
+ * that are in the input key. The input key is a
+ * maximum of 32 bytes ( 256 bits ), so the range
+ * for k64Cnt is 1..4
+ */
+ for (int i=0,p=0; i> 24);
+ A += B;
+ gSubKeys[i*2] = A;
+ A += B;
+ gSubKeys[i*2 + 1] = A << SK_ROTL | (int)((uint)A >> (32-SK_ROTL));
+ }
+
+ /*
+ * fully expand the table for speed
+ */
+ int k0 = sBoxKeys[0];
+ int k1 = sBoxKeys[1];
+ int k2 = sBoxKeys[2];
+ int k3 = sBoxKeys[3];
+ int b0, b1, b2, b3;
+ gSBox = new int[4*MAX_KEY_BITS];
+ for (int i=0; i>1) | x2 << 31;
+ x3 = (x3 << 1 | (int) ((uint)x3 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x0 ^= t0 + t1 + gSubKeys[k++];
+ x0 = (int) ((uint)x0 >>1) | x0 << 31;
+ x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
+ }
+
+ Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12);
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void DecryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
+ int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
+ int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
+ int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3];
+
+ int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
+ int t0, t1;
+ for (int r = 0; r< ROUNDS ; r +=2)
+ {
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x1 ^= t0 + 2*t1 + gSubKeys[k--];
+ x0 = (x0 << 1 | (int)((uint) x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+ x1 = (int) ((uint)x1 >>1) | x1 << 31;
+
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x3 ^= t0 + 2*t1 + gSubKeys[k--];
+ x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+ x3 = (int)((uint)x3 >>1) | x3 << 31;
+ }
+
+ Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
+ }
+
+ /*
+ * TODO: This can be optimised and made cleaner by combining
+ * the functionality in this function and applying it appropriately
+ * to the creation of the subkeys during key setup.
+ */
+ private int F32(int x, int[] k32)
+ {
+ int b0 = M_b0(x);
+ int b1 = M_b1(x);
+ int b2 = M_b2(x);
+ int b3 = M_b3(x);
+ int k0 = k32[0];
+ int k1 = k32[1];
+ int k2 = k32[2];
+ int k3 = k32[3];
+
+ int result = 0;
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ result = gMDS0[(P[P_01,b0] & 0xff) ^ M_b0(k0)] ^
+ gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)] ^
+ gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)] ^
+ gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
+ break;
+ case 0: /* 256 bits of key */
+ b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
+ b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
+ b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
+ b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
+ goto case 3;
+ case 3:
+ b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
+ b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
+ b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
+ b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
+ goto case 2;
+ case 2:
+ result =
+ gMDS0[(P[P_01,(P[P_02,b0]&0xff)^M_b0(k1)]&0xff)^M_b0(k0)] ^
+ gMDS1[(P[P_11,(P[P_12,b1]&0xff)^M_b1(k1)]&0xff)^M_b1(k0)] ^
+ gMDS2[(P[P_21,(P[P_22,b2]&0xff)^M_b2(k1)]&0xff)^M_b2(k0)] ^
+ gMDS3[(P[P_31,(P[P_32,b3]&0xff)^M_b3(k1)]&0xff)^M_b3(k0)];
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce
+ * a key S-box 32-bit entity from 2 key material 32-bit
+ * entities.
+ *
+ * @param k0 first 32-bit entity
+ * @param k1 second 32-bit entity
+ * @return Remainder polynomial Generated using RS code
+ */
+ private int RS_MDS_Encode(int k0, int k1)
+ {
+ int r = k1;
+ for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
+ {
+ r = RS_rem(r);
+ }
+ r ^= k0;
+ for (int i=0 ; i < 4 ; i++)
+ {
+ r = RS_rem(r);
+ }
+
+ return r;
+ }
+
+ /**
+ * Reed-Solomon code parameters: (12,8) reversible code:
+ *
+ *
+ * G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
+ *
+ * where a = primitive root of field generator 0x14D
+ *
+ */
+ private int RS_rem(int x)
+ {
+ int b = (int) (((uint)x >> 24) & 0xff);
+ int g2 = ((b << 1) ^
+ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+ int g3 = ( (int)((uint)b >> 1) ^
+ ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2 ;
+ return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
+ }
+
+ private int LFSR1(int x)
+ {
+ return (x >> 1) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
+ }
+
+ private int LFSR2(int x)
+ {
+ return (x >> 2) ^
+ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
+ }
+
+ private int Mx_X(int x)
+ {
+ return x ^ LFSR2(x);
+ } // 5B
+
+ private int Mx_Y(int x)
+ {
+ return x ^ LFSR1(x) ^ LFSR2(x);
+ } // EF
+
+ private int M_b0(int x)
+ {
+ return x & 0xff;
+ }
+
+ private int M_b1(int x)
+ {
+ return (int)((uint)x >> 8) & 0xff;
+ }
+
+ private int M_b2(int x)
+ {
+ return (int)((uint)x >> 16) & 0xff;
+ }
+
+ private int M_b3(int x)
+ {
+ return (int)((uint)x >> 24) & 0xff;
+ }
+
+ private int Fe32_0(int x)
+ {
+ return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+ gSBox[ 0x001 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+ gSBox[ 0x200 + 2*((int)((uint)x >> 16) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((int)((uint)x >> 24) & 0xff) ];
+ }
+
+ private int Fe32_3(int x)
+ {
+ return gSBox[ 0x000 + 2*((int)((uint)x >> 24) & 0xff) ] ^
+ gSBox[ 0x001 + 2*(x & 0xff) ] ^
+ gSBox[ 0x200 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((int)((uint)x >> 16) & 0xff) ];
+ }
+
+ private int BytesTo32Bits(byte[] b, int p)
+ {
+ return ((b[p] & 0xff) ) |
+ ((b[p+1] & 0xff) << 8) |
+ ((b[p+2] & 0xff) << 16) |
+ ((b[p+3] & 0xff) << 24);
+ }
+
+ private void Bits32ToBytes(int inData, byte[] b, int offset)
+ {
+ b[offset] = (byte)inData;
+ b[offset + 1] = (byte)(inData >> 8);
+ b[offset + 2] = (byte)(inData >> 16);
+ b[offset + 3] = (byte)(inData >> 24);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/engines/VMPCEngine.cs b/src/core/srcbc/crypto/engines/VMPCEngine.cs
new file mode 100644
index 0000000..df79593
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/VMPCEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class VmpcEngine
+ : IStreamCipher
+ {
+ /*
+ * variables to hold the state of the VMPC engine during encryption and
+ * decryption
+ */
+ protected byte n = 0;
+ protected byte[] P = null;
+ protected byte s = 0;
+
+ protected byte[] workingIV;
+ protected byte[] workingKey;
+
+ public virtual string AlgorithmName
+ {
+ get { return "VMPC"; }
+ }
+
+ /**
+ * initialise a VMPC cipher.
+ *
+ * @param forEncryption
+ * whether or not we are for encryption.
+ * @param params
+ * the parameters required to set up the cipher.
+ * @exception ArgumentException
+ * if the params argument is inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("VMPC Init parameters must include an IV");
+
+ ParametersWithIV ivParams = (ParametersWithIV) parameters;
+ KeyParameter key = (KeyParameter) ivParams.Parameters;
+
+ if (!(ivParams.Parameters is KeyParameter))
+ throw new ArgumentException("VMPC Init parameters must include a key");
+
+ this.workingIV = ivParams.GetIV();
+
+ if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+ throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
+
+ this.workingKey = key.GetKey();
+
+ InitKey(this.workingKey, this.workingIV);
+ }
+
+ protected virtual void InitKey(
+ byte[] keyBytes,
+ byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ output[i + outOff] = (byte) (input[i + inOff] ^ z);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ InitKey(this.workingKey, this.workingIV);
+ }
+
+ public virtual byte ReturnByte(
+ byte input)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ return (byte) (input ^ z);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/VMPCKSA3Engine.cs b/src/core/srcbc/crypto/engines/VMPCKSA3Engine.cs
new file mode 100644
index 0000000..7e0c64b
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/VMPCKSA3Engine.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class VmpcKsa3Engine
+ : VmpcEngine
+ {
+ public override string AlgorithmName
+ {
+ get { return "VMPC-KSA3"; }
+ }
+
+ protected override void InitKey(
+ byte[] keyBytes,
+ byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ n = 0;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/engines/XTEAEngine.cs b/src/core/srcbc/crypto/engines/XTEAEngine.cs
new file mode 100644
index 0000000..0d4036f
--- /dev/null
+++ b/src/core/srcbc/crypto/engines/XTEAEngine.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An XTEA engine.
+ */
+ public class XteaEngine
+ : IBlockCipher
+ {
+ private const int
+ rounds = 32,
+ block_size = 8,
+ key_size = 16,
+ delta = unchecked((int) 0x9E3779B9),
+ d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt
+
+ /*
+ * the expanded key array of 4 subkeys
+ */
+ private int[] _S = new int[4];
+ private bool _initialised;
+ private bool _forEncryption;
+
+ /**
+ * Create an instance of the TEA encryption algorithm
+ * and set some defaults
+ */
+ public XteaEngine()
+ {
+ _initialised = false;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "XTEA"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return block_size;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ {
+ throw new ArgumentException("invalid parameter passed to TEA init - "
+ + parameters.GetType().FullName);
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ if ((inOff + block_size) > inBytes.Length)
+ throw new DataLengthException("input buffer too short");
+
+ if ((outOff + block_size) > outBytes.Length)
+ throw new DataLengthException("output buffer too short");
+
+ return _forEncryption
+ ? encryptBlock(inBytes, inOff, outBytes, outOff)
+ : decryptBlock(inBytes, inOff, outBytes, outOff);
+ }
+
+ public void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ _S[0] = bytesToInt(key, 0);
+ _S[1] = bytesToInt(key, 4);
+ _S[2] = bytesToInt(key, 8);
+ _S[3] = bytesToInt(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(inBytes, inOff);
+ int v1 = bytesToInt(inBytes, inOff + 4);
+
+ int sum = 0;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ v0 += ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]);
+ sum += delta;
+ v1 += ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]);
+ }
+
+ unpackInt(v0, outBytes, outOff);
+ unpackInt(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(inBytes, inOff);
+ int v1 = bytesToInt(inBytes, inOff + 4);
+
+ int sum = d_sum;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ v1 -= ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]);
+ sum -= delta;
+ v0 -= ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]);
+ }
+
+ unpackInt(v0, outBytes, outOff);
+ unpackInt(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int bytesToInt(byte[] b, int inOff)
+ {
+ return ((b[inOff++]) << 24) |
+ ((b[inOff++] & 255) << 16) |
+ ((b[inOff++] & 255) << 8) |
+ ((b[inOff] & 255));
+ }
+
+ private void unpackInt(
+ int v,
+ byte[] b,
+ int outOff)
+ {
+ uint uv = (uint) v;
+ b[outOff++] = (byte)(uv >> 24);
+ b[outOff++] = (byte)(uv >> 16);
+ b[outOff++] = (byte)(uv >> 8);
+ b[outOff ] = (byte)uv;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/BaseKdfBytesGenerator.cs b/src/core/srcbc/crypto/generators/BaseKdfBytesGenerator.cs
new file mode 100644
index 0000000..56e23d4
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/BaseKdfBytesGenerator.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on ISO 18033/P1363a.
+ */
+ public class BaseKdfBytesGenerator
+ : IDerivationFunction
+ {
+ private int counterStart;
+ private IDigest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF Parameters generator.
+ *
+ * @param counterStart value of counter.
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ protected BaseKdfBytesGenerator(
+ int counterStart,
+ IDigest digest)
+ {
+ this.counterStart = counterStart;
+ this.digest = digest;
+ }
+
+ public void Init(
+ IDerivationParameters parameters)
+ {
+ if (parameters is KdfParameters)
+ {
+ KdfParameters p = (KdfParameters)parameters;
+
+ shared = p.GetSharedSecret();
+ iv = p.GetIV();
+ }
+ else if (parameters is Iso18033KdfParameters)
+ {
+ Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
+
+ shared = p.GetSeed();
+ iv = null;
+ }
+ else
+ {
+ throw new ArgumentException("KDF parameters required for KDF Generator");
+ }
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public IDigest Digest
+ {
+ get
+ {
+ return digest;
+ }
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws ArgumentException if the size of the request will cause an overflow.
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int GenerateBytes(
+ byte[] output,
+ int outOff,
+ int length)
+ {
+ if ((output.Length - length) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = length;
+ int outLen = digest.GetDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new ArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ int counter = counterStart;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.BlockUpdate(shared, 0, shared.Length);
+
+ digest.Update((byte)(counter >> 24));
+ digest.Update((byte)(counter >> 16));
+ digest.Update((byte)(counter >> 8));
+ digest.Update((byte)counter);
+
+ if (iv != null)
+ {
+ digest.BlockUpdate(iv, 0, iv.Length);
+ }
+
+ digest.DoFinal(dig, 0);
+
+ if (length > outLen)
+ {
+ Array.Copy(dig, 0, output, outOff, outLen);
+ outOff += outLen;
+ length -= outLen;
+ }
+ else
+ {
+ Array.Copy(dig, 0, output, outOff, length);
+ }
+
+ counter++;
+ }
+
+ digest.Reset();
+
+ return (int)oBytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs
new file mode 100644
index 0000000..843587e
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a basic Diffie-Helman key pair generator.
+ *
+ * This Generates keys consistent for use with the basic algorithm for
+ * Diffie-Helman.
+ */
+ public class DHBasicKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters) parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhParams = param.Parameters;
+
+ BigInteger p = dhParams.P;
+ BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L);
+ BigInteger y = helper.CalculatePublic(p, dhParams.G, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhParams),
+ new DHPrivateKeyParameters(x, dhParams));
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/generators/DHKeyGeneratorHelper.cs b/src/core/srcbc/crypto/generators/DHKeyGeneratorHelper.cs
new file mode 100644
index 0000000..4da5985
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DHKeyGeneratorHelper.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ class DHKeyGeneratorHelper
+ {
+ private const int MAX_ITERATIONS = 1000;
+
+ internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
+
+ private DHKeyGeneratorHelper()
+ {
+ }
+
+ internal BigInteger CalculatePrivate(
+ BigInteger p,
+ SecureRandom random,
+ int limit)
+ {
+ //
+ // calculate the private key
+ //
+ BigInteger pSub2 = p.Subtract(BigInteger.Two);
+ BigInteger x;
+
+ if (limit == 0)
+ {
+ x = createInRange(pSub2, random);
+ }
+ else
+ {
+ do
+ {
+ // TODO Check this (should the generated numbers always be odd,
+ // and length 'limit'?)
+ x = new BigInteger(limit, 0, random);
+ }
+ while (x.SignValue == 0);
+ }
+
+ return x;
+ }
+
+ private BigInteger createInRange(
+ BigInteger max,
+ SecureRandom random)
+ {
+ BigInteger x;
+ int maxLength = max.BitLength;
+ int count = 0;
+
+ do
+ {
+ x = new BigInteger(maxLength, random);
+ count++;
+ }
+ while ((x.SignValue == 0 || x.CompareTo(max) > 0) && count != MAX_ITERATIONS);
+
+ if (count == MAX_ITERATIONS) // fall back to a faster (restricted) method
+ {
+ return new BigInteger(maxLength - 1, random).SetBit(0);
+ }
+
+ return x;
+ }
+
+ internal BigInteger CalculatePublic(
+ BigInteger p,
+ BigInteger g,
+ BigInteger x)
+ {
+ return g.ModPow(x, p);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DHKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/DHKeyPairGenerator.cs
new file mode 100644
index 0000000..d22ffe7
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DHKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a Diffie-Helman key pair generator.
+ *
+ * This Generates keys consistent for use in the MTI/A0 key agreement protocol
+ * as described in "Handbook of Applied Cryptography", Pages 516-519.
+ */
+ public class DHKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters) parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhParams = param.Parameters;
+
+ BigInteger p = dhParams.P;
+ BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L);
+ BigInteger y = helper.CalculatePublic(p, dhParams.G, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhParams),
+ new DHPrivateKeyParameters(x, dhParams));
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/generators/DHParametersGenerator.cs b/src/core/srcbc/crypto/generators/DHParametersGenerator.cs
new file mode 100644
index 0000000..c4d39bd
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DHParametersGenerator.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DHParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public virtual void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the DHParameters object.
+ *
+ * Note: can take a while...
+ */
+ public virtual DHParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new DHParameters(p, g, q, BigInteger.Two, null);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DHParametersHelper.cs b/src/core/srcbc/crypto/generators/DHParametersHelper.cs
new file mode 100644
index 0000000..25076c1
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DHParametersHelper.cs
@@ -0,0 +1,244 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ internal class DHParametersHelper
+ {
+ // The primes b/w 2 and ~2^10
+ /*
+ 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
+ */
+
+ // Each list has a product < 2^31
+ private static readonly int[][] primeLists = new int[][]
+ {
+ new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
+ new int[]{ 29, 31, 37, 41, 43 },
+ new int[]{ 47, 53, 59, 61, 67 },
+ new int[]{ 71, 73, 79, 83 },
+ new int[]{ 89, 97, 101, 103 },
+
+ new int[]{ 107, 109, 113, 127 },
+ new int[]{ 131, 137, 139, 149 },
+ new int[]{ 151, 157, 163, 167 },
+ new int[]{ 173, 179, 181, 191 },
+ new int[]{ 193, 197, 199, 211 },
+
+ new int[]{ 223, 227, 229 },
+ new int[]{ 233, 239, 241 },
+ new int[]{ 251, 257, 263 },
+ new int[]{ 269, 271, 277 },
+ new int[]{ 281, 283, 293 },
+
+ new int[]{ 307, 311, 313 },
+ new int[]{ 317, 331, 337 },
+ new int[]{ 347, 349, 353 },
+ new int[]{ 359, 367, 373 },
+ new int[]{ 379, 383, 389 },
+
+ new int[]{ 397, 401, 409 },
+ new int[]{ 419, 421, 431 },
+ new int[]{ 433, 439, 443 },
+ new int[]{ 449, 457, 461 },
+ new int[]{ 463, 467, 479 },
+
+ new int[]{ 487, 491, 499 },
+ new int[]{ 503, 509, 521 },
+ new int[]{ 523, 541, 547 },
+ new int[]{ 557, 563, 569 },
+ new int[]{ 571, 577, 587 },
+
+ new int[]{ 593, 599, 601 },
+ new int[]{ 607, 613, 617 },
+ new int[]{ 619, 631, 641 },
+ new int[]{ 643, 647, 653 },
+ new int[]{ 659, 661, 673 },
+
+ new int[]{ 677, 683, 691 },
+ new int[]{ 701, 709, 719 },
+ new int[]{ 727, 733, 739 },
+ new int[]{ 743, 751, 757 },
+ new int[]{ 761, 769, 773 },
+
+ new int[]{ 787, 797, 809 },
+ new int[]{ 811, 821, 823 },
+ new int[]{ 827, 829, 839 },
+ new int[]{ 853, 857, 859 },
+ new int[]{ 863, 877, 881 },
+
+ new int[]{ 883, 887, 907 },
+ new int[]{ 911, 919, 929 },
+ new int[]{ 937, 941, 947 },
+ new int[]{ 953, 967, 971 },
+ new int[]{ 977, 983, 991 },
+
+ new int[]{ 997, 1009, 1013 },
+ new int[]{ 1019, 1021, 1031 },
+ };
+
+ private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+ private static readonly int[] primeProducts;
+ private static readonly BigInteger[] PrimeProducts;
+
+ static DHParametersHelper()
+ {
+ primeProducts = new int[primeLists.Length];
+ PrimeProducts = new BigInteger[primeLists.Length];
+
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int[] primeList = primeLists[i];
+ int product = 1;
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ product *= primeList[j];
+ }
+ primeProducts[i] = product;
+ PrimeProducts[i] = BigInteger.ValueOf(product);
+ }
+ }
+
+ // Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+ internal static BigInteger[] GenerateSafePrimes(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ BigInteger p, q;
+ int qLength = size - 1;
+
+ if (size <= 32)
+ {
+ for (;;)
+ {
+ q = new BigInteger(qLength, 2, random);
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (p.IsProbablePrime(certainty)
+ && (certainty <= 2 || q.IsProbablePrime(certainty)))
+ break;
+ }
+ }
+ else
+ {
+ // Note: Modified from Java version for speed
+ for (;;)
+ {
+ q = new BigInteger(qLength, 0, random);
+
+ retry:
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int test = q.Remainder(PrimeProducts[i]).IntValue;
+
+ if (i == 0)
+ {
+ int rem3 = test % 3;
+ if (rem3 != 2)
+ {
+ int diff = 2 * rem3 + 2;
+ q = q.Add(BigInteger.ValueOf(diff));
+ test = (test + diff) % primeProducts[i];
+ }
+ }
+
+ int[] primeList = primeLists[i];
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ int prime = primeList[j];
+ int qRem = test % prime;
+ if (qRem == 0 || qRem == (prime >> 1))
+ {
+ q = q.Add(Six);
+ goto retry;
+ }
+ }
+ }
+
+
+ if (q.BitLength != qLength)
+ continue;
+
+ if (!q.RabinMillerTest(2, random))
+ continue;
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (p.RabinMillerTest(certainty, random)
+ && (certainty <= 2 || q.RabinMillerTest(certainty - 2, random)))
+ break;
+ }
+ }
+
+ return new BigInteger[] { p, q };
+ }
+
+ // Select a high order element of the multiplicative group Zp*
+ // p and q must be s.t. p = 2*q + 1, where p and q are prime
+ internal static BigInteger SelectGenerator(
+ BigInteger p,
+ BigInteger q,
+ SecureRandom random)
+ {
+ BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
+ BigInteger g;
+
+ // Handbook of Applied Cryptography 4.86
+ do
+ {
+ g = CreateInRange(BigInteger.Two, pMinusTwo, random);
+ }
+ while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One)
+ || g.ModPow(q, p).Equals(BigInteger.One));
+
+/*
+ // RFC 2631 2.1.1 (and see Handbook of Applied Cryptography 4.81)
+ do
+ {
+ BigInteger h = CreateInRange(BigInteger.Two, pMinusTwo, random);
+
+ g = h.ModPow(BigInteger.Two, p);
+ }
+ while (g.Equals(BigInteger.One));
+*/
+
+ return g;
+ }
+
+ private static BigInteger CreateInRange(
+ BigInteger min,
+ BigInteger max,
+ SecureRandom random)
+ {
+ BigInteger x;
+ do
+ {
+ x = new BigInteger(max.BitLength, random);
+ }
+ while (x.CompareTo(min) < 0 || x.CompareTo(max) > 0);
+ return x;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DesEdeKeyGenerator.cs b/src/core/srcbc/crypto/generators/DesEdeKeyGenerator.cs
new file mode 100644
index 0000000..10ef4e7
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DesEdeKeyGenerator.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesEdeKeyGenerator
+ : DesKeyGenerator
+ {
+ public DesEdeKeyGenerator()
+ {
+ }
+
+ internal DesEdeKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key Generated will be 192 bits in size, otherwise
+ * strength can be 128 or 192 (or 112 or 168 if you don't count
+ * parity bits), depending on whether you wish to do 2-key or 3-key
+ * triple DES.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ protected override void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ base.engineInit(parameters);
+
+ if (strength == 0 || strength == (168 / 8))
+ {
+ strength = DesEdeParameters.DesEdeKeyLength;
+ }
+ else if (strength == (112 / 8))
+ {
+ strength = 2 * DesEdeParameters.DesKeyLength;
+ }
+ else if (strength != DesEdeParameters.DesEdeKeyLength
+ && strength != (2 * DesEdeParameters.DesKeyLength))
+ {
+ throw new ArgumentException("DESede key must be "
+ + (DesEdeParameters.DesEdeKeyLength * 8) + " or "
+ + (2 * 8 * DesEdeParameters.DesKeyLength)
+ + " bits long.");
+ }
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey;
+
+ do
+ {
+ newKey = random.GenerateSeed(strength);
+ DesEdeParameters.SetOddParity(newKey);
+ }
+ while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
+
+ return newKey;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DesKeyGenerator.cs b/src/core/srcbc/crypto/generators/DesKeyGenerator.cs
new file mode 100644
index 0000000..12dcc9d
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DesKeyGenerator.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesKeyGenerator
+ : CipherKeyGenerator
+ {
+ public DesKeyGenerator()
+ {
+ }
+
+ internal DesKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey;
+
+ do
+ {
+ newKey = random.GenerateSeed(DesParameters.DesKeyLength);
+ DesParameters.SetOddParity(newKey);
+ }
+ while (DesParameters.IsWeakKey(newKey, 0));
+
+ return newKey;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DsaKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/DsaKeyPairGenerator.cs
new file mode 100644
index 0000000..c231ece
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DsaKeyPairGenerator.cs
@@ -0,0 +1,56 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a DSA key pair generator.
+ *
+ * This Generates DSA keys in line with the method described
+ * in FIPS 186-2.
+ */
+ public class DsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DsaKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ // Note: If we start accepting instances of KeyGenerationParameters,
+ // must apply constraint checking on strength (see DsaParametersGenerator.Init)
+
+ this.param = (DsaKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DsaParameters dsaParams = param.Parameters;
+ SecureRandom random = param.Random;
+
+ BigInteger q = dsaParams.Q;
+ BigInteger x;
+
+ do
+ {
+ x = new BigInteger(160, random);
+ }
+ while (x.SignValue == 0 || x.CompareTo(q) >= 0);
+
+ //
+ // calculate the public key.
+ //
+ BigInteger y = dsaParams.G.ModPow(x, dsaParams.P);
+
+ return new AsymmetricCipherKeyPair(
+ new DsaPublicKeyParameters(y, dsaParams),
+ new DsaPrivateKeyParameters(x, dsaParams));
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/DsaParametersGenerator.cs b/src/core/srcbc/crypto/generators/DsaParametersGenerator.cs
new file mode 100644
index 0000000..fbe8942
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/DsaParametersGenerator.cs
@@ -0,0 +1,184 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generate suitable parameters for DSA, in line with FIPS 186-2.
+ */
+ public class DsaParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+ * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+ * @param random random byte source.
+ */
+ public void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ if (!IsValidDsaStrength(size))
+ throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
+
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * add value to b, returning the result in a. The a value is treated
+ * as a BigInteger of length (a.Length * 8) bits. The result is
+ * modulo 2^a.Length in case of overflow.
+ */
+ private static void Add(
+ byte[] a,
+ byte[] b,
+ int value)
+ {
+ int x = (b[b.Length - 1] & 0xff) + value;
+
+ a[b.Length - 1] = (byte)x;
+ x = (int) ((uint) x >>8);
+
+ for (int i = b.Length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff);
+ a[i] = (byte)x;
+ x = (int) ((uint) x >>8);
+ }
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the DsaParameters object.
+ *
+ * Note: can take a while...
+ */
+ public DsaParameters GenerateParameters()
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+ Sha1Digest sha1 = new Sha1Digest();
+ int n = (size - 1) / 160;
+ byte[] w = new byte[size / 8];
+
+ BigInteger q = null, p = null, g = null;
+ int counter = 0;
+ bool primesFound = false;
+
+ while (!primesFound)
+ {
+ do
+ {
+ random.NextBytes(seed);
+
+ sha1.BlockUpdate(seed, 0, seed.Length);
+
+ sha1.DoFinal(part1, 0);
+
+ Array.Copy(seed, 0, part2, 0, seed.Length);
+
+ Add(part2, seed, 1);
+
+ sha1.BlockUpdate(part2, 0, part2.Length);
+
+ sha1.DoFinal(part2, 0);
+
+ for (int i = 0; i != u.Length; i++)
+ {
+ u[i] = (byte)(part1[i] ^ part2[i]);
+ }
+
+ u[0] |= (byte)0x80;
+ u[19] |= (byte)0x01;
+
+ q = new BigInteger(1, u);
+ }
+ while (!q.IsProbablePrime(certainty));
+
+ counter = 0;
+
+ int offset = 2;
+
+ while (counter < 4096)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ Add(part1, seed, offset + k);
+ sha1.BlockUpdate(part1, 0, part1.Length);
+ sha1.DoFinal(part1, 0);
+ Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
+ }
+
+ Add(part1, seed, offset + n);
+ sha1.BlockUpdate(part1, 0, part1.Length);
+ sha1.DoFinal(part1, 0);
+ Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length);
+
+ w[0] |= (byte)0x80;
+
+ BigInteger x = new BigInteger(1, w);
+
+ BigInteger c = x.Mod(q.ShiftLeft(1));
+
+ p = x.Subtract(c.Subtract(BigInteger.One));
+
+ if (p.TestBit(size - 1))
+ {
+ if (p.IsProbablePrime(certainty))
+ {
+ primesFound = true;
+ break;
+ }
+ }
+
+ counter += 1;
+ offset += n + 1;
+ }
+ }
+
+ //
+ // calculate the generator g
+ //
+ BigInteger pMinusOneOverQ = p.Subtract(BigInteger.One).Divide(q);
+
+ for (;;)
+ {
+ BigInteger h = new BigInteger(size, random);
+ if (h.CompareTo(BigInteger.One) <= 0 || h.CompareTo(p.Subtract(BigInteger.One)) >= 0)
+ {
+ continue;
+ }
+
+ g = h.ModPow(pMinusOneOverQ, p);
+ if (g.CompareTo(BigInteger.One) <= 0)
+ {
+ continue;
+ }
+
+ break;
+ }
+
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+ }
+
+ private static bool IsValidDsaStrength(
+ int strength)
+ {
+ return strength >= 512 && strength <= 1024 && strength % 64 == 0;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/ECKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/ECKeyPairGenerator.cs
new file mode 100644
index 0000000..7d7718c
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/ECKeyPairGenerator.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ECKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private readonly string algorithm;
+
+ private ECDomainParameters parameters;
+ private DerObjectIdentifier publicKeyParamSet;
+ private SecureRandom random;
+
+ public ECKeyPairGenerator()
+ : this("EC")
+ {
+ }
+
+ public ECKeyPairGenerator(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ }
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is ECKeyGenerationParameters)
+ {
+ ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
+
+ if (ecP.PublicKeyParamSet != null)
+ {
+ if (algorithm != "ECGOST3410")
+ throw new ArgumentException("parameters invalid for algorithm: " + algorithm, "parameters");
+
+ this.publicKeyParamSet = ecP.PublicKeyParamSet;
+ }
+
+ this.parameters = ecP.DomainParameters;
+ }
+ else
+ {
+ DerObjectIdentifier oid;
+ switch (parameters.Strength)
+ {
+ case 192:
+ oid = X9ObjectIdentifiers.Prime192v1;
+ break;
+ case 239:
+ oid = X9ObjectIdentifiers.Prime239v1;
+ break;
+ case 256:
+ oid = X9ObjectIdentifiers.Prime256v1;
+ break;
+ default:
+ throw new InvalidParameterException("unknown key size.");
+ }
+
+ X9ECParameters ecps = X962NamedCurves.GetByOid(oid);
+
+ this.parameters = new ECDomainParameters(
+ ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
+ }
+
+ this.random = parameters.Random;
+ }
+
+ /**
+ * Given the domain parameters this routine Generates an EC key
+ * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ BigInteger n = parameters.N;
+ BigInteger d;
+
+ do
+ {
+ d = new BigInteger(n.BitLength, random);
+ }
+ while (d.SignValue == 0 || (d.CompareTo(n) >= 0));
+
+ ECPoint q = parameters.G.Multiply(d);
+
+ if (publicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(q, publicKeyParamSet),
+ new ECPrivateKeyParameters(d, publicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(algorithm, q, parameters),
+ new ECPrivateKeyParameters(algorithm, d, parameters));
+ }
+
+ private string VerifyAlgorithmName(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ switch (upper)
+ {
+ case "EC":
+ case "ECDSA":
+ case "ECGOST3410":
+ case "ECDH":
+ case "ECDHC":
+ break;
+ default:
+ throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
+ }
+
+ return upper;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs
new file mode 100644
index 0000000..9e3f54d
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a ElGamal key pair generator.
+ *
+ * This Generates keys consistent for use with ElGamal as described in
+ * page 164 of "Handbook of Applied Cryptography".
+ */
+ public class ElGamalKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private ElGamalKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (ElGamalKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ ElGamalParameters elParams = param.Parameters;
+
+ BigInteger p = elParams.P;
+ BigInteger x = helper.CalculatePrivate(p, param.Random, elParams.L);
+ BigInteger y = helper.CalculatePublic(p, elParams.G, x);
+
+ return new AsymmetricCipherKeyPair(
+ new ElGamalPublicKeyParameters(y, elParams),
+ new ElGamalPrivateKeyParameters(x, elParams));
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/generators/ElGamalParametersGenerator.cs b/src/core/srcbc/crypto/generators/ElGamalParametersGenerator.cs
new file mode 100644
index 0000000..1bb9f4e
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/ElGamalParametersGenerator.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ElGamalParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the ElGamalParameters object.
+ *
+ * Note: can take a while...
+ *
+ */
+ public ElGamalParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new ElGamalParameters(p, g);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs b/src/core/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs
new file mode 100644
index 0000000..e8bc48d
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -0,0 +1,73 @@
+using System;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a GOST3410 key pair generator.
+ * This generates GOST3410 keys in line with the method described
+ * in GOST R 34.10-94.
+ */
+ public class Gost3410KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private Gost3410KeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is Gost3410KeyGenerationParameters)
+ {
+ this.param = (Gost3410KeyGenerationParameters) parameters;
+ }
+ else
+ {
+ Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
+ parameters.Random,
+ CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
+
+ if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
+ {
+ // TODO Should we complain?
+ }
+
+ this.param = kgp;
+ }
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ SecureRandom random = param.Random;
+ Gost3410Parameters gost3410Params = param.Parameters;
+
+ BigInteger q = gost3410Params.Q;
+ BigInteger x;
+ do
+ {
+ x = new BigInteger(256, random);
+ }
+ while (x.SignValue < 1 || x.CompareTo(q) >= 0);
+
+ BigInteger p = gost3410Params.P;
+ BigInteger a = gost3410Params.A;
+
+ // calculate the public key.
+ BigInteger y = a.ModPow(x, p);
+
+ if (param.PublicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
+ new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, gost3410Params),
+ new Gost3410PrivateKeyParameters(x, gost3410Params));
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/GOST3410ParametersGenerator.cs b/src/core/srcbc/crypto/generators/GOST3410ParametersGenerator.cs
new file mode 100644
index 0000000..01d4a63
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/GOST3410ParametersGenerator.cs
@@ -0,0 +1,530 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * generate suitable parameters for GOST3410.
+ */
+ public class Gost3410ParametersGenerator
+ {
+ private int size;
+ private int typeproc;
+ private SecureRandom init_random;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key
+ * @param typeProcedure type procedure A,B = 1; A',B' - else
+ * @param random random byte source.
+ */
+ public void Init(
+ int size,
+ int typeProcedure,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.typeproc = typeProcedure;
+ this.init_random = random;
+ }
+
+ //Procedure A
+ private int procedure_A(int x0, int c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 065536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=17; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8003",16); //set min prime number length 16 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].IntValue; //return for procedure B step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].IntValue;
+ }
+
+ //Procedure A'
+ private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 04294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=33; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].LongValue; //return for procedure B' step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].LongValue;
+ }
+
+ //Procedure B
+ private void procedure_B(int x0, int c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 065536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ x0 = procedure_A(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_A(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[65];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<64; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+
+ for (int j=0; j<64; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(16*j));
+ }
+
+ y[0] = y[64]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+ //Procedure B'
+ private void procedure_Bb(long x0, long c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 04294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ x0 = procedure_Aa(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_Aa(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[33];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<32; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+ for (int j=0; j<32; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(32*j));
+ }
+
+ y[0] = y[32]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+
+ /**
+ * Procedure C
+ * procedure generates the a value from the given p,q,
+ * returning the a value.
+ */
+ private BigInteger procedure_C(BigInteger p, BigInteger q)
+ {
+ BigInteger pSub1 = p.Subtract(BigInteger.One);
+ BigInteger pSub1Divq = pSub1.Divide(q);
+
+ for(;;)
+ {
+ BigInteger d = new BigInteger(p.BitLength, init_random);
+
+ // 1 < d < p-1
+ if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0)
+ {
+ BigInteger a = d.ModPow(pSub1Divq, p);
+
+ if (a.CompareTo(BigInteger.One) != 0)
+ {
+ return a;
+ }
+ }
+ }
+ }
+
+ /**
+ * which generates the p , q and a values from the given parameters,
+ * returning the Gost3410Parameters object.
+ */
+ public Gost3410Parameters GenerateParameters()
+ {
+ BigInteger [] pq = new BigInteger[2];
+ BigInteger q = null, p = null, a = null;
+
+ int x0, c;
+ long x0L, cL;
+
+ if (typeproc==1)
+ {
+ x0 = init_random.NextInt();
+ c = init_random.NextInt();
+
+ switch(size)
+ {
+ case 512:
+ procedure_A(x0, c, pq, 512);
+ break;
+ case 1024:
+ procedure_B(x0, c, pq);
+ break;
+ default:
+ throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c));
+ }
+ else
+ {
+ x0L = init_random.NextLong();
+ cL = init_random.NextLong();
+
+ switch(size)
+ {
+ case 512:
+ procedure_Aa(x0L, cL, pq, 512);
+ break;
+ case 1024:
+ procedure_Bb(x0L, cL, pq);
+ break;
+ default:
+ throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL));
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Kdf1BytesGenerator.cs b/src/core/srcbc/crypto/generators/Kdf1BytesGenerator.cs
new file mode 100644
index 0000000..702e1f8
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Kdf1BytesGenerator.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf1BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF1 byte generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf1BytesGenerator(
+ IDigest digest)
+ : base(0, digest)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Kdf2BytesGenerator.cs b/src/core/srcbc/crypto/generators/Kdf2BytesGenerator.cs
new file mode 100644
index 0000000..6ed78ce
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Kdf2BytesGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf2BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF2 bytes generator. Generates key material
+ * according to IEEE P1363 or ISO 18033 depending on the initialisation.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf2BytesGenerator(
+ IDigest digest)
+ : base(1, digest)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Mgf1BytesGenerator.cs b/src/core/srcbc/crypto/generators/Mgf1BytesGenerator.cs
new file mode 100644
index 0000000..4c993a6
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Mgf1BytesGenerator.cs
@@ -0,0 +1,117 @@
+using System;
+//using Org.BouncyCastle.Math;
+//using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for MGF1 as defined in Pkcs 1v2
+ */
+ public class Mgf1BytesGenerator : IDerivationFunction
+ {
+ private IDigest digest;
+ private byte[] seed;
+ private int hLen;
+
+ /**
+ * @param digest the digest to be used as the source of Generated bytes
+ */
+ public Mgf1BytesGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ }
+
+ public void Init(
+ IDerivationParameters parameters)
+ {
+ if (!(typeof(MgfParameters).IsInstanceOfType(parameters)))
+ {
+ throw new ArgumentException("MGF parameters required for MGF1Generator");
+ }
+
+ MgfParameters p = (MgfParameters)parameters;
+
+ seed = p.GetSeed();
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public IDigest Digest
+ {
+ get
+ {
+ return digest;
+ }
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint) i >> 24);
+ sp[1] = (byte)((uint) i >> 16);
+ sp[2] = (byte)((uint) i >> 8);
+ sp[3] = (byte)((uint) i >> 0);
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes Generated from
+ * the derivation function.
+ *
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int GenerateBytes(
+ byte[] output,
+ int outOff,
+ int length)
+ {
+ if ((output.Length - length) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ if (length > hLen)
+ {
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen);
+ }
+ while (++counter < (length / hLen));
+ }
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen));
+ }
+
+ return length;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs
new file mode 100644
index 0000000..ad92230
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs
@@ -0,0 +1,330 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly int[] smallPrimes =
+ {
+ 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
+ };
+
+ private NaccacheSternKeyGenerationParameters param;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
+ */
+ public void Init(KeyGenerationParameters parameters)
+ {
+ this.param = (NaccacheSternKeyGenerationParameters)parameters;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ int strength = param.Strength;
+ SecureRandom rand = param.Random;
+ int certainty = param.Certainty;
+ bool debug = param.IsDebug;
+
+ if (debug)
+ {
+ Console.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
+ }
+
+ ArrayList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
+
+ smallPrimes = permuteList(smallPrimes, rand);
+
+ BigInteger u = BigInteger.One;
+ BigInteger v = BigInteger.One;
+
+ for (int i = 0; i < smallPrimes.Count / 2; i++)
+ {
+ u = u.Multiply((BigInteger)smallPrimes[i]);
+ }
+ for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++)
+ {
+ v = v.Multiply((BigInteger)smallPrimes[i]);
+ }
+
+ BigInteger sigma = u.Multiply(v);
+
+ // n = (2 a u p_ + 1 ) ( 2 b v q_ + 1)
+ // -> |n| = strength
+ // |2| = 1 in bits
+ // -> |a| * |b| = |n| - |u| - |v| - |p_| - |q_| - |2| -|2|
+ // remainingStrength = strength - sigma.bitLength() - p_.bitLength() -
+ // q_.bitLength() - 1 -1
+ int remainingStrength = strength - sigma.BitLength - 48;
+ BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+ BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+
+ BigInteger p_;
+ BigInteger q_;
+ BigInteger p;
+ BigInteger q;
+
+ long tries = 0;
+ if (debug)
+ {
+ Console.WriteLine("generating p and q");
+ }
+
+ BigInteger _2au = a.Multiply(u).ShiftLeft(1);
+ BigInteger _2bv = b.Multiply(v).ShiftLeft(1);
+
+ for (;;)
+ {
+ tries++;
+
+ p_ = generatePrime(24, certainty, rand);
+
+ p = p_.Multiply(_2au).Add(BigInteger.One);
+
+ if (!p.IsProbablePrime(certainty))
+ continue;
+
+ for (;;)
+ {
+ q_ = generatePrime(24, certainty, rand);
+
+ if (p_.Equals(q_))
+ continue;
+
+ q = q_.Multiply(_2bv).Add(BigInteger.One);
+
+ if (q.IsProbablePrime(certainty))
+ break;
+ }
+
+ if (!sigma.Gcd(p_.Multiply(q_)).Equals(BigInteger.One))
+ {
+ Console.WriteLine("sigma.gcd(p_.mult(q_)) != 1!\n p_: " + p_ +"\n q_: "+ q_ );
+ continue;
+ }
+
+ if (p.Multiply(q).BitLength < strength)
+ {
+ if (debug)
+ {
+ Console.WriteLine("key size too small. Should be " + strength + " but is actually "
+ + p.Multiply(q).BitLength);
+ }
+ continue;
+ }
+ break;
+ }
+
+ if (debug)
+ {
+ Console.WriteLine("needed " + tries + " tries to generate p and q.");
+ }
+
+ BigInteger n = p.Multiply(q);
+ BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
+ BigInteger g;
+ tries = 0;
+ if (debug)
+ {
+ Console.WriteLine("generating g");
+ }
+ for (;;)
+ {
+ // TODO After the first loop, just regenerate one randomly-selected gPart each time?
+ ArrayList gParts = new ArrayList();
+ for (int ind = 0; ind != smallPrimes.Count; ind++)
+ {
+ BigInteger i = (BigInteger)smallPrimes[ind];
+ BigInteger e = phi_n.Divide(i);
+
+ for (;;)
+ {
+ tries++;
+
+ g = generatePrime(strength, certainty, rand);
+
+ if (!g.ModPow(e, n).Equals(BigInteger.One))
+ {
+ gParts.Add(g);
+ break;
+ }
+ }
+ }
+ g = BigInteger.One;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ BigInteger gPart = (BigInteger) gParts[i];
+ BigInteger smallPrime = (BigInteger) smallPrimes[i];
+ g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n);
+ }
+
+ // make sure that g is not divisible by p_i or q_i
+ bool divisible = false;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
+ }
+ divisible = true;
+ break;
+ }
+ }
+
+ if (divisible)
+ {
+ continue;
+ }
+
+ // make sure that g has order > phi_n/4
+
+ //if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One))
+ if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/4\n g:" + g);
+ }
+ continue;
+ }
+
+ if (g.ModPow(phi_n.Divide(p_), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/p'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(q_), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/q'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/a\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ Console.WriteLine("g has order phi(n)/b\n g: " + g);
+ }
+ continue;
+ }
+ break;
+ }
+ if (debug)
+ {
+ Console.WriteLine("needed " + tries + " tries to generate g");
+ Console.WriteLine();
+ Console.WriteLine("found new NaccacheStern cipher variables:");
+ Console.WriteLine("smallPrimes: " + Arrays.ToString(smallPrimes.ToArray()));
+ Console.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)");
+ Console.WriteLine("a:.......... " + a);
+ Console.WriteLine("b:.......... " + b);
+ Console.WriteLine("p':......... " + p_);
+ Console.WriteLine("q':......... " + q_);
+ Console.WriteLine("p:.......... " + p);
+ Console.WriteLine("q:.......... " + q);
+ Console.WriteLine("n:.......... " + n);
+ Console.WriteLine("phi(n):..... " + phi_n);
+ Console.WriteLine("g:.......... " + g);
+ Console.WriteLine();
+ }
+
+ return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
+ new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n));
+ }
+
+ private static BigInteger generatePrime(
+ int bitLength,
+ int certainty,
+ SecureRandom rand)
+ {
+ return new BigInteger(bitLength, certainty, rand);
+ }
+
+ /**
+ * Generates a permuted ArrayList from the original one. The original List
+ * is not modified
+ *
+ * @param arr
+ * the ArrayList to be permuted
+ * @param rand
+ * the source of Randomness for permutation
+ * @return a new ArrayList with the permuted elements.
+ */
+ private static ArrayList permuteList(
+ ArrayList arr,
+ SecureRandom rand)
+ {
+ ArrayList retval = new ArrayList(arr.Count);
+
+ foreach (object element in arr)
+ {
+ int index = rand.Next(retval.Count + 1);
+ retval.Insert(index, element);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Finds the first 'count' primes starting with 3
+ *
+ * @param count
+ * the number of primes to find
+ * @return a vector containing the found primes as Integer
+ */
+ private static ArrayList findFirstPrimes(
+ int count)
+ {
+ ArrayList primes = new ArrayList(count);
+
+ for (int i = 0; i != count; i++)
+ {
+ primes.Add(BigInteger.ValueOf(smallPrimes[i]));
+ }
+
+ return primes;
+ }
+
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs b/src/core/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs
new file mode 100644
index 0000000..fd47f0e
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs
@@ -0,0 +1,167 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ *
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ *
+ */
+ public class OpenSslPbeParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest = new MD5Digest();
+
+ /**
+ * Construct a OpenSSL Parameters generator.
+ */
+ public OpenSslPbeParametersGenerator()
+ {
+ }
+
+ public override void Init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ // Ignore the provided iterationCount
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * Initialise - note the iteration count for this algorithm is fixed at 1.
+ *
+ * @param password password to use.
+ * @param salt salt to use.
+ */
+ public virtual void Init(
+ byte[] password,
+ byte[] salt)
+ {
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] GenerateDerivedKey(
+ int bytesNeeded)
+ {
+ byte[] buf = new byte[digest.GetDigestSize()];
+ byte[] key = new byte[bytesNeeded];
+ int offset = 0;
+
+ for (;;)
+ {
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(buf, 0);
+
+ int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded;
+ Array.Copy(buf, 0, key, offset, len);
+ offset += len;
+
+ // check if we need any more
+ bytesNeeded -= len;
+ if (bytesNeeded == 0)
+ {
+ break;
+ }
+
+ // do another round
+ digest.Reset();
+ digest.BlockUpdate(buf, 0, buf.Length);
+ }
+
+ return key;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs b/src/core/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs
new file mode 100644
index 0000000..9fc1f67
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -0,0 +1,245 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 12 V1.0.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs12 Page
+ *
+ */
+ public class Pkcs12ParametersGenerator
+ : PbeParametersGenerator
+ {
+ public const int KeyMaterial = 1;
+ public const int IVMaterial = 2;
+ public const int MacMaterial = 3;
+
+ private readonly IDigest digest;
+
+ private readonly int u;
+ private readonly int v;
+
+ /**
+ * Construct a Pkcs 12 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception ArgumentException if an unknown digest is passed in.
+ */
+ public Pkcs12ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+
+ u = digest.GetDigestSize();
+ v = digest.GetByteLength();
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.Length * 8) bits. The result is
+ * modulo 2^b.Length in case of overflow.
+ */
+ private void Adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.Length - 1] & 0xff) + (a[aOff + b.Length - 1] & 0xff) + 1;
+
+ a[aOff + b.Length - 1] = (byte)x;
+ x = (int) ((uint) x >> 8);
+
+ for (int i = b.Length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x = (int) ((uint) x >> 8);
+ }
+ }
+
+ /**
+ * generation of a derived key ala Pkcs12 V1.0.
+ */
+ private byte[] GenerateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.Length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((mSalt != null) && (mSalt.Length != 0))
+ {
+ S = new byte[v * ((mSalt.Length + v - 1) / v)];
+
+ for (int i = 0; i != S.Length; i++)
+ {
+ S[i] = mSalt[i % mSalt.Length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((mPassword != null) && (mPassword.Length != 0))
+ {
+ P = new byte[v * ((mPassword.Length + v - 1) / v)];
+
+ for (int i = 0; i != P.Length; i++)
+ {
+ P[i] = mPassword[i % mPassword.Length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.Length + P.Length];
+
+ Array.Copy(S, 0, I, 0, S.Length);
+ Array.Copy(P, 0, I, S.Length, P.Length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+
+ for (int i = 1; i <= c; i++)
+ {
+ byte[] A = new byte[u];
+
+ digest.BlockUpdate(D, 0, D.Length);
+ digest.BlockUpdate(I, 0, I.Length);
+ digest.DoFinal(A, 0);
+ for (int j = 1; j != mIterationCount; j++)
+ {
+ digest.BlockUpdate(A, 0, A.Length);
+ digest.DoFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.Length; j++)
+ {
+ B[j] = A[j % A.Length];
+ }
+
+ for (int j = 0; j != I.Length / v; j++)
+ {
+ Adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
+ }
+ else
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, A.Length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(key, iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs b/src/core/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs
new file mode 100644
index 0000000..5fa21f1
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs5 Page
+ *
+ */
+ public class Pkcs5S1ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest;
+
+ /**
+ * Construct a Pkcs 5 Scheme 1 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Pkcs5S1ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ /**
+ * the derived key function, the ith hash of the mPassword and the mSalt.
+ */
+ private byte[] GenerateDerivedKey()
+ {
+ byte[] digestBytes = new byte[digest.GetDigestSize()];
+
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(digestBytes, 0);
+ for (int i = 1; i < mIterationCount; i++)
+ {
+ digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
+ digest.DoFinal(digestBytes, 0);
+ }
+
+ return digestBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the mPassword, mSalt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the mPassword, mSalt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the mPassword,
+ * mSalt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs b/src/core/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs
new file mode 100644
index 0000000..dbe0be0
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -0,0 +1,175 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs5 Page
+ */
+ public class Pkcs5S2ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IMac hMac = new HMac(new Sha1Digest());
+
+ /**
+ * construct a Pkcs5 Scheme 2 Parameters generator.
+ */
+ public Pkcs5S2ParametersGenerator()
+ {
+ }
+
+ private void F(
+ byte[] P,
+ byte[] S,
+ int c,
+ byte[] iBuf,
+ byte[] outBytes,
+ int outOff)
+ {
+ byte[] state = new byte[hMac.GetMacSize()];
+ ICipherParameters param = new KeyParameter(P);
+
+ hMac.Init(param);
+
+ if (S != null)
+ {
+ hMac.BlockUpdate(S, 0, S.Length);
+ }
+
+ hMac.BlockUpdate(iBuf, 0, iBuf.Length);
+
+ hMac.DoFinal(state, 0);
+
+ Array.Copy(state, 0, outBytes, outOff, state.Length);
+
+ for (int count = 1; count != c; count++)
+ {
+ hMac.Init(param);
+ hMac.BlockUpdate(state, 0, state.Length);
+ hMac.DoFinal(state, 0);
+
+ for (int j = 0; j != state.Length; j++)
+ {
+ outBytes[outOff + j] ^= state[j];
+ }
+ }
+ }
+
+ private void IntToOctet(
+ byte[] Buffer,
+ int i)
+ {
+ Buffer[0] = (byte)((uint) i >> 24);
+ Buffer[1] = (byte)((uint) i >> 16);
+ Buffer[2] = (byte)((uint) i >> 8);
+ Buffer[3] = (byte)i;
+ }
+
+ private byte[] GenerateDerivedKey(
+ int dkLen)
+ {
+ int hLen = hMac.GetMacSize();
+ int l = (dkLen + hLen - 1) / hLen;
+ byte[] iBuf = new byte[4];
+ byte[] outBytes = new byte[l * hLen];
+
+ for (int i = 1; i <= l; i++)
+ {
+ IntToOctet(iBuf, i);
+
+ F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen);
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/RSABlindingFactorGenerator.cs b/src/core/srcbc/crypto/generators/RSABlindingFactorGenerator.cs
new file mode 100644
index 0000000..1583bd0
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/RSABlindingFactorGenerator.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generate a random factor suitable for use with RSA blind signatures
+ * as outlined in Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475.
+ */
+ public class RsaBlindingFactorGenerator
+ {
+ private RsaKeyParameters key;
+ private SecureRandom random;
+
+ /**
+ * Initialise the factor generator
+ *
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ ICipherParameters param)
+ {
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+
+ if (key.IsPrivate)
+ throw new ArgumentException("generator requires RSA public key");
+ }
+
+ /**
+ * Generate a suitable blind factor for the public key the generator was initialised with.
+ *
+ * @return a random blind factor
+ */
+ public BigInteger GenerateBlindingFactor()
+ {
+ if (key == null)
+ throw new InvalidOperationException("generator not initialised");
+
+ BigInteger m = key.Modulus;
+ int length = m.BitLength - 1; // must be less than m.BitLength
+ BigInteger factor;
+ BigInteger gcd;
+
+ do
+ {
+ factor = new BigInteger(length, random);
+ gcd = factor.Gcd(m);
+ }
+ while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One));
+
+ return factor;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/generators/RsaKeyPairGenerator.cs b/src/core/srcbc/crypto/generators/RsaKeyPairGenerator.cs
new file mode 100644
index 0000000..41fe687
--- /dev/null
+++ b/src/core/srcbc/crypto/generators/RsaKeyPairGenerator.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * an RSA key pair generator.
+ */
+ public class RsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+ private const int DefaultTests = 12;
+
+ private RsaKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is RsaKeyGenerationParameters)
+ {
+ this.param = (RsaKeyGenerationParameters)parameters;
+ }
+ else
+ {
+ this.param = new RsaKeyGenerationParameters(
+ DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
+ }
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ BigInteger p, q, n, d, e, pSub1, qSub1, phi;
+
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = param.Strength;
+ int pbitlength = (strength + 1) / 2;
+ int qbitlength = (strength - pbitlength);
+ int mindiffbits = strength / 3;
+
+ e = param.PublicExponent;
+
+ // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+ // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+
+ //
+ // Generate p, prime and (p-1) relatively prime to e
+ //
+ for (;;)
+ {
+ p = new BigInteger(pbitlength, 1, param.Random);
+
+ if (p.Mod(e).Equals(BigInteger.One))
+ continue;
+
+ if (!p.IsProbablePrime(param.Certainty))
+ continue;
+
+ if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
+ break;
+ }
+
+ //
+ // Generate a modulus of the required length
+ //
+ for (;;)
+ {
+ // Generate q, prime and (q-1) relatively prime to e,
+ // and not equal to p
+ //
+ for (;;)
+ {
+ q = new BigInteger(qbitlength, 1, param.Random);
+
+ if (q.Subtract(p).Abs().BitLength < mindiffbits)
+ continue;
+
+ if (q.Mod(e).Equals(BigInteger.One))
+ continue;
+
+ if (!q.IsProbablePrime(param.Certainty))
+ continue;
+
+ if (e.Gcd(q.Subtract(BigInteger.One)).Equals(BigInteger.One))
+ break;
+ }
+
+ //
+ // calculate the modulus
+ //
+ n = p.Multiply(q);
+
+ if (n.BitLength == param.Strength)
+ break;
+
+ //
+ // if we Get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.Max(q);
+ }
+
+ if (p.CompareTo(q) < 0)
+ {
+ phi = p;
+ p = q;
+ q = phi;
+ }
+
+ pSub1 = p.Subtract(BigInteger.One);
+ qSub1 = q.Subtract(BigInteger.One);
+ phi = pSub1.Multiply(qSub1);
+
+ //
+ // calculate the private exponent
+ //
+ d = e.ModInverse(phi);
+
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP, dQ, qInv;
+
+ dP = d.Remainder(pSub1);
+ dQ = d.Remainder(qSub1);
+ qInv = q.ModInverse(p);
+
+ return new AsymmetricCipherKeyPair(
+ new RsaKeyParameters(false, n, e),
+ new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/io/CipherStream.cs b/src/core/srcbc/crypto/io/CipherStream.cs
new file mode 100644
index 0000000..e69703c
--- /dev/null
+++ b/src/core/srcbc/crypto/io/CipherStream.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using Org.BouncyCastle.Crypto;
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class CipherStream : Stream
+ {
+ internal Stream stream;
+ internal IBufferedCipher inCipher, outCipher;
+ private byte[] mInBuf;
+ private int mInPos;
+ private bool inStreamEnded;
+
+ public CipherStream(
+ Stream stream,
+ IBufferedCipher readCipher,
+ IBufferedCipher writeCipher)
+ {
+ this.stream = stream;
+
+ if (readCipher != null)
+ {
+ this.inCipher = readCipher;
+ mInBuf = null;
+ }
+
+ if (writeCipher != null)
+ {
+ this.outCipher = writeCipher;
+ }
+ }
+
+ public IBufferedCipher ReadCipher
+ {
+ get { return inCipher; }
+ }
+
+ public IBufferedCipher WriteCipher
+ {
+ get { return outCipher; }
+ }
+
+ public override int ReadByte()
+ {
+ if (inCipher == null)
+ {
+ return stream.ReadByte();
+ }
+
+ if (mInBuf == null || mInPos >= mInBuf.Length)
+ {
+ if (!FillInBuf())
+ {
+ return -1;
+ }
+ }
+
+ return mInBuf[mInPos++];
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (inCipher == null)
+ {
+ return stream.Read(buffer, offset, count);
+ }
+
+// int pos = offset;
+// int end = offset + count;
+// try
+// {
+// while (pos < end)
+// {
+// if (mInPos >= mInBufEnd && !FillInBuf()) break;
+//
+// int len = System.Math.Min(end - pos, mInBufEnd - mInPos);
+// Array.Copy(mInBuf, mInPos, buffer, pos, len);
+// mInPos += len;
+// pos += len;
+// }
+// }
+// catch (IOException)
+// {
+// if (pos == offset) throw;
+// }
+// return pos - offset;
+
+ // TODO Optimise
+ int i = 0;
+ while (i < count)
+ {
+ int c = ReadByte();
+
+ if (c < 0) break;
+
+ buffer[offset + i++] = (byte) c;
+ }
+
+ return i;
+ }
+ private bool FillInBuf()
+ {
+ if (inStreamEnded)
+ {
+ return false;
+ }
+
+ mInPos = 0;
+
+ do
+ {
+ mInBuf = readAndProcessBlock();
+ }
+ while (!inStreamEnded && mInBuf == null);
+
+ return mInBuf != null;
+ }
+ private byte[] readAndProcessBlock()
+ {
+ int blockSize = inCipher.GetBlockSize();
+ int readSize = (blockSize == 0) ? 256 : blockSize;
+
+ byte[] block = new byte[readSize];
+ int numRead = 0;
+ do
+ {
+ int count = stream.Read(block, numRead, block.Length - numRead);
+ if (count < 1)
+ {
+ inStreamEnded = true;
+ break;
+ }
+ numRead += count;
+ }
+ while (numRead < block.Length);
+
+ Debug.Assert(inStreamEnded || numRead == block.Length);
+
+ byte[] bytes = inStreamEnded
+ ? inCipher.DoFinal(block, 0, numRead)
+ : inCipher.ProcessBytes(block);
+
+ if (bytes != null && bytes.Length == 0)
+ {
+ bytes = null;
+ }
+
+ return bytes;
+ }
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(0 <= offset && offset <= buffer.Length);
+ Debug.Assert(count >= 0);
+
+ int end = offset + count;
+
+ Debug.Assert(0 <= end && end <= buffer.Length);
+
+ if (outCipher == null)
+ {
+ stream.Write(buffer, offset, count);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessBytes(buffer, offset, count);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+ public override void WriteByte(
+ byte value)
+ {
+ if (outCipher == null)
+ {
+ stream.WriteByte(value);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessByte(value);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+ public override bool CanRead
+ {
+ get { return stream.CanRead && (inCipher != null); }
+ }
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite && (outCipher != null); }
+ }
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+ public override void Close()
+ {
+ if (outCipher != null)
+ {
+ byte[] data = outCipher.DoFinal();
+ stream.Write(data, 0, data.Length);
+ stream.Flush();
+ }
+ stream.Close();
+ }
+ public override void Flush()
+ {
+ // Note: outCipher.DoFinal is only called during Close()
+ stream.Flush();
+ }
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+ }
+}
diff --git a/src/core/srcbc/crypto/io/DigestStream.cs b/src/core/srcbc/crypto/io/DigestStream.cs
new file mode 100644
index 0000000..6a5ab42
--- /dev/null
+++ b/src/core/srcbc/crypto/io/DigestStream.cs
@@ -0,0 +1,116 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto;
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class DigestStream : Stream
+ {
+ internal Stream stream;
+ internal IDigest inDigest;
+ internal IDigest outDigest;
+
+ public DigestStream(
+ Stream stream,
+ IDigest readDigest,
+ IDigest writeDigest)
+ {
+ this.stream = stream;
+ this.inDigest = readDigest;
+ this.outDigest = writeDigest;
+ }
+ public IDigest ReadDigest()
+ {
+ return inDigest;
+ }
+ public IDigest WriteDigest()
+ {
+ return outDigest;
+ }
+ public override int ReadByte()
+ {
+ int b = stream.ReadByte();
+ if (inDigest != null)
+ {
+ if (b >= 0)
+ {
+ inDigest.Update((byte)b);
+ }
+ }
+ return b;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int n = stream.Read(buffer, offset, count);
+ if (inDigest != null)
+ {
+ if (n > 0)
+ {
+ inDigest.BlockUpdate(buffer, offset, n);
+ }
+ }
+ return n;
+ }
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (outDigest != null)
+ {
+ if (count > 0)
+ {
+ outDigest.BlockUpdate(buffer, offset, count);
+ }
+ }
+ stream.Write(buffer, offset, count);
+ }
+ public override void WriteByte(byte value)
+ {
+ if (outDigest != null)
+ {
+ outDigest.Update(value);
+ }
+ stream.WriteByte(value);
+ }
+ public override bool CanRead
+ {
+ get { return stream.CanRead && (inDigest != null); }
+ }
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite && (outDigest != null); }
+ }
+ public override bool CanSeek
+ {
+ get { return stream.CanSeek; }
+ }
+ public override long Length
+ {
+ get { return stream.Length; }
+ }
+ public override long Position
+ {
+ get { return stream.Position; }
+ set { stream.Position = value; }
+ }
+ public override void Close()
+ {
+ stream.Close();
+ }
+ public override void Flush()
+ {
+ stream.Flush();
+ }
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ return stream.Seek(offset,origin);
+ }
+ public override void SetLength(long value)
+ {
+ stream.SetLength(value);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/io/MacStream.cs b/src/core/srcbc/crypto/io/MacStream.cs
new file mode 100644
index 0000000..5f87b79
--- /dev/null
+++ b/src/core/srcbc/crypto/io/MacStream.cs
@@ -0,0 +1,116 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto;
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class MacStream : Stream
+ {
+ internal Stream stream;
+ internal IMac inMac;
+ internal IMac outMac;
+
+ public MacStream(
+ Stream stream,
+ IMac readMac,
+ IMac writeMac)
+ {
+ this.stream = stream;
+ this.inMac = readMac;
+ this.outMac = writeMac;
+ }
+ public IMac ReadMac()
+ {
+ return inMac;
+ }
+ public IMac WriteMac()
+ {
+ return outMac;
+ }
+ public override int ReadByte()
+ {
+ int b = stream.ReadByte();
+ if (inMac != null)
+ {
+ if (b >= 0)
+ {
+ inMac.Update((byte)b);
+ }
+ }
+ return b;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int n = stream.Read(buffer, offset, count);
+ if (inMac != null)
+ {
+ if (n > 0)
+ {
+ inMac.BlockUpdate(buffer, offset, count);
+ }
+ }
+ return n;
+ }
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (outMac != null)
+ {
+ if (count > 0)
+ {
+ outMac.BlockUpdate(buffer, offset, count);
+ }
+ }
+ stream.Write(buffer, offset, count);
+ }
+ public override void WriteByte(byte value)
+ {
+ if (outMac != null)
+ {
+ outMac.Update(value);
+ }
+ stream.WriteByte(value);
+ }
+ public override bool CanRead
+ {
+ get { return stream.CanRead && (inMac != null); }
+ }
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite && (outMac != null); }
+ }
+ public override bool CanSeek
+ {
+ get { return stream.CanSeek; }
+ }
+ public override long Length
+ {
+ get { return stream.Length; }
+ }
+ public override long Position
+ {
+ get { return stream.Position; }
+ set { stream.Position = value; }
+ }
+ public override void Close()
+ {
+ stream.Close();
+ }
+ public override void Flush()
+ {
+ stream.Flush();
+ }
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ return stream.Seek(offset,origin);
+ }
+ public override void SetLength(long value)
+ {
+ stream.SetLength(value);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/CMac.cs b/src/core/srcbc/crypto/macs/CMac.cs
new file mode 100644
index 0000000..75b2920
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/CMac.cs
@@ -0,0 +1,240 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
+ *
+ * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
+ *
+ * CMAC is a NIST recomendation - see
+ * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ *
+ * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
+ * analyzed by Tetsu Iwata and Kaoru Kurosawa.
+ *
+ * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message
+ * Authentication Code). OMAC stands for One-Key CBC MAC.
+ *
+ * It supports 128- or 64-bits block ciphers, with any key size, and returns
+ * a MAC with dimension less or equal to the block size of the underlying
+ * cipher.
+ *
+ */
+ public class CMac
+ : IMac
+ {
+ private const byte CONSTANT_128 = (byte)0x87;
+ private const byte CONSTANT_64 = (byte)0x1b;
+
+ private byte[] ZEROES;
+
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private IBlockCipher cipher;
+
+ private int macSize;
+
+ private byte[] L, Lu, Lu2;
+
+ /**
+ * create a standard MAC based on a CBC block cipher (64 or 128 bit block).
+ * This will produce an authentication code the length of the block size
+ * of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CMac(
+ IBlockCipher cipher)
+ : this(cipher, cipher.GetBlockSize() * 8)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and @lt;= 128.
+ */
+ public CMac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ if (macSizeInBits > (cipher.GetBlockSize() * 8))
+ {
+ throw new ArgumentException(
+ "MAC size must be less or equal to "
+ + (cipher.GetBlockSize() * 8));
+ }
+
+ if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16)
+ {
+ throw new ArgumentException(
+ "Block size must be either 64 or 128 bits");
+ }
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.GetBlockSize()];
+
+ buf = new byte[cipher.GetBlockSize()];
+
+ ZEROES = new byte[cipher.GetBlockSize()];
+
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ private byte[] doubleLu(
+ byte[] inBytes)
+ {
+ int FirstBit = (inBytes[0] & 0xFF) >> 7;
+ byte[] ret = new byte[inBytes.Length];
+ for (int i = 0; i < inBytes.Length - 1; i++)
+ {
+ ret[i] = (byte)((inBytes[i] << 1) + ((inBytes[i + 1] & 0xFF) >> 7));
+ }
+ ret[inBytes.Length - 1] = (byte)(inBytes[inBytes.Length - 1] << 1);
+ if (FirstBit == 1)
+ {
+ ret[inBytes.Length - 1] ^= inBytes.Length == 16 ? CONSTANT_128 : CONSTANT_64;
+ }
+ return ret;
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(true, parameters);
+
+ //initializes the L, Lu, Lu2 numbers
+ L = new byte[ZEROES.Length];
+ cipher.ProcessBlock(ZEROES, 0, L, 0);
+ Lu = doubleLu(L);
+ Lu2 = doubleLu(Lu);
+
+ cipher.Init(true, parameters);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] inBytes,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ cipher.ProcessBlock(inBytes, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(inBytes, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ byte[] lu;
+ if (bufOff == blockSize)
+ {
+ lu = Lu;
+ }
+ else
+ {
+ new ISO7816d4Padding().AddPadding(buf, bufOff);
+ lu = Lu2;
+ }
+
+ for (int i = 0; i < mac.Length; i++)
+ {
+ buf[i] ^= lu[i];
+ }
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ Array.Copy(mac, 0, outBytes, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ /*
+ * Reset the underlying cipher.
+ */
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/CbcBlockCipherMac.cs b/src/core/srcbc/crypto/macs/CbcBlockCipherMac.cs
new file mode 100644
index 0000000..95e8573
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/CbcBlockCipherMac.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ */
+ public class CbcBlockCipherMac
+ : IMac
+ {
+ private byte[] mac;
+ private byte[] Buffer;
+ private int bufOff;
+ private IBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher)
+ : this(cipher, (cipher.GetBlockSize() * 8) / 2, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, (cipher.GetBlockSize() * 8) / 2, padding)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ : this(cipher, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.GetBlockSize()];
+
+ Buffer = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == Buffer.Length)
+ {
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ Buffer[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, Buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ Buffer[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(Buffer, bufOff);
+ }
+
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ Array.Copy(mac, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(Buffer, 0, Buffer.Length);
+ bufOff = 0;
+
+ // Reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/CfbBlockCipherMac.cs b/src/core/srcbc/crypto/macs/CfbBlockCipherMac.cs
new file mode 100644
index 0000000..16f870a
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/CfbBlockCipherMac.cs
@@ -0,0 +1,368 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+ class MacCFBBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public MacCFBBlockCipher(
+ IBlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.cfbV = new byte[cipher.GetBlockSize()];
+ this.cfbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+
+ if ((outOff + blockSize) > outBytes.Length)
+ throw new DataLengthException("output buffer too short");
+
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+
+ //
+ // XOR the cfbV with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ IV.CopyTo(cfbV, 0);
+
+ cipher.Reset();
+ }
+
+ public void GetMacBlock(
+ byte[] mac)
+ {
+ cipher.ProcessBlock(cfbV, 0, mac, 0);
+ }
+ }
+
+ public class CfbBlockCipherMac
+ : IMac
+ {
+ private byte[] mac;
+ private byte[] Buffer;
+ private int bufOff;
+ private MacCFBBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher)
+ : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, padding)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits)
+ : this(cipher, cfbBitSize, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding a padding to be used.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ mac = new byte[cipher.GetBlockSize()];
+
+ this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ Buffer = new byte[this.cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == Buffer.Length)
+ {
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ Buffer[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, Buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ // pad with zeroes
+ if (this.padding == null)
+ {
+ while (bufOff < blockSize)
+ {
+ Buffer[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ padding.AddPadding(Buffer, bufOff);
+ }
+
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ cipher.GetMacBlock(mac);
+
+ Array.Copy(mac, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(Buffer, 0, Buffer.Length);
+ bufOff = 0;
+
+ // Reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/macs/GOST28147Mac.cs b/src/core/srcbc/crypto/macs/GOST28147Mac.cs
new file mode 100644
index 0000000..c0116a1
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/GOST28147Mac.cs
@@ -0,0 +1,296 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * implementation of GOST 28147-89 MAC
+ */
+ public class Gost28147Mac : IMac
+ {
+ private const int blockSize = 8;
+ private const int macSize = 4;
+ private int bufOff;
+ private byte[] buf;
+ private byte[] mac;
+ private bool firstStep = true;
+ private int[] workingKey;
+
+ //
+ // This is default S-box - E_A.
+ private byte[] S =
+ {
+ 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
+ 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
+ 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
+ 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
+ 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
+ 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
+ 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
+ 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
+ };
+
+ public Gost28147Mac()
+ {
+ mac = new byte[blockSize];
+ buf = new byte[blockSize];
+ bufOff = 0;
+ }
+
+ private static int[] generateWorkingKey(
+ byte[] userKey)
+ {
+ if (userKey.Length != 32)
+ throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
+
+ int[] key = new int[8];
+ for(int i=0; i!=8; i++)
+ {
+ key[i] = bytesToint(userKey,i*4);
+ }
+
+ return key;
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+ buf = new byte[blockSize];
+ if (parameters is ParametersWithSBox)
+ {
+ ParametersWithSBox param = (ParametersWithSBox)parameters;
+
+ //
+ // Set the S-Box
+ //
+ param.GetSBox().CopyTo(this.S, 0);
+
+ //
+ // set key if there is one
+ //
+ if (param.Parameters != null)
+ {
+ workingKey = generateWorkingKey(((KeyParameter)param.Parameters).GetKey());
+ }
+ }
+ else if (parameters is KeyParameter)
+ {
+ workingKey = generateWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to Gost28147 init - "
+ + parameters.GetType().Name);
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Gost28147Mac"; }
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ private int gost28147_mainStep(int n1, int key)
+ {
+ int cm = (key + n1); // CM1
+
+ // S-box replacing
+
+ int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
+ om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
+ om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
+ om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
+ om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
+ om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
+ om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
+ om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
+
+// return om << 11 | om >>> (32-11); // 11-leftshift
+ int omLeft = om << 11;
+ int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
+
+ return omLeft | omRight;
+ }
+
+ private void gost28147MacFunc(
+ int[] workingKey,
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ int N1, N2, tmp; //tmp -> for saving N1
+ N1 = bytesToint(input, inOff);
+ N2 = bytesToint(input, inOff + 4);
+
+ for (int k = 0; k < 2; k++) // 1-16 steps
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ tmp = N1;
+ N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+
+ intTobytes(N1, output, outOff);
+ intTobytes(N2, output, outOff + 4);
+ }
+
+ //array of bytes to type int
+ private static int bytesToint(
+ byte[] input,
+ int inOff)
+ {
+ return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000)
+ + ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff);
+ }
+
+ //int to array of bytes
+ private static void intTobytes(
+ int num,
+ byte[] output,
+ int outOff)
+ {
+ output[outOff + 3] = (byte)(num >> 24);
+ output[outOff + 2] = (byte)(num >> 16);
+ output[outOff + 1] = (byte)(num >> 8);
+ output[outOff] = (byte)num;
+ }
+
+ private static byte[] CM5func(
+ byte[] buf,
+ int bufOff,
+ byte[] mac)
+ {
+ byte[] sum = new byte[buf.Length - bufOff];
+
+ Array.Copy(buf, bufOff, sum, 0, mac.Length);
+
+ for (int i = 0; i != mac.Length; i++)
+ {
+ sum[i] = (byte)(sum[i] ^ mac[i]);
+ }
+
+ return sum;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ sumbuf = CM5func(input, inOff, mac);
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ //padding with zero
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ firstStep = true;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/HMac.cs b/src/core/srcbc/crypto/macs/HMac.cs
new file mode 100644
index 0000000..fe12329
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/HMac.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+ public class HMac : IMac
+ {
+ private const byte IPAD = (byte)0x36;
+ private const byte OPAD = (byte)0x5C;
+
+ private readonly IDigest digest;
+ private readonly int digestSize;
+ private readonly int blockLength;
+
+ private byte[] inputPad;
+ private byte[] outputPad;
+
+ public HMac(
+ IDigest digest)
+ {
+ this.digest = digest;
+ digestSize = digest.GetDigestSize();
+
+ blockLength = digest.GetByteLength();
+
+ inputPad = new byte[blockLength];
+ outputPad = new byte[blockLength];
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "/HMAC"; }
+ }
+
+ public IDigest GetUnderlyingDigest()
+ {
+ return digest;
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ digest.Reset();
+
+ byte[] key = ((KeyParameter)parameters).GetKey();
+
+ if (key.Length > blockLength)
+ {
+ digest.BlockUpdate(key, 0, key.Length);
+ digest.DoFinal(inputPad, 0);
+ for (int i = digestSize; i < inputPad.Length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(key, 0, inputPad, 0, key.Length);
+ for (int i = key.Length; i < inputPad.Length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+
+ outputPad = new byte[inputPad.Length];
+ Array.Copy(inputPad, 0, outputPad, 0, inputPad.Length);
+
+ for (int i = 0; i < inputPad.Length; i++)
+ {
+ inputPad[i] ^= IPAD;
+ }
+
+ for (int i = 0; i < outputPad.Length; i++)
+ {
+ outputPad[i] ^= OPAD;
+ }
+
+ digest.BlockUpdate(inputPad, 0, inputPad.Length);
+ }
+
+ public int GetMacSize()
+ {
+ return digestSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ digest.BlockUpdate(input, inOff, len);
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ byte[] tmp = new byte[digestSize];
+ digest.DoFinal(tmp, 0);
+
+ digest.BlockUpdate(outputPad, 0, outputPad.Length);
+ digest.BlockUpdate(tmp, 0, tmp.Length);
+
+ int len = digest.DoFinal(output, outOff);
+
+ Reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ /*
+ * reset the underlying digest.
+ */
+ digest.Reset();
+
+ /*
+ * reinitialize the digest.
+ */
+ digest.BlockUpdate(inputPad, 0, inputPad.Length);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/ISO9797Alg3Mac.cs b/src/core/srcbc/crypto/macs/ISO9797Alg3Mac.cs
new file mode 100644
index 0000000..a8474ed
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/ISO9797Alg3Mac.cs
@@ -0,0 +1,259 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC)
+ *
+ * This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
+ * class must be changed to protected
+ */
+ public class ISO9797Alg3Mac : IMac
+ {
+ private byte[] mac;
+ private byte[] buf;
+ private int bufOff;
+ private IBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+ private KeyParameter lastKey2;
+ private KeyParameter lastKey3;
+
+ /**
+ * create a Retail-MAC based on a CBC block cipher. This will produce an
+ * authentication code of the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation. This must
+ * be DESEngine.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher)
+ : this(cipher, cipher.GetBlockSize() * 8, null)
+ {
+ }
+
+ /**
+ * create a Retail-MAC based on a CBC block cipher. This will produce an
+ * authentication code of the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, cipher.GetBlockSize() * 8, padding)
+ {
+ }
+
+ /**
+ * create a Retail-MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ : this(cipher, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+ * MAC generation. The final block is decrypted and then encrypted using the
+ * middle and right part of the key.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ if (!(cipher is DesEngine))
+ throw new ArgumentException("cipher must be instance of DesEngine");
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.GetBlockSize()];
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "ISO9797Alg3"; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("parameters must be an instance of KeyParameter");
+
+ // KeyParameter must contain a double or triple length DES key,
+ // however the underlying cipher is a single DES. The middle and
+ // right key are used only in the final step.
+
+ KeyParameter kp = (KeyParameter)parameters;
+ KeyParameter key1;
+ byte[] keyvalue = kp.GetKey();
+
+ if (keyvalue.Length == 16)
+ { // Double length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = key1;
+ }
+ else if (keyvalue.Length == 24)
+ { // Triple length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
+ }
+ else
+ {
+ throw new ArgumentException("Key must be either 112 or 168 bit long");
+ }
+
+ cipher.Init(true, key1);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+ }
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ // Added to code from base class
+ DesEngine deseng = new DesEngine();
+
+ deseng.Init(false, this.lastKey2);
+ deseng.ProcessBlock(mac, 0, mac, 0);
+
+ deseng.Init(true, this.lastKey3);
+ deseng.ProcessBlock(mac, 0, mac, 0);
+ // ****
+
+ Array.Copy(mac, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ // reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/macs/VMPCMac.cs b/src/core/srcbc/crypto/macs/VMPCMac.cs
new file mode 100644
index 0000000..46450f4
--- /dev/null
+++ b/src/core/srcbc/crypto/macs/VMPCMac.cs
@@ -0,0 +1,173 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ public class VmpcMac
+ : IMac
+ {
+ private byte g;
+
+ private byte n = 0;
+ private byte[] P = null;
+ private byte s = 0;
+
+ private byte[] T;
+ private byte[] workingIV;
+
+ private byte[] workingKey;
+
+ private byte x1, x2, x3, x4;
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ // Execute the Post-Processing Phase
+ for (int r = 1; r < 25; r++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+
+ x4 = P[(x4 + x3 + r) & 0xff];
+ x3 = P[(x3 + x2 + r) & 0xff];
+ x2 = P[(x2 + x1 + r) & 0xff];
+ x1 = P[(x1 + s + r) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ // Input T to the IV-phase of the VMPC KSA
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ // Store 20 new outputs of the VMPC Stream Cipher input table M
+ byte[] M = new byte[20];
+ for (int i = 0; i < 20; i++)
+ {
+ s = P[(s + P[i & 0xff]) & 0xff];
+ M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+
+ byte temp = P[i & 0xff];
+ P[i & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ Array.Copy(M, 0, output, outOff, M.Length);
+ Reset();
+
+ return M.Length;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "VMPC-MAC"; }
+ }
+
+ public virtual int GetMacSize()
+ {
+ return 20;
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters");
+
+ ParametersWithIV ivParams = (ParametersWithIV) parameters;
+ KeyParameter key = (KeyParameter) ivParams.Parameters;
+
+ if (!(ivParams.Parameters is KeyParameter))
+ throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters");
+
+ this.workingIV = ivParams.GetIV();
+
+ if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+ throw new ArgumentException("VMPC-MAC requires 1 to 768 bytes of IV", "parameters");
+
+ this.workingKey = key.GetKey();
+
+ Reset();
+
+ }
+
+ private void initKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public virtual void Reset()
+ {
+ initKey(this.workingKey, this.workingIV);
+ g = x1 = x2 = x3 = x4 = n = 0;
+ T = new byte[32];
+ for (int i = 0; i < 32; i++)
+ {
+ T[i] = 0;
+ }
+ }
+
+ public virtual void Update(byte input)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte c = (byte) (input ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]);
+
+ x4 = P[(x4 + x3) & 0xff];
+ x3 = P[(x3 + x2) & 0xff];
+ x2 = P[(x2 + x1) & 0xff];
+ x1 = P[(x1 + s + c) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if ((inOff + len) > input.Length)
+ throw new DataLengthException("input buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ Update(input[i]);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/CbcBlockCipher.cs b/src/core/srcbc/crypto/modes/CbcBlockCipher.cs
new file mode 100644
index 0000000..34b9103
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/CbcBlockCipher.cs
@@ -0,0 +1,230 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ */
+ public class CbcBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV, cbcV, cbcNextV;
+ private int blockSize;
+ private IBlockCipher cipher;
+ private bool encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of chaining.
+ */
+ public CbcBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+
+ this.IV = new byte[blockSize];
+ this.cbcV = new byte[blockSize];
+ this.cbcNextV = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.encrypting = forEncryption;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length != blockSize)
+ {
+ throw new ArgumentException("initialisation vector must be the same length as block size");
+ }
+
+ Array.Copy(iv, 0, IV, 0, iv.Length);
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(encrypting, parameters);
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CBC".
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CBC"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ /**
+ * return the block size of the underlying cipher.
+ *
+ * @return the block size of the underlying cipher.
+ */
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (encrypting)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, cbcV, 0, IV.Length);
+
+ cipher.Reset();
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ /*
+ * XOR the cbcV and the input,
+ * then encrypt the cbcV
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ cbcV[i] ^= input[inOff + i];
+ }
+
+ int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
+
+ /*
+ * copy ciphertext to cbcV
+ */
+ Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
+
+ return length;
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the decrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ Array.Copy(input, inOff, cbcNextV, 0, blockSize);
+
+ int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
+
+ /*
+ * XOR the cbcV and the output
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] ^= cbcV[i];
+ }
+
+ /*
+ * swap the back up buffer into next position
+ */
+ byte[] tmp;
+
+ tmp = cbcV;
+ cbcV = cbcNextV;
+ cbcNextV = tmp;
+
+ return length;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/modes/CcmBlockCipher.cs b/src/core/srcbc/crypto/modes/CcmBlockCipher.cs
new file mode 100644
index 0000000..90451b9
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/CcmBlockCipher.cs
@@ -0,0 +1,345 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ *
+ * Note: this mode is a packet mode - it needs all the data up front.
+ *
+ */
+ public class CcmBlockCipher
+ : IAeadBlockCipher
+ {
+ private static readonly int BlockSize = 16;
+
+ private readonly IBlockCipher cipher;
+ private readonly byte[] macBlock;
+ private bool forEncryption;
+ private byte[] nonce;
+ private byte[] associatedText;
+ private int macSize;
+ private ICipherParameters keyParam;
+ private readonly MemoryStream data = new MemoryStream();
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used.
+ */
+ public CcmBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.macBlock = new byte[BlockSize];
+
+ if (cipher.GetBlockSize() != BlockSize)
+ throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters) parameters;
+
+ nonce = param.GetNonce();
+ associatedText = param.GetAssociatedText();
+ macSize = param.MacSize / 8;
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV) parameters;
+
+ nonce = param.GetIV();
+ associatedText = null;
+ macSize = macBlock.Length / 2;
+ keyParam = param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to CCM");
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CCM"; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ data.WriteByte(input);
+
+ return 0;
+ }
+
+ public virtual int ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int inLen,
+ byte[] outBytes,
+ int outOff)
+ {
+ data.Write(inBytes, inOff, inLen);
+
+ return 0;
+ }
+
+ public virtual int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+ byte[] text = data.ToArray();
+ byte[] enc = ProcessPacket(text, 0, text.Length);
+
+ Array.Copy(enc, 0, outBytes, outOff, enc.Length);
+
+ Reset();
+
+ return enc.Length;
+ }
+
+ public virtual void Reset()
+ {
+ cipher.Reset();
+ data.SetLength(0);
+ }
+
+ /**
+ * Returns a byte array containing the mac calculated as part of the
+ * last encrypt or decrypt operation.
+ *
+ * @return the last mac calculated.
+ */
+ public virtual byte[] GetMac()
+ {
+ byte[] mac = new byte[macSize];
+
+ Array.Copy(macBlock, 0, mac, 0, mac.Length);
+
+ return mac;
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ return 0;
+ }
+
+ public int GetOutputSize(
+ int len)
+ {
+ if (forEncryption)
+ {
+ return (int) data.Length + len + macSize;
+ }
+
+ return (int) data.Length + len - macSize;
+ }
+
+ public byte[] ProcessPacket(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (keyParam == null)
+ throw new InvalidOperationException("CCM cipher unitialized.");
+
+ IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+ byte[] iv = new byte[BlockSize];
+ byte[] output;
+
+ iv[0] = (byte)(((15 - nonce.Length) - 1) & 0x7);
+
+ Array.Copy(nonce, 0, iv, 1, nonce.Length);
+
+ ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+ if (forEncryption)
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ output = new byte[inLen + macSize];
+
+ calculateMac(input, inOff, inLen, macBlock);
+
+ ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0); // S0
+
+ while (index < inLen - BlockSize) // S1...
+ {
+ ctrCipher.ProcessBlock(input, index, output, outOff);
+ outOff += BlockSize;
+ index += BlockSize;
+ }
+
+ byte[] block = new byte[BlockSize];
+
+ Array.Copy(input, index, block, 0, inLen - index);
+
+ ctrCipher.ProcessBlock(block, 0, block, 0);
+
+ Array.Copy(block, 0, output, outOff, inLen - index);
+
+ outOff += inLen - index;
+
+ Array.Copy(macBlock, 0, output, outOff, output.Length - outOff);
+ }
+ else
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ output = new byte[inLen - macSize];
+
+ Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
+
+ ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ for (int i = macSize; i != macBlock.Length; i++)
+ {
+ macBlock[i] = 0;
+ }
+
+ while (outOff < output.Length - BlockSize)
+ {
+ ctrCipher.ProcessBlock(input, index, output, outOff);
+ outOff += BlockSize;
+ index += BlockSize;
+ }
+
+ byte[] block = new byte[BlockSize];
+
+ Array.Copy(input, index, block, 0, output.Length - outOff);
+
+ ctrCipher.ProcessBlock(block, 0, block, 0);
+
+ Array.Copy(block, 0, output, outOff, output.Length - outOff);
+
+ byte[] calculatedMacBlock = new byte[BlockSize];
+
+ calculateMac(output, 0, output.Length, calculatedMacBlock);
+
+ if (!Arrays.AreEqual(macBlock, calculatedMacBlock))
+ throw new InvalidCipherTextException("mac check in CCM failed");
+ }
+
+ return output;
+ }
+
+ private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ {
+ IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
+
+ cMac.Init(keyParam);
+
+ //
+ // build b0
+ //
+ byte[] b0 = new byte[16];
+
+ if (hasAssociatedText())
+ {
+ b0[0] |= 0x40;
+ }
+
+ b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
+
+ b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
+
+ Array.Copy(nonce, 0, b0, 1, nonce.Length);
+
+ int q = dataLen;
+ int count = 1;
+ while (q > 0)
+ {
+ b0[b0.Length - count] = (byte)(q & 0xff);
+ q >>= 8;
+ count++;
+ }
+
+ cMac.BlockUpdate(b0, 0, b0.Length);
+
+ //
+ // process associated text
+ //
+ if (hasAssociatedText())
+ {
+ int extra;
+
+ if (associatedText.Length < ((1 << 16) - (1 << 8)))
+ {
+ cMac.Update((byte)(associatedText.Length >> 8));
+ cMac.Update((byte)associatedText.Length);
+
+ extra = 2;
+ }
+ else // can't go any higher than 2^32
+ {
+ cMac.Update((byte)0xff);
+ cMac.Update((byte)0xfe);
+ cMac.Update((byte)(associatedText.Length >> 24));
+ cMac.Update((byte)(associatedText.Length >> 16));
+ cMac.Update((byte)(associatedText.Length >> 8));
+ cMac.Update((byte)associatedText.Length);
+
+ extra = 6;
+ }
+
+ cMac.BlockUpdate(associatedText, 0, associatedText.Length);
+
+ extra = (extra + associatedText.Length) % 16;
+ if (extra != 0)
+ {
+ for (int i = 0; i != 16 - extra; i++)
+ {
+ cMac.Update((byte)0x00);
+ }
+ }
+ }
+
+ //
+ // add the text
+ //
+ cMac.BlockUpdate(data, dataOff, dataLen);
+
+ return cMac.DoFinal(macBlock, 0);
+ }
+
+ private bool hasAssociatedText()
+ {
+ return associatedText != null && associatedText.Length != 0;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/CfbBlockCipher.cs b/src/core/srcbc/crypto/modes/CfbBlockCipher.cs
new file mode 100644
index 0000000..f83e8fa
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/CfbBlockCipher.cs
@@ -0,0 +1,218 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+ public class CfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+ private bool encrypting;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public CfbBlockCipher(
+ IBlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.cfbV = new byte[cipher.GetBlockSize()];
+ this.cfbOutV = new byte[cipher.GetBlockSize()];
+ }
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.encrypting = forEncryption;
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV) parameters;
+ byte[] iv = ivParam.GetIV();
+ int diff = IV.Length - iv.Length;
+ Array.Copy(iv, 0, IV, diff, iv.Length);
+ Array.Clear(IV, 0, diff);
+
+ parameters = ivParam.Parameters;
+ }
+ Reset();
+ cipher.Init(true, parameters);
+ }
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (encrypting)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+ //
+ // XOR the cfbV with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
+ return blockSize;
+ }
+ /**
+ * Do the appropriate processing for CFB mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
+ //
+ // XOR the cfbV with the plaintext producing the plain text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+ return blockSize;
+ }
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, cfbV, 0, IV.Length);
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/CtsBlockCipher.cs b/src/core/srcbc/crypto/modes/CtsBlockCipher.cs
new file mode 100644
index 0000000..eb1ce14
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/CtsBlockCipher.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same outLength as the plain text.
+ */
+ public class CtsBlockCipher
+ : BufferedBlockCipher
+ {
+ private readonly int blockSize;
+
+ /**
+ * Create a buffered block cipher that uses Cipher Text Stealing
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public CtsBlockCipher(
+ IBlockCipher cipher)
+ {
+ // TODO Should this test for acceptable ones instead?
+ if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
+ throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
+
+ this.cipher = cipher;
+
+ blockSize = cipher.GetBlockSize();
+
+ buf = new byte[blockSize * 2];
+ bufOff = 0;
+ }
+
+ /**
+ * return the size of the output buffer required for an update of 'length' bytes.
+ *
+ * @param length the outLength of the input.
+ * @return the space required to accommodate a call to update
+ * with length bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.Length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of length bytes.
+ *
+ * @param length the outLength of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with length bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ return length + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.Length)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ Debug.Assert(resultLen == blockSize);
+
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+ bufOff = blockSize;
+ }
+
+ buf[bufOff++] = input;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param length the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentException("Can't have a negative input outLength!");
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ if ((outOff + outLength) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+
+ length -= gapLen;
+ inOff += gapLen;
+
+ while (length > blockSize)
+ {
+ Array.Copy(input, inOff, buf, bufOff, blockSize);
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, length);
+
+ bufOff += length;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+ * case the exception will never Get thrown).
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ if (bufOff + outOff > output.Length)
+ {
+ throw new DataLengthException("output buffer too small in doFinal");
+ }
+
+ int blockSize = cipher.GetBlockSize();
+ int length = bufOff - blockSize;
+ byte[] block = new byte[blockSize];
+
+ if (forEncryption)
+ {
+ cipher.ProcessBlock(buf, 0, block, 0);
+
+ if (bufOff < blockSize)
+ {
+ throw new DataLengthException("need at least one block of input for CTS");
+ }
+
+ for (int i = bufOff; i != buf.Length; i++)
+ {
+ buf[i] = block[i - blockSize];
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ buf[i] ^= block[i - blockSize];
+ }
+
+ IBlockCipher c = (cipher is CbcBlockCipher)
+ ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
+ : cipher;
+
+ c.ProcessBlock(buf, blockSize, output, outOff);
+
+ Array.Copy(block, 0, output, outOff + blockSize, length);
+ }
+ else
+ {
+ byte[] lastBlock = new byte[blockSize];
+
+ IBlockCipher c = (cipher is CbcBlockCipher)
+ ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
+ : cipher;
+
+ c.ProcessBlock(buf, 0, block, 0);
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+ }
+
+ Array.Copy(buf, blockSize, block, 0, length);
+
+ cipher.ProcessBlock(block, 0, output, outOff);
+ Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
+ }
+
+ int offset = bufOff;
+
+ Reset();
+
+ return offset;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/EAXBlockCipher.cs b/src/core/srcbc/crypto/modes/EAXBlockCipher.cs
new file mode 100644
index 0000000..a069568
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/EAXBlockCipher.cs
@@ -0,0 +1,302 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
+ * Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+ *
+ * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+ *
+ * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
+ * cipher to encrypt and authenticate data. It's on-line (the length of a
+ * message isn't needed to begin processing it), has good performances, it's
+ * simple and provably secure (provided the underlying block cipher is secure).
+ *
+ * Of course, this implementations is NOT thread-safe.
+ */
+ public class EaxBlockCipher
+ : IAeadBlockCipher
+ {
+ private enum Tag : byte { N, H, C };
+
+ private SicBlockCipher cipher;
+
+ private bool forEncryption;
+
+ private int blockSize;
+
+ private IMac mac;
+
+ private byte[] nonceMac;
+ private byte[] associatedTextMac;
+ private byte[] macBlock;
+
+ private int macSize;
+ private byte[] bufBlock;
+ private int bufOff;
+
+ /**
+ * Constructor that accepts an instance of a block cipher engine.
+ *
+ * @param cipher the engine to use
+ */
+ public EaxBlockCipher(
+ IBlockCipher cipher)
+ {
+ blockSize = cipher.GetBlockSize();
+ mac = new CMac(cipher);
+ macBlock = new byte[blockSize];
+ bufBlock = new byte[blockSize * 2];
+ associatedTextMac = new byte[mac.GetMacSize()];
+ nonceMac = new byte[mac.GetMacSize()];
+ this.cipher = new SicBlockCipher(cipher);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ byte[] nonce, associatedText;
+ ICipherParameters keyParam;
+
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters) parameters;
+
+ nonce = param.GetNonce();
+ associatedText = param.GetAssociatedText();
+ macSize = param.MacSize / 8;
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV) parameters;
+
+ nonce = param.GetIV();
+ associatedText = new byte[0];
+ macSize = mac.GetMacSize() / 2;
+ keyParam = param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to EAX");
+ }
+
+ byte[] tag = new byte[blockSize];
+
+ mac.Init(keyParam);
+ tag[blockSize - 1] = (byte) Tag.H;
+ mac.BlockUpdate(tag, 0, blockSize);
+ mac.BlockUpdate(associatedText, 0, associatedText.Length);
+ mac.DoFinal(associatedTextMac, 0);
+
+ tag[blockSize - 1] = (byte) Tag.N;
+ mac.BlockUpdate(tag, 0, blockSize);
+ mac.BlockUpdate(nonce, 0, nonce.Length);
+ mac.DoFinal(nonceMac, 0);
+
+ tag[blockSize - 1] = (byte) Tag.C;
+ mac.BlockUpdate(tag, 0, blockSize);
+
+ cipher.Init(true, new ParametersWithIV(keyParam, nonceMac));
+ }
+
+ private void calculateMac()
+ {
+ byte[] outC = new byte[blockSize];
+ mac.DoFinal(outC, 0);
+
+ for (int i = 0; i < macBlock.Length; i++)
+ {
+ macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ private void Reset(
+ bool clearMac)
+ {
+ cipher.Reset();
+ mac.Reset();
+
+ bufOff = 0;
+ Array.Clear(bufBlock, 0, bufBlock.Length);
+
+ if (clearMac)
+ {
+ Array.Clear(macBlock, 0, macBlock.Length);
+ }
+
+ byte[] tag = new byte[blockSize];
+ tag[blockSize - 1] = (byte) Tag.C;
+ mac.BlockUpdate(tag, 0, blockSize);
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ return process(input, outBytes, outOff);
+ }
+
+ public virtual int ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+ resultLen += process(inBytes[inOff + i], outBytes, outOff + resultLen);
+ }
+
+ return resultLen;
+ }
+
+ public virtual int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+ int extra = bufOff;
+ byte[] tmp = new byte[bufBlock.Length];
+
+ bufOff = 0;
+
+ if (forEncryption)
+ {
+ cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+ cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+
+ Array.Copy(tmp, 0, outBytes, outOff, extra);
+
+ mac.BlockUpdate(tmp, 0, extra);
+
+ calculateMac();
+
+ Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
+
+ Reset(false);
+
+ return extra + macSize;
+ }
+ else
+ {
+ if (extra > macSize)
+ {
+ mac.BlockUpdate(bufBlock, 0, extra - macSize);
+
+ cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+ cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+
+ Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
+ }
+
+ calculateMac();
+
+ if (!verifyMac(bufBlock, extra - macSize))
+ throw new InvalidCipherTextException("mac check in EAX failed");
+
+ Reset(false);
+
+ return extra - macSize;
+ }
+ }
+
+ public virtual byte[] GetMac()
+ {
+ byte[] mac = new byte[macSize];
+
+ Array.Copy(macBlock, 0, mac, 0, macSize);
+
+ return mac;
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ return ((len + bufOff) / blockSize) * blockSize;
+ }
+
+ public virtual int GetOutputSize(
+ int len)
+ {
+ if (forEncryption)
+ {
+ return len + bufOff + macSize;
+ }
+
+ return len + bufOff - macSize;
+ }
+
+ private int process(
+ byte b,
+ byte[] outBytes,
+ int outOff)
+ {
+ bufBlock[bufOff++] = b;
+
+ if (bufOff == bufBlock.Length)
+ {
+ int size;
+
+ if (forEncryption)
+ {
+ size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+
+ mac.BlockUpdate(outBytes, outOff, blockSize);
+ }
+ else
+ {
+ mac.BlockUpdate(bufBlock, 0, blockSize);
+
+ size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+ }
+
+ bufOff = blockSize;
+ Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize);
+
+ return size;
+ }
+
+ return 0;
+ }
+
+ private bool verifyMac(byte[] mac, int off)
+ {
+ for (int i = 0; i < macSize; i++)
+ {
+ if (macBlock[i] != mac[off + i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/GCMBlockCipher.cs b/src/core/srcbc/crypto/modes/GCMBlockCipher.cs
new file mode 100644
index 0000000..bdeffe5
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/GCMBlockCipher.cs
@@ -0,0 +1,447 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ ///
+ /// Implements the Galois/Counter mode (GCM) detailed in
+ /// NIST Special Publication 800-38D.
+ ///
+ public class GcmBlockCipher
+ : IAeadBlockCipher
+ {
+ private const int BlockSize = 16;
+ private static readonly byte[] Zeroes = new byte[BlockSize];
+ private static readonly BigInteger R = new BigInteger("11100001", 2).ShiftLeft(120);
+
+ private readonly IBlockCipher cipher;
+
+ // These fields are set by Init and not modified by processing
+ private bool forEncryption;
+ private int macSize;
+ private byte[] nonce;
+ private byte[] A;
+ private KeyParameter keyParam;
+ // private int tagLength;
+ private BigInteger H;
+ private BigInteger initS;
+ private byte[] J0;
+
+ // These fields are modified during processing
+ private byte[] bufBlock;
+ private byte[] macBlock;
+ private BigInteger S;
+ private byte[] counter;
+ private int bufOff;
+ private long totalLength;
+
+ // Debug variables
+ // private int nCount, xCount, yCount;
+
+ public GcmBlockCipher(
+ IBlockCipher c)
+ {
+ if (c.GetBlockSize() != BlockSize)
+ throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+
+ this.cipher = c;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/GCM"; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ this.macSize = 16; // TODO Make configurable?
+ this.macBlock = null;
+
+ // TODO If macSize limitation is removed, be very careful about bufBlock
+ int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
+ this.bufBlock = new byte[bufLength];
+
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters)parameters;
+
+ nonce = param.GetNonce();
+ A = param.GetAssociatedText();
+ // macSize = param.getMacSize() / 8;
+ if (param.MacSize != 128)
+ {
+ // TODO Make configurable?
+ throw new ArgumentException("only 128-bit MAC supported currently");
+ }
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
+
+ nonce = param.GetIV();
+ A = null;
+ keyParam = (KeyParameter)param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to GCM");
+ }
+
+ if (nonce == null || nonce.Length < 1)
+ {
+ throw new ArgumentException("IV must be at least 1 byte");
+ }
+
+ if (A == null)
+ {
+ // Avoid lots of null checks
+ A = new byte[0];
+ }
+
+ // Cipher always used input forward mode
+ cipher.Init(true, keyParam);
+
+ // TODO This should be configurable by Init parameters
+ // (but must be 16 if nonce length not 12) (BlockSize?)
+ // this.tagLength = 16;
+
+ byte[] h = new byte[BlockSize];
+ cipher.ProcessBlock(Zeroes, 0, h, 0);
+ //trace("H: " + new string(Hex.encode(h)));
+ this.H = new BigInteger(1, h);
+ this.initS = gHASH(A, false);
+
+ if (nonce.Length == 12)
+ {
+ this.J0 = new byte[16];
+ Array.Copy(nonce, 0, J0, 0, nonce.Length);
+ this.J0[15] = 0x01;
+ }
+ else
+ {
+ BigInteger N = gHASH(nonce, true);
+ BigInteger X = BigInteger.ValueOf(nonce.Length * 8);
+ //trace("len({})||len(IV): " + dumpBigInt(X));
+
+ N = multiply(N.Xor(X), H);
+ //trace("GHASH(H,{},IV): " + dumpBigInt(N));
+ this.J0 = asBlock(N);
+ }
+
+ this.S = initS;
+ this.counter = Arrays.Clone(J0);
+ //trace("Y" + yCount + ": " + new string(Hex.encode(counter)));
+ this.bufOff = 0;
+ this.totalLength = 0;
+ }
+
+ public virtual byte[] GetMac()
+ {
+ return Arrays.Clone(macBlock);
+ }
+
+ public virtual int GetOutputSize(
+ int len)
+ {
+ if (forEncryption)
+ {
+ return len + bufOff + macSize;
+ }
+
+ return len + bufOff - macSize;
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ return ((len + bufOff) / BlockSize) * BlockSize;
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ return Process(input, output, outOff);
+ }
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+ resultLen += Process(input[inOff + i], output, outOff + resultLen);
+ }
+
+ return resultLen;
+ }
+
+ private int Process(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ bufBlock[bufOff++] = input;
+
+ if (bufOff == bufBlock.Length)
+ {
+ gCTRBlock(bufBlock, BlockSize, output, outOff);
+ if (!forEncryption)
+ {
+ Array.Copy(bufBlock, BlockSize, bufBlock, 0, BlockSize);
+ }
+ // bufOff = 0;
+ bufOff = bufBlock.Length - BlockSize;
+ // return bufBlock.Length;
+ return BlockSize;
+ }
+
+ return 0;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ int extra = bufOff;
+ if (!forEncryption)
+ {
+ if (extra < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ extra -= macSize;
+ }
+
+ if (extra > 0)
+ {
+ byte[] tmp = new byte[BlockSize];
+ Array.Copy(bufBlock, 0, tmp, 0, extra);
+ gCTRBlock(tmp, extra, output, outOff);
+ }
+
+ // Final gHASH
+ BigInteger X = BigInteger.ValueOf(A.Length * 8).ShiftLeft(64).Add(
+ BigInteger.ValueOf(totalLength * 8));
+ //trace("len(A)||len(C): " + dumpBigInt(X));
+
+ S = multiply(S.Xor(X), H);
+ //trace("GHASH(H,A,C): " + dumpBigInt(S));
+
+ // T = MSBt(GCTRk(J0,S))
+ byte[] tBytes = new byte[BlockSize];
+ cipher.ProcessBlock(J0, 0, tBytes, 0);
+ //trace("E(K,Y0): " + new string(Hex.encode(tmp)));
+ BigInteger T = S.Xor(new BigInteger(1, tBytes));
+
+ // TODO Fix this if tagLength becomes configurable
+ byte[] tag = asBlock(T);
+ //trace("T: " + new string(Hex.encode(tag)));
+
+ int resultLen = extra;
+
+ if (forEncryption)
+ {
+ this.macBlock = tag;
+ Array.Copy(tag, 0, output, outOff + bufOff, tag.Length);
+ resultLen += tag.Length;
+ }
+ else
+ {
+ this.macBlock = new byte[macSize];
+ Array.Copy(bufBlock, extra, macBlock, 0, macSize);
+ if (!Arrays.AreEqual(tag, this.macBlock))
+ throw new InvalidCipherTextException("mac check input GCM failed");
+ }
+
+ Reset(false);
+
+ return resultLen;
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ private void Reset(
+ bool clearMac)
+ {
+ // Debug
+ // nCount = xCount = yCount = 0;
+
+ S = initS;
+ counter = Arrays.Clone(J0);
+ bufOff = 0;
+ totalLength = 0;
+
+ if (bufBlock != null)
+ {
+ Array.Clear(bufBlock, 0, bufBlock.Length);
+ }
+
+ if (clearMac)
+ {
+ macBlock = null;
+ }
+
+ cipher.Reset();
+ }
+
+ private void gCTRBlock(byte[] buf, int bufCount, byte[] output, int outOff)
+ {
+ inc(counter);
+ //trace("Y" + ++yCount + ": " + new string(Hex.encode(counter)));
+
+ byte[] tmp = new byte[BlockSize];
+ cipher.ProcessBlock(counter, 0, tmp, 0);
+ //trace("E(K,Y" + yCount + "): " + new string(Hex.encode(tmp)));
+
+ if (forEncryption)
+ {
+ Array.Copy(Zeroes, bufCount, tmp, bufCount, BlockSize - bufCount);
+
+ for (int i = bufCount - 1; i >= 0; --i)
+ {
+ tmp[i] ^= buf[i];
+ output[outOff + i] = tmp[i];
+ }
+
+ gHASHBlock(tmp);
+ }
+ else
+ {
+ for (int i = bufCount - 1; i >= 0; --i)
+ {
+ tmp[i] ^= buf[i];
+ output[outOff + i] = tmp[i];
+ }
+
+ gHASHBlock(buf);
+ }
+
+ totalLength += bufCount;
+ }
+
+ private BigInteger gHASH(byte[] b, bool nonce)
+ {
+ //trace("" + b.Length);
+ BigInteger Y = BigInteger.Zero;
+
+ for (int pos = 0; pos < b.Length; pos += 16)
+ {
+ byte[] x = new byte[16];
+ int num = System.Math.Min(b.Length - pos, 16);
+ Array.Copy(b, pos, x, 0, num);
+ BigInteger X = new BigInteger(1, x);
+ Y = multiply(Y.Xor(X), H);
+ // if (nonce)
+ // {
+ // trace("N" + ++nCount + ": " + dumpBigInt(Y));
+ // }
+ // else
+ // {
+ // trace("X" + ++xCount + ": " + dumpBigInt(Y) + " (gHASH)");
+ // }
+ }
+
+ return Y;
+ }
+
+ private void gHASHBlock(byte[] block)
+ {
+ if (block.Length > BlockSize)
+ {
+ byte[] tmp = new byte[BlockSize];
+ Array.Copy(block, 0, tmp, 0, BlockSize);
+ block = tmp;
+ }
+
+ BigInteger X = new BigInteger(1, block);
+ S = multiply(S.Xor(X), H);
+ //trace("X" + ++xCount + ": " + dumpBigInt(S) + " (gHASHBlock)");
+ }
+
+ private static void inc(byte[] block)
+ {
+ // assert block.Length == 16;
+
+ for (int i = 15; i >= 12; --i)
+ {
+ byte b = (byte)((block[i] + 1) & 0xff);
+ block[i] = b;
+
+ if (b != 0)
+ {
+ break;
+ }
+ }
+ }
+
+ private BigInteger multiply(
+ BigInteger X,
+ BigInteger Y)
+ {
+ BigInteger Z = BigInteger.Zero;
+ BigInteger V = X;
+
+ for (int i = 0; i < 128; ++i)
+ {
+ if (Y.TestBit(127 - i))
+ {
+ Z = Z.Xor(V);
+ }
+
+ bool lsb = V.TestBit(0);
+ V = V.ShiftRight(1);
+ if (lsb)
+ {
+ V = V.Xor(R);
+ }
+ }
+
+ return Z;
+ }
+
+ private byte[] asBlock(
+ BigInteger bi)
+ {
+ byte[] b = BigIntegers.AsUnsignedByteArray(bi);
+ if (b.Length < 16)
+ {
+ byte[] tmp = new byte[16];
+ Array.Copy(b, 0, tmp, tmp.Length - b.Length, b.Length);
+ b = tmp;
+ }
+ return b;
+ }
+
+ // private string dumpBigInt(BigInteger bi)
+ // {
+ // byte[] b = asBlock(bi);
+ //
+ // return new string(Hex.encode(b));
+ // }
+ //
+ // private void trace(string msg)
+ // {
+ // System.err.println(msg);
+ // }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/crypto/modes/GOFBBlockCipher.cs b/src/core/srcbc/crypto/modes/GOFBBlockCipher.cs
new file mode 100644
index 0000000..9ddde26
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/GOFBBlockCipher.cs
@@ -0,0 +1,223 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements the GOST 28147 OFB counter mode (GCTR).
+ */
+ public class GOfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ bool firstStep = true;
+ int N3;
+ int N4;
+ const int C1 = 16843012; //00000001000000010000000100000100
+ const int C2 = 16843009; //00000001000000010000000100000001
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * counter mode (must have a 64 bit block size).
+ */
+ public GOfbBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+
+ if (blockSize != 8)
+ {
+ throw new ArgumentException("GCTR only for 64 bit block ciphers");
+ }
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.ofbV = new byte[cipher.GetBlockSize()];
+ this.ofbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param parameters the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is inappropriate.
+ */
+ public void Init(
+ bool forEncryption, //ignored by this CTR mode
+ ICipherParameters parameters)
+ {
+ firstStep = true;
+ N3 = 0;
+ N4 = 0;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/GCTR"
+ * and the block size in bits
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/GCTR"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (firstStep)
+ {
+ firstStep = false;
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+ N3 = bytesToint(ofbOutV, 0);
+ N4 = bytesToint(ofbOutV, 4);
+ }
+ N3 += C2;
+ N4 += C1;
+ intTobytes(N3, ofbV, 0);
+ intTobytes(N4, ofbV, 4);
+
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+ Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+ cipher.Reset();
+ }
+
+ //array of bytes to type int
+ private int bytesToint(
+ byte[] inBytes,
+ int inOff)
+ {
+ return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
+ ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
+ }
+
+ //int to array of bytes
+ private void intTobytes(
+ int num,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff + 3] = (byte)(num >> 24);
+ outBytes[outOff + 2] = (byte)(num >> 16);
+ outBytes[outOff + 1] = (byte)(num >> 8);
+ outBytes[outOff] = (byte)num;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/IAeadBlockCipher.cs b/src/core/srcbc/crypto/modes/IAeadBlockCipher.cs
new file mode 100644
index 0000000..1a7eb98
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/IAeadBlockCipher.cs
@@ -0,0 +1,90 @@
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ ///
+ /// A block cipher mode that includes authenticated encryption with a streaming mode
+ /// and optional associated data.
+ ///
+ public interface IAeadBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// Parameter can either be an AeadParameters or a ParametersWithIV object.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The block size for this cipher, in bytes.
+ int GetBlockSize();
+
+ /**
+ * Encrypt/decrypt a single byte.
+ *
+ * @param input the byte to be processed.
+ * @param outBytes the output buffer the processed byte goes into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ int ProcessByte(byte input, byte[] outBytes, int outOff);
+
+ /**
+ * Process a block of bytes from in putting the result into out.
+ *
+ * @param inBytes the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param outBytes the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
+
+ /**
+ * Finish the operation either appending or verifying the MAC at the end of the data.
+ *
+ * @param outBytes space for any resulting output data.
+ * @param outOff offset into out to start copying the data at.
+ * @return number of bytes written into out.
+ * @throws InvalidOperationException if the cipher is in an inappropriate state.
+ * @throws InvalidCipherTextException if the MAC fails to match.
+ */
+ int DoFinal(byte[] outBytes, int outOff);
+
+ /**
+ * Return the value of the MAC associated with the last stream processed.
+ *
+ * @return MAC for plaintext data.
+ */
+ byte[] GetMac();
+
+ /**
+ * Return the size of the output buffer required for a ProcessBytes
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to ProcessBytes
+ * with len bytes of input.
+ */
+ int GetUpdateOutputSize(int len);
+
+ /**
+ * Return the size of the output buffer required for a ProcessBytes plus a
+ * DoFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to ProcessBytes and DoFinal
+ * with len bytes of input.
+ */
+ int GetOutputSize(int len);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/OfbBlockCipher.cs b/src/core/srcbc/crypto/modes/OfbBlockCipher.cs
new file mode 100644
index 0000000..4929f80
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/OfbBlockCipher.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ */
+ public class OfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public OfbBlockCipher(
+ IBlockCipher cipher,
+ int blockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = blockSize / 8;
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.ofbV = new byte[cipher.GetBlockSize()];
+ this.ofbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption, //ignored by this OFB mode
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/OFB"
+ * and the block size in bits
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+ Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+ cipher.Reset();
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs b/src/core/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs
new file mode 100644
index 0000000..c5265d1
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -0,0 +1,344 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
+ * on top of a simple cipher. This class assumes the IV has been prepended
+ * to the data stream already, and just accomodates the reset after
+ * (blockSize + 2) bytes have been read.
+ *
+ * For further info see RFC 2440.
+ *
+ */
+ public class OpenPgpCfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] FR;
+ private byte[] FRE;
+ private byte[] tmp;
+
+ private readonly IBlockCipher cipher;
+ private readonly int blockSize;
+
+ private int count;
+ private bool forEncryption;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ */
+ public OpenPgpCfbBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+
+ this.blockSize = cipher.GetBlockSize();
+ this.IV = new byte[blockSize];
+ this.FR = new byte[blockSize];
+ this.FRE = new byte[blockSize];
+ this.tmp = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/PGPCFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/OpenPGPCFB"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ count = 0;
+
+ Array.Copy(IV, 0, FR, 0, FR.Length);
+
+ cipher.Reset();
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param parameters the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * Encrypt one byte of data according to CFB mode.
+ * @param data the byte to encrypt
+ * @param blockOff offset in the current block
+ * @returns the encrypted byte
+ */
+ private byte EncryptByte(byte data, int blockOff)
+ {
+ return (byte)(FRE[blockOff] ^ data);
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
+ FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+ }
+
+ Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2);
+ }
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
+ }
+
+ Array.Copy(outBytes, outOff, FR, 0, blockSize);
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ outBytes[outOff] = EncryptByte(input[inOff], 0);
+ outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1);
+
+ //
+ // do reset
+ //
+ Array.Copy(FR, 2, FR, 0, blockSize - 2);
+ Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+ }
+
+ Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2);
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ // copy in buffer so that this mode works if in and out are the same
+ Array.Copy(input, inOff, tmp, 0, blockSize);
+
+ outBytes[outOff] = EncryptByte(tmp[0], blockSize - 2);
+ outBytes[outOff + 1] = EncryptByte(tmp[1], blockSize - 1);
+
+ Array.Copy(tmp, 0, FR, blockSize - 2, 2);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ outBytes[outOff + n] = EncryptByte(tmp[n], n - 2);
+ }
+
+ Array.Copy(tmp, 2, FR, 0, blockSize - 2);
+ }
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = input[inOff + n];
+ outBytes[n] = EncryptByte(input[inOff + n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ Array.Copy(input, inOff, tmp, 0, blockSize);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ outBytes[outOff] = EncryptByte(tmp[0], 0);
+ outBytes[outOff + 1] = EncryptByte(tmp[1], 1);
+
+ Array.Copy(FR, 2, FR, 0, blockSize - 2);
+
+ FR[blockSize - 2] = tmp[0];
+ FR[blockSize - 1] = tmp[1];
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = input[inOff + n];
+ outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/modes/SicBlockCipher.cs b/src/core/srcbc/crypto/modes/SicBlockCipher.cs
new file mode 100644
index 0000000..9ccf76b
--- /dev/null
+++ b/src/core/srcbc/crypto/modes/SicBlockCipher.cs
@@ -0,0 +1,106 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher.
+ */
+ public class SicBlockCipher
+ : IBlockCipher
+ {
+ private readonly IBlockCipher cipher;
+ private readonly int blockSize;
+ private readonly byte[] IV;
+ private readonly byte[] counter;
+ private readonly byte[] counterOut;
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public SicBlockCipher(IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+ this.IV = new byte[blockSize];
+ this.counter = new byte[blockSize];
+ this.counterOut = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public void Init(
+ bool forEncryption, //ignored by this CTR mode
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV) parameters;
+ byte[] iv = ivParam.GetIV();
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+
+ Reset();
+ cipher.Init(true, ivParam.Parameters);
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/SIC"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ cipher.ProcessBlock(counter, 0, counterOut, 0);
+
+ //
+ // XOR the counterOut with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < counterOut.Length; i++)
+ {
+ output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
+ }
+
+ // Increment the counter
+ int j = counter.Length;
+ while (--j >= 0 && ++counter[j] == 0)
+ {
+ }
+
+ return counter.Length;
+ }
+
+ public void Reset()
+ {
+ Array.Copy(IV, 0, counter, 0, counter.Length);
+ cipher.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/paddings/BlockCipherPadding.cs b/src/core/srcbc/crypto/paddings/BlockCipherPadding.cs
new file mode 100644
index 0000000..2ab64fa
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/BlockCipherPadding.cs
@@ -0,0 +1,43 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * Block cipher padders are expected to conform to this interface
+ */
+ public interface IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param param parameters, if any required.
+ */
+ void Init(SecureRandom random);
+ //throws ArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ string PaddingName { get; }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ int AddPadding(byte[] input, int inOff);
+
+ /**
+ * return the number of pad bytes present in the block.
+ * @exception InvalidCipherTextException if the padding is badly formed
+ * or invalid.
+ */
+ int PadCount(byte[] input);
+ //throws InvalidCipherTextException;
+ }
+
+}
diff --git a/src/core/srcbc/crypto/paddings/ISO10126d2Padding.cs b/src/core/srcbc/crypto/paddings/ISO10126d2Padding.cs
new file mode 100644
index 0000000..890a502
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/ISO10126d2Padding.cs
@@ -0,0 +1,76 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /**
+ * A padder that adds ISO10126-2 padding to a block.
+ */
+ public class ISO10126d2Padding: IBlockCipherPadding
+ {
+ private SecureRandom random;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if available.
+ */
+ public void Init(
+ SecureRandom random)
+ //throws ArgumentException
+ {
+ this.random = (random != null) ? random : new SecureRandom();
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "ISO10126-2"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < (input.Length - 1))
+ {
+ input[inOff] = (byte)random.NextInt();
+ inOff++;
+ }
+
+ input[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(byte[] input)
+ //throws InvalidCipherTextException
+ {
+ int count = input[input.Length - 1] & 0xff;
+
+ if (count > input.Length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/paddings/ISO7816d4Padding.cs b/src/core/srcbc/crypto/paddings/ISO7816d4Padding.cs
new file mode 100644
index 0000000..1c8c5f0
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/ISO7816d4Padding.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds the padding according to the scheme referenced in
+ * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
+ */
+ public class ISO7816d4Padding
+ : IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void Init(
+ SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public string PaddingName
+ {
+ get { return "ISO7816-4"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ int added = (input.Length - inOff);
+
+ input[inOff]= (byte) 0x80;
+ inOff ++;
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input.Length - 1;
+
+ while (count > 0 && input[count] == 0)
+ {
+ count--;
+ }
+
+ if (input[count] != (byte)0x80)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return input.Length - count;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs b/src/core/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs
new file mode 100644
index 0000000..6b32fa0
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -0,0 +1,287 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The default padding mechanism used is the one outlined in Pkcs5/Pkcs7.
+ */
+ public class PaddedBufferedBlockCipher
+ : BufferedBlockCipher
+ {
+ private readonly IBlockCipherPadding padding;
+
+ /**
+ * Create a buffered block cipher with the desired padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ * @param padding the padding type.
+ */
+ public PaddedBufferedBlockCipher(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ {
+ this.cipher = cipher;
+ this.padding = padding;
+
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ /**
+ * Create a buffered block cipher Pkcs7 padding
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public PaddedBufferedBlockCipher(IBlockCipher cipher)
+ : this(cipher, new Pkcs7Padding()) { }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ SecureRandom initRandom = null;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)parameters;
+ initRandom = p.Random;
+ parameters = p.Parameters;
+ }
+
+ Reset();
+ padding.Init(initRandom);
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the minimum size of the output buffer required for an update
+ * plus a doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ if (forEncryption)
+ {
+ return total + buf.Length;
+ }
+
+ return total;
+ }
+
+ return total - leftOver + buf.Length;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.Length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.Length)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ if ((outOff + outLength) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+
+ bufOff = 0;
+ length -= gapLen;
+ inOff += gapLen;
+
+ while (length > buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, length);
+
+ bufOff += length;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer. If the buffer is currently
+ * full and padding needs to be added a call to doFinal will produce
+ * 2 * GetBlockSize() bytes.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output or we are decrypting and the input is not block size aligned.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+
+ if (forEncryption)
+ {
+ if (bufOff == blockSize)
+ {
+ if ((outOff + 2 * blockSize) > output.Length)
+ {
+ Reset();
+
+ throw new DataLengthException("output buffer too short");
+ }
+
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+
+ Reset();
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+ else
+ {
+ Reset();
+
+ throw new DataLengthException("last block incomplete in decryption");
+ }
+
+ try
+ {
+ resultLen -= padding.PadCount(buf);
+
+ Array.Copy(buf, 0, output, outOff, resultLen);
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs b/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs
new file mode 100644
index 0000000..c72a108
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs
@@ -0,0 +1,77 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds Pkcs7/Pkcs5 padding to a block.
+ */
+ public class Pkcs7Padding: IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void Init(SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "PKCS7"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = code;
+ inOff++;
+ }
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ int count = (int) input[input.Length - 1];
+
+ if (count < 1 || count > input.Length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ for (int i = 1; i <= count; i++)
+ {
+ if (input[input.Length - i] != count)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+ }
+
+ return count;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/paddings/TbcPadding.cs b/src/core/srcbc/crypto/paddings/TbcPadding.cs
new file mode 100644
index 0000000..d929849
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/TbcPadding.cs
@@ -0,0 +1,79 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /// A padder that adds Trailing-Bit-Compliment padding to a block.
+ ///
+ /// This padding pads the block out compliment of the last bit
+ /// of the plain text.
+ ///
+ ///
+ public class TbcPadding
+ : IBlockCipherPadding
+ {
+ /// Return the name of the algorithm the cipher implements.
+ /// the name of the algorithm the cipher implements.
+ ///
+ public string PaddingName
+ {
+ get { return "TBC"; }
+ }
+
+ /// Initialise the padder.
+ /// - a SecureRandom if available.
+ ///
+ public virtual void Init(SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /// add the pad bytes to the passed in block, returning the
+ /// number of bytes added.
+ ///
+ /// Note: this assumes that the last block of plain text is always
+ /// passed to it inside in. i.e. if inOff is zero, indicating the
+ /// entire block is to be overwritten with padding the value of in
+ /// should be the same as the last block of plain text.
+ ///
+ ///
+ public virtual int AddPadding(byte[] input, int inOff)
+ {
+ int count = input.Length - inOff;
+ byte code;
+
+ if (inOff > 0)
+ {
+ code = (byte)((input[inOff - 1] & 0x01) == 0?0xff:0x00);
+ }
+ else
+ {
+ code = (byte)((input[input.Length - 1] & 0x01) == 0?0xff:0x00);
+ }
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = code;
+ inOff++;
+ }
+
+ return count;
+ }
+
+ /// return the number of pad bytes present in the block.
+ public virtual int PadCount(byte[] input)
+ {
+ byte code = input[input.Length - 1];
+
+ int index = input.Length - 1;
+ while (index > 0 && input[index - 1] == code)
+ {
+ index--;
+ }
+
+ return input.Length - index;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/paddings/X923Padding.cs b/src/core/srcbc/crypto/paddings/X923Padding.cs
new file mode 100644
index 0000000..9dc7724
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/X923Padding.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds X9.23 padding to a block - if a SecureRandom is
+ * passed in random padding is assumed, otherwise padding with zeros is used.
+ */
+ public class X923Padding
+ : IBlockCipherPadding
+ {
+ private SecureRandom random;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if one is available.
+ */
+ public void Init(
+ SecureRandom random)
+ {
+ this.random = random;
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "X9.23"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < input.Length - 1)
+ {
+ if (random == null)
+ {
+ input[inOff] = 0;
+ }
+ else
+ {
+ input[inOff] = (byte)random.NextInt();
+ }
+ inOff++;
+ }
+
+ input[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input[input.Length - 1] & 0xff;
+
+ if (count > input.Length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/paddings/ZeroBytePadding.cs b/src/core/srcbc/crypto/paddings/ZeroBytePadding.cs
new file mode 100644
index 0000000..9f9e9d2
--- /dev/null
+++ b/src/core/srcbc/crypto/paddings/ZeroBytePadding.cs
@@ -0,0 +1,68 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /// A padder that adds Null byte padding to a block.
+ public class ZeroBytePadding : IBlockCipherPadding
+ {
+ /// Return the name of the algorithm the cipher implements.
+ ///
+ ///
+ /// the name of the algorithm the cipher implements.
+ ///
+ public string PaddingName
+ {
+ get { return "ZeroBytePadding"; }
+ }
+
+ /// Initialise the padder.
+ ///
+ ///
+ /// - a SecureRandom if available.
+ ///
+ public void Init(SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /// add the pad bytes to the passed in block, returning the
+ /// number of bytes added.
+ ///
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ int added = (input.Length - inOff);
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /// return the number of pad bytes present in the block.
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input.Length;
+
+ while (count > 0)
+ {
+ if (input[count - 1] != 0)
+ {
+ break;
+ }
+
+ count--;
+ }
+
+ return input.Length - count;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/AEADParameters.cs b/src/core/srcbc/crypto/parameters/AEADParameters.cs
new file mode 100644
index 0000000..f776c22
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/AEADParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class AeadParameters
+ : ICipherParameters
+ {
+ private readonly byte[] associatedText;
+ private readonly byte[] nonce;
+ private readonly KeyParameter key;
+ private readonly int macSize;
+
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ * @param associatedText associated text, if any
+ */
+ public AeadParameters(
+ KeyParameter key,
+ int macSize,
+ byte[] nonce,
+ byte[] associatedText)
+ {
+ this.key = key;
+ this.nonce = nonce;
+ this.macSize = macSize;
+ this.associatedText = associatedText;
+ }
+
+ public virtual KeyParameter Key
+ {
+ get { return key; }
+ }
+
+ public virtual int MacSize
+ {
+ get { return macSize; }
+ }
+
+ public virtual byte[] GetAssociatedText()
+ {
+ return associatedText;
+ }
+
+ public virtual byte[] GetNonce()
+ {
+ return nonce;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/CcmParameters.cs b/src/core/srcbc/crypto/parameters/CcmParameters.cs
new file mode 100644
index 0000000..a915778
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/CcmParameters.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class CcmParameters
+ : AeadParameters
+ {
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ * @param associatedText associated text, if any
+ */
+ public CcmParameters(
+ KeyParameter key,
+ int macSize,
+ byte[] nonce,
+ byte[] associatedText)
+ : base(key, macSize, nonce, associatedText)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/DHKeyGenerationParameters.cs
new file mode 100644
index 0000000..f83dfaf
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHKeyGenerationParameters.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly DHParameters parameters;
+
+ public DHKeyGenerationParameters(
+ SecureRandom random,
+ DHParameters parameters)
+ : base(random, parameters.P.BitLength)
+ {
+ this.parameters = parameters;
+ }
+
+ public DHParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHKeyParameters.cs b/src/core/srcbc/crypto/parameters/DHKeyParameters.cs
new file mode 100644
index 0000000..bd82946
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly DHParameters parameters;
+
+ protected DHKeyParameters(
+ bool isPrivate,
+ DHParameters parameters)
+ : base(isPrivate)
+ {
+ // TODO Should we allow parameters to be null?
+ this.parameters = parameters;
+ }
+
+ public DHParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHKeyParameters other = obj as DHKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHParameters.cs b/src/core/srcbc/crypto/parameters/DHParameters.cs
new file mode 100644
index 0000000..575e096
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHParameters.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHParameters
+ : ICipherParameters
+ {
+ private const int DefaultMinimumLength = 160;
+
+ private readonly BigInteger p, g, q, j;
+ private readonly int m, l;
+ private readonly DHValidationParameters validation;
+
+ private static int GetDefaultM(
+ BigInteger p,
+ int l)
+ {
+ int effectiveL = l != 0 ? l : p.BitLength - 1;
+
+ return System.Math.Min(DefaultMinimumLength, effectiveL);
+
+// return DefaultMinimumLength;
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g)
+ : this(p, g, null, GetDefaultM(p, 0), 0, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q)
+ : this(p, g, q, GetDefaultM(p, 0), 0, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int l)
+ : this(p, g, q, GetDefaultM(p, l), l, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l)
+ : this(p, g, q, m, l, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ BigInteger j,
+ DHValidationParameters validation)
+ : this(p, g, q, GetDefaultM(p, 0), 0, j, validation)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (g == null)
+ throw new ArgumentNullException("g");
+ if (!p.TestBit(0))
+ throw new ArgumentException("field must be an odd prime", "p");
+ if (g.CompareTo(BigInteger.Two) < 0
+ || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
+ throw new ArgumentException("generator must in the range [2, p - 2]", "g");
+ if (m >= p.BitLength)
+ throw new ArgumentException("m value must be < bitlength of p", "m");
+ if (l != 0 && l < m)
+ throw new ArgumentException("l value must be >= m, or zero", "l");
+ if (j != null && j.CompareTo(BigInteger.Two) < 0)
+ throw new ArgumentException("subgroup factor must be >= 2", "j");
+
+ this.p = p;
+ this.g = g;
+ this.q = q;
+ this.m = m;
+ this.l = l;
+ this.j = j;
+ this.validation = validation;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger J
+ {
+ get { return j; }
+ }
+
+ /// The minimum bitlength of the private value.
+ public int M
+ {
+ get { return m; }
+ }
+
+ /// The bitlength of the private value.
+ /// If zero, bitLength(p) - 1 will be used.
+ public int L
+ {
+ get { return l; }
+ }
+
+ public DHValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHParameters other = obj as DHParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHParameters other)
+ {
+ return p.Equals(other.p)
+ && g.Equals(other.g)
+ && Platform.Equals(q, other.q);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = p.GetHashCode() ^ g.GetHashCode();
+
+ if (q != null)
+ {
+ hc ^= q.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHPrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/DHPrivateKeyParameters.cs
new file mode 100644
index 0000000..1932ac0
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHPrivateKeyParameters.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHPrivateKeyParameters
+ : DHKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public DHPrivateKeyParameters(
+ BigInteger x,
+ DHParameters parameters)
+ : base(true, parameters)
+ {
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHPrivateKeyParameters other = obj as DHPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHPrivateKeyParameters other)
+ {
+ return x.Equals(other.x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHPublicKeyParameters.cs b/src/core/srcbc/crypto/parameters/DHPublicKeyParameters.cs
new file mode 100644
index 0000000..d081841
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHPublicKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHPublicKeyParameters
+ : DHKeyParameters
+ {
+ private readonly BigInteger y;
+
+ public DHPublicKeyParameters(
+ BigInteger y,
+ DHParameters parameters)
+ : base(false, parameters)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHPublicKeyParameters other = obj as DHPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DHValidationParameters.cs b/src/core/srcbc/crypto/parameters/DHValidationParameters.cs
new file mode 100644
index 0000000..cdd883b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DHValidationParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHValidationParameters
+ {
+ private readonly byte[] seed;
+ private readonly int counter;
+
+ public DHValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ if (seed == null)
+ throw new ArgumentNullException("seed");
+
+ this.seed = (byte[]) seed.Clone();
+ this.counter = counter;
+ }
+
+ public byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+
+ public int Counter
+ {
+ get { return counter; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHValidationParameters other = obj as DHValidationParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHValidationParameters other)
+ {
+ return counter == other.counter
+ && Arrays.AreEqual(this.seed, other.seed);
+ }
+
+ public override int GetHashCode()
+ {
+ return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DesEdeParameters.cs b/src/core/srcbc/crypto/parameters/DesEdeParameters.cs
new file mode 100644
index 0000000..20991c9
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DesEdeParameters.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DesEdeParameters
+ : DesParameters
+ {
+ /*
+ * DES-EDE Key length in bytes.
+ */
+ public const int DesEdeKeyLength = 24;
+
+ private static byte[] FixKey(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ byte[] tmp = new byte[24];
+
+ switch (keyLen)
+ {
+ case 16:
+ Array.Copy(key, keyOff, tmp, 0, 16);
+ Array.Copy(key, keyOff, tmp, 16, 8);
+ break;
+ case 24:
+ Array.Copy(key, keyOff, tmp, 0, 24);
+ break;
+ default:
+ throw new ArgumentException("Bad length for DESede key: " + keyLen, "keyLen");
+ }
+
+ if (IsWeakKey(tmp))
+ throw new ArgumentException("attempt to create weak DESede key");
+
+ return tmp;
+ }
+
+ public DesEdeParameters(
+ byte[] key)
+ : base(FixKey(key, 0, key.Length))
+ {
+ }
+
+ public DesEdeParameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : base(FixKey(key, keyOff, keyLen))
+ {
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ * @param length number of bytes making up the key
+ */
+ public static bool IsWeakKey(
+ byte[] key,
+ int offset,
+ int length)
+ {
+ for (int i = offset; i < length; i += DesKeyLength)
+ {
+ if (DesParameters.IsWeakKey(key, i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static new bool IsWeakKey(
+ byte[] key,
+ int offset)
+ {
+ return IsWeakKey(key, offset, key.Length - offset);
+ }
+
+ public static new bool IsWeakKey(
+ byte[] key)
+ {
+ return IsWeakKey(key, 0, key.Length);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DesParameters.cs b/src/core/srcbc/crypto/parameters/DesParameters.cs
new file mode 100644
index 0000000..66d6433
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DesParameters.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DesParameters
+ : KeyParameter
+ {
+ public DesParameters(
+ byte[] key)
+ : base(key)
+ {
+ if (IsWeakKey(key))
+ throw new ArgumentException("attempt to create weak DES key");
+ }
+
+ public DesParameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : base(key, keyOff, keyLen)
+ {
+ if (IsWeakKey(key, keyOff))
+ throw new ArgumentException("attempt to create weak DES key");
+ }
+
+ /*
+ * DES Key Length in bytes.
+ */
+ public const int DesKeyLength = 8;
+
+ /*
+ * Table of weak and semi-weak keys taken from Schneier pp281
+ */
+ private const int N_DES_WEAK_KEYS = 16;
+
+ private static readonly byte[] DES_weak_keys =
+ {
+ /* weak keys */
+ (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
+ (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
+ (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
+ (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
+
+ /* semi-weak keys */
+ (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
+ (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
+ (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
+ (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
+ (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
+ (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
+ (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
+ (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
+ (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
+ (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
+ (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
+ (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
+ };
+
+ /**
+ * DES has 16 weak keys. This method will check
+ * if the given DES key material is weak or semi-weak.
+ * Key material that is too short is regarded as weak.
+ *
+ * See "Applied
+ * Cryptography" by Bruce Schneier for more information.
+ *
+ * @return true if the given DES key material is weak or semi-weak,
+ * false otherwise.
+ */
+ public static bool IsWeakKey(
+ byte[] key,
+ int offset)
+ {
+ if (key.Length - offset < DesKeyLength)
+ throw new ArgumentException("key material too short.");
+
+ //nextkey:
+ for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+ {
+ bool unmatch = false;
+ for (int j = 0; j < DesKeyLength; j++)
+ {
+ if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j])
+ {
+ //continue nextkey;
+ unmatch = true;
+ break;
+ }
+ }
+
+ if (!unmatch)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static bool IsWeakKey(
+ byte[] key)
+ {
+ return IsWeakKey(key, 0);
+ }
+
+ /**
+ * DES Keys use the LSB as the odd parity bit. This can
+ * be used to check for corrupt keys.
+ *
+ * @param bytes the byte array to set the parity on.
+ */
+ public static void SetOddParity(
+ byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ int b = bytes[i];
+ bytes[i] = (byte)((b & 0xfe) |
+ ((((b >> 1) ^
+ (b >> 2) ^
+ (b >> 3) ^
+ (b >> 4) ^
+ (b >> 5) ^
+ (b >> 6) ^
+ (b >> 7)) ^ 0x01) & 0x01));
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs
new file mode 100644
index 0000000..622ac7b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly DsaParameters parameters;
+
+ public DsaKeyGenerationParameters(
+ SecureRandom random,
+ DsaParameters parameters)
+ : base(random, parameters.P.BitLength - 1)
+ {
+ this.parameters = parameters;
+ }
+
+ public DsaParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaKeyParameters.cs b/src/core/srcbc/crypto/parameters/DsaKeyParameters.cs
new file mode 100644
index 0000000..8b5d508
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly DsaParameters parameters;
+
+ public DsaKeyParameters(
+ bool isPrivate,
+ DsaParameters parameters)
+ : base(isPrivate)
+ {
+ // Note: parameters may be null
+ this.parameters = parameters;
+ }
+
+ public DsaParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaKeyParameters other = obj as DsaKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaParameters.cs b/src/core/srcbc/crypto/parameters/DsaParameters.cs
new file mode 100644
index 0000000..ec349ba
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaParameters.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaParameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, q , g;
+ private readonly DsaValidationParameters validation;
+
+ public DsaParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ : this(p, q, g, null)
+ {
+ }
+
+ public DsaParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ DsaValidationParameters parameters)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (q == null)
+ throw new ArgumentNullException("q");
+ if (g == null)
+ throw new ArgumentNullException("g");
+
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ this.validation = parameters;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public DsaValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaParameters other = obj as DsaParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaParameters other)
+ {
+ return p.Equals(other.p) && q.Equals(other.q) && g.Equals(other.g);
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ q.GetHashCode() ^ g.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs
new file mode 100644
index 0000000..3061b70
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaPrivateKeyParameters
+ : DsaKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public DsaPrivateKeyParameters(
+ BigInteger x,
+ DsaParameters parameters)
+ : base(true, parameters)
+ {
+ if (x == null)
+ throw new ArgumentNullException("x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaPrivateKeyParameters other = obj as DsaPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaPrivateKeyParameters other)
+ {
+ return x.Equals(other.x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaPublicKeyParameters.cs b/src/core/srcbc/crypto/parameters/DsaPublicKeyParameters.cs
new file mode 100644
index 0000000..5334c34
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaPublicKeyParameters.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaPublicKeyParameters
+ : DsaKeyParameters
+ {
+ private readonly BigInteger y;
+
+ public DsaPublicKeyParameters(
+ BigInteger y,
+ DsaParameters parameters)
+ : base(false, parameters)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaPublicKeyParameters other = obj as DsaPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/DsaValidationParameters.cs b/src/core/srcbc/crypto/parameters/DsaValidationParameters.cs
new file mode 100644
index 0000000..635eae1
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/DsaValidationParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaValidationParameters
+ {
+ private readonly byte[] seed;
+ private readonly int counter;
+
+ public DsaValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ if (seed == null)
+ throw new ArgumentNullException("seed");
+
+ this.seed = (byte[]) seed.Clone();
+ this.counter = counter;
+ }
+
+ public byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+
+ public int Counter
+ {
+ get { return counter; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaValidationParameters other = obj as DsaValidationParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaValidationParameters other)
+ {
+ return counter == other.counter
+ && Arrays.AreEqual(seed, other.seed);
+ }
+
+ public override int GetHashCode()
+ {
+ return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ECDomainParameters.cs b/src/core/srcbc/crypto/parameters/ECDomainParameters.cs
new file mode 100644
index 0000000..aaedaf5
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ECDomainParameters.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECDomainParameters
+ {
+ internal ECCurve curve;
+ internal byte[] seed;
+ internal ECPoint g;
+ internal BigInteger n;
+ internal BigInteger h;
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n)
+ : this(curve, g, n, BigInteger.One)
+ {
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ : this(curve, g, n, h, null)
+ {
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ if (curve == null)
+ throw new ArgumentNullException("curve");
+ if (g == null)
+ throw new ArgumentNullException("g");
+ if (n == null)
+ throw new ArgumentNullException("n");
+ if (h == null)
+ throw new ArgumentNullException("h");
+
+ this.curve = curve;
+ this.g = g;
+ this.n = n;
+ this.h = h;
+ this.seed = Arrays.Clone(seed);
+ }
+
+ public ECCurve Curve
+ {
+ get { return curve; }
+ }
+
+ public ECPoint G
+ {
+ get { return g; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+
+ public BigInteger H
+ {
+ get { return h; }
+ }
+
+ public byte[] GetSeed()
+ {
+ return Arrays.Clone(seed);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECDomainParameters other = obj as ECDomainParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECDomainParameters other)
+ {
+ return curve.Equals(other.curve)
+ && g.Equals(other.g)
+ && n.Equals(other.n)
+ && h.Equals(other.h)
+ && Arrays.AreEqual(seed, other.seed);
+ }
+
+ public override int GetHashCode()
+ {
+ return curve.GetHashCode()
+ ^ g.GetHashCode()
+ ^ n.GetHashCode()
+ ^ h.GetHashCode()
+ ^ Arrays.GetHashCode(seed);
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/ECKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/ECKeyGenerationParameters.cs
new file mode 100644
index 0000000..e55eaac
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ECKeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly ECDomainParameters domainParams;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ public ECKeyGenerationParameters(
+ ECDomainParameters domainParameters,
+ SecureRandom random)
+ : base(random, domainParameters.N.BitLength)
+ {
+ this.domainParams = domainParameters;
+ }
+
+ public ECKeyGenerationParameters(
+ DerObjectIdentifier publicKeyParamSet,
+ SecureRandom random)
+ : this(LookupParameters(publicKeyParamSet), random)
+ {
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public ECDomainParameters DomainParameters
+ {
+ get { return domainParams; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ private static ECDomainParameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return p;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ECKeyParameters.cs b/src/core/srcbc/crypto/parameters/ECKeyParameters.cs
new file mode 100644
index 0000000..9dab882
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ECKeyParameters.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public abstract class ECKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly string algorithm;
+ private readonly ECDomainParameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ protected ECKeyParameters(
+ string algorithm,
+ bool isPrivate,
+ ECDomainParameters parameters)
+ : base(isPrivate)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ this.parameters = parameters;
+ }
+
+ protected ECKeyParameters(
+ string algorithm,
+ bool isPrivate,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(isPrivate)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ this.parameters = LookupParameters(publicKeyParamSet);
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public string AlgorithmName
+ {
+ get { return algorithm; }
+ }
+
+ public ECDomainParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECDomainParameters other = obj as ECDomainParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECKeyParameters other)
+ {
+ return parameters.Equals(other.parameters) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return parameters.GetHashCode() ^ base.GetHashCode();
+ }
+
+ private string VerifyAlgorithmName(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ switch (upper)
+ {
+ case "EC":
+ case "ECDSA":
+ case "ECGOST3410":
+ case "ECDH":
+ case "ECDHC":
+ break;
+ default:
+ throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
+ }
+
+ return upper;
+ }
+
+ private static ECDomainParameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return p;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ECPrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/ECPrivateKeyParameters.cs
new file mode 100644
index 0000000..53f1861
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ECPrivateKeyParameters.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECPrivateKeyParameters
+ : ECKeyParameters
+ {
+ private readonly BigInteger d;
+
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ ECDomainParameters parameters)
+ : this("EC", d, parameters)
+ {
+ }
+
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ DerObjectIdentifier publicKeyParamSet)
+ : base("ECGOST3410", true, publicKeyParamSet)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ this.d = d;
+ }
+
+ public ECPrivateKeyParameters(
+ string algorithm,
+ BigInteger d,
+ ECDomainParameters parameters)
+ : base(algorithm, true, parameters)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ this.d = d;
+ }
+
+ public BigInteger D
+ {
+ get { return d; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECPrivateKeyParameters other = obj as ECPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECPrivateKeyParameters other)
+ {
+ return d.Equals(other.d) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return d.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ECPublicKeyParameters.cs b/src/core/srcbc/crypto/parameters/ECPublicKeyParameters.cs
new file mode 100644
index 0000000..48dfd0c
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ECPublicKeyParameters.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECPublicKeyParameters
+ : ECKeyParameters
+ {
+ private readonly ECPoint q;
+
+ public ECPublicKeyParameters(
+ ECPoint q,
+ ECDomainParameters parameters)
+ : this("EC", q, parameters)
+ {
+ }
+
+ public ECPublicKeyParameters(
+ ECPoint q,
+ DerObjectIdentifier publicKeyParamSet)
+ : base("ECGOST3410", false, publicKeyParamSet)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.q = q;
+ }
+
+ public ECPublicKeyParameters(
+ string algorithm,
+ ECPoint q,
+ ECDomainParameters parameters)
+ : base(algorithm, false, parameters)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.q = q;
+ }
+
+ public ECPoint Q
+ {
+ get { return q; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECPublicKeyParameters other = obj as ECPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECPublicKeyParameters other)
+ {
+ return q.Equals(other.q) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return q.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs
new file mode 100644
index 0000000..fb00bf6
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly ElGamalParameters parameters;
+
+ public ElGamalKeyGenerationParameters(
+ SecureRandom random,
+ ElGamalParameters parameters)
+ : base(random, parameters.P.BitLength)
+ {
+ this.parameters = parameters;
+ }
+
+ public ElGamalParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ElGamalKeyParameters.cs b/src/core/srcbc/crypto/parameters/ElGamalKeyParameters.cs
new file mode 100644
index 0000000..d545a98
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ElGamalKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly ElGamalParameters parameters;
+
+ protected ElGamalKeyParameters(
+ bool isPrivate,
+ ElGamalParameters parameters)
+ : base(isPrivate)
+ {
+ // TODO Should we allow 'parameters' to be null?
+ this.parameters = parameters;
+ }
+
+ public ElGamalParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalKeyParameters other = obj as ElGamalKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ElGamalParameters.cs b/src/core/srcbc/crypto/parameters/ElGamalParameters.cs
new file mode 100644
index 0000000..9e7799b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ElGamalParameters.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalParameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, g;
+ private readonly int l;
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g)
+ : this(p, g, 0)
+ {
+ }
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g,
+ int l)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (g == null)
+ throw new ArgumentNullException("g");
+
+ this.p = p;
+ this.g = g;
+ this.l = l;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ /**
+ * return the generator - g
+ */
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ /**
+ * return private value limit - l
+ */
+ public int L
+ {
+ get { return l; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalParameters other = obj as ElGamalParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalParameters other)
+ {
+ return p.Equals(other.p) && g.Equals(other.g) && l == other.l;
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ g.GetHashCode() ^ l;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs
new file mode 100644
index 0000000..73dbd8e
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalPrivateKeyParameters
+ : ElGamalKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public ElGamalPrivateKeyParameters(
+ BigInteger x,
+ ElGamalParameters parameters)
+ : base(true, parameters)
+ {
+ if (x == null)
+ throw new ArgumentNullException("x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalPrivateKeyParameters other = obj as ElGamalPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalPrivateKeyParameters other)
+ {
+ return other.x.Equals(x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs b/src/core/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs
new file mode 100644
index 0000000..799f293
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalPublicKeyParameters
+ : ElGamalKeyParameters
+ {
+ private readonly BigInteger y;
+
+ public ElGamalPublicKeyParameters(
+ BigInteger y,
+ ElGamalParameters parameters)
+ : base(false, parameters)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalPublicKeyParameters other = obj as ElGamalPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs
new file mode 100644
index 0000000..3343717
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly Gost3410Parameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ public Gost3410KeyGenerationParameters(
+ SecureRandom random,
+ Gost3410Parameters parameters)
+ : base(random, parameters.P.BitLength - 1)
+ {
+ this.parameters = parameters;
+ }
+
+ public Gost3410KeyGenerationParameters(
+ SecureRandom random,
+ DerObjectIdentifier publicKeyParamSet)
+ : this(random, LookupParameters(publicKeyParamSet))
+ {
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public Gost3410Parameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ private static Gost3410Parameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return new Gost3410Parameters(p.P, p.Q, p.A);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410KeyParameters.cs b/src/core/srcbc/crypto/parameters/GOST3410KeyParameters.cs
new file mode 100644
index 0000000..98b5767
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410KeyParameters.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public abstract class Gost3410KeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly Gost3410Parameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ protected Gost3410KeyParameters(
+ bool isPrivate,
+ Gost3410Parameters parameters)
+ : base(isPrivate)
+ {
+ this.parameters = parameters;
+ }
+
+ protected Gost3410KeyParameters(
+ bool isPrivate,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(isPrivate)
+ {
+ this.parameters = LookupParameters(publicKeyParamSet);
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public Gost3410Parameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ // TODO Implement Equals/GetHashCode
+
+ private static Gost3410Parameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return new Gost3410Parameters(p.P, p.Q, p.A);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410Parameters.cs b/src/core/srcbc/crypto/parameters/GOST3410Parameters.cs
new file mode 100644
index 0000000..d4b4029
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410Parameters.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410Parameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, q, a;
+ private readonly Gost3410ValidationParameters validation;
+
+ public Gost3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ : this(p, q, a, null)
+ {
+ }
+
+ public Gost3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a,
+ Gost3410ValidationParameters validation)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (q == null)
+ throw new ArgumentNullException("q");
+ if (a == null)
+ throw new ArgumentNullException("a");
+
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ this.validation = validation;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger A
+ {
+ get { return a; }
+ }
+
+ public Gost3410ValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ Gost3410Parameters other = obj as Gost3410Parameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ Gost3410Parameters other)
+ {
+ return p.Equals(other.p) && q.Equals(other.q) && a.Equals(other.a);
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ q.GetHashCode() ^ a.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs
new file mode 100644
index 0000000..6348c36
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410PrivateKeyParameters
+ : Gost3410KeyParameters
+ {
+ private readonly BigInteger x;
+
+ public Gost3410PrivateKeyParameters(
+ BigInteger x,
+ Gost3410Parameters parameters)
+ : base(true, parameters)
+ {
+ if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+ throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+ this.x = x;
+ }
+
+ public Gost3410PrivateKeyParameters(
+ BigInteger x,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(true, publicKeyParamSet)
+ {
+ if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+ throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs b/src/core/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs
new file mode 100644
index 0000000..7f3286b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410PublicKeyParameters
+ : Gost3410KeyParameters
+ {
+ private readonly BigInteger y;
+
+ public Gost3410PublicKeyParameters(
+ BigInteger y,
+ Gost3410Parameters parameters)
+ : base(false, parameters)
+ {
+ if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+ throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+ this.y = y;
+ }
+
+ public Gost3410PublicKeyParameters(
+ BigInteger y,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(false, publicKeyParamSet)
+ {
+ if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+ throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/GOST3410ValidationParameters.cs b/src/core/srcbc/crypto/parameters/GOST3410ValidationParameters.cs
new file mode 100644
index 0000000..6ff41c5
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/GOST3410ValidationParameters.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410ValidationParameters
+ {
+ private int x0;
+ private int c;
+ private long x0L;
+ private long cL;
+
+ public Gost3410ValidationParameters(
+ int x0,
+ int c)
+ {
+ this.x0 = x0;
+ this.c = c;
+ }
+
+ public Gost3410ValidationParameters(
+ long x0L,
+ long cL)
+ {
+ this.x0L = x0L;
+ this.cL = cL;
+ }
+
+ public int C { get { return c; } }
+ public int X0 { get { return x0; } }
+ public long CL { get { return cL; } }
+ public long X0L { get { return x0L; } }
+
+ public override bool Equals(
+ object obj)
+ {
+ Gost3410ValidationParameters other = obj as Gost3410ValidationParameters;
+
+ return other != null
+ && other.c == this.c
+ && other.x0 == this.x0
+ && other.cL == this.cL
+ && other.x0L == this.x0L;
+ }
+
+ public override int GetHashCode()
+ {
+ return c.GetHashCode() ^ x0.GetHashCode() ^ cL.GetHashCode() ^ x0L.GetHashCode();
+ }
+
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ISO18033KDFParameters.cs b/src/core/srcbc/crypto/parameters/ISO18033KDFParameters.cs
new file mode 100644
index 0000000..e82dc99
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ISO18033KDFParameters.cs
@@ -0,0 +1,25 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for Key derivation functions for ISO-18033
+ */
+ public class Iso18033KdfParameters
+ : IDerivationParameters
+ {
+ byte[] seed;
+
+ public Iso18033KdfParameters(
+ byte[] seed)
+ {
+ this.seed = seed;
+ }
+
+ public byte[] GetSeed()
+ {
+ return seed;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/IesParameters.cs b/src/core/srcbc/crypto/parameters/IesParameters.cs
new file mode 100644
index 0000000..eee6be0
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/IesParameters.cs
@@ -0,0 +1,49 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for using an integrated cipher in stream mode.
+ */
+ public class IesParameters : ICipherParameters
+ {
+ private byte[] derivation;
+ private byte[] encoding;
+ private int macKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ */
+ public IesParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize)
+ {
+ this.derivation = derivation;
+ this.encoding = encoding;
+ this.macKeySize = macKeySize;
+ }
+
+ public byte[] GetDerivationV()
+ {
+ return derivation;
+ }
+
+ public byte[] GetEncodingV()
+ {
+ return encoding;
+ }
+
+ public int MacKeySize
+ {
+ get
+ {
+ return macKeySize;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/IesWithCipherParameters.cs b/src/core/srcbc/crypto/parameters/IesWithCipherParameters.cs
new file mode 100644
index 0000000..b2f8804
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/IesWithCipherParameters.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class IesWithCipherParameters : IesParameters
+ {
+ private int cipherKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ * @param cipherKeySize the size of the associated Cipher key (in bits).
+ */
+ public IesWithCipherParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize,
+ int cipherKeySize) : base(derivation, encoding, macKeySize)
+ {
+ this.cipherKeySize = cipherKeySize;
+ }
+
+ public int CipherKeySize
+ {
+ get
+ {
+ return cipherKeySize;
+ }
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/KdfParameters.cs b/src/core/srcbc/crypto/parameters/KdfParameters.cs
new file mode 100644
index 0000000..7eb4c09
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/KdfParameters.cs
@@ -0,0 +1,33 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for Key derivation functions for IEEE P1363a
+ */
+ public class KdfParameters : IDerivationParameters
+ {
+ byte[] iv;
+ byte[] shared;
+
+ public KdfParameters(
+ byte[] shared,
+ byte[] iv)
+ {
+ this.shared = shared;
+ this.iv = iv;
+ }
+
+ public byte[] GetSharedSecret()
+ {
+ return shared;
+ }
+
+ public byte[] GetIV()
+ {
+ return iv;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/KeyParameter.cs b/src/core/srcbc/crypto/parameters/KeyParameter.cs
new file mode 100644
index 0000000..96b5708
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/KeyParameter.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class KeyParameter
+ : ICipherParameters
+ {
+ private readonly byte[] key;
+
+ public KeyParameter(
+ byte[] key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ this.key = (byte[]) key.Clone();
+ }
+
+ public KeyParameter(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (keyOff < 0 || keyOff > key.Length)
+ throw new ArgumentOutOfRangeException("keyOff");
+ if (keyLen < 0 || (keyOff + keyLen) > key.Length)
+ throw new ArgumentOutOfRangeException("keyLen");
+
+ this.key = new byte[keyLen];
+ Array.Copy(key, keyOff, this.key, 0, keyLen);
+ }
+
+ public byte[] GetKey()
+ {
+ return (byte[]) key.Clone();
+ }
+ }
+
+}
diff --git a/src/core/srcbc/crypto/parameters/MgfParameters.cs b/src/core/srcbc/crypto/parameters/MgfParameters.cs
new file mode 100644
index 0000000..5fbc16a
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/MgfParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /// Parameters for mask derivation functions.
+ public class MgfParameters
+ : IDerivationParameters
+ {
+ private readonly byte[] seed;
+
+ public MgfParameters(
+ byte[] seed)
+ : this(seed, 0, seed.Length)
+ {
+ }
+
+ public MgfParameters(
+ byte[] seed,
+ int off,
+ int len)
+ {
+ this.seed = new byte[len];
+ Array.Copy(seed, off, this.seed, 0, len);
+ }
+
+ public byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
new file mode 100644
index 0000000..828592a
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Parameters for NaccacheStern public private key generation. For details on
+ * this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyGenerationParameters : KeyGenerationParameters
+ {
+ // private BigInteger publicExponent;
+ private readonly int certainty;
+ private readonly int countSmallPrimes;
+ private bool debug;
+
+ /**
+ * Parameters for generating a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param countSmallPrimes
+ * How many small key factors are desired
+ */
+ public NaccacheSternKeyGenerationParameters(
+ SecureRandom random,
+ int strength,
+ int certainty,
+ int countSmallPrimes)
+ : this(random, strength, certainty, countSmallPrimes, false)
+ {
+ }
+
+ /**
+ * Parameters for a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param cntSmallPrimes
+ * How many small key factors are desired
+ * @param debug
+ * Turn debugging on or off (reveals secret information, use with
+ * caution)
+ */
+ public NaccacheSternKeyGenerationParameters(SecureRandom random,
+ int strength,
+ int certainty,
+ int countSmallPrimes,
+ bool debug)
+ : base(random, strength)
+ {
+ if (countSmallPrimes % 2 == 1)
+ {
+ throw new ArgumentException("countSmallPrimes must be a multiple of 2");
+ }
+ if (countSmallPrimes < 30)
+ {
+ throw new ArgumentException("countSmallPrimes must be >= 30 for security reasons");
+ }
+ this.certainty = certainty;
+ this.countSmallPrimes = countSmallPrimes;
+ this.debug = debug;
+ }
+
+ /**
+ * @return Returns the certainty.
+ */
+ public int Certainty
+ {
+ get { return certainty; }
+ }
+
+ /**
+ * @return Returns the countSmallPrimes.
+ */
+ public int CountSmallPrimes
+ {
+ get { return countSmallPrimes; }
+ }
+
+ public bool IsDebug
+ {
+ get { return debug; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs b/src/core/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs
new file mode 100644
index 0000000..4604170
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Public key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyParameters : AsymmetricKeyParameter
+ {
+ private readonly BigInteger g, n;
+ private readonly int lowerSigmaBound;
+
+ /**
+ * @param privateKey
+ */
+ public NaccacheSternKeyParameters(bool privateKey, BigInteger g, BigInteger n, int lowerSigmaBound)
+ : base(privateKey)
+ {
+ this.g = g;
+ this.n = n;
+ this.lowerSigmaBound = lowerSigmaBound;
+ }
+
+ /**
+ * @return Returns the g.
+ */
+ public BigInteger G { get { return g; } }
+
+ /**
+ * @return Returns the lowerSigmaBound.
+ */
+ public int LowerSigmaBound { get { return lowerSigmaBound; } }
+
+ /**
+ * @return Returns the n.
+ */
+ public BigInteger Modulus { get { return n; } }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs b/src/core/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
new file mode 100644
index 0000000..c4c9419
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Private key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternPrivateKeyParameters : NaccacheSternKeyParameters
+ {
+ private readonly BigInteger phiN;
+ private readonly ArrayList smallPrimes;
+
+ /**
+ * Constructs a NaccacheSternPrivateKey
+ *
+ * @param g
+ * the public enryption parameter g
+ * @param n
+ * the public modulus n = p*q
+ * @param lowerSigmaBound
+ * the public lower sigma bound up to which data can be encrypted
+ * @param smallPrimes
+ * the small primes, of which sigma is constructed in the right
+ * order
+ * @param phi_n
+ * the private modulus phi(n) = (p-1)(q-1)
+ */
+ public NaccacheSternPrivateKeyParameters(
+ BigInteger g,
+ BigInteger n,
+ int lowerSigmaBound,
+ ArrayList smallPrimes,
+ BigInteger phiN)
+ : base(true, g, n, lowerSigmaBound)
+ {
+ this.smallPrimes = smallPrimes;
+ this.phiN = phiN;
+ }
+
+ public BigInteger PhiN
+ {
+ get { return phiN; }
+ }
+
+ public ArrayList SmallPrimes
+ {
+ get { return smallPrimes; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ParametersWithIV.cs b/src/core/srcbc/crypto/parameters/ParametersWithIV.cs
new file mode 100644
index 0000000..85bee1f
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ParametersWithIV.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithIV
+ : ICipherParameters
+ {
+ private readonly ICipherParameters parameters;
+ private readonly byte[] iv;
+
+ public ParametersWithIV(
+ ICipherParameters parameters,
+ byte[] iv)
+ : this(parameters, iv, 0, iv.Length)
+ {
+ }
+
+ public ParametersWithIV(
+ ICipherParameters parameters,
+ byte[] iv,
+ int ivOff,
+ int ivLen)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+ if (iv == null)
+ throw new ArgumentNullException("iv");
+
+ this.parameters = parameters;
+ this.iv = new byte[ivLen];
+ Array.Copy(iv, ivOff, this.iv, 0, ivLen);
+ }
+
+ public byte[] GetIV()
+ {
+ return (byte[]) iv.Clone();
+ }
+
+ public ICipherParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ParametersWithRandom.cs b/src/core/srcbc/crypto/parameters/ParametersWithRandom.cs
new file mode 100644
index 0000000..aecc30b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ParametersWithRandom.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithRandom
+ : ICipherParameters
+ {
+ private readonly ICipherParameters parameters;
+ private readonly SecureRandom random;
+
+ public ParametersWithRandom(
+ ICipherParameters parameters,
+ SecureRandom random)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("random");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ this.parameters = parameters;
+ this.random = random;
+ }
+
+ public ParametersWithRandom(
+ ICipherParameters parameters)
+ : this(parameters, new SecureRandom())
+ {
+ }
+
+ [Obsolete("Use Random property instead")]
+ public SecureRandom GetRandom()
+ {
+ return Random;
+ }
+
+ public SecureRandom Random
+ {
+ get { return random; }
+ }
+
+ public ICipherParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ParametersWithSBox.cs b/src/core/srcbc/crypto/parameters/ParametersWithSBox.cs
new file mode 100644
index 0000000..2c57528
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ParametersWithSBox.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithSBox : ICipherParameters
+ {
+ private ICipherParameters parameters;
+ private byte[] sBox;
+
+ public ParametersWithSBox(
+ ICipherParameters parameters,
+ byte[] sBox)
+ {
+ this.parameters = parameters;
+ this.sBox = sBox;
+ }
+
+ public byte[] GetSBox() { return sBox; }
+
+ public ICipherParameters Parameters { get { return parameters; } }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/ParametersWithSalt.cs b/src/core/srcbc/crypto/parameters/ParametersWithSalt.cs
new file mode 100644
index 0000000..7ada5b7
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/ParametersWithSalt.cs
@@ -0,0 +1,39 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+ /// Cipher parameters with a fixed salt value associated with them.
+ public class ParametersWithSalt : ICipherParameters
+ {
+ private byte[] salt;
+ private ICipherParameters parameters;
+
+ public ParametersWithSalt(ICipherParameters parameters, byte[] salt):this(parameters, salt, 0, salt.Length)
+ {
+ }
+
+ public ParametersWithSalt(ICipherParameters parameters, byte[] salt, int saltOff, int saltLen)
+ {
+ this.salt = new byte[saltLen];
+ this.parameters = parameters;
+
+ Array.Copy(salt, saltOff, this.salt, 0, saltLen);
+ }
+
+ public byte[] GetSalt()
+ {
+ return salt;
+ }
+
+ public ICipherParameters Parameters
+ {
+ get
+ {
+ return parameters;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RC2Parameters.cs b/src/core/srcbc/crypto/parameters/RC2Parameters.cs
new file mode 100644
index 0000000..cb0d38b
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RC2Parameters.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RC2Parameters
+ : KeyParameter
+ {
+ private readonly int bits;
+
+ public RC2Parameters(
+ byte[] key)
+ : this(key, (key.Length > 128) ? 1024 : (key.Length * 8))
+ {
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : this(key, keyOff, keyLen, (keyLen > 128) ? 1024 : (keyLen * 8))
+ {
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int bits)
+ : base(key)
+ {
+ this.bits = bits;
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int keyOff,
+ int keyLen,
+ int bits)
+ : base(key, keyOff, keyLen)
+ {
+ this.bits = bits;
+ }
+
+ public int EffectiveKeyBits
+ {
+ get { return bits; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RC5Parameters.cs b/src/core/srcbc/crypto/parameters/RC5Parameters.cs
new file mode 100644
index 0000000..d84c659
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RC5Parameters.cs
@@ -0,0 +1,27 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RC5Parameters
+ : KeyParameter
+ {
+ private readonly int rounds;
+
+ public RC5Parameters(
+ byte[] key,
+ int rounds)
+ : base(key)
+ {
+ if (key.Length > 255)
+ throw new ArgumentException("RC5 key length can be no greater than 255");
+
+ this.rounds = rounds;
+ }
+
+ public int Rounds
+ {
+ get { return rounds; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RSABlindingParameters.cs b/src/core/srcbc/crypto/parameters/RSABlindingParameters.cs
new file mode 100644
index 0000000..6ccda67
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RSABlindingParameters.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaBlindingParameters
+ : ICipherParameters
+ {
+ private readonly RsaKeyParameters publicKey;
+ private readonly BigInteger blindingFactor;
+
+ public RsaBlindingParameters(
+ RsaKeyParameters publicKey,
+ BigInteger blindingFactor)
+ {
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("RSA parameters should be for a public key");
+
+ this.publicKey = publicKey;
+ this.blindingFactor = blindingFactor;
+ }
+
+ public RsaKeyParameters PublicKey
+ {
+ get { return publicKey; }
+ }
+
+ public BigInteger BlindingFactor
+ {
+ get { return blindingFactor; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs b/src/core/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs
new file mode 100644
index 0000000..1a70f5d
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly BigInteger publicExponent;
+ private readonly int certainty;
+
+ public RsaKeyGenerationParameters(
+ BigInteger publicExponent,
+ SecureRandom random,
+ int strength,
+ int certainty)
+ : base(random, strength)
+ {
+ this.publicExponent = publicExponent;
+ this.certainty = certainty;
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return publicExponent; }
+ }
+
+ public int Certainty
+ {
+ get { return certainty; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ RsaKeyGenerationParameters other = obj as RsaKeyGenerationParameters;
+
+ if (other == null)
+ {
+ return false;
+ }
+
+ return certainty == other.certainty
+ && publicExponent.Equals(other.publicExponent);
+ }
+
+ public override int GetHashCode()
+ {
+ return certainty.GetHashCode() ^ publicExponent.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RsaKeyParameters.cs b/src/core/srcbc/crypto/parameters/RsaKeyParameters.cs
new file mode 100644
index 0000000..0158747
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RsaKeyParameters.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly BigInteger modulus;
+ private readonly BigInteger exponent;
+
+ public RsaKeyParameters(
+ bool isPrivate,
+ BigInteger modulus,
+ BigInteger exponent)
+ : base(isPrivate)
+ {
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ public BigInteger Modulus
+ {
+ get { return modulus; }
+ }
+
+ public BigInteger Exponent
+ {
+ get { return exponent; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ RsaKeyParameters kp = obj as RsaKeyParameters;
+
+ if (kp == null)
+ {
+ return false;
+ }
+
+ return kp.IsPrivate == this.IsPrivate
+ && kp.Modulus.Equals(this.modulus)
+ && kp.Exponent.Equals(this.exponent);
+ }
+
+ public override int GetHashCode()
+ {
+ return modulus.GetHashCode() ^ exponent.GetHashCode() ^ IsPrivate.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs b/src/core/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs
new file mode 100644
index 0000000..d2e5e42
--- /dev/null
+++ b/src/core/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaPrivateCrtKeyParameters
+ : RsaKeyParameters
+ {
+ private readonly BigInteger e, p, q, dP, dQ, qInv;
+
+ public RsaPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ : base(true, modulus, privateExponent)
+ {
+ this.e = publicExponent;
+ this.p = p;
+ this.q = q;
+ this.dP = dP;
+ this.dQ = dQ;
+ this.qInv = qInv;
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return e; }
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger DP
+ {
+ get { return dP; }
+ }
+
+ public BigInteger DQ
+ {
+ get { return dQ; }
+ }
+
+ public BigInteger QInv
+ {
+ get { return qInv; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters;
+
+ if (kp == null)
+ return false;
+
+ return kp.DP.Equals(dP)
+ && kp.DQ.Equals(dQ)
+ && kp.Exponent.Equals(this.Exponent)
+ && kp.Modulus.Equals(this.Modulus)
+ && kp.P.Equals(p)
+ && kp.Q.Equals(q)
+ && kp.PublicExponent.Equals(e)
+ && kp.QInv.Equals(qInv);
+ }
+
+ public override int GetHashCode()
+ {
+ return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode()
+ ^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/prng/CryptoApiRandomGenerator.cs b/src/core/srcbc/crypto/prng/CryptoApiRandomGenerator.cs
new file mode 100644
index 0000000..bc82ec0
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/CryptoApiRandomGenerator.cs
@@ -0,0 +1,61 @@
+#if !NETCF_1_0
+
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ ///
+ /// Uses Microsoft's RNGCryptoServiceProvider
+ ///
+ public class CryptoApiRandomGenerator
+ : IRandomGenerator
+ {
+ private readonly RNGCryptoServiceProvider rndProv;
+
+ public CryptoApiRandomGenerator()
+ {
+ rndProv = new RNGCryptoServiceProvider();
+ }
+
+ #region IRandomGenerator Members
+
+ public virtual void AddSeedMaterial(byte[] seed)
+ {
+ // We don't care about the seed
+ }
+
+ public virtual void AddSeedMaterial(long seed)
+ {
+ // We don't care about the seed
+ }
+
+ public virtual void NextBytes(byte[] bytes)
+ {
+ rndProv.GetBytes(bytes);
+ }
+
+ public virtual void NextBytes(byte[] bytes, int start, int len)
+ {
+ if (start < 0)
+ throw new ArgumentException("Start offset cannot be negative", "start");
+ if (bytes.Length < (start + len))
+ throw new ArgumentException("Byte array too small for requested offset and length");
+
+ if (bytes.Length == len && start == 0)
+ {
+ NextBytes(bytes);
+ }
+ else
+ {
+ byte[] tmpBuf = new byte[len];
+ rndProv.GetBytes(tmpBuf);
+ Array.Copy(tmpBuf, 0, bytes, start, len);
+ }
+ }
+
+ #endregion
+ }
+}
+
+#endif
diff --git a/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs b/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs
new file mode 100644
index 0000000..5f0cc75
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Random generation based on the digest with counter. Calling addSeedMaterial will
+ * always increase the entropy of the hash.
+ *
+ * Internal access to the digest is syncrhonized so a single one of these can be shared.
+ *
+ */
+ public class DigestRandomGenerator
+ : IRandomGenerator
+ {
+ private long counter;
+ private IDigest digest;
+ private byte[] state;
+
+ public DigestRandomGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.state = new byte[digest.GetDigestSize()];
+ this.counter = 1;
+ }
+
+ public void AddSeedMaterial(
+ byte[] inSeed)
+ {
+ lock (this)
+ {
+ DigestUpdate(inSeed);
+ }
+ }
+
+ public void AddSeedMaterial(
+ long rSeed)
+ {
+ lock (this)
+ {
+ for (int i = 0; i != 8; i++)
+ {
+ DigestUpdate((byte)rSeed);
+// rSeed >>>= 8;
+ rSeed >>= 8;
+ }
+ }
+ }
+
+ public void NextBytes(
+ byte[] bytes)
+ {
+ NextBytes(bytes, 0, bytes.Length);
+ }
+
+ public void NextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ lock (this)
+ {
+ int stateOff = 0;
+
+ DigestDoFinal(state);
+
+ int end = start + len;
+ for (int i = start; i < end; ++i)
+ {
+ if (stateOff == state.Length)
+ {
+ DigestUpdate(counter++);
+ DigestUpdate(state);
+ DigestDoFinal(state);
+ stateOff = 0;
+ }
+ bytes[i] = state[stateOff++];
+ }
+
+ DigestUpdate(counter++);
+ DigestUpdate(state);
+ }
+ }
+
+ private void DigestUpdate(long seed)
+ {
+ for (int i = 0; i != 8; i++)
+ {
+ digest.Update((byte)seed);
+// seed >>>= 8;
+ seed >>= 8;
+ }
+ }
+
+ private void DigestUpdate(byte[] inSeed)
+ {
+ digest.BlockUpdate(inSeed, 0, inSeed.Length);
+ }
+
+ private void DigestDoFinal(byte[] result)
+ {
+ digest.DoFinal(result, 0);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/prng/IRandomGenerator.cs b/src/core/srcbc/crypto/prng/IRandomGenerator.cs
new file mode 100644
index 0000000..36c7dff
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/IRandomGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /// Generic interface for objects generating random bytes.
+ public interface IRandomGenerator
+ {
+ /// Add more seed material to the generator.
+ /// A byte array to be mixed into the generator's state.
+ void AddSeedMaterial(byte[] seed);
+
+ /// Add more seed material to the generator.
+ /// A long value to be mixed into the generator's state.
+ void AddSeedMaterial(long seed);
+
+ /// Fill byte array with random values.
+ /// Array to be filled.
+ void NextBytes(byte[] bytes);
+
+ /// Fill byte array with random values.
+ /// Array to receive bytes.
+ /// Index to start filling at.
+ /// Length of segment to fill.
+ void NextBytes(byte[] bytes, int start, int len);
+ }
+}
diff --git a/src/core/srcbc/crypto/prng/ReversedWindowGenerator.cs b/src/core/srcbc/crypto/prng/ReversedWindowGenerator.cs
new file mode 100644
index 0000000..ec121e2
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/ReversedWindowGenerator.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ ///
+ /// Takes bytes generated by an underling RandomGenerator and reverses the order in
+ /// each small window (of configurable size).
+ ///
+ /// Access to internals is synchronized so a single one of these can be shared.
+ ///
+ ///
+ public class ReversedWindowGenerator
+ : IRandomGenerator
+ {
+ private readonly IRandomGenerator generator;
+
+ private byte[] window;
+ private int windowCount;
+
+ public ReversedWindowGenerator(
+ IRandomGenerator generator,
+ int windowSize)
+ {
+ if (generator == null)
+ throw new ArgumentNullException("generator");
+ if (windowSize < 2)
+ throw new ArgumentException("Window size must be at least 2", "windowSize");
+
+ this.generator = generator;
+ this.window = new byte[windowSize];
+ }
+
+ /// Add more seed material to the generator.
+ /// A byte array to be mixed into the generator's state.
+ public virtual void AddSeedMaterial(
+ byte[] seed)
+ {
+ lock (this)
+ {
+ windowCount = 0;
+ generator.AddSeedMaterial(seed);
+ }
+ }
+
+ /// Add more seed material to the generator.
+ /// A long value to be mixed into the generator's state.
+ public virtual void AddSeedMaterial(
+ long seed)
+ {
+ lock (this)
+ {
+ windowCount = 0;
+ generator.AddSeedMaterial(seed);
+ }
+ }
+
+ /// Fill byte array with random values.
+ /// Array to be filled.
+ public virtual void NextBytes(
+ byte[] bytes)
+ {
+ doNextBytes(bytes, 0, bytes.Length);
+ }
+
+ /// Fill byte array with random values.
+ /// Array to receive bytes.
+ /// Index to start filling at.
+ /// Length of segment to fill.
+ public virtual void NextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ doNextBytes(bytes, start, len);
+ }
+
+ private void doNextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ lock (this)
+ {
+ int done = 0;
+ while (done < len)
+ {
+ if (windowCount < 1)
+ {
+ generator.NextBytes(window, 0, window.Length);
+ windowCount = window.Length;
+ }
+
+ bytes[start + done++] = window[--windowCount];
+ }
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/prng/ThreadedSeedGenerator.cs b/src/core/srcbc/crypto/prng/ThreadedSeedGenerator.cs
new file mode 100644
index 0000000..ef5e8dc
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/ThreadedSeedGenerator.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Threading;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * A thread based seed generator - one source of randomness.
+ *
+ * Based on an idea from Marcus Lippert.
+ *
+ */
+ public class ThreadedSeedGenerator
+ {
+ private class SeedGenerator
+ {
+#if NETCF_1_0
+ // No volatile keyword, but all fields implicitly volatile anyway
+ private int counter = 0;
+ private bool stop = false;
+#else
+ private volatile int counter = 0;
+ private volatile bool stop = false;
+#endif
+
+ private void Run(object ignored)
+ {
+ while (!this.stop)
+ {
+ this.counter++;
+ }
+ }
+
+ public byte[] GenerateSeed(
+ int numBytes,
+ bool fast)
+ {
+ this.counter = 0;
+ this.stop = false;
+
+ byte[] result = new byte[numBytes];
+ int last = 0;
+ int end = fast ? numBytes : numBytes * 8;
+
+ ThreadPool.QueueUserWorkItem(new WaitCallback(Run));
+
+ for (int i = 0; i < end; i++)
+ {
+ while (this.counter == last)
+ {
+ try
+ {
+ Thread.Sleep(1);
+ }
+ catch (Exception)
+ {
+ // ignore
+ }
+ }
+
+ last = this.counter;
+
+ if (fast)
+ {
+ result[i] = (byte) last;
+ }
+ else
+ {
+ int bytepos = i / 8;
+ result[bytepos] = (byte) ((result[bytepos] << 1) | (last & 1));
+ }
+ }
+
+ this.stop = true;
+
+ return result;
+ }
+ }
+
+ /**
+ * Generate seed bytes. Set fast to false for best quality.
+ *
+ * If fast is set to true, the code should be round about 8 times faster when
+ * generating a long sequence of random bytes. 20 bytes of random values using
+ * the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+ * it takes round about 2500 ms.
+ *
+ * @param numBytes the number of bytes to generate
+ * @param fast true if fast mode should be used
+ */
+ public byte[] GenerateSeed(
+ int numBytes,
+ bool fast)
+ {
+ return new SeedGenerator().GenerateSeed(numBytes, fast);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/prng/VMPCRandomGenerator.cs b/src/core/srcbc/crypto/prng/VMPCRandomGenerator.cs
new file mode 100644
index 0000000..d3a5a19
--- /dev/null
+++ b/src/core/srcbc/crypto/prng/VMPCRandomGenerator.cs
@@ -0,0 +1,115 @@
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class VmpcRandomGenerator
+ : IRandomGenerator
+ {
+ private byte n = 0;
+
+ ///
+ /// Permutation generated by code:
+ ///
+ /// // First 1850 fractional digit of Pi number.
+ /// byte[] key = new BigInteger("14159265358979323846...5068006422512520511").ToByteArray();
+ /// s = 0;
+ /// P = new byte[256];
+ /// for (int i = 0; i < 256; i++)
+ /// {
+ /// P[i] = (byte) i;
+ /// }
+ /// for (int m = 0; m < 768; m++)
+ /// {
+ /// s = P[(s + P[m & 0xff] + key[m % key.length]) & 0xff];
+ /// byte temp = P[m & 0xff];
+ /// P[m & 0xff] = P[s & 0xff];
+ /// P[s & 0xff] = temp;
+ /// }
+ ///
+ private byte[] P =
+ {
+ (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4,
+ (byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1,
+ (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10,
+ (byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8,
+ (byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
+ (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43,
+ (byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c,
+ (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4,
+ (byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97,
+ (byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
+ (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38,
+ (byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc,
+ (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86,
+ (byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40,
+ (byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
+ (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4,
+ (byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff,
+ (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76,
+ (byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28,
+ (byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
+ (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3,
+ (byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47,
+ (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37,
+ (byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b,
+ (byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
+ (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb,
+ (byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a,
+ (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9,
+ (byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc,
+ (byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
+ (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72,
+ (byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b,
+ (byte) 0x54
+ };
+
+ /// Value generated in the same way as P.
+ private byte s = (byte) 0xbe;
+
+ public VmpcRandomGenerator()
+ {
+ }
+
+ public virtual void AddSeedMaterial(byte[] seed)
+ {
+ for (int m = 0; m < seed.Length; m++)
+ {
+ s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+
+ public virtual void AddSeedMaterial(long seed)
+ {
+ byte[] s = new byte[4];
+ s[3] = (byte) (seed & 0x000000ff);
+ s[2] = (byte) ((seed & 0x0000ff00) >> 8);
+ s[1] = (byte) ((seed & 0x00ff0000) >> 16);
+ s[0] = (byte) ((seed & 0xff000000) >> 24);
+ AddSeedMaterial(s);
+ }
+
+ public virtual void NextBytes(byte[] bytes)
+ {
+ NextBytes(bytes, 0, bytes.Length);
+ }
+
+ public virtual void NextBytes(byte[] bytes, int start, int len)
+ {
+ lock (P)
+ {
+ int end = start + len;
+ for (int i = start; i != end; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/DsaDigestSigner.cs b/src/core/srcbc/crypto/signers/DsaDigestSigner.cs
new file mode 100644
index 0000000..a807e34
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/DsaDigestSigner.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class DsaDigestSigner
+ : ISigner
+ {
+ private readonly IDigest digest;
+ private readonly IDsa dsaSigner;
+ private bool forSigning;
+
+ public DsaDigestSigner(
+ IDsa signer,
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.dsaSigner = signer;
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ {
+ throw new InvalidKeyException("Signing Requires Private Key.");
+ }
+
+ if (!forSigning && k.IsPrivate)
+ {
+ throw new InvalidKeyException("Verification Requires Public Key.");
+ }
+
+ Reset();
+
+ dsaSigner.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+
+ return DerEncode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.Message, e);
+ }
+ }
+
+ /// true if the internal state represents the signature described in the passed in array.
+ public bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ BigInteger[] sig;
+ try
+ {
+ sig = DerDecode(signature);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.", e);
+ }
+
+ return dsaSigner.VerifySignature(hash, sig[0], sig[1]);
+ }
+
+ /// Reset the internal state
+ public void Reset()
+ {
+ digest.Reset();
+ }
+
+ private byte[] DerEncode(
+ BigInteger r,
+ BigInteger s)
+ {
+ return new DerSequence(new DerInteger(r), new DerInteger(s)).GetDerEncoded();
+ }
+
+ private BigInteger[] DerDecode(
+ byte[] encoding)
+ {
+ Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+ return new BigInteger[]
+ {
+ ((DerInteger) s[0]).Value,
+ ((DerInteger) s[1]).Value
+ };
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/DsaSigner.cs b/src/core/srcbc/crypto/signers/DsaSigner.cs
new file mode 100644
index 0000000..f6c4f19
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/DsaSigner.cs
@@ -0,0 +1,136 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ */
+ public class DsaSigner
+ : IDsa
+ {
+ private DsaKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "DSA"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is DsaPrivateKeyParameters))
+ throw new InvalidKeyException("DSA private key required for signing");
+
+ this.key = (DsaPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is DsaPublicKeyParameters))
+ throw new InvalidKeyException("DSA public key required for verification");
+
+ this.key = (DsaPublicKeyParameters) parameters;
+ }
+ }
+
+ /**
+ * Generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ DsaParameters parameters = key.Parameters;
+ BigInteger q = parameters.Q;
+ BigInteger m = calculateE(q, message);
+ BigInteger k;
+
+ do
+ {
+ k = new BigInteger(q.BitLength, random);
+ }
+ while (k.CompareTo(q) >= 0);
+
+ BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
+
+ k = k.ModInverse(q).Multiply(
+ m.Add(((DsaPrivateKeyParameters)key).X.Multiply(r)));
+
+ BigInteger s = k.Mod(q);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message for standard DSA the message should be a
+ * SHA-1 hash of the real message to be verified.
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ DsaParameters parameters = key.Parameters;
+ BigInteger q = parameters.Q;
+ BigInteger m = calculateE(q, message);
+
+ if (r.SignValue <= 0 || q.CompareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (s.SignValue <= 0 || q.CompareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger w = s.ModInverse(q);
+
+ BigInteger u1 = m.Multiply(w).Mod(q);
+ BigInteger u2 = r.Multiply(w).Mod(q);
+
+ BigInteger p = parameters.P;
+ u1 = parameters.G.ModPow(u1, p);
+ u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p);
+
+ BigInteger v = u1.Multiply(u2).Mod(p).Mod(q);
+
+ return v.Equals(r);
+ }
+
+ private BigInteger calculateE(
+ BigInteger n,
+ byte[] message)
+ {
+ int length = System.Math.Min(message.Length, n.BitLength / 8);
+
+ return new BigInteger(1, message, 0, length);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/ECDsaSigner.cs b/src/core/srcbc/crypto/signers/ECDsaSigner.cs
new file mode 100644
index 0000000..1d10143
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/ECDsaSigner.cs
@@ -0,0 +1,150 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * EC-DSA as described in X9.62
+ */
+ public class ECDsaSigner
+ : IDsa
+ {
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "ECDSA"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom) parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters) parameters;
+ }
+ }
+
+ // 5.3 pg 28
+ /**
+ * Generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ BigInteger n = key.Parameters.N;
+ BigInteger e = calculateE(n, message);
+
+ BigInteger r = null;
+ BigInteger s = null;
+
+ // 5.3.2
+ do // Generate s
+ {
+ BigInteger k = null;
+
+ do // Generate r
+ {
+ do
+ {
+ k = new BigInteger(n.BitLength, random);
+ }
+ while (k.SignValue == 0);
+
+ ECPoint p = key.Parameters.G.Multiply(k);
+
+ // 5.3.3
+ BigInteger x = p.X.ToBigInteger();
+
+ r = x.Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+ s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n);
+ }
+ while (s.SignValue == 0);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ // 5.4 pg 29
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message (for standard DSA the message should be
+ * a SHA-1 hash of the real message to be verified).
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ BigInteger n = key.Parameters.N;
+
+ // r and s should both in the range [1,n-1]
+ if (r.SignValue < 1 || s.SignValue < 1
+ || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger e = calculateE(n, message);
+ BigInteger c = s.ModInverse(n);
+
+ BigInteger u1 = e.Multiply(c).Mod(n);
+ BigInteger u2 = r.Multiply(c).Mod(n);
+
+ ECPoint G = key.Parameters.G;
+ ECPoint Q = ((ECPublicKeyParameters) key).Q;
+
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
+
+ BigInteger v = point.X.ToBigInteger().Mod(n);
+
+ return v.Equals(r);
+ }
+
+ private BigInteger calculateE(
+ BigInteger n,
+ byte[] message)
+ {
+ int length = System.Math.Min(message.Length, n.BitLength / 8);
+
+ return new BigInteger(1, message, 0, length);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/ECGOST3410Signer.cs b/src/core/srcbc/crypto/signers/ECGOST3410Signer.cs
new file mode 100644
index 0000000..aef64a4
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/ECGOST3410Signer.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * GOST R 34.10-2001 Signature Algorithm
+ */
+ public class ECGost3410Signer
+ : IDsa
+ {
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "ECGOST3410"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters)parameters;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional GOST3410 the message should be a GOST3411
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+ BigInteger n = key.Parameters.N;
+
+ BigInteger r = null;
+ BigInteger s = null;
+
+ do // generate s
+ {
+ BigInteger k = null;
+
+ do // generate r
+ {
+ do
+ {
+ k = new BigInteger(n.BitLength, random);
+ }
+ while (k.SignValue == 0);
+
+ ECPoint p = key.Parameters.G.Multiply(k);
+
+ BigInteger x = p.X.ToBigInteger();
+
+ r = x.Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+ s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
+ }
+ while (s.SignValue == 0);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a GOST3410 signature for
+ * the passed in message (for standard GOST3410 the message should be
+ * a GOST3411 hash of the real message to be verified).
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+ BigInteger n = key.Parameters.N;
+
+ // r in the range [1,n-1]
+ if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [1,n-1]
+ if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger v = e.ModInverse(n);
+
+ BigInteger z1 = s.Multiply(v).Mod(n);
+ BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);
+
+ ECPoint G = key.Parameters.G; // P
+ ECPoint Q = ((ECPublicKeyParameters)key).Q;
+
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2);
+
+ BigInteger R = point.X.ToBigInteger().Mod(n);
+
+ return R.Equals(r);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/ECNRSigner.cs b/src/core/srcbc/crypto/signers/ECNRSigner.cs
new file mode 100644
index 0000000..4c17e7c
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/ECNRSigner.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * EC-NR as described in IEEE 1363-2000
+ */
+ public class ECNRSigner
+ : IDsa
+ {
+ private bool forSigning;
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "ECNR"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom) parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters) parameters;
+ }
+ }
+
+ // Section 7.2.5 ECSP-NR, pg 34
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR it *must* be at least as long.
+ *
+ * @param digest the digest to be signed.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ if (!this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for signing");
+ }
+
+ BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ BigInteger r = null;
+ BigInteger s = null;
+
+ AsymmetricCipherKeyPair tempPair;
+ do // generate r
+ {
+ // generate another, but very temporary, key pair using
+ // the same EC parameters
+ ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+ keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
+
+ tempPair = keyGen.GenerateKeyPair();
+
+ // BigInteger Vx = tempPair.getPublic().getW().getAffineX();
+ ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
+ BigInteger Vx = V.Q.X.ToBigInteger(); // get the point's x coordinate
+
+ r = Vx.Add(e).Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ // generate s
+ BigInteger x = privKey.D; // private key value
+ BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
+ s = u.Subtract(r.Multiply(x)).Mod(n);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ // Section 7.2.6 ECVP-NR, pg 35
+ /**
+ * return true if the value r and s represent a signature for the
+ * message passed in. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR, it *must* be at least as long. But just in case the signer
+ * applied mod(n) to the longer digest, this implementation will
+ * apply mod(n) during verification.
+ *
+ * @param digest the digest to be verified.
+ * @param r the r value of the signature.
+ * @param s the s value of the signature.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ if (this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for verifying");
+ }
+
+ ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
+ BigInteger n = pubKey.Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ // r in the range [1,n-1]
+ if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // TODO So why is this different from the spec?
+ // s in the range [0,n-1] NB: ECNR spec says 0
+ if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // compute P = sG + rW
+
+ ECPoint G = pubKey.Parameters.G;
+ ECPoint W = pubKey.Q;
+ // calculate P using Bouncy math
+ ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r);
+
+ BigInteger x = P.X.ToBigInteger();
+ BigInteger t = r.Subtract(x).Mod(n);
+
+ return t.Equals(e);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/GOST3410DigestSigner.cs b/src/core/srcbc/crypto/signers/GOST3410DigestSigner.cs
new file mode 100644
index 0000000..fd990fc
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/GOST3410DigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Gost3410DigestSigner
+ : ISigner
+ {
+ private readonly IDigest digest;
+ private readonly IDsa dsaSigner;
+ private bool forSigning;
+
+ public Gost3410DigestSigner(
+ IDsa signer,
+ IDigest digest)
+ {
+ this.dsaSigner = signer;
+ this.digest = digest;
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ {
+ throw new InvalidKeyException("Signing Requires Private Key.");
+ }
+
+ if (!forSigning && k.IsPrivate)
+ {
+ throw new InvalidKeyException("Verification Requires Public Key.");
+ }
+
+ Reset();
+
+ dsaSigner.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+ byte[] sigBytes = new byte[64];
+
+ // TODO Add methods to allow writing BigInteger to existing byte array?
+ byte[] r = sig[0].ToByteArrayUnsigned();
+ byte[] s = sig[1].ToByteArrayUnsigned();
+ s.CopyTo(sigBytes, 32 - s.Length);
+ r.CopyTo(sigBytes, 64 - r.Length);
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.Message, e);
+ }
+ }
+
+ /// true if the internal state represents the signature described in the passed in array.
+ public bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ BigInteger R, S;
+ try
+ {
+ R = new BigInteger(1, signature, 32, 32);
+ S = new BigInteger(1, signature, 0, 32);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.", e);
+ }
+
+ return dsaSigner.VerifySignature(hash, R, S);
+ }
+
+ /// Reset the internal state
+ public void Reset()
+ {
+ digest.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/GOST3410Signer.cs b/src/core/srcbc/crypto/signers/GOST3410Signer.cs
new file mode 100644
index 0000000..25df7a6
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/GOST3410Signer.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * Gost R 34.10-94 Signature Algorithm
+ */
+ public class Gost3410Signer
+ : IDsa
+ {
+ private Gost3410KeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "GOST3410"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is Gost3410PrivateKeyParameters))
+ throw new InvalidKeyException("GOST3410 private key required for signing");
+
+ this.key = (Gost3410PrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is Gost3410PublicKeyParameters))
+ throw new InvalidKeyException("GOST3410 public key required for signing");
+
+ this.key = (Gost3410PublicKeyParameters) parameters;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional Gost3410 the message should be a Gost3411
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger m = new BigInteger(1, mRev);
+ Gost3410Parameters parameters = key.Parameters;
+ BigInteger k;
+
+ do
+ {
+ k = new BigInteger(parameters.Q.BitLength, random);
+ }
+ while (k.CompareTo(parameters.Q) >= 0);
+
+ BigInteger r = parameters.A.ModPow(k, parameters.P).Mod(parameters.Q);
+
+ BigInteger s = k.Multiply(m).
+ Add(((Gost3410PrivateKeyParameters)key).X.Multiply(r)).
+ Mod(parameters.Q);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a Gost3410 signature for
+ * the passed in message for standard Gost3410 the message should be a
+ * Gost3411 hash of the real message to be verified.
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger m = new BigInteger(1, mRev);
+ Gost3410Parameters parameters = key.Parameters;
+
+ if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (s.SignValue < 0 || parameters.Q.CompareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger v = m.ModPow(parameters.Q.Subtract(BigInteger.Two), parameters.Q);
+
+ BigInteger z1 = s.Multiply(v).Mod(parameters.Q);
+ BigInteger z2 = (parameters.Q.Subtract(r)).Multiply(v).Mod(parameters.Q);
+
+ z1 = parameters.A.ModPow(z1, parameters.P);
+ z2 = ((Gost3410PublicKeyParameters)key).Y.ModPow(z2, parameters.P);
+
+ BigInteger u = z1.Multiply(z2).Mod(parameters.P).Mod(parameters.Q);
+
+ return u.Equals(r);
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/Iso9796d2PssSigner.cs b/src/core/srcbc/crypto/signers/Iso9796d2PssSigner.cs
new file mode 100644
index 0000000..a91c599
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/Iso9796d2PssSigner.cs
@@ -0,0 +1,561 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /// ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3).
+ ///
+ /// Note: the usual length for the salt is the length of the hash
+ /// function used in bytes.
+ ///
+ public class Iso9796d2PssSigner
+ : ISignerWithRecovery
+ {
+ ///
+ /// Return a reference to the recoveredMessage message.
+ ///
+ /// The full/partial recoveredMessage message.
+ ///
+ public byte[] GetRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+
+ public const int TrailerImplicit = 0xBC;
+ public const int TrailerRipeMD160 = 0x31CC;
+ public const int TrailerRipeMD128 = 0x32CC;
+ public const int TrailerSha1 = 0x33CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+
+ private SecureRandom random;
+ private byte[] standardSalt;
+
+ private int hLen;
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private readonly int saltLength;
+ private bool fullMessage;
+ private byte[] recoveredMessage;
+
+ ///
+ /// Generate a signer for the with either implicit or explicit trailers
+ /// for ISO9796-2, scheme 2 or 3.
+ ///
+ /// base cipher to use for signature creation/verification
+ /// digest to use.
+ /// length of salt in bytes.
+ /// whether or not the trailer is implicit or gives the hash.
+ public Iso9796d2PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLength,
+ bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ this.saltLength = saltLength;
+
+ if (isImplicit)
+ {
+ trailer = TrailerImplicit;
+ }
+ else
+ {
+ if (digest is Sha1Digest)
+ {
+ trailer = TrailerSha1;
+ }
+ else if (digest is RipeMD160Digest)
+ {
+ trailer = TrailerRipeMD160;
+ }
+ else if (digest is RipeMD128Digest)
+ {
+ trailer = TrailerRipeMD128;
+ }
+ else
+ {
+ throw new ArgumentException("no valid trailer for digest");
+ }
+ }
+ }
+
+ /// Constructor for a signer with an explicit digest trailer.
+ ///
+ ///
+ /// cipher to use.
+ ///
+ /// digest to sign with.
+ ///
+ /// length of salt in bytes.
+ ///
+ public Iso9796d2PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLength)
+ : this(cipher, digest, saltLength, false)
+ {
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
+ }
+
+ /// Initialise the signer.
+ /// true if for signing, false if for verification.
+ /// parameters for signature generation/verification. If the
+ /// parameters are for generation they should be a ParametersWithRandom,
+ /// a ParametersWithSalt, or just an RsaKeyParameters object. If RsaKeyParameters
+ /// are passed in a SecureRandom will be created.
+ ///
+ /// if wrong parameter type or a fixed
+ /// salt is passed in which is the wrong length.
+ ///
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ kParam = (RsaKeyParameters) p.Parameters;
+
+ if (forSigning)
+ {
+ random = p.Random;
+ }
+ }
+ else if (parameters is ParametersWithSalt)
+ {
+ if (!forSigning)
+ throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters");
+
+ ParametersWithSalt p = (ParametersWithSalt) parameters;
+
+ kParam = (RsaKeyParameters) p.Parameters;
+ standardSalt = p.GetSalt();
+
+ if (standardSalt.Length != saltLength)
+ throw new ArgumentException("Fixed salt is of wrong length");
+ }
+ else
+ {
+ kParam = (RsaKeyParameters) parameters;
+
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+
+ if (trailer == TrailerImplicit)
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
+ }
+ else
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 2];
+ }
+
+ Reset();
+ }
+
+ /// compare two byte arrays.
+ private bool IsSameAs(byte[] a, byte[] b)
+ {
+ if (messageLength != b.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != b.Length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /// update the internal digest with the byte b
+ public virtual void Update(
+ byte input)
+ {
+ if (messageLength < mBuf.Length)
+ {
+ mBuf[messageLength++] = input;
+ }
+ else
+ {
+ digest.Update(input);
+ }
+ }
+
+ /// update the internal digest with the byte array in
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ while (length > 0 && messageLength < mBuf.Length)
+ {
+ this.Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ if (length > 0)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ messageLength = 0;
+ if (mBuf != null)
+ {
+ ClearBlock(mBuf);
+ }
+ if (recoveredMessage != null)
+ {
+ ClearBlock(recoveredMessage);
+ recoveredMessage = null;
+ }
+ fullMessage = false;
+ }
+
+ /// Generate a signature for the loaded message using the key we were
+ /// initialised with.
+ ///
+ public byte[] GenerateSignature()
+ {
+ int digSize = digest.GetDigestSize();
+ byte[] m2Hash = new byte[digSize];
+ digest.DoFinal(m2Hash, 0);
+
+ byte[] C = new byte[8];
+ LtoOSP(messageLength * 8, C);
+
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.BlockUpdate(mBuf, 0, messageLength);
+ digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+ byte[] salt;
+ if (standardSalt != null)
+ {
+ salt = standardSalt;
+ }
+ else
+ {
+ salt = new byte[saltLength];
+ random.NextBytes(salt);
+ }
+
+ digest.BlockUpdate(salt, 0, salt.Length);
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ int tLength = 2;
+ if (trailer == TrailerImplicit)
+ {
+ tLength = 1;
+ }
+
+ int off = block.Length - messageLength - salt.Length - hLen - tLength - 1;
+
+ block[off] = (byte) (0x01);
+
+ Array.Copy(mBuf, 0, block, off + 1, messageLength);
+ Array.Copy(salt, 0, block, off + 1 + messageLength, salt.Length);
+
+ byte[] dbMask = MaskGeneratorFunction1(hash, 0, hash.Length, block.Length - hLen - tLength);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
+
+ if (trailer == TrailerImplicit)
+ {
+ block[block.Length - 1] = (byte)TrailerImplicit;
+ }
+ else
+ {
+ block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+ block[block.Length - 1] = (byte) trailer;
+ }
+
+ block[0] &= (byte) (0x7f);
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+ messageLength = 0;
+
+ return b;
+ }
+
+ /// return true if the signature represents a ISO9796-2 signature
+ /// for the passed in message.
+ ///
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+ //
+ // adjust block size for leading zeroes if necessary
+ //
+ int expectedSize = (keyBits + 7) / 8;
+ if (block.Length < expectedSize)
+ {
+ byte[] tmp = new byte[expectedSize];
+ block.CopyTo(tmp, tmp.Length - block.Length);
+ ClearBlock(block);
+ block = tmp;
+ }
+
+ int tLength;
+
+ if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ tLength = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+ switch (sigTrail)
+ {
+ case TrailerRipeMD160:
+ if (!(digest is RipeMD160Digest))
+ {
+ throw new ArgumentException("signer should be initialised with RipeMD160");
+ }
+ break;
+ case TrailerSha1:
+ if (!(digest is Sha1Digest))
+ {
+ throw new ArgumentException("signer should be initialised with SHA1");
+ }
+ break;
+ case TrailerRipeMD128:
+ if (!(digest is RipeMD128Digest))
+ {
+ throw new ArgumentException("signer should be initialised with RipeMD128");
+ }
+ break;
+ default:
+ throw new ArgumentException("unrecognised hash in signature");
+ }
+
+ tLength = 2;
+ }
+
+ //
+ // calculate H(m2)
+ //
+ byte[] m2Hash = new byte[hLen];
+ digest.DoFinal(m2Hash, 0);
+
+ //
+ // remove the mask
+ //
+ byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - tLength, hLen, block.Length - hLen - tLength);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= 0x7f;
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+ while (mStart < block.Length)
+ {
+ if (block[mStart++] == 0x01)
+ break;
+ }
+
+ if (mStart >= block.Length)
+ {
+ ClearBlock(block);
+ return false;
+ }
+
+ fullMessage = (mStart > 1);
+
+ // TODO Should we check if a standardSalt was set and, if so, use its length instead?
+ recoveredMessage = new byte[dbMask.Length - mStart - saltLength];
+
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+
+ //
+ // check the hashes
+ //
+ byte[] C = new byte[8];
+ LtoOSP(recoveredMessage.Length * 8, C);
+
+ digest.BlockUpdate(C, 0, C.Length);
+
+ if (recoveredMessage.Length != 0)
+ {
+ digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
+ }
+
+ digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+ // Update for the salt
+ digest.BlockUpdate(block, mStart + recoveredMessage.Length, saltLength);
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ int off = block.Length - tLength - hash.Length;
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ if (hash[i] != block[off + i])
+ {
+ ClearBlock(block);
+ ClearBlock(hash);
+ ClearBlock(recoveredMessage);
+ fullMessage = false;
+
+ return false;
+ }
+ }
+
+ ClearBlock(block);
+ ClearBlock(hash);
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0)
+ {
+ if (!IsSameAs(mBuf, recoveredMessage))
+ {
+ ClearBlock(mBuf);
+ return false;
+ }
+
+ messageLength = 0;
+ }
+
+ ClearBlock(mBuf);
+ return true;
+ }
+
+ ///
+ /// Return true if the full message was recoveredMessage.
+ ///
+ /// true on full message recovery, false otherwise, or if not sure.
+ ///
+ public virtual bool HasFullMessage()
+ {
+ return fullMessage;
+ }
+
+ /// int to octet string.
+ /// int to octet string.
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint)i >> 24);
+ sp[1] = (byte)((uint)i >> 16);
+ sp[2] = (byte)((uint)i >> 8);
+ sp[3] = (byte)((uint)i >> 0);
+ }
+
+ /// long to octet string.
+ private void LtoOSP(long l, byte[] sp)
+ {
+ sp[0] = (byte)((ulong)l >> 56);
+ sp[1] = (byte)((ulong)l >> 48);
+ sp[2] = (byte)((ulong)l >> 40);
+ sp[3] = (byte)((ulong)l >> 32);
+ sp[4] = (byte)((ulong)l >> 24);
+ sp[5] = (byte)((ulong)l >> 16);
+ sp[6] = (byte)((ulong)l >> 8);
+ sp[7] = (byte)((ulong)l >> 0);
+ }
+
+ /// mask generator function, as described in Pkcs1v2.
+ private byte[] MaskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hLen, hLen);
+ }
+ while (++counter < (length / hLen));
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen));
+ }
+
+ return mask;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/Iso9796d2Signer.cs b/src/core/srcbc/crypto/signers/Iso9796d2Signer.cs
new file mode 100644
index 0000000..ef924f6
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/Iso9796d2Signer.cs
@@ -0,0 +1,451 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+
+ /// ISO9796-2 - mechanism using a hash function with recovery (scheme 1)
+ public class Iso9796d2Signer : ISignerWithRecovery
+ {
+ ///
+ /// Return a reference to the recoveredMessage message.
+ ///
+ /// The full/partial recoveredMessage message.
+ ///
+ public byte[] GetRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+
+ public const int TrailerImplicit = 0xBC;
+ public const int TrailerRipeMD160 = 0x31CC;
+ public const int TrailerRipeMD128 = 0x32CC;
+ public const int TrailerSha1 = 0x33CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private bool fullMessage;
+ private byte[] recoveredMessage;
+
+ ///
+ /// Generate a signer for the with either implicit or explicit trailers
+ /// for ISO9796-2.
+ ///
+ /// base cipher to use for signature creation/verification
+ /// digest to use.
+ /// whether or not the trailer is implicit or gives the hash.
+ public Iso9796d2Signer(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (isImplicit)
+ {
+ trailer = TrailerImplicit;
+ }
+ else
+ {
+ if (digest is Sha1Digest)
+ {
+ trailer = TrailerSha1;
+ }
+ else if (digest is RipeMD160Digest)
+ {
+ trailer = TrailerRipeMD160;
+ }
+ else if (digest is RipeMD128Digest)
+ {
+ trailer = TrailerRipeMD128;
+ }
+ else
+ {
+ throw new System.ArgumentException("no valid trailer for digest");
+ }
+ }
+ }
+
+ /// Constructor for a signer with an explicit digest trailer.
+ ///
+ ///
+ /// cipher to use.
+ ///
+ /// digest to sign with.
+ ///
+ public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest):this(cipher, digest, false)
+ {
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam = (RsaKeyParameters) parameters;
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+ if (trailer == TrailerImplicit)
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
+ }
+ else
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - 3];
+ }
+
+ Reset();
+ }
+
+ /// compare two byte arrays.
+ private bool IsSameAs(byte[] a, byte[] b)
+ {
+ if (messageLength > mBuf.Length)
+ {
+ if (mBuf.Length > b.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != mBuf.Length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (messageLength != b.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != b.Length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /// update the internal digest with the byte b
+ public void Update(
+ byte input)
+ {
+ digest.Update(input);
+
+ if (messageLength < mBuf.Length)
+ {
+ mBuf[messageLength] = input;
+ }
+
+ messageLength++;
+ }
+
+ /// update the internal digest with the byte array in
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+
+ if (messageLength < mBuf.Length)
+ {
+ for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++)
+ {
+ mBuf[messageLength + i] = input[inOff + i];
+ }
+ }
+
+ messageLength += length;
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ messageLength = 0;
+ ClearBlock(mBuf);
+
+ if (recoveredMessage != null)
+ {
+ ClearBlock(recoveredMessage);
+ }
+
+ recoveredMessage = null;
+ fullMessage = false;
+ }
+
+ /// Generate a signature for the loaded message using the key we were
+ /// initialised with.
+ ///
+ public virtual byte[] GenerateSignature()
+ {
+ int digSize = digest.GetDigestSize();
+
+ int t = 0;
+ int delta = 0;
+
+ if (trailer == TrailerImplicit)
+ {
+ t = 8;
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte) TrailerImplicit;
+ }
+ else
+ {
+ t = 16;
+ delta = block.Length - digSize - 2;
+ digest.DoFinal(block, delta);
+ block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+ block[block.Length - 1] = (byte) trailer;
+ }
+
+ byte header = 0;
+ int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
+
+ if (x > 0)
+ {
+ int mR = messageLength - ((x + 7) / 8);
+ header = (byte) (0x60);
+
+ delta -= mR;
+
+ Array.Copy(mBuf, 0, block, delta, mR);
+ }
+ else
+ {
+ header = (byte) (0x40);
+ delta -= messageLength;
+
+ Array.Copy(mBuf, 0, block, delta, messageLength);
+ }
+
+ if ((delta - 1) > 0)
+ {
+ for (int i = delta - 1; i != 0; i--)
+ {
+ block[i] = (byte) 0xbb;
+ }
+ block[delta - 1] ^= (byte) 0x01;
+ block[0] = (byte) 0x0b;
+ block[0] |= header;
+ }
+ else
+ {
+ block[0] = (byte) 0x0a;
+ block[0] |= header;
+ }
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return b;
+ }
+
+ /// return true if the signature represents a ISO9796-2 signature
+ /// for the passed in message.
+ ///
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+ if (((block[0] & 0xC0) ^ 0x40) != 0)
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+
+ if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+
+ int delta = 0;
+
+ if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ delta = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+ switch (sigTrail)
+ {
+ case TrailerRipeMD160:
+ if (!(digest is RipeMD160Digest))
+ {
+ throw new ArgumentException("signer should be initialised with RipeMD160");
+ }
+ break;
+ case TrailerSha1:
+ if (!(digest is Sha1Digest))
+ {
+ throw new ArgumentException("signer should be initialised with SHA1");
+ }
+ break;
+ case TrailerRipeMD128:
+ if (!(digest is RipeMD128Digest))
+ {
+ throw new ArgumentException("signer should be initialised with RipeMD128");
+ }
+ break;
+ default:
+ throw new ArgumentException("unrecognised hash in signature");
+ }
+
+ delta = 2;
+ }
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+ for (; mStart != block.Length; mStart++)
+ {
+ if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+ {
+ break;
+ }
+ }
+
+ mStart++;
+
+ //
+ // check the hashes
+ //
+ byte[] hash = new byte[digest.GetDigestSize()];
+
+ int off = block.Length - delta - hash.Length;
+
+ //
+ // there must be at least one byte of message string
+ //
+ if ((off - mStart) <= 0)
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+
+ //
+ // if we contain the whole message as well, check the hash of that.
+ //
+ if ((block[0] & 0x20) == 0)
+ {
+ fullMessage = true;
+
+ digest.Reset();
+ digest.BlockUpdate(block, mStart, off - mStart);
+ digest.DoFinal(hash, 0);
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+ else
+ {
+ fullMessage = false;
+
+ digest.DoFinal(hash, 0);
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0)
+ {
+ if (!IsSameAs(mBuf, recoveredMessage))
+ {
+ ClearBlock(mBuf);
+ ClearBlock(block);
+ ClearBlock(recoveredMessage);
+
+ return false;
+ }
+ }
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return true;
+ }
+
+ ///
+ /// Return true if the full message was recoveredMessage.
+ ///
+ /// true on full message recovery, false otherwise.
+ ///
+ public virtual bool HasFullMessage()
+ {
+ return fullMessage;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/PssSigner.cs b/src/core/srcbc/crypto/signers/PssSigner.cs
new file mode 100644
index 0000000..063d68f
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/PssSigner.cs
@@ -0,0 +1,299 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /// RSA-PSS as described in Pkcs# 1 v 2.1.
+ ///
+ /// Note: the usual value for the salt length is the number of
+ /// bytes in the hash function.
+ ///
+ public class PssSigner
+ : ISigner
+ {
+ public const byte TrailerImplicit = (byte)0xBC;
+
+ private readonly IDigest digest;
+ private readonly IAsymmetricBlockCipher cipher;
+
+ private SecureRandom random;
+
+ private int hLen;
+ private int sLen;
+ private int emBits;
+ private byte[] salt;
+ private byte[] mDash;
+ private byte[] block;
+ private byte trailer;
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest)
+ : this(cipher, digest, digest.GetDigestSize())
+ {
+ }
+
+ /// Basic constructor
+ /// the asymmetric cipher to use.
+ /// the digest to use.
+ /// the length of the salt to use (in bytes).
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLen)
+ : this(cipher, digest, saltLen, TrailerImplicit)
+ {
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLen,
+ byte trailer)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ this.sLen = saltLen;
+ this.salt = new byte[saltLen];
+ this.mDash = new byte[8 + saltLen + hLen];
+ this.trailer = trailer;
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "withRSAandMGF1"; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ parameters = p.Parameters;
+ random = p.Random;
+ }
+ else
+ {
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.Init(forSigning, parameters);
+
+ RsaKeyParameters kParam;
+ if (parameters is RsaBlindingParameters)
+ {
+ kParam = ((RsaBlindingParameters) parameters).PublicKey;
+ }
+ else
+ {
+ kParam = (RsaKeyParameters) parameters;
+ }
+
+ emBits = kParam.Modulus.BitLength - 1;
+
+ block = new byte[(emBits + 7) / 8];
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /// update the internal digest with the byte b
+ public virtual void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /// update the internal digest with the byte array in
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+
+ /// Generate a signature for the message we've been loaded with using
+ /// the key we were initialised with.
+ ///
+ public virtual byte[] GenerateSignature()
+ {
+ if (emBits < (8 * hLen + 8 * sLen + 9))
+ {
+ throw new DataLengthException("encoding error");
+ }
+
+ digest.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+ if (sLen != 0)
+ {
+ random.NextBytes(salt);
+ salt.CopyTo(mDash, mDash.Length - sLen);
+ }
+
+ byte[] h = new byte[hLen];
+
+ digest.BlockUpdate(mDash, 0, mDash.Length);
+
+ digest.DoFinal(h, 0);
+
+ block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01);
+ salt.CopyTo(block, block.Length - sLen - hLen - 1);
+
+ byte[] dbMask = MaskGeneratorFunction1(h, 0, h.Length, block.Length - hLen - 1);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+ h.CopyTo(block, block.Length - hLen - 1);
+
+ block[block.Length - 1] = trailer;
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ ClearBlock(block);
+
+ return b;
+ }
+
+ /// return true if the internal state represents the signature described
+ /// in the passed in array.
+ ///
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ if (emBits < (8 * hLen + 8 * sLen + 9))
+ {
+ return false;
+ }
+
+ digest.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+ byte[] b = cipher.ProcessBlock(signature, 0, signature.Length);
+ b.CopyTo(block, block.Length - b.Length);
+
+ if (block[block.Length - 1] != trailer)
+ {
+ ClearBlock(block);
+ return false;
+ }
+
+ byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
+
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+ for (int i = 0; i != block.Length - hLen - sLen - 2; i++)
+ {
+ if (block[i] != 0)
+ {
+ ClearBlock(block);
+ return false;
+ }
+ }
+
+ if (block[block.Length - hLen - sLen - 2] != 0x01)
+ {
+ ClearBlock(block);
+ return false;
+ }
+
+ Array.Copy(block, block.Length - sLen - hLen - 1, mDash, mDash.Length - sLen, sLen);
+
+ digest.BlockUpdate(mDash, 0, mDash.Length);
+ digest.DoFinal(mDash, mDash.Length - hLen);
+
+ for (int i = block.Length - hLen - 1, j = mDash.Length - hLen; j != mDash.Length; i++, j++)
+ {
+ if ((block[i] ^ mDash[j]) != 0)
+ {
+ ClearBlock(mDash);
+ ClearBlock(block);
+ return false;
+ }
+ }
+
+ ClearBlock(mDash);
+ ClearBlock(block);
+
+ return true;
+ }
+
+ /// int to octet string.
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint) i >> 24);
+ sp[1] = (byte)((uint) i >> 16);
+ sp[2] = (byte)((uint) i >> 8);
+ sp[3] = (byte)((uint) i >> 0);
+ }
+
+ /// mask generator function, as described in Pkcs1v2.
+ private byte[] MaskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ while (counter < (length / hLen))
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ hashBuf.CopyTo(mask, counter * hLen);
+ ++counter;
+ }
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen));
+ }
+
+ return mask;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/signers/RsaDigestSigner.cs b/src/core/srcbc/crypto/signers/RsaDigestSigner.cs
new file mode 100644
index 0000000..4d98425
--- /dev/null
+++ b/src/core/srcbc/crypto/signers/RsaDigestSigner.cs
@@ -0,0 +1,213 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class RsaDigestSigner
+ : ISigner
+ {
+ private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
+ private readonly AlgorithmIdentifier algId;
+ private readonly IDigest digest;
+ private bool forSigning;
+
+ private static readonly Hashtable oidMap = new Hashtable();
+
+ ///
+ /// Load oid table.
+ ///
+ static RsaDigestSigner()
+ {
+ oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+
+ oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
+ oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
+ oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
+ oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
+ oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
+
+ oidMap["MD2"] = PkcsObjectIdentifiers.MD2;
+ oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
+ oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
+ }
+
+ public RsaDigestSigner(
+ IDigest digest)
+ {
+ this.digest = digest;
+
+ algId = new AlgorithmIdentifier( (DerObjectIdentifier)oidMap[digest.AlgorithmName] , DerNull.Instance);
+ }
+
+ public string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "withRSA"; }
+ }
+
+ /**
+ * Initialise the signer for signing or verification.
+ *
+ * @param forSigning true if for signing, false otherwise
+ * @param param necessary parameters.
+ */
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+ AsymmetricKeyParameter k;
+
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ throw new InvalidKeyException("Signing requires private key.");
+
+ if (!forSigning && k.IsPrivate)
+ throw new InvalidKeyException("Verification requires public key.");
+
+ Reset();
+
+ rsaEngine.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ byte[] data = DerEncode(hash);
+ return rsaEngine.ProcessBlock(data, 0, data.Length);
+ }
+
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ public bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
+ expected = DerEncode(hash);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (sig.Length == expected.Length)
+ {
+ for (int i = 0; i < sig.Length; i++)
+ {
+ if (sig[i] != expected[i])
+ {
+ return false;
+ }
+ }
+ }
+ else if (sig.Length == expected.Length - 2) // NULL left out
+ {
+ int sigOffset = sig.Length - hash.Length - 2;
+ int expectedOffset = expected.Length - hash.Length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ for (int i = 0; i < hash.Length; i++)
+ {
+ if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ if (sig[i] != expected[i]) // check header less NULL
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public void Reset()
+ {
+ digest.Reset();
+ }
+
+ private byte[] DerEncode(
+ byte[] hash)
+ {
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.GetDerEncoded();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/AlwaysValidVerifyer.cs b/src/core/srcbc/crypto/tls/AlwaysValidVerifyer.cs
new file mode 100644
index 0000000..e5b8ac2
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/AlwaysValidVerifyer.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A certificate verifyer, that will always return true.
+ ///
+ /// DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
+ ///
+ ///
+ public class AlwaysValidVerifyer
+ : ICertificateVerifyer
+ {
+ /// Return true.
+ public bool IsValid(
+ X509CertificateStructure[] certs)
+ {
+ return true;
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/ByteQueue.cs b/src/core/srcbc/crypto/tls/ByteQueue.cs
new file mode 100644
index 0000000..c9628fd
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/ByteQueue.cs
@@ -0,0 +1,125 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A queue for bytes.
+ ///
+ /// This file could be more optimized.
+ ///
+ ///
+ public class ByteQueue
+ {
+ /// The smallest number which can be written as 2^x which is bigger than i.
+ public static int NextTwoPow(
+ int i)
+ {
+ /*
+ * This code is based of a lot of code I found on the Internet
+ * which mostly referenced a book called "Hacking delight".
+ *
+ */
+ i |= (i >> 1);
+ i |= (i >> 2);
+ i |= (i >> 4);
+ i |= (i >> 8);
+ i |= (i >> 16);
+ return i + 1;
+ }
+
+ /**
+ * The initial size for our buffer.
+ */
+ private const int InitBufSize = 1024;
+
+ /**
+ * The buffer where we store our data.
+ */
+ private byte[] databuf = new byte[ByteQueue.InitBufSize];
+
+ /**
+ * How many bytes at the beginning of the buffer are skipped.
+ */
+ private int skipped = 0;
+
+ /**
+ * How many bytes in the buffer are valid data.
+ */
+ private int available = 0;
+
+ /// Read data from the buffer.
+ /// The buffer where the read data will be copied to.
+ /// How many bytes to skip at the beginning of buf.
+ /// How many bytes to read at all.
+ /// How many bytes from our data to skip.
+ public void Read(
+ byte[] buf,
+ int offset,
+ int len,
+ int skip)
+ {
+ if ((available - skip) < len)
+ {
+ throw new TlsException("Not enough data to read");
+ }
+ if ((buf.Length - offset) < len)
+ {
+ throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
+ }
+ Array.Copy(databuf, skipped + skip, buf, offset, len);
+ }
+
+ /// Add some data to our buffer.
+ /// A byte-array to read data from.
+ /// How many bytes to skip at the beginning of the array.
+ /// How many bytes to read from the array.
+ public void AddData(
+ byte[] data,
+ int offset,
+ int len)
+ {
+ if ((skipped + available + len) > databuf.Length)
+ {
+ byte[] tmp = new byte[ByteQueue.NextTwoPow(data.Length)];
+ Array.Copy(databuf, skipped, tmp, 0, available);
+ skipped = 0;
+ databuf = tmp;
+ }
+ Array.Copy(data, offset, databuf, skipped + available, len);
+ available += len;
+ }
+
+ /// Remove some bytes from our data from the beginning.
+ /// How many bytes to remove.
+ public void RemoveData(
+ int i)
+ {
+ if (i > available)
+ {
+ throw new TlsException("Cannot remove " + i + " bytes, only got " + available);
+ }
+
+ /*
+ * Skip the data.
+ */
+ available -= i;
+ skipped += i;
+
+ /*
+ * If more than half of our data is skipped, we will move the data
+ * in the buffer.
+ */
+ if (skipped > (databuf.Length / 2))
+ {
+ Array.Copy(databuf, skipped, databuf, 0, available);
+ skipped = 0;
+ }
+ }
+
+ /// The number of bytes which are available in this buffer.
+ public int Available
+ {
+ get { return available; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/Certificate.cs b/src/core/srcbc/crypto/tls/Certificate.cs
new file mode 100644
index 0000000..a4ab841
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/Certificate.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * A representation for a certificate chain as used by an tls server.
+ */
+ public class Certificate
+ {
+ /**
+ * The certificates.
+ */
+ internal X509CertificateStructure[] certs;
+
+ /**
+ * Parse the ServerCertificate message.
+ *
+ * @param is The stream where to parse from.
+ * @return A Certificate object with the certs, the server has sended.
+ * @throws IOException If something goes wrong during parsing.
+ */
+ internal static Certificate Parse(
+ Stream inStr)
+ {
+ X509CertificateStructure[] certs;
+ int left = TlsUtilities.ReadUint24(inStr);
+ ArrayList tmp = new ArrayList();
+ while (left > 0)
+ {
+ int size = TlsUtilities.ReadUint24(inStr);
+ left -= 3 + size;
+ byte[] buf = new byte[size];
+ TlsUtilities.ReadFully(buf, inStr);
+ MemoryStream bis = new MemoryStream(buf, false);
+ Asn1InputStream ais = new Asn1InputStream(bis);
+ Asn1Object o = ais.ReadObject();
+ tmp.Add(X509CertificateStructure.GetInstance(o));
+// if (bis.available() > 0)
+ if (bis.Position < bis.Length)
+ {
+ throw new ArgumentException("Sorry, there is garbage data left after the certificate");
+ }
+ }
+// certs = new X509CertificateStructure[tmp.size()];
+// for (int i = 0; i < tmp.size(); i++)
+// {
+// certs[i] = (X509CertificateStructure)tmp.elementAt(i);
+// }
+ certs = (X509CertificateStructure[]) tmp.ToArray(typeof(X509CertificateStructure));
+ return new Certificate(certs);
+ }
+
+ /**
+ * Private constructure from an cert array.
+ *
+ * @param certs The certs the chain should contain.
+ */
+ private Certificate(
+ X509CertificateStructure[] certs)
+ {
+ this.certs = certs;
+ }
+
+ /// An array which contains the certs, this chain contains.
+ public X509CertificateStructure[] GetCerts()
+ {
+// X509CertificateStructure[] result = new X509CertificateStructure[certs.Length];
+// Array.Copy(certs, 0, result, 0, certs.Length);
+// return result;
+ return (X509CertificateStructure[]) certs.Clone();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/CombinedHash.cs b/src/core/srcbc/crypto/tls/CombinedHash.cs
new file mode 100644
index 0000000..3976b36
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/CombinedHash.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// A combined hash, which implements md5(m) || sha1(m).
+ public class CombinedHash
+ : IDigest
+ {
+ private IDigest md5 = new MD5Digest();
+ private IDigest sha1 = new Sha1Digest();
+
+ ///
+ public string AlgorithmName
+ {
+ get
+ {
+ return md5.AlgorithmName + " and " + sha1.AlgorithmName + " for TLS 1.0";
+ }
+ }
+
+ ///
+ public int GetByteLength()
+ {
+ return System.Math.Max(md5.GetByteLength(), sha1.GetByteLength());
+ }
+
+ ///
+ public int GetDigestSize()
+ {
+ return md5.GetDigestSize() + sha1.GetDigestSize();
+ }
+
+ ///
+ public void Update(
+ byte input)
+ {
+ md5.Update(input);
+ sha1.Update(input);
+ }
+
+ ///
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ md5.BlockUpdate(input, inOff, len);
+ sha1.BlockUpdate(input, inOff, len);
+ }
+
+ ///
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int i1 = md5.DoFinal(output, outOff);
+ int i2 = sha1.DoFinal(output, outOff + i1);
+ return i1 + i2;
+ }
+
+ ///
+ public void Reset()
+ {
+ md5.Reset();
+ sha1.Reset();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/ICertificateVerifyer.cs b/src/core/srcbc/crypto/tls/ICertificateVerifyer.cs
new file mode 100644
index 0000000..5f6ae39
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/ICertificateVerifyer.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// This should be implemented by any class which can find out, if a given
+ /// certificate chain is beeing accepted by an client.
+ ///
+ public interface ICertificateVerifyer
+ {
+ /// The certs, which are part of the chain.
+ /// True, if the chain is accepted, false otherwise
+ bool IsValid(X509CertificateStructure[] certs);
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/RecordStream.cs b/src/core/srcbc/crypto/tls/RecordStream.cs
new file mode 100644
index 0000000..ee83723
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/RecordStream.cs
@@ -0,0 +1,107 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// An implementation of the TLS 1.0 record layer.
+ public class RecordStream
+ {
+ private TlsProtocolHandler handler;
+ private Stream inStr;
+ private Stream outStr;
+ internal CombinedHash hash1;
+ internal CombinedHash hash2;
+ internal TlsCipherSuite readSuite = null;
+ internal TlsCipherSuite writeSuite = null;
+
+ internal RecordStream(
+ TlsProtocolHandler handler,
+ Stream inStr,
+ Stream outStr)
+ {
+ this.handler = handler;
+ this.inStr = inStr;
+ this.outStr = outStr;
+ hash1 = new CombinedHash();
+ hash2 = new CombinedHash();
+ this.readSuite = new TlsNullCipherSuite();
+ this.writeSuite = this.readSuite;
+ }
+
+ public void ReadData()
+ {
+ short type = TlsUtilities.ReadUint8(inStr);
+ TlsUtilities.CheckVersion(inStr, handler);
+ int size = TlsUtilities.ReadUint16(inStr);
+ byte[] buf = DecodeAndVerify(type, inStr, size);
+ handler.ProcessData(type, buf, 0, buf.Length);
+
+ }
+
+ internal byte[] DecodeAndVerify(
+ short type,
+ Stream inStr,
+ int len)
+ {
+ byte[] buf = new byte[len];
+ TlsUtilities.ReadFully(buf, inStr);
+ byte[] result = readSuite.DecodeCiphertext(type, buf, 0, buf.Length, handler);
+ return result;
+ }
+
+ internal void WriteMessage(
+ short type,
+ byte[] message,
+ int offset,
+ int len)
+ {
+ if (type == 22)
+ {
+ hash1.BlockUpdate(message, offset, len);
+ hash2.BlockUpdate(message, offset, len);
+ }
+ byte[] ciphertext = writeSuite.EncodePlaintext(type, message, offset, len);
+ byte[] writeMessage = new byte[ciphertext.Length + 5];
+ TlsUtilities.WriteUint8(type, writeMessage, 0);
+ TlsUtilities.WriteUint8((short)3, writeMessage, 1);
+ TlsUtilities.WriteUint8((short)1, writeMessage, 2);
+ TlsUtilities.WriteUint16(ciphertext.Length, writeMessage, 3);
+ Array.Copy(ciphertext, 0, writeMessage, 5, ciphertext.Length);
+ outStr.Write(writeMessage, 0, writeMessage.Length);
+ outStr.Flush();
+ }
+
+ internal void Close()
+ {
+ IOException e = null;
+ try
+ {
+ inStr.Close();
+ }
+ catch (IOException ex)
+ {
+ e = ex;
+ }
+
+ try
+ {
+ // NB: This is harmless if outStr == inStr
+ outStr.Close();
+ }
+ catch (IOException ex)
+ {
+ e = ex;
+ }
+
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ internal void Flush()
+ {
+ outStr.Flush();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs b/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs
new file mode 100644
index 0000000..004f6ac
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// A generic TLS 1.0 block cipher suite. This can be used for AES or 3DES for example.
+ public class TlsBlockCipherCipherSuite
+ : TlsCipherSuite
+ {
+ private IBlockCipher encryptCipher;
+
+ private IBlockCipher decryptCipher;
+
+ private IDigest writeDigest;
+
+ private IDigest readDigest;
+
+ private int cipherKeySize;
+
+ private short keyExchange;
+
+ private TlsMac writeMac;
+
+ private TlsMac readMac;
+
+ internal TlsBlockCipherCipherSuite(
+ IBlockCipher encrypt,
+ IBlockCipher decrypt,
+ IDigest writeDigest,
+ IDigest readDigest,
+ int cipherKeySize,
+ short keyExchange)
+ {
+ this.encryptCipher = encrypt;
+ this.decryptCipher = decrypt;
+ this.writeDigest = writeDigest;
+ this.readDigest = readDigest;
+ this.cipherKeySize = cipherKeySize;
+ this.keyExchange = keyExchange;
+ }
+
+ internal override void Init(byte[] ms, byte[] cr, byte[] sr)
+ {
+ int prfSize = (2 * cipherKeySize) + (2 * writeDigest.GetDigestSize())
+ + (2 * encryptCipher.GetBlockSize());
+ byte[] key_block = new byte[prfSize];
+ byte[] random = new byte[cr.Length + sr.Length];
+ Array.Copy(cr, 0, random, sr.Length, cr.Length);
+ Array.Copy(sr, 0, random, 0, sr.Length);
+ TlsUtilities.PRF(ms, TlsUtilities.ToByteArray("key expansion"), random, key_block);
+
+ int offset = 0;
+
+ // Init MACs
+ writeMac = new TlsMac(writeDigest, key_block, offset, writeDigest
+ .GetDigestSize());
+ offset += writeDigest.GetDigestSize();
+ readMac = new TlsMac(readDigest, key_block, offset, readDigest
+ .GetDigestSize());
+ offset += readDigest.GetDigestSize();
+
+ // Init Ciphers
+ this.initCipher(true, encryptCipher, key_block, cipherKeySize, offset,
+ offset + (cipherKeySize * 2));
+ offset += cipherKeySize;
+ this.initCipher(false, decryptCipher, key_block, cipherKeySize, offset,
+ offset + cipherKeySize + decryptCipher.GetBlockSize());
+ }
+
+ private void initCipher(bool forEncryption, IBlockCipher cipher,
+ byte[] key_block, int key_size, int key_offset, int iv_offset)
+ {
+ KeyParameter key_parameter = new KeyParameter(key_block, key_offset,
+ key_size);
+ ParametersWithIV parameters_with_iv = new ParametersWithIV(
+ key_parameter, key_block, iv_offset, cipher.GetBlockSize());
+ cipher.Init(forEncryption, parameters_with_iv);
+ }
+
+ internal override byte[] EncodePlaintext(
+ short type,
+ byte[] plaintext,
+ int offset,
+ int len)
+ {
+ int blocksize = encryptCipher.GetBlockSize();
+ int paddingsize = blocksize
+ - ((len + writeMac.Size + 1) % blocksize);
+ int totalsize = len + writeMac.Size + paddingsize + 1;
+ byte[] outbuf = new byte[totalsize];
+ Array.Copy(plaintext, offset, outbuf, 0, len);
+ byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len);
+ Array.Copy(mac, 0, outbuf, len, mac.Length);
+ int paddoffset = len + mac.Length;
+ for (int i = 0; i <= paddingsize; i++)
+ {
+ outbuf[i + paddoffset] = (byte)paddingsize;
+ }
+ for (int i = 0; i < totalsize; i += blocksize)
+ {
+ encryptCipher.ProcessBlock(outbuf, i, outbuf, i);
+ }
+ return outbuf;
+ }
+
+ internal override byte[] DecodeCiphertext(
+ short type,
+ byte[] ciphertext,
+ int offset,
+ int len,
+ TlsProtocolHandler handler)
+ {
+ int blocksize = decryptCipher.GetBlockSize();
+ bool decrypterror = false;
+
+ /*
+ * Decrypt all the ciphertext using the blockcipher
+ */
+ for (int i = 0; i < len; i += blocksize)
+ {
+ decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i
+ + offset);
+ }
+
+ /*
+ * Check if padding is correct
+ */
+ int paddingsize = ciphertext[offset + len - 1];
+ if (offset + len - 1 - paddingsize < 0)
+ {
+ /*
+ * This would lead to an negativ array index, so this padding
+ * must be incorrect!
+ */
+ decrypterror = true;
+ paddingsize = 0;
+ }
+ else
+ {
+ /*
+ * Now, check all the padding-bytes.
+ */
+ for (int i = 0; i <= paddingsize; i++)
+ {
+ if (ciphertext[offset + len - 1 - i] != paddingsize)
+ {
+ /* Wrong padding */
+ decrypterror = true;
+ }
+ }
+ }
+
+ /*
+ * We now don't care if padding verification has failed or not,
+ * we will calculate the mac to give an attacker no kind of timing
+ * profile he can use to find out if mac verification failed or
+ * padding verification failed.
+ */
+ int plaintextlength = len - readMac.Size - paddingsize - 1;
+ byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset,
+ plaintextlength);
+
+ /*
+ * Check all bytes in the mac.
+ */
+ for (int i = 0; i < calculatedMac.Length; i++)
+ {
+ if (ciphertext[offset + plaintextlength + i] != calculatedMac[i])
+ {
+ decrypterror = true;
+ }
+ }
+
+ /*
+ * Now, it is save to fail.
+ */
+ if (decrypterror)
+ {
+ handler.FailWithError(TlsProtocolHandler.AL_fatal,
+ TlsProtocolHandler.AP_bad_record_mac);
+ }
+ byte[] plaintext = new byte[plaintextlength];
+ Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength);
+ return plaintext;
+
+ }
+
+ internal override short KeyExchangeAlgorithm
+ {
+ get { return this.keyExchange; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsCipherSuite.cs b/src/core/srcbc/crypto/tls/TlsCipherSuite.cs
new file mode 100644
index 0000000..0f6386c
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsCipherSuite.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// A generic class for ciphersuites in TLS 1.0.
+ public abstract class TlsCipherSuite
+ {
+ internal const short KE_RSA = 1;
+ internal const short KE_RSA_EXPORT = 2;
+ internal const short KE_DHE_DSS = 3;
+ internal const short KE_DHE_DSS_EXPORT = 4;
+ internal const short KE_DHE_RSA = 5;
+ internal const short KE_DHE_RSA_EXPORT = 6;
+ internal const short KE_DH_DSS = 7;
+ internal const short KE_DH_RSA = 8;
+ internal const short KE_DH_anon = 9;
+
+ internal abstract void Init(byte[] ms, byte[] cr, byte[] sr);
+
+ internal abstract byte[] EncodePlaintext(short type, byte[] plaintext, int offset, int len);
+
+ internal abstract byte[] DecodeCiphertext(short type, byte[] plaintext, int offset, int len, TlsProtocolHandler handler);
+
+ internal abstract short KeyExchangeAlgorithm { get; }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsCipherSuiteManager.cs b/src/core/srcbc/crypto/tls/TlsCipherSuiteManager.cs
new file mode 100644
index 0000000..505841d
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsCipherSuiteManager.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A manager for ciphersuite. This class does manage all ciphersuites
+ /// which are used by MicroTLS.
+ ///
+ public class TlsCipherSuiteManager
+ {
+ private const int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000a;
+ private const int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016;
+ private const int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002f;
+ private const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033;
+ private const int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
+ private const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039;
+
+ internal static void WriteCipherSuites(
+ Stream outStr)
+ {
+ TlsUtilities.WriteUint16(2 * 6, outStr);
+
+ TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, outStr);
+ TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, outStr);
+ TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, outStr);
+
+ TlsUtilities.WriteUint16(TLS_RSA_WITH_AES_256_CBC_SHA, outStr);
+ TlsUtilities.WriteUint16(TLS_RSA_WITH_AES_128_CBC_SHA, outStr);
+ TlsUtilities.WriteUint16(TLS_RSA_WITH_3DES_EDE_CBC_SHA, outStr);
+
+ }
+
+ internal static TlsCipherSuite GetCipherSuite(
+ int number,
+ TlsProtocolHandler handler)
+ {
+ switch (number)
+ {
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new DesEdeEngine()), new CbcBlockCipher(new DesEdeEngine()), new Sha1Digest(), new Sha1Digest(), 24, TlsCipherSuite.KE_RSA);
+
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new DesEdeEngine()), new CbcBlockCipher(new DesEdeEngine()), new Sha1Digest(), new Sha1Digest(), 24, TlsCipherSuite.KE_DHE_RSA);
+
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 16, TlsCipherSuite.KE_RSA);
+
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 16, TlsCipherSuite.KE_DHE_RSA);
+
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 32, TlsCipherSuite.KE_RSA);
+
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 32, TlsCipherSuite.KE_DHE_RSA);
+
+ default:
+ handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_handshake_failure);
+
+ /*
+ * Unreachable Code, failWithError will always throw an exception!
+ */
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsException.cs b/src/core/srcbc/crypto/tls/TlsException.cs
new file mode 100644
index 0000000..bc908b6
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsException : Exception
+ {
+ public TlsException() : base() { }
+ public TlsException(string message) : base(message) { }
+ public TlsException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsInputStream.cs b/src/core/srcbc/crypto/tls/TlsInputStream.cs
new file mode 100644
index 0000000..38408dc
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsInputStream.cs
@@ -0,0 +1,42 @@
+using System;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// An input Stream for a TLS 1.0 connection.
+ // TODO Fix name and make internal once TlsProtocolHandler.TlsInputStream is removed
+ public class TlsInputStream
+ : BaseInputStream
+ {
+ private readonly TlsProtocolHandler handler;
+
+ internal TlsInputStream(
+ TlsProtocolHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public override int Read(
+ byte[] buf,
+ int offset,
+ int len)
+ {
+ return this.handler.ReadApplicationData(buf, offset, len);
+ }
+
+ public override int ReadByte()
+ {
+ byte[] buf = new byte[1];
+ if (this.Read(buf, 0, 1) <= 0)
+ return -1;
+ return buf[0];
+ }
+
+ public override void Close()
+ {
+ handler.Close();
+ base.Close();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsMac.cs b/src/core/srcbc/crypto/tls/TlsMac.cs
new file mode 100644
index 0000000..fde1179
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsMac.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A generic TLS MAC implementation, which can be used with any kind of
+ /// IDigest to act as an HMAC.
+ ///
+ public class TlsMac
+ {
+ private long seqNo;
+ private HMac mac;
+
+ /**
+ * Generate a new instance of an TlsMac.
+ *
+ * @param digest The digest to use.
+ * @param key_block A byte-array where the key for this mac is located.
+ * @param offset The number of bytes to skip, before the key starts in the buffer.
+ * @param len The length of the key.
+ */
+ internal TlsMac(
+ IDigest digest,
+ byte[] key_block,
+ int offset,
+ int len)
+ {
+ this.mac = new HMac(digest);
+ KeyParameter param = new KeyParameter(key_block, offset, len);
+ this.mac.Init(param);
+ this.seqNo = 0;
+ }
+
+ /**
+ * @return The Keysize of the mac.
+ */
+ internal int Size
+ {
+ get { return mac.GetMacSize(); }
+ }
+
+ /**
+ * Calculate the mac for some given data.
+ *
+ * TlsMac will keep track of the sequence number internally.
+ *
+ * @param type The message type of the message.
+ * @param message A byte-buffer containing the message.
+ * @param offset The number of bytes to skip, before the message starts.
+ * @param len The length of the message.
+ * @return A new byte-buffer containing the mac value.
+ */
+ internal byte[] CalculateMac(
+ short type,
+ byte[] message,
+ int offset,
+ int len)
+ {
+ try
+ {
+ MemoryStream bosMac = new MemoryStream(13 + len);
+ TlsUtilities.WriteUint64(seqNo++, bosMac);
+ TlsUtilities.WriteUint8(type, bosMac);
+ TlsUtilities.WriteVersion(bosMac);
+ TlsUtilities.WriteUint16(len, bosMac);
+ bosMac.Write(message, offset, len);
+ byte[] macData = bosMac.ToArray();
+ mac.BlockUpdate(macData, 0, macData.Length);
+ byte[] result = new byte[mac.GetMacSize()];
+ mac.DoFinal(result, 0);
+ mac.Reset();
+ return result;
+ }
+ catch (IOException)
+ {
+ // This should never happen
+ throw new InvalidOperationException("Internal error during mac calculation");
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsNullCipherSuite.cs b/src/core/srcbc/crypto/tls/TlsNullCipherSuite.cs
new file mode 100644
index 0000000..25c3f91
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsNullCipherSuite.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// A NULL CipherSuite in java, this should only be used during handshake.
+ public class TlsNullCipherSuite
+ : TlsCipherSuite
+ {
+ internal override void Init(
+ byte[] ms,
+ byte[] cr,
+ byte[] sr)
+ {
+ throw new TlsException("Sorry, init of TLS_NULL_WITH_NULL_NULL is forbidden");
+ }
+
+ internal override byte[] EncodePlaintext(
+ short type,
+ byte[] plaintext,
+ int offset,
+ int len)
+ {
+ byte[] result = new byte[len];
+ Array.Copy(plaintext, offset, result, 0, len);
+ return result;
+ }
+
+ internal override byte[] DecodeCiphertext(
+ short type,
+ byte[] plaintext,
+ int offset,
+ int len,
+ TlsProtocolHandler handler)
+ {
+ byte[] result = new byte[len];
+ Array.Copy(plaintext, offset, result, 0, len);
+ return result;
+ }
+
+ internal override short KeyExchangeAlgorithm
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsOutputStream.cs b/src/core/srcbc/crypto/tls/TlsOutputStream.cs
new file mode 100644
index 0000000..8dda729
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsOutputStream.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// An output Stream for a TLS 1.0 connection.
+ // TODO Fix name and make internal once TlsProtocolHandler.TlsOuputStream is removed
+ public class TlsOuputStream
+ : BaseOutputStream
+ {
+ private readonly TlsProtocolHandler handler;
+
+ internal TlsOuputStream(
+ TlsProtocolHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public override void Write(
+ byte[] buf,
+ int offset,
+ int len)
+ {
+ this.handler.WriteData(buf, offset, len);
+ }
+
+ [Obsolete("Use version that takes a 'byte' argument")]
+ public void WriteByte(int arg0)
+ {
+ this.Write((byte)arg0);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ this.Write(b);
+ }
+
+ public override void Close()
+ {
+ handler.Close();
+ base.Close();
+ }
+
+ public override void Flush()
+ {
+ handler.Flush();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs b/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs
new file mode 100644
index 0000000..eb860cd
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs
@@ -0,0 +1,1152 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// An implementation of all high level protocols in TLS 1.0.
+ public class TlsProtocolHandler
+ {
+ private const short RL_CHANGE_CIPHER_SPEC = 20;
+ private const short RL_ALERT = 21;
+ private const short RL_HANDSHAKE = 22;
+ private const short RL_APPLICATION_DATA = 23;
+
+ /*
+ hello_request(0), client_hello(1), server_hello(2),
+ certificate(11), server_key_exchange (12),
+ certificate_request(13), server_hello_done(14),
+ certificate_verify(15), client_key_exchange(16),
+ finished(20), (255)
+ */
+
+ private const short HP_HELLO_REQUEST = 0;
+ private const short HP_CLIENT_HELLO = 1;
+ private const short HP_SERVER_HELLO = 2;
+ private const short HP_CERTIFICATE = 11;
+ private const short HP_SERVER_KEY_EXCHANGE = 12;
+ private const short HP_CERTIFICATE_REQUEST = 13;
+ private const short HP_SERVER_HELLO_DONE = 14;
+ private const short HP_CERTIFICATE_VERIFY = 15;
+ private const short HP_CLIENT_KEY_EXCHANGE = 16;
+ private const short HP_FINISHED = 20;
+
+ /*
+ * Our Connection states
+ */
+
+ private const short CS_CLIENT_HELLO_SEND = 1;
+ private const short CS_SERVER_HELLO_RECEIVED = 2;
+ private const short CS_SERVER_CERTIFICATE_RECEIVED = 3;
+ private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4;
+ private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5;
+ private const short CS_SERVER_HELLO_DONE_RECEIVED = 6;
+ private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7;
+ private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 8;
+ private const short CS_CLIENT_FINISHED_SEND = 9;
+ private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 10;
+ private const short CS_DONE = 11;
+
+ internal const short AP_close_notify = 0;
+ internal const short AP_unexpected_message = 10;
+ internal const short AP_bad_record_mac = 20;
+ internal const short AP_decryption_failed = 21;
+ internal const short AP_record_overflow = 22;
+ internal const short AP_decompression_failure = 30;
+ internal const short AP_handshake_failure = 40;
+ internal const short AP_bad_certificate = 42;
+ internal const short AP_unsupported_certificate = 43;
+ internal const short AP_certificate_revoked = 44;
+ internal const short AP_certificate_expired = 45;
+ internal const short AP_certificate_unknown = 46;
+ internal const short AP_illegal_parameter = 47;
+ internal const short AP_unknown_ca = 48;
+ internal const short AP_access_denied = 49;
+ internal const short AP_decode_error = 50;
+ internal const short AP_decrypt_error = 51;
+ internal const short AP_export_restriction = 60;
+ internal const short AP_protocol_version = 70;
+ internal const short AP_insufficient_security = 71;
+ internal const short AP_internal_error = 80;
+ internal const short AP_user_canceled = 90;
+ internal const short AP_no_renegotiation = 100;
+
+ internal const short AL_warning = 1;
+ internal const short AL_fatal = 2;
+
+ private static readonly byte[] emptybuf = new byte[0];
+
+ private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
+
+ /*
+ * Queues for data from some protocols.
+ */
+
+ private ByteQueue applicationDataQueue = new ByteQueue();
+ private ByteQueue changeCipherSpecQueue = new ByteQueue();
+ private ByteQueue alertQueue = new ByteQueue();
+ private ByteQueue handshakeQueue = new ByteQueue();
+
+ /*
+ * The Record Stream we use
+ */
+ private RecordStream rs;
+
+ private SecureRandom random;
+
+ /*
+ * The public rsa-key of the server.
+ */
+ private RsaKeyParameters serverRsaKey = null;
+
+ private TlsInputStream tlsInputStream = null;
+ private TlsOuputStream tlsOutputStream = null;
+
+ private bool closed = false;
+ private bool failedWithError = false;
+ private bool appDataReady = false;
+
+ private byte[] clientRandom;
+ private byte[] serverRandom;
+ private byte[] ms;
+
+ private TlsCipherSuite choosenCipherSuite = null;
+
+ private BigInteger Yc;
+ private byte[] pms;
+
+ private ICertificateVerifyer verifyer = null;
+
+ /*
+ * Both streams can be the same object
+ */
+ public TlsProtocolHandler(
+ Stream inStr,
+ Stream outStr)
+ {
+ /*
+ * We use a threaded seed generator to generate a good random
+ * seed. If the user has a better random seed, he should use
+ * the constructor with a SecureRandom.
+ *
+ * Hopefully, 20 bytes in fast mode are good enough.
+ */
+ byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true);
+
+ this.random = new SecureRandom(seed);
+ this.rs = new RecordStream(this, inStr, outStr);
+ }
+
+ public TlsProtocolHandler(
+ Stream inStr,
+ Stream outStr,
+ SecureRandom sr)
+ {
+ this.random = sr;
+ this.rs = new RecordStream(this, inStr, outStr);
+ }
+
+ private short connection_state;
+
+ internal void ProcessData(
+ short protocol,
+ byte[] buf,
+ int offset,
+ int len)
+ {
+ /*
+ * Have a look at the protocol type, and add it to the correct queue.
+ */
+ switch (protocol)
+ {
+ case RL_CHANGE_CIPHER_SPEC:
+ changeCipherSpecQueue.AddData(buf, offset, len);
+ processChangeCipherSpec();
+ break;
+ case RL_ALERT:
+ alertQueue.AddData(buf, offset, len);
+ processAlert();
+ break;
+ case RL_HANDSHAKE:
+ handshakeQueue.AddData(buf, offset, len);
+ processHandshake();
+ break;
+ case RL_APPLICATION_DATA:
+ if (!appDataReady)
+ {
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ }
+ applicationDataQueue.AddData(buf, offset, len);
+ processApplicationData();
+ break;
+ default:
+ /*
+ * Uh, we don't know this protocol.
+ *
+ * RFC2246 defines on page 13, that we should ignore this.
+ */
+ break;
+ }
+ }
+
+ private void processHandshake()
+ {
+ bool read;
+ do
+ {
+ read = false;
+
+ /*
+ * We need the first 4 bytes, they contain type and length of
+ * the message.
+ */
+ if (handshakeQueue.Available >= 4)
+ {
+ byte[] beginning = new byte[4];
+ handshakeQueue.Read(beginning, 0, 4, 0);
+ MemoryStream bis = new MemoryStream(beginning, false);
+ short type = TlsUtilities.ReadUint8(bis);
+ int len = TlsUtilities.ReadUint24(bis);
+
+ /*
+ * Check if we have enough bytes in the buffer to read
+ * the full message.
+ */
+ if (handshakeQueue.Available >= (len + 4))
+ {
+ /*
+ * Read the message.
+ */
+ byte[] buf = new byte[len];
+ handshakeQueue.Read(buf, 0, len, 4);
+ handshakeQueue.RemoveData(len + 4);
+
+ /*
+ * If it is not a finished message, update our hashes
+ * we prepare for the finish message.
+ */
+ if (type != HP_FINISHED)
+ {
+ rs.hash1.BlockUpdate(beginning, 0, 4);
+ rs.hash2.BlockUpdate(beginning, 0, 4);
+ rs.hash1.BlockUpdate(buf, 0, len);
+ rs.hash2.BlockUpdate(buf, 0, len);
+ }
+
+ /*
+ * Now, parse the message.
+ */
+ MemoryStream inStr = new MemoryStream(buf, false);
+
+ /*
+ * Check the type.
+ */
+ switch (type)
+ {
+ case HP_CERTIFICATE:
+ switch (connection_state)
+ {
+ case CS_SERVER_HELLO_RECEIVED:
+ /*
+ * Parse the certificates.
+ */
+ Certificate cert = Certificate.Parse(inStr);
+ AssertEmpty(inStr);
+
+ /*
+ * Verify them.
+ */
+ if (!this.verifyer.IsValid(cert.GetCerts()))
+ {
+ this.FailWithError(AL_fatal, AP_user_canceled);
+ }
+
+ /*
+ * We only support RSA certificates. Lets hope
+ * this is one.
+ */
+ RsaPublicKeyStructure rsaKey = null;
+ try
+ {
+ rsaKey = RsaPublicKeyStructure.GetInstance(
+ cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
+ }
+ catch (Exception)
+ {
+ /*
+ * Sorry, we have to fail ;-(
+ */
+ this.FailWithError(AL_fatal, AP_unsupported_certificate);
+ }
+
+ /*
+ * Parse the servers public RSA key.
+ */
+ this.serverRsaKey = new RsaKeyParameters(
+ false,
+ rsaKey.Modulus,
+ rsaKey.PublicExponent);
+
+ connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+ }
+ break;
+ case HP_FINISHED:
+ switch (connection_state)
+ {
+ case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
+ /*
+ * Read the checksum from the finished message,
+ * it has always 12 bytes.
+ */
+ byte[] receivedChecksum = new byte[12];
+ TlsUtilities.ReadFully(receivedChecksum, inStr);
+ AssertEmpty(inStr);
+
+ /*
+ * Calculate our own checksum.
+ */
+ byte[] checksum = new byte[12];
+ byte[] md5andsha1 = new byte[16 + 20];
+ rs.hash2.DoFinal(md5andsha1, 0);
+ TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);
+
+ /*
+ * Compare both checksums.
+ */
+ for (int i = 0; i < receivedChecksum.Length; i++)
+ {
+ if (receivedChecksum[i] != checksum[i])
+ {
+ /*
+ * Wrong checksum in the finished message.
+ */
+ this.FailWithError(AL_fatal, AP_handshake_failure);
+ }
+ }
+
+ connection_state = CS_DONE;
+
+ /*
+ * We are now ready to receive application data.
+ */
+ this.appDataReady = true;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+ }
+ break;
+ case HP_SERVER_HELLO:
+ switch (connection_state)
+ {
+ case CS_CLIENT_HELLO_SEND:
+ /*
+ * Read the server hello message
+ */
+ TlsUtilities.CheckVersion(inStr, this);
+
+ /*
+ * Read the server random
+ */
+ this.serverRandom = new byte[32];
+ TlsUtilities.ReadFully(this.serverRandom, inStr);
+
+ /*
+ * Currently, we don't support session ids
+ */
+ short sessionIdLength = TlsUtilities.ReadUint8(inStr);
+ byte[] sessionId = new byte[sessionIdLength];
+ TlsUtilities.ReadFully(sessionId, inStr);
+
+ /*
+ * Find out which ciphersuite the server has
+ * chosen. If we don't support this ciphersuite,
+ * the TlsCipherSuiteManager will throw an
+ * exception.
+ */
+ this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
+ TlsUtilities.ReadUint16(inStr), this);
+
+ /*
+ * We support only the null compression which
+ * means no compression.
+ */
+ short compressionMethod = TlsUtilities.ReadUint8(inStr);
+ if (compressionMethod != 0)
+ {
+ this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
+ }
+ AssertEmpty(inStr);
+
+ connection_state = CS_SERVER_HELLO_RECEIVED;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+ }
+ break;
+ case HP_SERVER_HELLO_DONE:
+ switch (connection_state)
+ {
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+ case CS_SERVER_KEY_EXCHANGE_RECEIVED:
+ case CS_CERTIFICATE_REQUEST_RECEIVED:
+
+ // NB: Original code used case label fall-through
+ if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
+ {
+ /*
+ * There was no server key exchange message, check
+ * that we are doing RSA key exchange.
+ */
+ if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
+ {
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ }
+ }
+
+ AssertEmpty(inStr);
+ bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED);
+ connection_state = CS_SERVER_HELLO_DONE_RECEIVED;
+
+ if (isCertReq)
+ {
+ sendClientCertificate();
+ }
+
+ /*
+ * Send the client key exchange message, depending
+ * on the key exchange we are using in our
+ * ciphersuite.
+ */
+ short ke = this.choosenCipherSuite.KeyExchangeAlgorithm;
+
+ switch (ke)
+ {
+ case TlsCipherSuite.KE_RSA:
+ /*
+ * We are doing RSA key exchange. We will
+ * choose a pre master secret and send it
+ * rsa encrypted to the server.
+ *
+ * Prepare pre master secret.
+ */
+ pms = new byte[48];
+ pms[0] = 3;
+ pms[1] = 1;
+ random.NextBytes(pms, 2, 46);
+
+ /*
+ * Encode the pms and send it to the server.
+ *
+ * Prepare an Pkcs1Encoding with good random
+ * padding.
+ */
+ RsaBlindedEngine rsa = new RsaBlindedEngine();
+ Pkcs1Encoding encoding = new Pkcs1Encoding(rsa);
+ encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random));
+ byte[] encrypted = null;
+ try
+ {
+ encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
+ }
+ catch (InvalidCipherTextException)
+ {
+ /*
+ * This should never happen, only during decryption.
+ */
+ this.FailWithError(AL_fatal, AP_internal_error);
+ }
+
+ /*
+ * Send the encrypted pms.
+ */
+ MemoryStream bos = new MemoryStream();
+ TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
+ TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
+ TlsUtilities.WriteUint16(encrypted.Length, bos);
+ bos.Write(encrypted, 0, encrypted.Length);
+ byte[] message = bos.ToArray();
+
+ rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length);
+ break;
+ case TlsCipherSuite.KE_DHE_RSA:
+ /*
+ * Send the Client Key Exchange message for
+ * DHE key exchange.
+ */
+ byte[] YcByte = this.Yc.ToByteArray();
+ MemoryStream DHbos = new MemoryStream();
+ TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
+ TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
+ TlsUtilities.WriteUint16(YcByte.Length, DHbos);
+ DHbos.Write(YcByte, 0, YcByte.Length);
+ byte[] DHmessage = DHbos.ToArray();
+
+ rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length);
+
+ break;
+ default:
+ /*
+ * Problem during handshake, we don't know
+ * how to handle this key exchange method.
+ */
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+
+ }
+
+ connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
+
+ /*
+ * Now, we send change cipher state
+ */
+ byte[] cmessage = new byte[1];
+ cmessage[0] = 1;
+ rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);
+
+ connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
+
+ /*
+ * Calculate the ms
+ */
+ this.ms = new byte[48];
+ byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
+ Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
+ Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
+ TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);
+
+ /*
+ * Initialize our cipher suite
+ */
+ rs.writeSuite = this.choosenCipherSuite;
+ rs.writeSuite.Init(this.ms, clientRandom, serverRandom);
+
+ /*
+ * Send our finished message.
+ */
+ byte[] checksum = new byte[12];
+ byte[] md5andsha1 = new byte[16 + 20];
+ rs.hash1.DoFinal(md5andsha1, 0);
+ TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);
+
+ MemoryStream bos2 = new MemoryStream();
+ TlsUtilities.WriteUint8(HP_FINISHED, bos2);
+ TlsUtilities.WriteUint24(12, bos2);
+ bos2.Write(checksum, 0, checksum.Length);
+ byte[] message2 = bos2.ToArray();
+
+ rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);
+
+ this.connection_state = CS_CLIENT_FINISHED_SEND;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_handshake_failure);
+ break;
+ }
+ break;
+ case HP_SERVER_KEY_EXCHANGE:
+ switch (connection_state)
+ {
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+ /*
+ * Check that we are doing DHE key exchange
+ */
+ if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
+ {
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ }
+
+ /*
+ * Parse the Structure
+ */
+ int pLength = TlsUtilities.ReadUint16(inStr);
+ byte[] pByte = new byte[pLength];
+ TlsUtilities.ReadFully(pByte, inStr);
+
+ int gLength = TlsUtilities.ReadUint16(inStr);
+ byte[] gByte = new byte[gLength];
+ TlsUtilities.ReadFully(gByte, inStr);
+
+ int YsLength = TlsUtilities.ReadUint16(inStr);
+ byte[] YsByte = new byte[YsLength];
+ TlsUtilities.ReadFully(YsByte, inStr);
+
+ int sigLength = TlsUtilities.ReadUint16(inStr);
+ byte[] sigByte = new byte[sigLength];
+ TlsUtilities.ReadFully(sigByte, inStr);
+
+ AssertEmpty(inStr);
+
+ /*
+ * Verify the Signature.
+ *
+ * First, calculate the hash.
+ */
+ CombinedHash sigDigest = new CombinedHash();
+ MemoryStream signedData = new MemoryStream();
+ TlsUtilities.WriteUint16(pLength, signedData);
+ signedData.Write(pByte, 0, pByte.Length);
+ TlsUtilities.WriteUint16(gLength, signedData);
+ signedData.Write(gByte, 0, gByte.Length);
+ TlsUtilities.WriteUint16(YsLength, signedData);
+ signedData.Write(YsByte, 0, YsByte.Length);
+ byte[] signed = signedData.ToArray();
+
+ sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
+ sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
+ sigDigest.BlockUpdate(signed, 0, signed.Length);
+ byte[] hash = new byte[sigDigest.GetDigestSize()];
+ sigDigest.DoFinal(hash, 0);
+
+ /*
+ * Now, do the RSA operation
+ */
+ RsaBlindedEngine rsa = new RsaBlindedEngine();
+ Pkcs1Encoding encoding = new Pkcs1Encoding(rsa);
+ encoding.Init(false, this.serverRsaKey);
+
+ /*
+ * The data which was signed
+ */
+ byte[] sigHash = null;
+
+ try
+ {
+ sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length);
+ }
+ catch (InvalidCipherTextException)
+ {
+ this.FailWithError(AL_fatal, AP_bad_certificate);
+ }
+
+ /*
+ * Check if the data which was signed is equal to
+ * the hash we calculated.
+ */
+ if (sigHash.Length != hash.Length)
+ {
+ this.FailWithError(AL_fatal, AP_bad_certificate);
+ }
+
+ for (int i = 0; i < sigHash.Length; i++)
+ {
+ if (sigHash[i] != hash[i])
+ {
+ this.FailWithError(AL_fatal, AP_bad_certificate);
+ }
+ }
+
+ /*
+ * OK, Signature was correct.
+ *
+ * Do the DH calculation.
+ */
+ BigInteger p = new BigInteger(1, pByte);
+ BigInteger g = new BigInteger(1, gByte);
+ BigInteger Ys = new BigInteger(1, YsByte);
+ BigInteger x = new BigInteger(p.BitLength - 1, this.random);
+ Yc = g.ModPow(x, p);
+ this.pms = Ys.ModPow(x, p).ToByteArrayUnsigned();
+
+ this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+ }
+ break;
+ case HP_CERTIFICATE_REQUEST:
+ switch (connection_state)
+ {
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+ case CS_SERVER_KEY_EXCHANGE_RECEIVED:
+
+ // NB: Original code used case label fall-through
+ if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
+ {
+ /*
+ * There was no server key exchange message, check
+ * that we are doing RSA key exchange.
+ */
+ if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
+ {
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ }
+ }
+
+ int typesLength = TlsUtilities.ReadUint8(inStr);
+ byte[] types = new byte[typesLength];
+ TlsUtilities.ReadFully(types, inStr);
+
+ int authsLength = TlsUtilities.ReadUint16(inStr);
+ byte[] auths = new byte[authsLength];
+ TlsUtilities.ReadFully(auths, inStr);
+
+ AssertEmpty(inStr);
+
+ this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
+ read = true;
+ break;
+ default:
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+ }
+ break;
+ case HP_HELLO_REQUEST:
+ case HP_CLIENT_KEY_EXCHANGE:
+ case HP_CERTIFICATE_VERIFY:
+ case HP_CLIENT_HELLO:
+ default:
+ // We do not support this!
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+ break;
+
+ }
+
+ }
+ }
+ }
+ while (read);
+
+ }
+
+ private void processApplicationData()
+ {
+ /*
+ * There is nothing we need to do here.
+ *
+ * This function could be used for callbacks when application
+ * data arrives in the future.
+ */
+ }
+
+ private void processAlert()
+ {
+ while (alertQueue.Available >= 2)
+ {
+ /*
+ * An alert is always 2 bytes. Read the alert.
+ */
+ byte[] tmp = new byte[2];
+ alertQueue.Read(tmp, 0, 2, 0);
+ alertQueue.RemoveData(2);
+ short level = tmp[0];
+ short description = tmp[1];
+ if (level == AL_fatal)
+ {
+ /*
+ * This is a fatal error.
+ */
+ this.failedWithError = true;
+ this.closed = true;
+ /*
+ * Now try to Close the stream, ignore errors.
+ */
+ try
+ {
+ rs.Close();
+ }
+ catch (Exception)
+ {
+ }
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ else
+ {
+ /*
+ * This is just a warning.
+ */
+ if (description == AP_close_notify)
+ {
+ /*
+ * Close notify
+ */
+ this.FailWithError(AL_warning, AP_close_notify);
+ }
+ /*
+ * If it is just a warning, we continue.
+ */
+ }
+ }
+
+ }
+
+ /**
+ * This method is called, when a change cipher spec message is received.
+ *
+ * @throws IOException If the message has an invalid content or the
+ * handshake is not in the correct state.
+ */
+ private void processChangeCipherSpec()
+ {
+ while (changeCipherSpecQueue.Available > 0)
+ {
+ /*
+ * A change cipher spec message is only one byte with the value 1.
+ */
+ byte[] b = new byte[1];
+ changeCipherSpecQueue.Read(b, 0, 1, 0);
+ changeCipherSpecQueue.RemoveData(1);
+ if (b[0] != 1)
+ {
+ /*
+ * This should never happen.
+ */
+ this.FailWithError(AL_fatal, AP_unexpected_message);
+
+ }
+ else
+ {
+ /*
+ * Check if we are in the correct connection state.
+ */
+ if (this.connection_state == CS_CLIENT_FINISHED_SEND)
+ {
+ rs.readSuite = rs.writeSuite;
+ this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
+ }
+ else
+ {
+ /*
+ * We are not in the correct connection state.
+ */
+ this.FailWithError(AL_fatal, AP_handshake_failure);
+ }
+
+ }
+ }
+ }
+
+ private void sendClientCertificate()
+ {
+ /*
+ * just write back the "no client certificate" message
+ * see also gnutls, auth_cert.c:643 (0B 00 00 03 00 00 00)
+ */
+ MemoryStream bos = new MemoryStream();
+ TlsUtilities.WriteUint8(HP_CERTIFICATE, bos);
+ TlsUtilities.WriteUint24(3, bos);
+ TlsUtilities.WriteUint24(0, bos);
+ byte[] message = bos.ToArray();
+
+ rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length);
+ }
+
+ /// Connects to the remote system.
+ /// Will be used when a certificate is received to verify
+ /// that this certificate is accepted by the client.
+ /// If handshake was not successful
+ public virtual void Connect(
+ ICertificateVerifyer verifyer)
+ {
+ this.verifyer = verifyer;
+
+ /*
+ * Send Client hello
+ *
+ * First, generate some random data.
+ */
+ this.clientRandom = new byte[32];
+
+ /*
+ * TLS 1.0 requires a unix-timestamp in the first 4 bytes
+ */
+ int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
+ this.clientRandom[0] = (byte)(t >> 24);
+ this.clientRandom[1] = (byte)(t >> 16);
+ this.clientRandom[2] = (byte)(t >> 8);
+ this.clientRandom[3] = (byte)t;
+
+ random.NextBytes(this.clientRandom, 4, 28);
+
+
+ MemoryStream outStr = new MemoryStream();
+ TlsUtilities.WriteVersion(outStr);
+ outStr.Write(this.clientRandom, 0, this.clientRandom.Length);
+
+ /*
+ * Length of Session id
+ */
+ TlsUtilities.WriteUint8((short)0, outStr);
+
+ /*
+ * Cipher suites
+ */
+ TlsCipherSuiteManager.WriteCipherSuites(outStr);
+
+ /*
+ * Compression methods, just the null method.
+ */
+ byte[] compressionMethods = new byte[]{0x00};
+ TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr);
+ outStr.Write(compressionMethods,0, compressionMethods.Length);
+
+
+ MemoryStream bos = new MemoryStream();
+ TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos);
+ TlsUtilities.WriteUint24((int) outStr.Length, bos);
+ byte[] outBytes = outStr.ToArray();
+ bos.Write(outBytes, 0, outBytes.Length);
+ byte[] message = bos.ToArray();
+ rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length);
+ connection_state = CS_CLIENT_HELLO_SEND;
+
+ /*
+ * We will now read data, until we have completed the handshake.
+ */
+ while (connection_state != CS_DONE)
+ {
+ rs.ReadData();
+ }
+
+ this.tlsInputStream = new TlsInputStream(this);
+ this.tlsOutputStream = new TlsOuputStream(this);
+ }
+
+ /**
+ * Read data from the network. The method will return immed, if there is
+ * still some data left in the buffer, or block untill some application
+ * data has been read from the network.
+ *
+ * @param buf The buffer where the data will be copied to.
+ * @param offset The position where the data will be placed in the buffer.
+ * @param len The maximum number of bytes to read.
+ * @return The number of bytes read.
+ * @throws IOException If something goes wrong during reading data.
+ */
+ internal int ReadApplicationData(byte[] buf, int offset, int len)
+ {
+ while (applicationDataQueue.Available == 0)
+ {
+ /*
+ * We need to read some data.
+ */
+ if (this.failedWithError)
+ {
+ /*
+ * Something went terribly wrong, we should throw an IOException
+ */
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ if (this.closed)
+ {
+ /*
+ * Connection has been closed, there is no more data to read.
+ */
+ return 0;
+ }
+
+ try
+ {
+ rs.ReadData();
+ }
+ catch (IOException e)
+ {
+ if (!this.closed)
+ {
+ this.FailWithError(AL_fatal, AP_internal_error);
+ }
+ throw e;
+ }
+ catch (Exception e)
+ {
+ if (!this.closed)
+ {
+ this.FailWithError(AL_fatal, AP_internal_error);
+ }
+ throw e;
+ }
+ }
+ len = System.Math.Min(len, applicationDataQueue.Available);
+ applicationDataQueue.Read(buf, offset, len, 0);
+ applicationDataQueue.RemoveData(len);
+ return len;
+ }
+
+ /**
+ * Send some application data to the remote system.
+ *
+ * The method will handle fragmentation internally.
+ *
+ * @param buf The buffer with the data.
+ * @param offset The position in the buffer where the data is placed.
+ * @param len The length of the data.
+ * @throws IOException If something goes wrong during sending.
+ */
+ internal void WriteData(byte[] buf, int offset, int len)
+ {
+ if (this.failedWithError)
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ if (this.closed)
+ {
+ throw new IOException("Sorry, connection has been closed, you cannot write more data");
+ }
+
+ /*
+ * Protect against known IV attack!
+ *
+ * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT
+ * YOU ARE DOING HERE.
+ */
+ rs.WriteMessage(RL_APPLICATION_DATA, emptybuf, 0, 0);
+
+ do
+ {
+ /*
+ * We are only allowed to write fragments up to 2^14 bytes.
+ */
+ int toWrite = System.Math.Min(len, 1 << 14);
+
+ try
+ {
+ rs.WriteMessage(RL_APPLICATION_DATA, buf, offset, toWrite);
+ }
+ catch (IOException e)
+ {
+ if (!closed)
+ {
+ this.FailWithError(AL_fatal, AP_internal_error);
+ }
+ throw e;
+ }
+ catch (Exception e)
+ {
+ if (!closed)
+ {
+ this.FailWithError(AL_fatal, AP_internal_error);
+ }
+ throw e;
+ }
+
+
+ offset += toWrite;
+ len -= toWrite;
+ }
+ while (len > 0);
+
+ }
+
+ [Obsolete("Use 'OutputStream' property instead")]
+ public TlsOuputStream TlsOuputStream
+ {
+ get { return this.tlsOutputStream; }
+ }
+
+ /// A Stream which can be used to send data.
+ public virtual Stream OutputStream
+ {
+ get { return this.tlsOutputStream; }
+ }
+
+ [Obsolete("Use 'InputStream' property instead")]
+ public TlsInputStream TlsInputStream
+ {
+ get { return this.tlsInputStream; }
+ }
+
+ /// A Stream which can be used to read data.
+ public virtual Stream InputStream
+ {
+ get { return this.tlsInputStream; }
+ }
+
+ /**
+ * Terminate this connection whith an alert.
+ *
+ * Can be used for normal closure too.
+ *
+ * @param alertLevel The level of the alert, an be AL_fatal or AL_warning.
+ * @param alertDescription The exact alert message.
+ * @throws IOException If alert was fatal.
+ */
+ internal void FailWithError(
+ short alertLevel,
+ short alertDescription)
+ {
+ /*
+ * Check if the connection is still open.
+ */
+ if (!closed)
+ {
+ /*
+ * Prepare the message
+ */
+ byte[] error = new byte[2];
+ error[0] = (byte)alertLevel;
+ error[1] = (byte)alertDescription;
+ this.closed = true;
+
+ if (alertLevel == AL_fatal)
+ {
+ /*
+ * This is a fatal message.
+ */
+ this.failedWithError = true;
+ }
+ rs.WriteMessage(RL_ALERT, error, 0, 2);
+ rs.Close();
+ if (alertLevel == AL_fatal)
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+
+ }
+ else
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ }
+
+ /// Closes this connection
+ /// If something goes wrong during closing.
+ public virtual void Close()
+ {
+ if (!closed)
+ {
+ this.FailWithError((short)1, (short)0);
+ }
+ }
+
+ /**
+ * Make sure the Stream is now empty. Fail otherwise.
+ *
+ * @param is The Stream to check.
+ * @throws IOException If is is not empty.
+ */
+ internal void AssertEmpty(
+ MemoryStream inStr)
+ {
+// if (inStr.available() > 0)
+ if (inStr.Position < inStr.Length)
+ {
+ this.FailWithError(AL_fatal, AP_decode_error);
+ }
+ }
+
+ internal void Flush()
+ {
+ rs.Flush();
+ }
+ }
+}
diff --git a/src/core/srcbc/crypto/tls/TlsUtilities.cs b/src/core/srcbc/crypto/tls/TlsUtilities.cs
new file mode 100644
index 0000000..c51d3e5
--- /dev/null
+++ b/src/core/srcbc/crypto/tls/TlsUtilities.cs
@@ -0,0 +1,223 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// Some helper fuctions for MicroTLS.
+ public class TlsUtilities
+ {
+ internal static byte[] ToByteArray(string str)
+ {
+ return Strings.ToByteArray(str);
+ }
+
+ internal static void WriteUint8(short i, Stream os)
+ {
+ os.WriteByte((byte)i);
+ }
+
+ internal static void WriteUint8(short i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)i;
+ }
+
+ internal static void WriteUint16(int i, Stream os)
+ {
+ os.WriteByte((byte)(i >> 8));
+ os.WriteByte((byte)i);
+ }
+
+ internal static void WriteUint16(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 8);
+ buf[offset + 1] = (byte)i;
+ }
+
+ internal static void WriteUint24(int i, Stream os)
+ {
+ os.WriteByte((byte)(i >> 16));
+ os.WriteByte((byte)(i >> 8));
+ os.WriteByte((byte)i);
+ }
+
+ internal static void WriteUint24(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 16);
+ buf[offset + 1] = (byte)(i >> 8);
+ buf[offset + 2] = (byte)(i);
+ }
+
+ internal static void WriteUint32(long i, Stream os)
+ {
+ os.WriteByte((byte)(i >> 24));
+ os.WriteByte((byte)(i >> 16));
+ os.WriteByte((byte)(i >> 8));
+ os.WriteByte((byte)i);
+ }
+
+ internal static void WriteUint32(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 24);
+ buf[offset + 1] = (byte)(i >> 16);
+ buf[offset + 2] = (byte)(i >> 8);
+ buf[offset + 3] = (byte)(i);
+ }
+
+ internal static void WriteUint64(long i, Stream os)
+ {
+ os.WriteByte((byte)(i >> 56));
+ os.WriteByte((byte)(i >> 48));
+ os.WriteByte((byte)(i >> 40));
+ os.WriteByte((byte)(i >> 32));
+ os.WriteByte((byte)(i >> 24));
+ os.WriteByte((byte)(i >> 16));
+ os.WriteByte((byte)(i >> 8));
+ os.WriteByte((byte)i);
+ }
+
+ internal static void WriteUint64(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 56);
+ buf[offset + 1] = (byte)(i >> 48);
+ buf[offset + 2] = (byte)(i >> 40);
+ buf[offset + 3] = (byte)(i >> 32);
+ buf[offset + 4] = (byte)(i >> 24);
+ buf[offset + 5] = (byte)(i >> 16);
+ buf[offset + 6] = (byte)(i >> 8);
+ buf[offset + 7] = (byte)(i);
+ }
+
+ internal static short ReadUint8(Stream inStr)
+ {
+ int i = inStr.ReadByte();
+ if (i < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return (short)i;
+ }
+
+ internal static int ReadUint16(Stream inStr)
+ {
+ int i1 = inStr.ReadByte();
+ int i2 = inStr.ReadByte();
+ if ((i1 | i2) < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return i1 << 8 | i2;
+ }
+
+ internal static int ReadUint24(Stream inStr)
+ {
+ int i1 = inStr.ReadByte();
+ int i2 = inStr.ReadByte();
+ int i3 = inStr.ReadByte();
+ if ((i1 | i2 | i3) < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ return (i1 << 16) | (i2 << 8) | i3;
+ }
+
+ internal static long ReadUint32(Stream inStr)
+ {
+ int i1 = inStr.ReadByte();
+ int i2 = inStr.ReadByte();
+ int i3 = inStr.ReadByte();
+ int i4 = inStr.ReadByte();
+ if ((i1 | i2 | i3 | i4) < 0)
+ {
+ throw new EndOfStreamException();
+ }
+ // TODO Examine this
+// return (((long)i1) << 24) | (((long)i2) << 16) | (((long)i3) << 8) | ((long)i4);
+ return ((long)i1 << 24) | ((long)i2 << 16) | ((long)i3 << 8) | (uint)i4;
+ }
+
+ internal static void ReadFully(byte[] buf, Stream inStr)
+ {
+ if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
+ throw new EndOfStreamException();
+ }
+
+ internal static void CheckVersion(byte[] readVersion, TlsProtocolHandler handler)
+ {
+ if ((readVersion[0] != 3) || (readVersion[1] != 1))
+ {
+ handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_protocol_version);
+ }
+ }
+
+ internal static void CheckVersion(Stream inStr, TlsProtocolHandler handler)
+ {
+ int i1 = inStr.ReadByte();
+ int i2 = inStr.ReadByte();
+ if ((i1 != 3) || (i2 != 1))
+ {
+ handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_protocol_version);
+ }
+ }
+
+ internal static void WriteVersion(Stream os)
+ {
+ os.WriteByte(3);
+ os.WriteByte(1);
+ }
+
+ private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+ {
+ HMac mac = new HMac(digest);
+ KeyParameter param = new KeyParameter(secret);
+ byte[] a = seed;
+ int size = digest.GetDigestSize();
+ int iterations = (output.Length + size - 1) / size;
+ byte[] buf = new byte[mac.GetMacSize()];
+ byte[] buf2 = new byte[mac.GetMacSize()];
+ for (int i = 0; i < iterations; i++)
+ {
+ mac.Init(param);
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.DoFinal(buf, 0);
+ a = buf;
+ mac.Init(param);
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.BlockUpdate(seed, 0, seed.Length);
+ mac.DoFinal(buf2, 0);
+ Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+ }
+ }
+
+ internal static void PRF(
+ byte[] secret,
+ byte[] label,
+ byte[] seed,
+ byte[] buf)
+ {
+ int s_half = (secret.Length + 1) / 2;
+ byte[] s1 = new byte[s_half];
+ byte[] s2 = new byte[s_half];
+ Array.Copy(secret, 0, s1, 0, s_half);
+ Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
+
+ byte[] ls = new byte[label.Length + seed.Length];
+ Array.Copy(label, 0, ls, 0, label.Length);
+ Array.Copy(seed, 0, ls, label.Length, seed.Length);
+
+ byte[] prf = new byte[buf.Length];
+ hmac_hash(new MD5Digest(), s1, ls, prf);
+ hmac_hash(new Sha1Digest(), s2, ls, buf);
+ for (int i = 0; i < buf.Length; i++)
+ {
+ buf[i] ^= prf[i];
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/math/BigInteger.cs b/src/core/srcbc/math/BigInteger.cs
new file mode 100644
index 0000000..0943f68
--- /dev/null
+++ b/src/core/srcbc/math/BigInteger.cs
@@ -0,0 +1,3152 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+
+namespace Org.BouncyCastle.Math
+{
+#if !NETCF_1_0
+ [Serializable]
+#endif
+ public class BigInteger
+ {
+ // The primes b/w 2 and ~2^10
+ /*
+ 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
+ */
+
+ // Each list has a product < 2^31
+ private static readonly int[][] primeLists = new int[][]
+ {
+ new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
+ new int[]{ 29, 31, 37, 41, 43 },
+ new int[]{ 47, 53, 59, 61, 67 },
+ new int[]{ 71, 73, 79, 83 },
+ new int[]{ 89, 97, 101, 103 },
+
+ new int[]{ 107, 109, 113, 127 },
+ new int[]{ 131, 137, 139, 149 },
+ new int[]{ 151, 157, 163, 167 },
+ new int[]{ 173, 179, 181, 191 },
+ new int[]{ 193, 197, 199, 211 },
+
+ new int[]{ 223, 227, 229 },
+ new int[]{ 233, 239, 241 },
+ new int[]{ 251, 257, 263 },
+ new int[]{ 269, 271, 277 },
+ new int[]{ 281, 283, 293 },
+
+ new int[]{ 307, 311, 313 },
+ new int[]{ 317, 331, 337 },
+ new int[]{ 347, 349, 353 },
+ new int[]{ 359, 367, 373 },
+ new int[]{ 379, 383, 389 },
+
+ new int[]{ 397, 401, 409 },
+ new int[]{ 419, 421, 431 },
+ new int[]{ 433, 439, 443 },
+ new int[]{ 449, 457, 461 },
+ new int[]{ 463, 467, 479 },
+
+ new int[]{ 487, 491, 499 },
+ new int[]{ 503, 509, 521 },
+ new int[]{ 523, 541, 547 },
+ new int[]{ 557, 563, 569 },
+ new int[]{ 571, 577, 587 },
+
+ new int[]{ 593, 599, 601 },
+ new int[]{ 607, 613, 617 },
+ new int[]{ 619, 631, 641 },
+ new int[]{ 643, 647, 653 },
+ new int[]{ 659, 661, 673 },
+
+ new int[]{ 677, 683, 691 },
+ new int[]{ 701, 709, 719 },
+ new int[]{ 727, 733, 739 },
+ new int[]{ 743, 751, 757 },
+ new int[]{ 761, 769, 773 },
+
+ new int[]{ 787, 797, 809 },
+ new int[]{ 811, 821, 823 },
+ new int[]{ 827, 829, 839 },
+ new int[]{ 853, 857, 859 },
+ new int[]{ 863, 877, 881 },
+
+ new int[]{ 883, 887, 907 },
+ new int[]{ 911, 919, 929 },
+ new int[]{ 937, 941, 947 },
+ new int[]{ 953, 967, 971 },
+ new int[]{ 977, 983, 991 },
+
+ new int[]{ 997, 1009, 1013 },
+ new int[]{ 1019, 1021, 1031 },
+ };
+
+ private static readonly int[] primeProducts;
+
+ private const long IMASK = 0xffffffffL;
+ private static readonly ulong UIMASK = (ulong)IMASK;
+
+ private static readonly int[] ZeroMagnitude = new int[0];
+ private static readonly byte[] ZeroEncoding = new byte[0];
+
+ public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false);
+ public static readonly BigInteger One = createUValueOf(1);
+ public static readonly BigInteger Two = createUValueOf(2);
+ public static readonly BigInteger Three = createUValueOf(3);
+ public static readonly BigInteger Ten = createUValueOf(10);
+
+ private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time
+ private static readonly BigInteger radix2 = ValueOf(2);
+ private static readonly BigInteger radix2E = radix2.Pow(chunk2);
+
+ private static readonly int chunk10 = 19;
+ private static readonly BigInteger radix10 = ValueOf(10);
+ private static readonly BigInteger radix10E = radix10.Pow(chunk10);
+
+ private static readonly int chunk16 = 16;
+ private static readonly BigInteger radix16 = ValueOf(16);
+ private static readonly BigInteger radix16E = radix16.Pow(chunk16);
+
+ private static readonly Random RandomSource = new Random();
+
+ private const int BitsPerByte = 8;
+ private const int BitsPerInt = 32;
+ private const int BytesPerInt = 4;
+
+ static BigInteger()
+ {
+ primeProducts = new int[primeLists.Length];
+
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int[] primeList = primeLists[i];
+ int product = 1;
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ product *= primeList[j];
+ }
+ primeProducts[i] = product;
+ }
+ }
+
+ private int sign; // -1 means -ve; +1 means +ve; 0 means 0;
+ private int[] magnitude; // array of ints with [0] being the most significant
+ private int nBits = -1; // cache BitCount() value
+ private int nBitLength = -1; // cache calcBitLength() value
+ private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.)
+
+ private static int GetByteLength(
+ int nBits)
+ {
+ return (nBits + BitsPerByte - 1) / BitsPerByte;
+ }
+
+ private BigInteger()
+ {
+ }
+
+ private BigInteger(
+ int signum,
+ int[] mag,
+ bool checkMag)
+ {
+ if (checkMag)
+ {
+ int i = 0;
+ while (i < mag.Length && mag[i] == 0)
+ {
+ ++i;
+ }
+
+ if (i == mag.Length)
+ {
+// this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ }
+ else
+ {
+ this.sign = signum;
+
+ if (i == 0)
+ {
+ this.magnitude = mag;
+ }
+ else
+ {
+ // strip leading 0 words
+ this.magnitude = new int[mag.Length - i];
+ Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length);
+ }
+ }
+ }
+ else
+ {
+ this.sign = signum;
+ this.magnitude = mag;
+ }
+ }
+
+ public BigInteger(
+ string value)
+ : this(value, 10)
+ {
+ }
+
+ public BigInteger(
+ string str,
+ int radix)
+ {
+ if (str.Length == 0)
+ throw new FormatException("Zero length BigInteger");
+
+ NumberStyles style;
+ int chunk;
+ BigInteger r;
+ BigInteger rE;
+
+ switch (radix)
+ {
+ case 2:
+ // Is there anyway to restrict to binary digits?
+ style = NumberStyles.Integer;
+ chunk = chunk2;
+ r = radix2;
+ rE = radix2E;
+ break;
+ case 10:
+ // This style seems to handle spaces and minus sign already (our processing redundant?)
+ style = NumberStyles.Integer;
+ chunk = chunk10;
+ r = radix10;
+ rE = radix10E;
+ break;
+ case 16:
+ // TODO Should this be HexNumber?
+ style = NumberStyles.AllowHexSpecifier;
+ chunk = chunk16;
+ r = radix16;
+ rE = radix16E;
+ break;
+ default:
+ throw new FormatException("Only bases 2, 10, or 16 allowed");
+ }
+
+
+ int index = 0;
+ sign = 1;
+
+ if (str[0] == '-')
+ {
+ if (str.Length == 1)
+ throw new FormatException("Zero length BigInteger");
+
+ sign = -1;
+ index = 1;
+ }
+
+ // strip leading zeros from the string str
+ while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0)
+ {
+ index++;
+ }
+
+ if (index >= str.Length)
+ {
+ // zero value - we're done
+ sign = 0;
+ magnitude = ZeroMagnitude;
+ return;
+ }
+
+ //////
+ // could we work out the max number of ints required to store
+ // str.Length digits in the given base, then allocate that
+ // storage in one hit?, then Generate the magnitude in one hit too?
+ //////
+
+ BigInteger b = Zero;
+
+
+ int next = index + chunk;
+
+ if (next <= str.Length)
+ {
+ do
+ {
+ string s = str.Substring(index, chunk);
+ ulong i = ulong.Parse(s, style);
+ BigInteger bi = createUValueOf(i);
+
+ switch (radix)
+ {
+ case 2:
+ // TODO Need this because we are parsing in radix 10 above
+ if (i > 1)
+ throw new FormatException("Bad character in radix 2 string: " + s);
+
+ // TODO Parse 64 bits at a time
+ b = b.ShiftLeft(1);
+ break;
+ case 16:
+ b = b.ShiftLeft(64);
+ break;
+ default:
+ b = b.Multiply(rE);
+ break;
+ }
+
+ b = b.Add(bi);
+
+ index = next;
+ next += chunk;
+ }
+ while (next <= str.Length);
+ }
+
+ if (index < str.Length)
+ {
+ string s = str.Substring(index);
+ ulong i = ulong.Parse(s, style);
+ BigInteger bi = createUValueOf(i);
+
+ if (b.sign > 0)
+ {
+ if (radix == 2)
+ {
+ // NB: Can't reach here since we are parsing one char at a time
+ Debug.Assert(false);
+
+ // TODO Parse all bits at once
+// b = b.ShiftLeft(s.Length);
+ }
+ else if (radix == 16)
+ {
+ b = b.ShiftLeft(s.Length << 2);
+ }
+ else
+ {
+ b = b.Multiply(r.Pow(s.Length));
+ }
+
+ b = b.Add(bi);
+ }
+ else
+ {
+ b = bi;
+ }
+ }
+
+ // Note: This is the previous (slower) algorithm
+ // while (index < value.Length)
+ // {
+ // char c = value[index];
+ // string s = c.ToString();
+ // int i = Int32.Parse(s, style);
+ //
+ // b = b.Multiply(r).Add(ValueOf(i));
+ // index++;
+ // }
+
+ magnitude = b.magnitude;
+ }
+
+ public BigInteger(
+ byte[] bytes)
+ : this(bytes, 0, bytes.Length)
+ {
+ }
+
+ public BigInteger(
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ if (length == 0)
+ throw new FormatException("Zero length BigInteger");
+
+ // TODO Move this processing into MakeMagnitude (provide sign argument)
+ if ((sbyte)bytes[offset] < 0)
+ {
+ this.sign = -1;
+
+ int end = offset + length;
+
+ int iBval;
+ // strip leading sign bytes
+ for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++)
+ {
+ }
+
+ if (iBval >= end)
+ {
+ this.magnitude = One.magnitude;
+ }
+ else
+ {
+ int numBytes = end - iBval;
+ byte[] inverse = new byte[numBytes];
+
+ int index = 0;
+ while (index < numBytes)
+ {
+ inverse[index++] = (byte)~bytes[iBval++];
+ }
+
+ Debug.Assert(iBval == end);
+
+ while (inverse[--index] == byte.MaxValue)
+ {
+ inverse[index] = byte.MinValue;
+ }
+
+ inverse[index]++;
+
+ this.magnitude = MakeMagnitude(inverse, 0, inverse.Length);
+ }
+ }
+ else
+ {
+ // strip leading zero bytes and return magnitude bytes
+ this.magnitude = MakeMagnitude(bytes, offset, length);
+ this.sign = this.magnitude.Length > 0 ? 1 : 0;
+ }
+ }
+
+ private static int[] MakeMagnitude(
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ int end = offset + length;
+
+ // strip leading zeros
+ int firstSignificant;
+ for (firstSignificant = offset; firstSignificant < end
+ && bytes[firstSignificant] == 0; firstSignificant++)
+ {
+ }
+
+ if (firstSignificant >= end)
+ {
+ return ZeroMagnitude;
+ }
+
+ int nInts = (end - firstSignificant + 3) / BytesPerInt;
+ int bCount = (end - firstSignificant) % BytesPerInt;
+ if (bCount == 0)
+ {
+ bCount = BytesPerInt;
+ }
+
+ if (nInts < 1)
+ {
+ return ZeroMagnitude;
+ }
+
+ int[] mag = new int[nInts];
+
+ int v = 0;
+ int magnitudeIndex = 0;
+ for (int i = firstSignificant; i < end; ++i)
+ {
+ v <<= 8;
+ v |= bytes[i] & 0xff;
+ bCount--;
+ if (bCount <= 0)
+ {
+ mag[magnitudeIndex] = v;
+ magnitudeIndex++;
+ bCount = BytesPerInt;
+ v = 0;
+ }
+ }
+
+ if (magnitudeIndex < mag.Length)
+ {
+ mag[magnitudeIndex] = v;
+ }
+
+ return mag;
+ }
+
+ public BigInteger(
+ int sign,
+ byte[] bytes)
+ : this(sign, bytes, 0, bytes.Length)
+ {
+ }
+
+ public BigInteger(
+ int sign,
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ if (sign < -1 || sign > 1)
+ throw new FormatException("Invalid sign value");
+
+ if (sign == 0)
+ {
+ //this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ }
+ else
+ {
+ // copy bytes
+ this.magnitude = MakeMagnitude(bytes, offset, length);
+ this.sign = this.magnitude.Length < 1 ? 0 : sign;
+ }
+ }
+
+ public BigInteger(
+ int sizeInBits,
+ Random random)
+ {
+ if (sizeInBits < 0)
+ throw new ArgumentException("sizeInBits must be non-negative");
+
+ this.nBits = -1;
+ this.nBitLength = -1;
+
+ if (sizeInBits == 0)
+ {
+// this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ return;
+ }
+
+ int nBytes = GetByteLength(sizeInBits);
+ byte[] b = new byte[nBytes];
+ random.NextBytes(b);
+
+ // strip off any excess bits in the MSB
+ b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits];
+
+ this.magnitude = MakeMagnitude(b, 0, b.Length);
+ this.sign = this.magnitude.Length < 1 ? 0 : 1;
+ }
+
+ private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 };
+
+ public BigInteger(
+ int bitLength,
+ int certainty,
+ Random random)
+ {
+ if (bitLength < 2)
+ throw new ArithmeticException("bitLength < 2");
+
+ this.sign = 1;
+ this.nBitLength = bitLength;
+
+ if (bitLength == 2)
+ {
+ this.magnitude = random.Next(2) == 0
+ ? Two.magnitude
+ : Three.magnitude;
+ return;
+ }
+
+ int nBytes = GetByteLength(bitLength);
+ byte[] b = new byte[nBytes];
+
+ int xBits = BitsPerByte * nBytes - bitLength;
+ byte mask = rndMask[xBits];
+
+ for (;;)
+ {
+ random.NextBytes(b);
+
+ // strip off any excess bits in the MSB
+ b[0] &= mask;
+
+ // ensure the leading bit is 1 (to meet the strength requirement)
+ b[0] |= (byte)(1 << (7 - xBits));
+
+ // ensure the trailing bit is 1 (i.e. must be odd)
+ b[nBytes - 1] |= 1;
+
+ this.magnitude = MakeMagnitude(b, 0, b.Length);
+ this.nBits = -1;
+ this.mQuote = -1L;
+
+ if (certainty < 1)
+ break;
+
+ if (CheckProbablePrime(certainty, random))
+ break;
+
+ if (bitLength > 32)
+ {
+ for (int rep = 0; rep < 10000; ++rep)
+ {
+ int n = 33 + random.Next(bitLength - 2);
+ this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31));
+ this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1);
+ this.mQuote = -1L;
+
+ if (CheckProbablePrime(certainty, random))
+ return;
+ }
+ }
+ }
+ }
+
+ public BigInteger Abs()
+ {
+ return sign >= 0 ? this : Negate();
+ }
+
+ /**
+ * return a = a + b - b preserved.
+ */
+ private static int[] AddMagnitudes(
+ int[] a,
+ int[] b)
+ {
+ int tI = a.Length - 1;
+ int vI = b.Length - 1;
+ long m = 0;
+
+ while (vI >= 0)
+ {
+ m += ((long)(uint)a[tI] + (long)(uint)b[vI--]);
+ a[tI--] = (int)m;
+ m = (long)((ulong)m >> 32);
+ }
+
+ if (m != 0)
+ {
+ while (tI >= 0 && ++a[tI--] == 0)
+ {
+ }
+ }
+
+ return a;
+ }
+
+ public BigInteger Add(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (this.sign != value.sign)
+ {
+ if (value.sign == 0)
+ return this;
+
+ if (value.sign < 0)
+ return Subtract(value.Negate());
+
+ return value.Subtract(Negate());
+ }
+
+ return AddToMagnitude(value.magnitude);
+ }
+
+ private BigInteger AddToMagnitude(
+ int[] magToAdd)
+ {
+ int[] big, small;
+ if (this.magnitude.Length < magToAdd.Length)
+ {
+ big = magToAdd;
+ small = this.magnitude;
+ }
+ else
+ {
+ big = this.magnitude;
+ small = magToAdd;
+ }
+
+ // Conservatively avoid over-allocation when no overflow possible
+ uint limit = uint.MaxValue;
+ if (big.Length == small.Length)
+ limit -= (uint) small[0];
+
+ bool possibleOverflow = (uint) big[0] >= limit;
+
+ int[] bigCopy;
+ if (possibleOverflow)
+ {
+ bigCopy = new int[big.Length + 1];
+ big.CopyTo(bigCopy, 1);
+ }
+ else
+ {
+ bigCopy = (int[]) big.Clone();
+ }
+
+ bigCopy = AddMagnitudes(bigCopy, small);
+
+ return new BigInteger(this.sign, bigCopy, possibleOverflow);
+ }
+
+ public BigInteger And(
+ BigInteger value)
+ {
+ if (this.sign == 0 || value.sign == 0)
+ {
+ return Zero;
+ }
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ bool resultNeg = sign < 0 && value.sign < 0;
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord & bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger AndNot(
+ BigInteger val)
+ {
+ return And(val.Not());
+ }
+
+ public int BitCount
+ {
+ get
+ {
+ if (nBits == -1)
+ {
+ if (sign < 0)
+ {
+ // TODO Optimise this case
+ nBits = Not().BitCount;
+ }
+ else
+ {
+ int sum = 0;
+ for (int i = 0; i < magnitude.Length; i++)
+ {
+ sum += bitCounts[(byte) magnitude[i]];
+ sum += bitCounts[(byte)(magnitude[i] >> 8)];
+ sum += bitCounts[(byte)(magnitude[i] >> 16)];
+ sum += bitCounts[(byte)(magnitude[i] >> 24)];
+ }
+ nBits = sum;
+ }
+ }
+
+ return nBits;
+ }
+ }
+
+ private readonly static byte[] bitCounts =
+ {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1,
+ 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
+ 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
+ 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2,
+ 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,
+ 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,
+ 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
+ 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5,
+ 6, 6, 7, 6, 7, 7, 8
+ };
+
+ private int calcBitLength(
+ int indx,
+ int[] mag)
+ {
+ for (;;)
+ {
+ if (indx >= mag.Length)
+ return 0;
+
+ if (mag[indx] != 0)
+ break;
+
+ ++indx;
+ }
+
+ // bit length for everything after the first int
+ int bitLength = 32 * ((mag.Length - indx) - 1);
+
+ // and determine bitlength of first int
+ int firstMag = mag[indx];
+ bitLength += BitLen(firstMag);
+
+ // Check for negative powers of two
+ if (sign < 0 && ((firstMag & -firstMag) == firstMag))
+ {
+ do
+ {
+ if (++indx >= mag.Length)
+ {
+ --bitLength;
+ break;
+ }
+ }
+ while (mag[indx] == 0);
+ }
+
+ return bitLength;
+ }
+
+ public int BitLength
+ {
+ get
+ {
+ if (nBitLength == -1)
+ {
+ nBitLength = sign == 0
+ ? 0
+ : calcBitLength(0, magnitude);
+ }
+
+ return nBitLength;
+ }
+ }
+
+ //
+ // BitLen(value) is the number of bits in value.
+ //
+ private static int BitLen(
+ int w)
+ {
+ // Binary search - decision tree (5 tests, rarely 6)
+ return (w < 1 << 15 ? (w < 1 << 7
+ ? (w < 1 << 3 ? (w < 1 << 1
+ ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1)
+ : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5
+ ? (w < 1 << 4 ? 4 : 5)
+ : (w < 1 << 6 ? 6 : 7)))
+ : (w < 1 << 11
+ ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11))
+ : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19
+ ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19))
+ : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27
+ ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27))
+ : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31)))));
+ }
+
+// private readonly static byte[] bitLengths =
+// {
+// 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+// 8, 8, 8, 8, 8, 8, 8, 8
+// };
+
+ private bool QuickPow2Check()
+ {
+ return sign > 0 && nBits == 1;
+ }
+
+ public int CompareTo(
+ object obj)
+ {
+ return CompareTo((BigInteger)obj);
+ }
+
+ /**
+ * unsigned comparison on two arrays - note the arrays may
+ * start with leading zeros.
+ */
+ private static int CompareTo(
+ int xIndx,
+ int[] x,
+ int yIndx,
+ int[] y)
+ {
+ while (xIndx != x.Length && x[xIndx] == 0)
+ {
+ xIndx++;
+ }
+
+ while (yIndx != y.Length && y[yIndx] == 0)
+ {
+ yIndx++;
+ }
+
+ return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
+ }
+
+ private static int CompareNoLeadingZeroes(
+ int xIndx,
+ int[] x,
+ int yIndx,
+ int[] y)
+ {
+ int diff = (x.Length - y.Length) - (xIndx - yIndx);
+
+ if (diff != 0)
+ {
+ return diff < 0 ? -1 : 1;
+ }
+
+ // lengths of magnitudes the same, test the magnitude values
+
+ while (xIndx < x.Length)
+ {
+ uint v1 = (uint)x[xIndx++];
+ uint v2 = (uint)y[yIndx++];
+
+ if (v1 != v2)
+ return v1 < v2 ? -1 : 1;
+ }
+
+ return 0;
+ }
+
+ public int CompareTo(
+ BigInteger value)
+ {
+ return sign < value.sign ? -1
+ : sign > value.sign ? 1
+ : sign == 0 ? 0
+ : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude);
+ }
+
+ /**
+ * return z = x / y - done in place (z value preserved, x contains the
+ * remainder)
+ */
+ private int[] Divide(
+ int[] x,
+ int[] y)
+ {
+ int xStart = 0;
+ while (xStart < x.Length && x[xStart] == 0)
+ {
+ ++xStart;
+ }
+
+ int yStart = 0;
+ while (yStart < y.Length && y[yStart] == 0)
+ {
+ ++yStart;
+ }
+
+ Debug.Assert(yStart < y.Length);
+
+ int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+ int[] count;
+
+ if (xyCmp > 0)
+ {
+ int yBitLength = calcBitLength(yStart, y);
+ int xBitLength = calcBitLength(xStart, x);
+ int shift = xBitLength - yBitLength;
+
+ int[] iCount;
+ int iCountStart = 0;
+
+ int[] c;
+ int cStart = 0;
+ int cBitLength = yBitLength;
+ if (shift > 0)
+ {
+// iCount = ShiftLeft(One.magnitude, shift);
+ iCount = new int[(shift >> 5) + 1];
+ iCount[0] = 1 << (shift % 32);
+
+ c = ShiftLeft(y, shift);
+ cBitLength += shift;
+ }
+ else
+ {
+ iCount = new int[] { 1 };
+
+ int len = y.Length - yStart;
+ c = new int[len];
+ Array.Copy(y, yStart, c, 0, len);
+ }
+
+ count = new int[iCount.Length];
+
+ for (;;)
+ {
+ if (cBitLength < xBitLength
+ || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+ {
+ Subtract(xStart, x, cStart, c);
+ AddMagnitudes(count, iCount);
+
+ while (x[xStart] == 0)
+ {
+ if (++xStart == x.Length)
+ return count;
+ }
+
+ //xBitLength = calcBitLength(xStart, x);
+ xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+ if (xBitLength <= yBitLength)
+ {
+ if (xBitLength < yBitLength)
+ return count;
+
+ xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp <= 0)
+ break;
+ }
+ }
+
+ shift = cBitLength - xBitLength;
+
+ // NB: The case where c[cStart] is 1-bit is harmless
+ if (shift == 1)
+ {
+ uint firstC = (uint) c[cStart] >> 1;
+ uint firstX = (uint) x[xStart];
+ if (firstC > firstX)
+ ++shift;
+ }
+
+ if (shift < 2)
+ {
+ c = ShiftRightOneInPlace(cStart, c);
+ --cBitLength;
+ iCount = ShiftRightOneInPlace(iCountStart, iCount);
+ }
+ else
+ {
+ c = ShiftRightInPlace(cStart, c, shift);
+ cBitLength -= shift;
+ iCount = ShiftRightInPlace(iCountStart, iCount, shift);
+ }
+
+ //cStart = c.Length - ((cBitLength + 31) / 32);
+ while (c[cStart] == 0)
+ {
+ ++cStart;
+ }
+
+ while (iCount[iCountStart] == 0)
+ {
+ ++iCountStart;
+ }
+ }
+ }
+ else
+ {
+ count = new int[1];
+ }
+
+ if (xyCmp == 0)
+ {
+ AddMagnitudes(count, One.magnitude);
+ Array.Clear(x, xStart, x.Length - xStart);
+ }
+
+ return count;
+ }
+
+ public BigInteger Divide(
+ BigInteger val)
+ {
+ if (val.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ if (sign == 0)
+ return Zero;
+
+ if (val.QuickPow2Check()) // val is power of two
+ {
+ BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1);
+ return val.sign == this.sign ? result : result.Negate();
+ }
+
+ int[] mag = (int[]) this.magnitude.Clone();
+
+ return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true);
+ }
+
+ public BigInteger[] DivideAndRemainder(
+ BigInteger val)
+ {
+ if (val.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ BigInteger[] biggies = new BigInteger[2];
+
+ if (sign == 0)
+ {
+ biggies[0] = Zero;
+ biggies[1] = Zero;
+ }
+ else if (val.QuickPow2Check()) // val is power of two
+ {
+ int e = val.Abs().BitLength - 1;
+ BigInteger quotient = this.Abs().ShiftRight(e);
+ int[] remainder = this.LastNBits(e);
+
+ biggies[0] = val.sign == this.sign ? quotient : quotient.Negate();
+ biggies[1] = new BigInteger(this.sign, remainder, true);
+ }
+ else
+ {
+ int[] remainder = (int[]) this.magnitude.Clone();
+ int[] quotient = Divide(remainder, val.magnitude);
+
+ biggies[0] = new BigInteger(this.sign * val.sign, quotient, true);
+ biggies[1] = new BigInteger(this.sign, remainder, true);
+ }
+
+ return biggies;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ BigInteger biggie = obj as BigInteger;
+ if (biggie == null)
+ return false;
+
+ if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length)
+ return false;
+
+ for (int i = 0; i < magnitude.Length; i++)
+ {
+ if (biggie.magnitude[i] != magnitude[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public BigInteger Gcd(
+ BigInteger value)
+ {
+ if (value.sign == 0)
+ return Abs();
+
+ if (sign == 0)
+ return value.Abs();
+
+ BigInteger r;
+ BigInteger u = this;
+ BigInteger v = value;
+
+ while (v.sign != 0)
+ {
+ r = u.Mod(v);
+ u = v;
+ v = r;
+ }
+
+ return u;
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = magnitude.Length;
+ if (magnitude.Length > 0)
+ {
+ hc ^= magnitude[0];
+
+ if (magnitude.Length > 1)
+ {
+ hc ^= magnitude[magnitude.Length - 1];
+ }
+ }
+
+ return sign < 0 ? ~hc : hc;
+ }
+
+ // TODO Make public?
+ private BigInteger Inc()
+ {
+ if (this.sign == 0)
+ return One;
+
+ if (this.sign < 0)
+ return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true);
+
+ return AddToMagnitude(One.magnitude);
+ }
+
+ public int IntValue
+ {
+ get
+ {
+ return sign == 0 ? 0
+ : sign > 0 ? magnitude[magnitude.Length - 1]
+ : -magnitude[magnitude.Length - 1];
+ }
+ }
+
+ /**
+ * return whether or not a BigInteger is probably prime with a
+ * probability of 1 - (1/2)**certainty.
+ * From Knuth Vol 2, pg 395.
+ */
+ public bool IsProbablePrime(
+ int certainty)
+ {
+ if (certainty <= 0)
+ return true;
+
+ BigInteger n = Abs();
+
+ if (!n.TestBit(0))
+ return n.Equals(Two);
+
+ if (n.Equals(One))
+ return false;
+
+ return n.CheckProbablePrime(certainty, RandomSource);
+ }
+
+ private bool CheckProbablePrime(
+ int certainty,
+ Random random)
+ {
+ Debug.Assert(certainty > 0);
+ Debug.Assert(CompareTo(Two) > 0);
+ Debug.Assert(TestBit(0));
+
+
+ // Try to reduce the penalty for really small numbers
+ int numLists = System.Math.Min(BitLength - 1, primeLists.Length);
+
+ for (int i = 0; i < numLists; ++i)
+ {
+ int test = Remainder(primeProducts[i]);
+
+ int[] primeList = primeLists[i];
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ int prime = primeList[j];
+ int qRem = test % prime;
+ if (qRem == 0)
+ {
+ // We may find small numbers in the list
+ return BitLength < 16 && IntValue == prime;
+ }
+ }
+ }
+
+
+ // TODO Special case for < 10^16 (RabinMiller fixed list)
+// if (BitLength < 30)
+// {
+// RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient
+// }
+
+
+ // TODO Is it worth trying to create a hybrid of these two?
+ return RabinMillerTest(certainty, random);
+// return SolovayStrassenTest(certainty, random);
+
+// bool rbTest = RabinMillerTest(certainty, random);
+// bool ssTest = SolovayStrassenTest(certainty, random);
+//
+// Debug.Assert(rbTest == ssTest);
+//
+// return rbTest;
+ }
+
+ internal bool RabinMillerTest(
+ int certainty,
+ Random random)
+ {
+ Debug.Assert(certainty > 0);
+ Debug.Assert(BitLength > 2);
+ Debug.Assert(TestBit(0));
+
+ // let n = 1 + d . 2^s
+ BigInteger n = this;
+ BigInteger nMinusOne = n.Subtract(One);
+ int s = nMinusOne.GetLowestSetBit();
+ BigInteger r = nMinusOne.ShiftRight(s);
+
+ Debug.Assert(s >= 1);
+
+ do
+ {
+ // TODO Make a method for random BigIntegers in range 0 < x < n)
+ // - Method can be optimized by only replacing examined bits at each trial
+ BigInteger a;
+ do
+ {
+ a = new BigInteger(n.BitLength, random);
+ }
+ while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0);
+
+ BigInteger y = a.ModPow(r, n);
+
+ if (!y.Equals(One))
+ {
+ int j = 0;
+ while (!y.Equals(nMinusOne))
+ {
+ if (++j == s)
+ return false;
+
+ y = y.ModPow(Two, n);
+
+ if (y.Equals(One))
+ return false;
+ }
+ }
+
+ certainty -= 2; // composites pass for only 1/4 possible 'a'
+ }
+ while (certainty > 0);
+
+ return true;
+ }
+
+// private bool SolovayStrassenTest(
+// int certainty,
+// Random random)
+// {
+// Debug.Assert(certainty > 0);
+// Debug.Assert(CompareTo(Two) > 0);
+// Debug.Assert(TestBit(0));
+//
+// BigInteger n = this;
+// BigInteger nMinusOne = n.Subtract(One);
+// BigInteger e = nMinusOne.ShiftRight(1);
+//
+// do
+// {
+// BigInteger a;
+// do
+// {
+// a = new BigInteger(nBitLength, random);
+// }
+// // NB: Spec says 0 < x < n, but 1 is trivial
+// while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0);
+//
+//
+// // TODO Check this is redundant given the way Jacobi() works?
+//// if (!a.Gcd(n).Equals(One))
+//// return false;
+//
+// int x = Jacobi(a, n);
+//
+// if (x == 0)
+// return false;
+//
+// BigInteger check = a.ModPow(e, n);
+//
+// if (x == 1 && !check.Equals(One))
+// return false;
+//
+// if (x == -1 && !check.Equals(nMinusOne))
+// return false;
+//
+// --certainty;
+// }
+// while (certainty > 0);
+//
+// return true;
+// }
+//
+// private static int Jacobi(
+// BigInteger a,
+// BigInteger b)
+// {
+// Debug.Assert(a.sign >= 0);
+// Debug.Assert(b.sign > 0);
+// Debug.Assert(b.TestBit(0));
+// Debug.Assert(a.CompareTo(b) < 0);
+//
+// int totalS = 1;
+// for (;;)
+// {
+// if (a.sign == 0)
+// return 0;
+//
+// if (a.Equals(One))
+// break;
+//
+// int e = a.GetLowestSetBit();
+//
+// int bLsw = b.magnitude[b.magnitude.Length - 1];
+// if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5))
+// totalS = -totalS;
+//
+// // TODO Confirm this is faster than later a1.Equals(One) test
+// if (a.BitLength == e + 1)
+// break;
+// BigInteger a1 = a.ShiftRight(e);
+//// if (a1.Equals(One))
+//// break;
+//
+// int a1Lsw = a1.magnitude[a1.magnitude.Length - 1];
+// if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3)
+// totalS = -totalS;
+//
+//// a = b.Mod(a1);
+// a = b.Remainder(a1);
+// b = a1;
+// }
+// return totalS;
+// }
+
+ public long LongValue
+ {
+ get
+ {
+ if (sign == 0)
+ return 0;
+
+ long v;
+ if (magnitude.Length > 1)
+ {
+ v = ((long)magnitude[magnitude.Length - 2] << 32)
+ | (magnitude[magnitude.Length - 1] & IMASK);
+ }
+ else
+ {
+ v = (magnitude[magnitude.Length - 1] & IMASK);
+ }
+
+ return sign < 0 ? -v : v;
+ }
+ }
+
+ public BigInteger Max(
+ BigInteger value)
+ {
+ return CompareTo(value) > 0 ? this : value;
+ }
+
+ public BigInteger Min(
+ BigInteger value)
+ {
+ return CompareTo(value) < 0 ? this : value;
+ }
+
+ public BigInteger Mod(
+ BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ BigInteger biggie = Remainder(m);
+
+ return (biggie.sign >= 0 ? biggie : biggie.Add(m));
+ }
+
+ public BigInteger ModInverse(
+ BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ // TODO Too slow at the moment
+// // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
+// if (m.TestBit(0))
+// {
+// //The Almost Inverse Algorithm
+// int k = 0;
+// BigInteger B = One, C = Zero, F = this, G = m, tmp;
+//
+// for (;;)
+// {
+// // While F is even, do F=F/u, C=C*u, k=k+1.
+// int zeroes = F.GetLowestSetBit();
+// if (zeroes > 0)
+// {
+// F = F.ShiftRight(zeroes);
+// C = C.ShiftLeft(zeroes);
+// k += zeroes;
+// }
+//
+// // If F = 1, then return B,k.
+// if (F.Equals(One))
+// {
+// BigInteger half = m.Add(One).ShiftRight(1);
+// BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m);
+// return B.Multiply(halfK).Mod(m);
+// }
+//
+// if (F.CompareTo(G) < 0)
+// {
+// tmp = G; G = F; F = tmp;
+// tmp = B; B = C; C = tmp;
+// }
+//
+// F = F.Add(G);
+// B = B.Add(C);
+// }
+// }
+
+ BigInteger x = new BigInteger();
+ BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null);
+
+ if (!gcd.Equals(One))
+ throw new ArithmeticException("Numbers not relatively prime.");
+
+ if (x.sign < 0)
+ {
+ x.sign = 1;
+ //x = m.Subtract(x);
+ x.magnitude = doSubBigLil(m.magnitude, x.magnitude);
+ }
+
+ return x;
+ }
+
+ /**
+ * Calculate the numbers u1, u2, and u3 such that:
+ *
+ * u1 * a + u2 * b = u3
+ *
+ * where u3 is the greatest common divider of a and b.
+ * a and b using the extended Euclid algorithm (refer p. 323
+ * of The Art of Computer Programming vol 2, 2nd ed).
+ * This also seems to have the side effect of calculating
+ * some form of multiplicative inverse.
+ *
+ * @param a First number to calculate gcd for
+ * @param b Second number to calculate gcd for
+ * @param u1Out the return object for the u1 value
+ * @param u2Out the return object for the u2 value
+ * @return The greatest common divisor of a and b
+ */
+ private static BigInteger ExtEuclid(
+ BigInteger a,
+ BigInteger b,
+ BigInteger u1Out,
+ BigInteger u2Out)
+ {
+ BigInteger u1 = One;
+ BigInteger u3 = a;
+ BigInteger v1 = Zero;
+ BigInteger v3 = b;
+
+ while (v3.sign > 0)
+ {
+ BigInteger[] q = u3.DivideAndRemainder(v3);
+
+ BigInteger tmp = v1.Multiply(q[0]);
+ BigInteger tn = u1.Subtract(tmp);
+ u1 = v1;
+ v1 = tn;
+
+ u3 = v3;
+ v3 = q[1];
+ }
+
+ if (u1Out != null)
+ {
+ u1Out.sign = u1.sign;
+ u1Out.magnitude = u1.magnitude;
+ }
+
+ if (u2Out != null)
+ {
+ BigInteger tmp = u1.Multiply(a);
+ tmp = u3.Subtract(tmp);
+ BigInteger res = tmp.Divide(b);
+ u2Out.sign = res.sign;
+ u2Out.magnitude = res.magnitude;
+ }
+
+ return u3;
+ }
+
+ private static void ZeroOut(
+ int[] x)
+ {
+ Array.Clear(x, 0, x.Length);
+ }
+
+ public BigInteger ModPow(
+ BigInteger exponent,
+ BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ if (m.Equals(One))
+ return Zero;
+
+ if (exponent.sign == 0)
+ return One;
+
+ if (sign == 0)
+ return Zero;
+
+ int[] zVal = null;
+ int[] yAccum = null;
+ int[] yVal;
+
+ // Montgomery exponentiation is only possible if the modulus is odd,
+ // but AFAIK, this is always the case for crypto algo's
+ bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1);
+ long mQ = 0;
+ if (useMonty)
+ {
+ mQ = m.GetMQuote();
+
+ // tmp = this * R mod m
+ BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m);
+ zVal = tmp.magnitude;
+
+ useMonty = (zVal.Length <= m.magnitude.Length);
+
+ if (useMonty)
+ {
+ yAccum = new int[m.magnitude.Length + 1];
+ if (zVal.Length < m.magnitude.Length)
+ {
+ int[] longZ = new int[m.magnitude.Length];
+ zVal.CopyTo(longZ, longZ.Length - zVal.Length);
+ zVal = longZ;
+ }
+ }
+ }
+
+ if (!useMonty)
+ {
+ if (magnitude.Length <= m.magnitude.Length)
+ {
+ //zAccum = new int[m.magnitude.Length * 2];
+ zVal = new int[m.magnitude.Length];
+ magnitude.CopyTo(zVal, zVal.Length - magnitude.Length);
+ }
+ else
+ {
+ //
+ // in normal practice we'll never see this...
+ //
+ BigInteger tmp = Remainder(m);
+
+ //zAccum = new int[m.magnitude.Length * 2];
+ zVal = new int[m.magnitude.Length];
+ tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length);
+ }
+
+ yAccum = new int[m.magnitude.Length * 2];
+ }
+
+ yVal = new int[m.magnitude.Length];
+
+ //
+ // from LSW to MSW
+ //
+ for (int i = 0; i < exponent.magnitude.Length; i++)
+ {
+ int v = exponent.magnitude[i];
+ int bits = 0;
+
+ if (i == 0)
+ {
+ while (v > 0)
+ {
+ v <<= 1;
+ bits++;
+ }
+
+ //
+ // first time in initialise y
+ //
+ zVal.CopyTo(yVal, 0);
+
+ v <<= 1;
+ bits++;
+ }
+
+ while (v != 0)
+ {
+ if (useMonty)
+ {
+ // Montgomery square algo doesn't exist, and a normal
+ // square followed by a Montgomery reduction proved to
+ // be almost as heavy as a Montgomery mulitply.
+ MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
+ }
+ else
+ {
+ Square(yAccum, yVal);
+ Remainder(yAccum, m.magnitude);
+ Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
+ ZeroOut(yAccum);
+ }
+ bits++;
+
+ if (v < 0)
+ {
+ if (useMonty)
+ {
+ MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
+ }
+ else
+ {
+ Multiply(yAccum, yVal, zVal);
+ Remainder(yAccum, m.magnitude);
+ Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0,
+ yVal.Length);
+ ZeroOut(yAccum);
+ }
+ }
+
+ v <<= 1;
+ }
+
+ while (bits < 32)
+ {
+ if (useMonty)
+ {
+ MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
+ }
+ else
+ {
+ Square(yAccum, yVal);
+ Remainder(yAccum, m.magnitude);
+ Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
+ ZeroOut(yAccum);
+ }
+ bits++;
+ }
+ }
+
+ if (useMonty)
+ {
+ // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m
+ ZeroOut(zVal);
+ zVal[zVal.Length - 1] = 1;
+ MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
+ }
+
+ BigInteger result = new BigInteger(1, yVal, true);
+
+ return exponent.sign > 0
+ ? result
+ : result.ModInverse(m);
+ }
+
+ /**
+ * return w with w = x * x - w is assumed to have enough space.
+ */
+ private static int[] Square(
+ int[] w,
+ int[] x)
+ {
+ // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
+// if (w.Length != 2 * x.Length)
+// throw new ArgumentException("no I don't think so...");
+
+ ulong u1, u2, c;
+
+ int wBase = w.Length - 1;
+
+ for (int i = x.Length - 1; i != 0; i--)
+ {
+ ulong v = (ulong)(uint) x[i];
+
+ u1 = v * v;
+ u2 = u1 >> 32;
+ u1 = (uint) u1;
+
+ u1 += (ulong)(uint) w[wBase];
+
+ w[wBase] = (int)(uint) u1;
+ c = u2 + (u1 >> 32);
+
+ for (int j = i - 1; j >= 0; j--)
+ {
+ --wBase;
+ u1 = v * (ulong)(uint) x[j];
+ u2 = u1 >> 31; // multiply by 2!
+ u1 = (uint)(u1 << 1); // multiply by 2!
+ u1 += c + (ulong)(uint) w[wBase];
+
+ w[wBase] = (int)(uint) u1;
+ c = u2 + (u1 >> 32);
+ }
+
+ c += (ulong)(uint) w[--wBase];
+ w[wBase] = (int)(uint) c;
+
+ if (--wBase >= 0)
+ {
+ w[wBase] = (int)(uint)(c >> 32);
+ }
+ else
+ {
+ Debug.Assert((uint)(c >> 32) == 0);
+ }
+ wBase += i;
+ }
+
+ u1 = (ulong)(uint) x[0];
+ u1 = u1 * u1;
+ u2 = u1 >> 32;
+ u1 = u1 & IMASK;
+
+ u1 += (ulong)(uint) w[wBase];
+
+ w[wBase] = (int)(uint) u1;
+ if (--wBase >= 0)
+ {
+ w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint) w[wBase]);
+ }
+ else
+ {
+ Debug.Assert((uint)(u2 + (u1 >> 32)) == 0);
+ }
+
+ return w;
+ }
+
+ /**
+ * return x with x = y * z - x is assumed to have enough space.
+ */
+ private static int[] Multiply(
+ int[] x,
+ int[] y,
+ int[] z)
+ {
+ int i = z.Length;
+
+ if (i < 1)
+ return x;
+
+ int xBase = x.Length - y.Length;
+
+ for (;;)
+ {
+ long a = z[--i] & IMASK;
+ long val = 0;
+
+ for (int j = y.Length - 1; j >= 0; j--)
+ {
+ val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
+
+ x[xBase + j] = (int)val;
+
+ val = (long)((ulong)val >> 32);
+ }
+
+ --xBase;
+
+ if (i < 1)
+ {
+ if (xBase >= 0)
+ {
+ x[xBase] = (int)val;
+ }
+ else
+ {
+ Debug.Assert(val == 0);
+ }
+ break;
+ }
+
+ x[xBase] = (int)val;
+ }
+
+ return x;
+ }
+
+ private static long FastExtEuclid(
+ long a,
+ long b,
+ long[] uOut)
+ {
+ long u1 = 1;
+ long u3 = a;
+ long v1 = 0;
+ long v3 = b;
+
+ while (v3 > 0)
+ {
+ long q, tn;
+
+ q = u3 / v3;
+
+ tn = u1 - (v1 * q);
+ u1 = v1;
+ v1 = tn;
+
+ tn = u3 - (v3 * q);
+ u3 = v3;
+ v3 = tn;
+ }
+
+ uOut[0] = u1;
+ uOut[1] = (u3 - (u1 * a)) / b;
+
+ return u3;
+ }
+
+ private static long FastModInverse(
+ long v,
+ long m)
+ {
+ if (m < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ long[] x = new long[2];
+ long gcd = FastExtEuclid(v, m, x);
+
+ if (gcd != 1)
+ throw new ArithmeticException("Numbers not relatively prime.");
+
+ if (x[0] < 0)
+ {
+ x[0] += m;
+ }
+
+ return x[0];
+ }
+
+// private static BigInteger MQuoteB = One.ShiftLeft(32);
+// private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One);
+
+ /**
+ * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
+ */
+ private long GetMQuote()
+ {
+ Debug.Assert(this.sign > 0);
+
+ if (mQuote != -1)
+ {
+ return mQuote; // already calculated
+ }
+
+ if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0)
+ {
+ return -1; // not for even numbers
+ }
+
+ long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL);
+ mQuote = FastModInverse(v, 0x100000000L);
+
+ return mQuote;
+ }
+
+ /**
+ * Montgomery multiplication: a = x * y * R^(-1) mod m
+ *
+ * Based algorithm 14.36 of Handbook of Applied Cryptography.
+ *
+ * m, x, y should have length n
+ * a should have length (n + 1)
+ * b = 2^32, R = b^n
+ *
+ * The result is put in x
+ *
+ * NOTE: the indices of x, y, m, a different in HAC and in Java
+ */
+ private static void MultiplyMonty(
+ int[] a,
+ int[] x,
+ int[] y,
+ int[] m,
+ long mQuote)
+ // mQuote = -m^(-1) mod b
+ {
+ if (m.Length == 1)
+ {
+ x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote);
+ return;
+ }
+
+ int n = m.Length;
+ int nMinus1 = n - 1;
+ long y_0 = y[nMinus1] & IMASK;
+
+ // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} )
+ Array.Clear(a, 0, n + 1);
+
+ // 2. for i from 0 to (n - 1) do the following:
+ for (int i = n; i > 0; i--)
+ {
+ long x_i = x[i - 1] & IMASK;
+
+ // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b
+ long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK;
+
+ // 2.2 a = (a + x_i * y + u * m) / b
+ long prod1 = x_i * y_0;
+ long prod2 = u * (m[nMinus1] & IMASK);
+ long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK);
+ long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32);
+ for (int j = nMinus1; j > 0; j--)
+ {
+ prod1 = x_i * (y[j - 1] & IMASK);
+ prod2 = u * (m[j - 1] & IMASK);
+ tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK);
+ carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) +
+ (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32);
+ a[j + 1] = (int)tmp; // division by b
+ }
+ carry += (a[0] & IMASK);
+ a[1] = (int)carry;
+ a[0] = (int)((ulong)carry >> 32); // OJO!!!!!
+ }
+
+ // 3. if x >= m the x = x - m
+ if (CompareTo(0, a, 0, m) >= 0)
+ {
+ Subtract(0, a, 0, m);
+ }
+
+ // put the result in x
+ Array.Copy(a, 1, x, 0, n);
+ }
+
+ private static uint MultiplyMontyNIsOne(
+ uint x,
+ uint y,
+ uint m,
+ ulong mQuote)
+ {
+ ulong um = m;
+ ulong prod1 = (ulong)x * (ulong)y;
+ ulong u = (prod1 * mQuote) & UIMASK;
+ ulong prod2 = u * um;
+ ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK);
+ ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32);
+
+ if (carry > um)
+ {
+ carry -= um;
+ }
+
+ return (uint)(carry & UIMASK);
+ }
+
+ public BigInteger Multiply(
+ BigInteger val)
+ {
+ if (sign == 0 || val.sign == 0)
+ return Zero;
+
+ if (val.QuickPow2Check()) // val is power of two
+ {
+ BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1);
+ return val.sign > 0 ? result : result.Negate();
+ }
+
+ if (this.QuickPow2Check()) // this is power of two
+ {
+ BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1);
+ return this.sign > 0 ? result : result.Negate();
+ }
+
+ int maxBitLength = this.BitLength + val.BitLength;
+ int resLength = (maxBitLength + BitsPerInt - 1) / BitsPerInt;
+
+ int[] res = new int[resLength];
+
+ if (val == this)
+ {
+ Square(res, this.magnitude);
+ }
+ else
+ {
+ Multiply(res, this.magnitude, val.magnitude);
+ }
+
+ return new BigInteger(sign * val.sign, res, true);
+ }
+
+ public BigInteger Negate()
+ {
+ if (sign == 0)
+ return this;
+
+ return new BigInteger(-sign, magnitude, false);
+ }
+
+ public BigInteger NextProbablePrime()
+ {
+ if (sign < 0)
+ throw new ArithmeticException("Cannot be called on value < 0");
+
+ if (CompareTo(Two) < 0)
+ return Two;
+
+ BigInteger n = Inc().SetBit(0);
+
+ while (!n.CheckProbablePrime(100, RandomSource))
+ {
+ n = n.Add(Two);
+ }
+
+ return n;
+ }
+
+ public BigInteger Not()
+ {
+ return Inc().Negate();
+ }
+
+ public BigInteger Pow(int exp)
+ {
+ if (exp < 0)
+ {
+ throw new ArithmeticException("Negative exponent");
+ }
+
+ if (exp == 0)
+ {
+ return One;
+ }
+
+ if (sign == 0 || Equals(One))
+ {
+ return this;
+ }
+
+ BigInteger y = One;
+ BigInteger z = this;
+
+ for (;;)
+ {
+ if ((exp & 0x1) == 1)
+ {
+ y = y.Multiply(z);
+ }
+ exp >>= 1;
+ if (exp == 0) break;
+ z = z.Multiply(z);
+ }
+
+ return y;
+ }
+
+ public static BigInteger ProbablePrime(
+ int bitLength,
+ Random random)
+ {
+ return new BigInteger(bitLength, 100, random);
+ }
+
+ private int Remainder(
+ int m)
+ {
+ Debug.Assert(m > 0);
+
+ long acc = 0;
+ for (int pos = 0; pos < magnitude.Length; ++pos)
+ {
+ long posVal = (uint) magnitude[pos];
+ acc = (acc << 32 | posVal) % m;
+ }
+
+ return (int) acc;
+ }
+
+ /**
+ * return x = x % y - done in place (y value preserved)
+ */
+ private int[] Remainder(
+ int[] x,
+ int[] y)
+ {
+ int xStart = 0;
+ while (xStart < x.Length && x[xStart] == 0)
+ {
+ ++xStart;
+ }
+
+ int yStart = 0;
+ while (yStart < y.Length && y[yStart] == 0)
+ {
+ ++yStart;
+ }
+
+ Debug.Assert(yStart < y.Length);
+
+ int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp > 0)
+ {
+ int yBitLength = calcBitLength(yStart, y);
+ int xBitLength = calcBitLength(xStart, x);
+ int shift = xBitLength - yBitLength;
+
+ int[] c;
+ int cStart = 0;
+ int cBitLength = yBitLength;
+ if (shift > 0)
+ {
+ c = ShiftLeft(y, shift);
+ cBitLength += shift;
+ Debug.Assert(c[0] != 0);
+ }
+ else
+ {
+ int len = y.Length - yStart;
+ c = new int[len];
+ Array.Copy(y, yStart, c, 0, len);
+ }
+
+ for (;;)
+ {
+ if (cBitLength < xBitLength
+ || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+ {
+ Subtract(xStart, x, cStart, c);
+
+ while (x[xStart] == 0)
+ {
+ if (++xStart == x.Length)
+ return x;
+ }
+
+ //xBitLength = calcBitLength(xStart, x);
+ xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+ if (xBitLength <= yBitLength)
+ {
+ if (xBitLength < yBitLength)
+ return x;
+
+ xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp <= 0)
+ break;
+ }
+ }
+
+ shift = cBitLength - xBitLength;
+
+ // NB: The case where c[cStart] is 1-bit is harmless
+ if (shift == 1)
+ {
+ uint firstC = (uint) c[cStart] >> 1;
+ uint firstX = (uint) x[xStart];
+ if (firstC > firstX)
+ ++shift;
+ }
+
+ if (shift < 2)
+ {
+ c = ShiftRightOneInPlace(cStart, c);
+ --cBitLength;
+ }
+ else
+ {
+ c = ShiftRightInPlace(cStart, c, shift);
+ cBitLength -= shift;
+ }
+
+ //cStart = c.Length - ((cBitLength + 31) / 32);
+ while (c[cStart] == 0)
+ {
+ ++cStart;
+ }
+ }
+ }
+
+ if (xyCmp == 0)
+ {
+ Array.Clear(x, xStart, x.Length - xStart);
+ }
+
+ return x;
+ }
+
+ public BigInteger Remainder(
+ BigInteger n)
+ {
+ if (n.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ if (this.sign == 0)
+ return Zero;
+
+ // For small values, use fast remainder method
+ if (n.magnitude.Length == 1)
+ {
+ int val = n.magnitude[0];
+
+ if (val > 0)
+ {
+ if (val == 1)
+ return Zero;
+
+ // TODO Make this func work on uint, and handle val == 1?
+ int rem = Remainder(val);
+
+ return rem == 0
+ ? Zero
+ : new BigInteger(sign, new int[]{ rem }, false);
+ }
+ }
+
+ if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
+ return this;
+
+ int[] result;
+ if (n.QuickPow2Check()) // n is power of two
+ {
+ // TODO Move before small values branch above?
+ result = LastNBits(n.Abs().BitLength - 1);
+ }
+ else
+ {
+ result = (int[]) this.magnitude.Clone();
+ result = Remainder(result, n.magnitude);
+ }
+
+ return new BigInteger(sign, result, true);
+ }
+
+ private int[] LastNBits(
+ int n)
+ {
+ if (n < 1)
+ return ZeroMagnitude;
+
+ int numWords = (n + BitsPerInt - 1) / BitsPerInt;
+ numWords = System.Math.Min(numWords, this.magnitude.Length);
+ int[] result = new int[numWords];
+
+ Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords);
+
+ int hiBits = n % 32;
+ if (hiBits != 0)
+ {
+ result[0] &= ~(-1 << hiBits);
+ }
+
+ return result;
+ }
+
+ /**
+ * do a left shift - this returns a new array.
+ */
+ private static int[] ShiftLeft(
+ int[] mag,
+ int n)
+ {
+ int nInts = (int)((uint)n >> 5);
+ int nBits = n & 0x1f;
+ int magLen = mag.Length;
+ int[] newMag;
+
+ if (nBits == 0)
+ {
+ newMag = new int[magLen + nInts];
+ mag.CopyTo(newMag, 0);
+ }
+ else
+ {
+ int i = 0;
+ int nBits2 = 32 - nBits;
+ int highBits = (int)((uint)mag[0] >> nBits2);
+
+ if (highBits != 0)
+ {
+ newMag = new int[magLen + nInts + 1];
+ newMag[i++] = highBits;
+ }
+ else
+ {
+ newMag = new int[magLen + nInts];
+ }
+
+ int m = mag[0];
+ for (int j = 0; j < magLen - 1; j++)
+ {
+ int next = mag[j + 1];
+
+ newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2);
+ m = next;
+ }
+
+ newMag[i] = mag[magLen - 1] << nBits;
+ }
+
+ return newMag;
+ }
+
+ public BigInteger ShiftLeft(
+ int n)
+ {
+ if (sign == 0 || magnitude.Length == 0)
+ return Zero;
+
+ if (n == 0)
+ return this;
+
+ if (n < 0)
+ return ShiftRight(-n);
+
+ BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true);
+
+ if (this.nBits != -1)
+ {
+ result.nBits = sign > 0
+ ? this.nBits
+ : this.nBits + n;
+ }
+
+ if (this.nBitLength != -1)
+ {
+ result.nBitLength = this.nBitLength + n;
+ }
+
+ return result;
+ }
+
+ /**
+ * do a right shift - this does it in place.
+ */
+ private static int[] ShiftRightInPlace(
+ int start,
+ int[] mag,
+ int n)
+ {
+ int nInts = (int)((uint)n >> 5) + start;
+ int nBits = n & 0x1f;
+ int magEnd = mag.Length - 1;
+
+ if (nInts != start)
+ {
+ int delta = (nInts - start);
+
+ for (int i = magEnd; i >= nInts; i--)
+ {
+ mag[i] = mag[i - delta];
+ }
+ for (int i = nInts - 1; i >= start; i--)
+ {
+ mag[i] = 0;
+ }
+ }
+
+ if (nBits != 0)
+ {
+ int nBits2 = 32 - nBits;
+ int m = mag[magEnd];
+
+ for (int i = magEnd; i > nInts; --i)
+ {
+ int next = mag[i - 1];
+
+ mag[i] = (int)((uint)m >> nBits) | (next << nBits2);
+ m = next;
+ }
+
+ mag[nInts] = (int)((uint)mag[nInts] >> nBits);
+ }
+
+ return mag;
+ }
+
+ /**
+ * do a right shift by one - this does it in place.
+ */
+ private static int[] ShiftRightOneInPlace(
+ int start,
+ int[] mag)
+ {
+ int i = mag.Length;
+ int m = mag[i - 1];
+
+ while (--i > start)
+ {
+ int next = mag[i - 1];
+ mag[i] = ((int)((uint)m >> 1)) | (next << 31);
+ m = next;
+ }
+
+ mag[start] = (int)((uint)mag[start] >> 1);
+
+ return mag;
+ }
+
+ public BigInteger ShiftRight(
+ int n)
+ {
+ if (n == 0)
+ return this;
+
+ if (n < 0)
+ return ShiftLeft(-n);
+
+ if (n >= BitLength)
+ return (this.sign < 0 ? One.Negate() : Zero);
+
+// int[] res = (int[]) this.magnitude.Clone();
+//
+// res = ShiftRightInPlace(0, res, n);
+//
+// return new BigInteger(this.sign, res, true);
+
+ int resultLength = (BitLength - n + 31) >> 5;
+ int[] res = new int[resultLength];
+
+ int numInts = n >> 5;
+ int numBits = n & 31;
+
+ if (numBits == 0)
+ {
+ Array.Copy(this.magnitude, 0, res, 0, res.Length);
+ }
+ else
+ {
+ int numBits2 = 32 - numBits;
+
+ int magPos = this.magnitude.Length - 1 - numInts;
+ for (int i = resultLength - 1; i >= 0; --i)
+ {
+ res[i] = (int)((uint) this.magnitude[magPos--] >> numBits);
+
+ if (magPos >= 0)
+ {
+ res[i] |= this.magnitude[magPos] << numBits2;
+ }
+ }
+ }
+
+ Debug.Assert(res[0] != 0);
+
+ return new BigInteger(this.sign, res, false);
+ }
+
+ public int SignValue
+ {
+ get { return sign; }
+ }
+
+ /**
+ * returns x = x - y - we assume x is >= y
+ */
+ private static int[] Subtract(
+ int xStart,
+ int[] x,
+ int yStart,
+ int[] y)
+ {
+ Debug.Assert(yStart < y.Length);
+ Debug.Assert(x.Length - xStart >= y.Length - yStart);
+
+ int iT = x.Length;
+ int iV = y.Length;
+ long m;
+ int borrow = 0;
+
+ do
+ {
+ m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
+ x[iT] = (int) m;
+
+// borrow = (m < 0) ? -1 : 0;
+ borrow = (int)(m >> 63);
+ }
+ while (iV > yStart);
+
+ if (borrow != 0)
+ {
+ while (--x[--iT] == -1)
+ {
+ }
+ }
+
+ return x;
+ }
+
+ public BigInteger Subtract(
+ BigInteger n)
+ {
+ if (n.sign == 0)
+ return this;
+
+ if (this.sign == 0)
+ return n.Negate();
+
+ if (this.sign != n.sign)
+ return Add(n.Negate());
+
+ int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
+ if (compare == 0)
+ return Zero;
+
+ BigInteger bigun, lilun;
+ if (compare < 0)
+ {
+ bigun = n;
+ lilun = this;
+ }
+ else
+ {
+ bigun = this;
+ lilun = n;
+ }
+
+ return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
+ }
+
+ private static int[] doSubBigLil(
+ int[] bigMag,
+ int[] lilMag)
+ {
+ int[] res = (int[]) bigMag.Clone();
+
+ return Subtract(0, res, 0, lilMag);
+ }
+
+ public byte[] ToByteArray()
+ {
+ return ToByteArray(false);
+ }
+
+ public byte[] ToByteArrayUnsigned()
+ {
+ return ToByteArray(true);
+ }
+
+ private byte[] ToByteArray(
+ bool unsigned)
+ {
+ if (sign == 0)
+ return unsigned ? ZeroEncoding : new byte[1];
+
+ int nBits = (unsigned && sign > 0)
+ ? BitLength
+ : BitLength + 1;
+
+ int nBytes = GetByteLength(nBits);
+ byte[] bytes = new byte[nBytes];
+
+ int magIndex = magnitude.Length;
+ int bytesIndex = bytes.Length;
+
+ if (sign > 0)
+ {
+ while (magIndex > 1)
+ {
+ uint mag = (uint) magnitude[--magIndex];
+ bytes[--bytesIndex] = (byte) mag;
+ bytes[--bytesIndex] = (byte)(mag >> 8);
+ bytes[--bytesIndex] = (byte)(mag >> 16);
+ bytes[--bytesIndex] = (byte)(mag >> 24);
+ }
+
+ uint lastMag = (uint) magnitude[0];
+ while (lastMag > byte.MaxValue)
+ {
+ bytes[--bytesIndex] = (byte) lastMag;
+ lastMag >>= 8;
+ }
+
+ bytes[--bytesIndex] = (byte) lastMag;
+ }
+ else // sign < 0
+ {
+ bool carry = true;
+
+ while (magIndex > 1)
+ {
+ uint mag = ~((uint) magnitude[--magIndex]);
+
+ if (carry)
+ {
+ carry = (++mag == uint.MinValue);
+ }
+
+ bytes[--bytesIndex] = (byte) mag;
+ bytes[--bytesIndex] = (byte)(mag >> 8);
+ bytes[--bytesIndex] = (byte)(mag >> 16);
+ bytes[--bytesIndex] = (byte)(mag >> 24);
+ }
+
+ uint lastMag = (uint) magnitude[0];
+
+ if (carry)
+ {
+ // Never wraps because magnitude[0] != 0
+ --lastMag;
+ }
+
+ while (lastMag > byte.MaxValue)
+ {
+ bytes[--bytesIndex] = (byte) ~lastMag;
+ lastMag >>= 8;
+ }
+
+ bytes[--bytesIndex] = (byte) ~lastMag;
+
+ if (bytesIndex > 0)
+ {
+ bytes[--bytesIndex] = byte.MaxValue;
+ }
+ }
+
+ return bytes;
+ }
+
+ public override string ToString()
+ {
+ return ToString(10);
+ }
+
+ public string ToString(
+ int radix)
+ {
+ // TODO Make this method work for other radices (ideally 2 <= radix <= 16)
+
+ switch (radix)
+ {
+ case 2:
+ case 10:
+ case 16:
+ break;
+ default:
+ throw new FormatException("Only bases 2, 10, 16 are allowed");
+ }
+
+ // NB: Can only happen to internally managed instances
+ if (magnitude == null)
+ return "null";
+
+ if (sign == 0)
+ return "0";
+
+ Debug.Assert(magnitude.Length > 0);
+
+ StringBuilder sb = new StringBuilder();
+
+ if (radix == 16)
+ {
+ sb.Append(magnitude[0].ToString("x"));
+
+ for (int i = 1; i < magnitude.Length; i++)
+ {
+ sb.Append(magnitude[i].ToString("x8"));
+ }
+ }
+ else if (radix == 2)
+ {
+ sb.Append('1');
+
+ for (int i = BitLength - 2; i >= 0; --i)
+ {
+ sb.Append(TestBit(i) ? '1' : '0');
+ }
+ }
+ else
+ {
+ // This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works
+ Stack S = new Stack();
+ BigInteger bs = ValueOf(radix);
+
+ // The sign is handled separatly.
+ // Notice however that for this to work, radix 16 _MUST_ be a special case,
+ // unless we want to enter a recursion well. In their infinite wisdom, why did not
+ // the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter?
+ // (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.)
+// BigInteger u = new BigInteger(Abs().ToString(16), 16);
+ BigInteger u = this.Abs();
+ BigInteger b;
+
+ while (u.sign != 0)
+ {
+ b = u.Mod(bs);
+ if (b.sign == 0)
+ {
+ S.Push("0");
+ }
+ else
+ {
+ // see how to interact with different bases
+ S.Push(b.magnitude[0].ToString("d"));
+ }
+ u = u.Divide(bs);
+ }
+
+ // Then pop the stack
+ while (S.Count != 0)
+ {
+ sb.Append((string) S.Pop());
+ }
+ }
+
+ string s = sb.ToString();
+
+ Debug.Assert(s.Length > 0);
+
+ // Strip leading zeros. (We know this number is not all zeroes though)
+ if (s[0] == '0')
+ {
+ int nonZeroPos = 0;
+ while (s[++nonZeroPos] == '0') {}
+
+ s = s.Substring(nonZeroPos);
+ }
+
+ if (sign == -1)
+ {
+ s = "-" + s;
+ }
+
+ return s;
+ }
+
+ private static BigInteger createUValueOf(
+ ulong value)
+ {
+ int msw = (int)(value >> 32);
+ int lsw = (int)value;
+
+ if (msw != 0)
+ return new BigInteger(1, new int[] { msw, lsw }, false);
+
+ if (lsw != 0)
+ {
+ BigInteger n = new BigInteger(1, new int[] { lsw }, false);
+ // Check for a power of two
+ if ((lsw & -lsw) == lsw)
+ {
+ n.nBits = 1;
+ }
+ return n;
+ }
+
+ return Zero;
+ }
+
+ private static BigInteger createValueOf(
+ long value)
+ {
+ if (value < 0)
+ {
+ if (value == long.MinValue)
+ return createValueOf(~value).Not();
+
+ return createValueOf(-value).Negate();
+ }
+
+ return createUValueOf((ulong)value);
+
+// // store value into a byte array
+// byte[] b = new byte[8];
+// for (int i = 0; i < 8; i++)
+// {
+// b[7 - i] = (byte)value;
+// value >>= 8;
+// }
+//
+// return new BigInteger(b);
+ }
+
+ public static BigInteger ValueOf(
+ long value)
+ {
+ switch (value)
+ {
+ case 0:
+ return Zero;
+ case 1:
+ return One;
+ case 2:
+ return Two;
+ case 3:
+ return Three;
+ case 10:
+ return Ten;
+ }
+
+ return createValueOf(value);
+ }
+
+ public int GetLowestSetBit()
+ {
+ if (this.sign == 0)
+ return -1;
+
+ int w = magnitude.Length;
+
+ while (--w > 0)
+ {
+ if (magnitude[w] != 0)
+ break;
+ }
+
+ int word = (int) magnitude[w];
+ Debug.Assert(word != 0);
+
+ int b = (word & 0x0000FFFF) == 0
+ ? (word & 0x00FF0000) == 0
+ ? 7
+ : 15
+ : (word & 0x000000FF) == 0
+ ? 23
+ : 31;
+
+ while (b > 0)
+ {
+ if ((word << b) == int.MinValue)
+ break;
+
+ b--;
+ }
+
+ return ((magnitude.Length - w) * 32 - (b + 1));
+ }
+
+ public bool TestBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit position must not be negative");
+
+ if (sign < 0)
+ return !Not().TestBit(n);
+
+ int wordNum = n / 32;
+ if (wordNum >= magnitude.Length)
+ return false;
+
+ int word = magnitude[magnitude.Length - 1 - wordNum];
+ return ((word >> (n % 32)) & 1) > 0;
+ }
+
+ public BigInteger Or(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (value.sign == 0)
+ return this;
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ bool resultNeg = sign < 0 || value.sign < 0;
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord | bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger Xor(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (value.sign == 0)
+ return this;
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ // TODO Can just replace with sign != value.sign?
+ bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0);
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord ^ bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger SetBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ if (TestBit(n))
+ return this;
+
+ // TODO Handle negative values and zero
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return Or(One.ShiftLeft(n));
+ }
+
+ public BigInteger ClearBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ if (!TestBit(n))
+ return this;
+
+ // TODO Handle negative values
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return AndNot(One.ShiftLeft(n));
+ }
+
+ public BigInteger FlipBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ // TODO Handle negative values and zero
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return Xor(One.ShiftLeft(n));
+ }
+
+ private BigInteger FlipExistingBit(
+ int n)
+ {
+ Debug.Assert(sign > 0);
+ Debug.Assert(n >= 0);
+ Debug.Assert(n < BitLength - 1);
+
+ int[] mag = (int[]) this.magnitude.Clone();
+ mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit
+ //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
+ return new BigInteger(this.sign, mag, false);
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/ECAlgorithms.cs b/src/core/srcbc/math/ec/ECAlgorithms.cs
new file mode 100644
index 0000000..c37e584
--- /dev/null
+++ b/src/core/srcbc/math/ec/ECAlgorithms.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public class ECAlgorithms
+ {
+ public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a,
+ ECPoint Q, BigInteger b)
+ {
+ ECCurve c = P.Curve;
+ if (!c.Equals(Q.Curve))
+ throw new ArgumentException("P and Q must be on same curve");
+
+ // TODO Put back in once WTNAF F2m point multiplication is enabled
+// // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+// if (c is F2mCurve)
+// {
+// F2mCurve f2mCurve = (F2mCurve) c;
+// if (f2mCurve.IsKoblitz)
+// {
+// return P.Multiply(a).Add(Q.Multiply(b));
+// }
+// }
+
+ return ImplShamirsTrick(P, a, Q, b);
+ }
+
+ /*
+ * "Shamir's Trick", originally due to E. G. Straus
+ * (Addition chains of vectors. American Mathematical Monthly,
+ * 71(7):806–808, Aug./Sept. 1964)
+ *
+ * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+ * and scalar l = (lm?, ... , l1, l0).
+ * Output: R = k * P + l * Q.
+ * 1: Z <- P + Q
+ * 2: R <- O
+ * 3: for i from m-1 down to 0 do
+ * 4: R <- R + R {point doubling}
+ * 5: if (ki = 1) and (li = 0) then R <- R + P end if
+ * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
+ * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
+ * 8: end for
+ * 9: return R
+ */
+ public static ECPoint ShamirsTrick(
+ ECPoint P,
+ BigInteger k,
+ ECPoint Q,
+ BigInteger l)
+ {
+ if (!P.Curve.Equals(Q.Curve))
+ throw new ArgumentException("P and Q must be on same curve");
+
+ return ImplShamirsTrick(P, k, Q, l);
+ }
+
+ private static ECPoint ImplShamirsTrick(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ int m = System.Math.Max(k.BitLength, l.BitLength);
+ ECPoint Z = P.Add(Q);
+ ECPoint R = P.Curve.Infinity;
+
+ for (int i = m - 1; i >= 0; --i)
+ {
+ R = R.Twice();
+
+ if (k.TestBit(i))
+ {
+ if (l.TestBit(i))
+ {
+ R = R.Add(Z);
+ }
+ else
+ {
+ R = R.Add(P);
+ }
+ }
+ else
+ {
+ if (l.TestBit(i))
+ {
+ R = R.Add(Q);
+ }
+ }
+ }
+
+ return R;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/ECCurve.cs b/src/core/srcbc/math/ec/ECCurve.cs
new file mode 100644
index 0000000..41112c7
--- /dev/null
+++ b/src/core/srcbc/math/ec/ECCurve.cs
@@ -0,0 +1,661 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math.EC.Abc;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ /// Base class for an elliptic curve.
+ public abstract class ECCurve
+ {
+ internal ECFieldElement a, b;
+
+ public abstract int FieldSize { get; }
+ public abstract ECFieldElement FromBigInteger(BigInteger x);
+ public abstract ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression);
+ public abstract ECPoint DecodePoint(byte[] encoded);
+ public abstract ECPoint Infinity { get; }
+
+ public ECFieldElement A
+ {
+ get { return a; }
+ }
+
+ public ECFieldElement B
+ {
+ get { return b; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECCurve other = obj as ECCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECCurve other)
+ {
+ return a.Equals(other.a) && b.Equals(other.b);
+ }
+
+ public override int GetHashCode()
+ {
+ return a.GetHashCode() ^ b.GetHashCode();
+ }
+ }
+
+ public abstract class ECCurveBase : ECCurve
+ {
+ protected internal ECCurveBase()
+ {
+ }
+
+ protected internal abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
+
+ /**
+ * Decode a point on this curve from its ASN.1 encoding. The different
+ * encodings are taken account of, including point compression for
+ * Fp
(X9.62 s 4.2.1 pg 17).
+ * @return The decoded point.
+ */
+ public override ECPoint DecodePoint(
+ byte[] encoded)
+ {
+ ECPoint p = null;
+ int expectedLength = (FieldSize + 7) / 8;
+
+ switch (encoded[0])
+ {
+ case 0x00: // infinity
+ {
+ if (encoded.Length != 1)
+ throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
+
+ p = Infinity;
+ break;
+ }
+
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (encoded.Length != (expectedLength + 1))
+ throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
+
+ int yTilde = encoded[0] & 1;
+ BigInteger X1 = new BigInteger(1, encoded, 1, encoded.Length - 1);
+
+ p = DecompressPoint(yTilde, X1);
+ break;
+ }
+
+ case 0x04: // uncompressed
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ {
+ if (encoded.Length != (2 * expectedLength + 1))
+ throw new ArgumentException("Incorrect length for uncompressed/hybrid encoding", "encoded");
+
+ BigInteger X1 = new BigInteger(1, encoded, 1, expectedLength);
+ BigInteger Y1 = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+ p = CreatePoint(X1, Y1, false);
+ break;
+ }
+
+ default:
+ throw new FormatException("Invalid point encoding " + encoded[0]);
+ }
+
+ return p;
+ }
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public class FpCurve : ECCurveBase
+ {
+ private readonly BigInteger q;
+ private readonly FpPoint infinity;
+
+ public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+ {
+ this.q = q;
+ this.a = FromBigInteger(a);
+ this.b = FromBigInteger(b);
+ this.infinity = new FpPoint(this, null, null);
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new FpFieldElement(this.q, x);
+ }
+
+ public override ECPoint CreatePoint(
+ BigInteger X1,
+ BigInteger Y1,
+ bool withCompression)
+ {
+ // TODO Validation of X1, Y1?
+ return new FpPoint(
+ this,
+ FromBigInteger(X1),
+ FromBigInteger(Y1),
+ withCompression);
+ }
+
+ protected internal override ECPoint DecompressPoint(
+ int yTilde,
+ BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1);
+ ECFieldElement alpha = x.Multiply(x.Square().Add(a)).Add(b);
+ ECFieldElement beta = alpha.Sqrt();
+
+ //
+ // if we can't find a sqrt we haven't got a point on the
+ // curve - run!
+ //
+ if (beta == null)
+ throw new ArithmeticException("Invalid point compression");
+
+ BigInteger betaValue = beta.ToBigInteger();
+ int bit0 = betaValue.TestBit(0) ? 1 : 0;
+
+ if (bit0 != yTilde)
+ {
+ // Use the other root
+ beta = FromBigInteger(q.Subtract(betaValue));
+ }
+
+ return new FpPoint(this, x, beta, true);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ FpCurve other = obj as FpCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ FpCurve other)
+ {
+ return base.Equals(other) && q.Equals(other.q);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode() ^ q.GetHashCode();
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * y2 + xy = x3 + ax2 + b
.
+ */
+ public class F2mCurve : ECCurveBase
+ {
+ /**
+ * The exponent m
of F2m
.
+ */
+ private readonly int m;
+
+ /**
+ * TPB: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * PPB: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k1;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k2;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k3;
+
+ /**
+ * The order of the base point of the curve.
+ */
+ private readonly BigInteger n;
+
+ /**
+ * The cofactor of the curve.
+ */
+ private readonly BigInteger h;
+
+ /**
+ * The point at infinity on this curve.
+ */
+ private readonly F2mPoint infinity;
+
+ /**
+ * The parameter μ
of the elliptic curve if this is
+ * a Koblitz curve.
+ */
+ private sbyte mu = 0;
+
+ /**
+ * The auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2mCurve(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b)
+ : this(m, k, 0, 0, a, b, null, null)
+ {
+ }
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * #Ea(F2m) = h * n
.
+ */
+ public F2mCurve(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ : this(m, k, 0, 0, a, b, n, h)
+ {
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2mCurve(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b)
+ : this(m, k1, k2, k3, a, b, null, null)
+ {
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * #Ea(F2m) = h * n
.
+ */
+ public F2mCurve(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.n = n;
+ this.h = h;
+ this.infinity = new F2mPoint(this, null, null);
+
+ if (k1 == 0)
+ throw new ArgumentException("k1 must be > 0");
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ throw new ArgumentException("k3 must be 0 if k2 == 0");
+ }
+ else
+ {
+ if (k2 <= k1)
+ throw new ArgumentException("k2 must be > k1");
+
+ if (k3 <= k2)
+ throw new ArgumentException("k3 must be > k2");
+ }
+
+ this.a = FromBigInteger(a);
+ this.b = FromBigInteger(b);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return m; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public bool IsKoblitz
+ {
+ get
+ {
+ return n != null && h != null
+ && (a.ToBigInteger().Equals(BigInteger.Zero)
+ || a.ToBigInteger().Equals(BigInteger.One))
+ && b.ToBigInteger().Equals(BigInteger.One);
+ }
+ }
+
+ /**
+ * Returns the parameter μ
of the elliptic curve.
+ * @return μ
of the elliptic curve.
+ * @throws ArgumentException if the given ECCurve is not a
+ * Koblitz curve.
+ */
+ internal sbyte GetMu()
+ {
+ if (mu == 0)
+ {
+ lock (this)
+ {
+ if (mu == 0)
+ {
+ mu = Tnaf.GetMu(this);
+ }
+ }
+ }
+
+ return mu;
+ }
+
+ /**
+ * @return the auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ internal BigInteger[] GetSi()
+ {
+ if (si == null)
+ {
+ lock (this)
+ {
+ if (si == null)
+ {
+ si = Tnaf.GetSi(this);
+ }
+ }
+ }
+ return si;
+ }
+
+ public override ECPoint CreatePoint(
+ BigInteger X1,
+ BigInteger Y1,
+ bool withCompression)
+ {
+ // TODO Validation of X1, Y1?
+ return new F2mPoint(
+ this,
+ FromBigInteger(X1),
+ FromBigInteger(Y1),
+ withCompression);
+ }
+
+ protected internal override ECPoint DecompressPoint(
+ int yTilde,
+ BigInteger X1)
+ {
+ ECFieldElement xp = FromBigInteger(X1);
+ ECFieldElement yp = null;
+ if (xp.ToBigInteger().SignValue == 0)
+ {
+ yp = (F2mFieldElement)b;
+ for (int i = 0; i < m - 1; i++)
+ {
+ yp = yp.Square();
+ }
+ }
+ else
+ {
+ ECFieldElement beta = xp.Add(a).Add(
+ b.Multiply(xp.Square().Invert()));
+ ECFieldElement z = solveQuadradicEquation(beta);
+
+ if (z == null)
+ throw new ArithmeticException("Invalid point compression");
+
+ int zBit = z.ToBigInteger().TestBit(0) ? 1 : 0;
+ if (zBit != yTilde)
+ {
+ z = z.Add(FromBigInteger(BigInteger.One));
+ }
+
+ yp = xp.Multiply(z);
+ }
+
+ return new F2mPoint(this, xp, yp, true);
+ }
+
+ /**
+ * Solves a quadratic equation z2 + z = beta
(X9.62
+ * D.1.6) The other solution is z + 1
.
+ *
+ * @param beta
+ * The value to solve the qradratic equation for.
+ * @return the solution for z2 + z = beta
or
+ * null
if no solution exists.
+ */
+ private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+ {
+ if (beta.ToBigInteger().SignValue == 0)
+ {
+ return FromBigInteger(BigInteger.Zero);
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = FromBigInteger(BigInteger.Zero);
+
+ while (gamma.ToBigInteger().SignValue == 0)
+ {
+ ECFieldElement t = FromBigInteger(new BigInteger(m, new Random()));
+ z = FromBigInteger(BigInteger.Zero);
+
+ ECFieldElement w = beta;
+ for (int i = 1; i <= m - 1; i++)
+ {
+ ECFieldElement w2 = w.Square();
+ z = z.Square().Add(w2.Multiply(t));
+ w = w2.Add(beta);
+ }
+ if (w.ToBigInteger().SignValue != 0)
+ {
+ return null;
+ }
+ gamma = z.Square().Add(z);
+ }
+ return z;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ F2mCurve other = obj as F2mCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ F2mCurve other)
+ {
+ return m == other.m
+ && k1 == other.k1
+ && k2 == other.k2
+ && k3 == other.k3
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+
+ public int M
+ {
+ get { return m; }
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public bool IsTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int K1
+ {
+ get { return k1; }
+ }
+
+ public int K2
+ {
+ get { return k2; }
+ }
+
+ public int K3
+ {
+ get { return k3; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+
+ public BigInteger H
+ {
+ get { return h; }
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/ECFieldElement.cs b/src/core/srcbc/math/ec/ECFieldElement.cs
new file mode 100644
index 0000000..7a30c14
--- /dev/null
+++ b/src/core/srcbc/math/ec/ECFieldElement.cs
@@ -0,0 +1,1253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public abstract class ECFieldElement
+ {
+ public abstract BigInteger ToBigInteger();
+ public abstract string FieldName { get; }
+ public abstract int FieldSize { get; }
+ public abstract ECFieldElement Add(ECFieldElement b);
+ public abstract ECFieldElement Subtract(ECFieldElement b);
+ public abstract ECFieldElement Multiply(ECFieldElement b);
+ public abstract ECFieldElement Divide(ECFieldElement b);
+ public abstract ECFieldElement Negate();
+ public abstract ECFieldElement Square();
+ public abstract ECFieldElement Invert();
+ public abstract ECFieldElement Sqrt();
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECFieldElement other = obj as ECFieldElement;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECFieldElement other)
+ {
+ return ToBigInteger().Equals(other.ToBigInteger());
+ }
+
+ public override int GetHashCode()
+ {
+ return ToBigInteger().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return this.ToBigInteger().ToString(2);
+ }
+ }
+
+ public class FpFieldElement
+ : ECFieldElement
+ {
+ private readonly BigInteger q, x;
+
+ public FpFieldElement(
+ BigInteger q,
+ BigInteger x)
+ {
+ if (x.CompareTo(q) >= 0)
+ throw new ArgumentException("x value too large in field element");
+
+ this.q = q;
+ this.x = x;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return x;
+ }
+
+ /**
+ * return the field name for this field.
+ *
+ * @return the string "Fp".
+ */
+ public override string FieldName
+ {
+ get { return "Fp"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECFieldElement Add(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, x.Add(b.ToBigInteger()).Mod(q));
+ }
+
+ public override ECFieldElement Subtract(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, x.Subtract(b.ToBigInteger()).Mod(q));
+ }
+
+ public override ECFieldElement Multiply(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, x.Multiply(b.ToBigInteger()).Mod(q));
+ }
+
+ public override ECFieldElement Divide(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, x.Multiply(b.ToBigInteger().ModInverse(q)).Mod(q));
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return new FpFieldElement(q, x.Negate().Mod(q));
+ }
+
+ public override ECFieldElement Square()
+ {
+ return new FpFieldElement(q, x.Multiply(x).Mod(q));
+ }
+
+ public override ECFieldElement Invert()
+ {
+ return new FpFieldElement(q, x.ModInverse(q));
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation
+ * returns the right value - if none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ if (!q.TestBit(0))
+ throw Platform.CreateNotImplementedException("even value of q");
+
+ // p mod 4 == 3
+ if (q.TestBit(1))
+ {
+ // TODO Can this be optimised (inline the Square?)
+ // z = g^(u+1) + p, p = 4u + 3
+ ECFieldElement z = new FpFieldElement(q, x.ModPow(q.ShiftRight(2).Add(BigInteger.One), q));
+
+ return z.Square().Equals(this) ? z : null;
+ }
+
+ // p mod 4 == 1
+ BigInteger qMinusOne = q.Subtract(BigInteger.One);
+
+ BigInteger legendreExponent = qMinusOne.ShiftRight(1);
+ if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
+ return null;
+
+ BigInteger u = qMinusOne.ShiftRight(2);
+ BigInteger k = u.ShiftLeft(1).Add(BigInteger.One);
+
+ BigInteger Q = this.x;
+ BigInteger fourQ = Q.ShiftLeft(2).Mod(q);
+
+ BigInteger U, V;
+ do
+ {
+ Random rand = new Random();
+ BigInteger P;
+ do
+ {
+ P = new BigInteger(q.BitLength, rand);
+ }
+ while (P.CompareTo(q) >= 0
+ || !(P.Multiply(P).Subtract(fourQ).ModPow(legendreExponent, q).Equals(qMinusOne)));
+
+ BigInteger[] result = fastLucasSequence(q, P, Q, k);
+ U = result[0];
+ V = result[1];
+
+ if (V.Multiply(V).Mod(q).Equals(fourQ))
+ {
+ // Integer division by 2, mod q
+ if (V.TestBit(0))
+ {
+ V = V.Add(q);
+ }
+
+ V = V.ShiftRight(1);
+
+ Debug.Assert(V.Multiply(V).Mod(q).Equals(x));
+
+ return new FpFieldElement(q, V);
+ }
+ }
+ while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
+
+ return null;
+
+
+// BigInteger qMinusOne = q.Subtract(BigInteger.One);
+//
+// BigInteger legendreExponent = qMinusOne.ShiftRight(1);
+// if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
+// return null;
+//
+// Random rand = new Random();
+// BigInteger fourX = x.ShiftLeft(2);
+//
+// BigInteger r;
+// do
+// {
+// r = new BigInteger(q.BitLength, rand);
+// }
+// while (r.CompareTo(q) >= 0
+// || !(r.Multiply(r).Subtract(fourX).ModPow(legendreExponent, q).Equals(qMinusOne)));
+//
+// BigInteger n1 = qMinusOne.ShiftRight(2);
+// BigInteger n2 = n1.Add(BigInteger.One);
+//
+// BigInteger wOne = WOne(r, x, q);
+// BigInteger wSum = W(n1, wOne, q).Add(W(n2, wOne, q)).Mod(q);
+// BigInteger twoR = r.ShiftLeft(1);
+//
+// BigInteger root = twoR.ModPow(q.Subtract(BigInteger.Two), q)
+// .Multiply(x).Mod(q)
+// .Multiply(wSum).Mod(q);
+//
+// return new FpFieldElement(q, root);
+ }
+
+// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p)
+// {
+// if (n.Equals(BigInteger.One))
+// return wOne;
+//
+// bool isEven = !n.TestBit(0);
+// n = n.ShiftRight(1);
+// if (isEven)
+// {
+// BigInteger w = W(n, wOne, p);
+// return w.Multiply(w).Subtract(BigInteger.Two).Mod(p);
+// }
+// BigInteger w1 = W(n.Add(BigInteger.One), wOne, p);
+// BigInteger w2 = W(n, wOne, p);
+// return w1.Multiply(w2).Subtract(wOne).Mod(p);
+// }
+//
+// private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p)
+// {
+// return r.Multiply(r).Multiply(x.ModPow(q.Subtract(BigInteger.Two), q)).Subtract(BigInteger.Two).Mod(p);
+// }
+
+ private static BigInteger[] fastLucasSequence(
+ BigInteger p,
+ BigInteger P,
+ BigInteger Q,
+ BigInteger k)
+ {
+ // TODO Research and apply "common-multiplicand multiplication here"
+
+ int n = k.BitLength;
+ int s = k.GetLowestSetBit();
+
+ Debug.Assert(k.TestBit(s));
+
+ BigInteger Uh = BigInteger.One;
+ BigInteger Vl = BigInteger.Two;
+ BigInteger Vh = P;
+ BigInteger Ql = BigInteger.One;
+ BigInteger Qh = BigInteger.One;
+
+ for (int j = n - 1; j >= s + 1; --j)
+ {
+ Ql = Ql.Multiply(Qh).Mod(p);
+
+ if (k.TestBit(j))
+ {
+ Qh = Ql.Multiply(Q).Mod(p);
+ Uh = Uh.Multiply(Vh).Mod(p);
+ Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p);
+ Vh = Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)).Mod(p);
+ }
+ else
+ {
+ Qh = Ql;
+ Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p);
+ Vh = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p);
+ Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p);
+ }
+ }
+
+ Ql = Ql.Multiply(Qh).Mod(p);
+ Qh = Ql.Multiply(Q).Mod(p);
+ Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p);
+ Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p);
+ Ql = Ql.Multiply(Qh).Mod(p);
+
+ for (int j = 1; j <= s; ++j)
+ {
+ Uh = Uh.Multiply(Vl).Mod(p);
+ Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p);
+ Ql = Ql.Multiply(Ql).Mod(p);
+ }
+
+ return new BigInteger[]{ Uh, Vl };
+ }
+
+// private static BigInteger[] verifyLucasSequence(
+// BigInteger p,
+// BigInteger P,
+// BigInteger Q,
+// BigInteger k)
+// {
+// BigInteger[] actual = fastLucasSequence(p, P, Q, k);
+// BigInteger[] plus1 = fastLucasSequence(p, P, Q, k.Add(BigInteger.One));
+// BigInteger[] plus2 = fastLucasSequence(p, P, Q, k.Add(BigInteger.Two));
+//
+// BigInteger[] check = stepLucasSequence(p, P, Q, actual, plus1);
+//
+// Debug.Assert(check[0].Equals(plus2[0]));
+// Debug.Assert(check[1].Equals(plus2[1]));
+//
+// return actual;
+// }
+//
+// private static BigInteger[] stepLucasSequence(
+// BigInteger p,
+// BigInteger P,
+// BigInteger Q,
+// BigInteger[] backTwo,
+// BigInteger[] backOne)
+// {
+// return new BigInteger[]
+// {
+// P.Multiply(backOne[0]).Subtract(Q.Multiply(backTwo[0])).Mod(p),
+// P.Multiply(backOne[1]).Subtract(Q.Multiply(backTwo[1])).Mod(p)
+// };
+// }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ FpFieldElement other = obj as FpFieldElement;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ FpFieldElement other)
+ {
+ return q.Equals(other.q) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return q.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+
+// /**
+// * Class representing the Elements of the finite field
+// * F2m
in polynomial basis (PB)
+// * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial
+// * basis representations are supported. Gaussian normal basis (GNB)
+// * representation is not supported.
+// */
+// public class F2mFieldElement
+// : ECFieldElement
+// {
+// /**
+// * Indicates gaussian normal basis representation (GNB). Number chosen
+// * according to X9.62. GNB is not implemented at present.
+// */
+// public const int Gnb = 1;
+//
+// /**
+// * Indicates trinomial basis representation (Tpb). Number chosen
+// * according to X9.62.
+// */
+// public const int Tpb = 2;
+//
+// /**
+// * Indicates pentanomial basis representation (Ppb). Number chosen
+// * according to X9.62.
+// */
+// public const int Ppb = 3;
+//
+// /**
+// * Tpb or Ppb.
+// */
+// private int representation;
+//
+// /**
+// * The exponent m
of F2m
.
+// */
+// private int m;
+//
+// /**
+// * Tpb: The integer k
where xm +
+// * xk + 1
represents the reduction polynomial
+// * f(z)
.
+// * Ppb: The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k1;
+//
+// /**
+// * Tpb: Always set to 0
+// * Ppb: The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k2;
+//
+// /**
+// * Tpb: Always set to 0
+// * Ppb: The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k3;
+//
+// /**
+// * Constructor for Ppb.
+// * @param m The exponent m
of
+// * F2m
.
+// * @param k1 The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param k2 The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param k3 The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param x The BigInteger representing the value of the field element.
+// */
+// public F2mFieldElement(
+// int m,
+// int k1,
+// int k2,
+// int k3,
+// BigInteger x)
+// : base(x)
+// {
+// if ((k2 == 0) && (k3 == 0))
+// {
+// this.representation = Tpb;
+// }
+// else
+// {
+// if (k2 >= k3)
+// throw new ArgumentException("k2 must be smaller than k3");
+// if (k2 <= 0)
+// throw new ArgumentException("k2 must be larger than 0");
+//
+// this.representation = Ppb;
+// }
+//
+// if (x.SignValue < 0)
+// throw new ArgumentException("x value cannot be negative");
+//
+// this.m = m;
+// this.k1 = k1;
+// this.k2 = k2;
+// this.k3 = k3;
+// }
+//
+// /**
+// * Constructor for Tpb.
+// * @param m The exponent m
of
+// * F2m
.
+// * @param k The integer k
where xm +
+// * xk + 1
represents the reduction
+// * polynomial f(z)
.
+// * @param x The BigInteger representing the value of the field element.
+// */
+// public F2mFieldElement(
+// int m,
+// int k,
+// BigInteger x)
+// : this(m, k, 0, 0, x)
+// {
+// // Set k1 to k, and set k2 and k3 to 0
+// }
+//
+// public override string FieldName
+// {
+// get { return "F2m"; }
+// }
+//
+// /**
+// * Checks, if the ECFieldElements a
and b
+// * are elements of the same field F2m
+// * (having the same representation).
+// * @param a field element.
+// * @param b field element to be compared.
+// * @throws ArgumentException if a
and b
+// * are not elements of the same field
+// * F2m
(having the same
+// * representation).
+// */
+// public static void CheckFieldElements(
+// ECFieldElement a,
+// ECFieldElement b)
+// {
+// if (!(a is F2mFieldElement) || !(b is F2mFieldElement))
+// {
+// throw new ArgumentException("Field elements are not "
+// + "both instances of F2mFieldElement");
+// }
+//
+// if ((a.x.SignValue < 0) || (b.x.SignValue < 0))
+// {
+// throw new ArgumentException(
+// "x value may not be negative");
+// }
+//
+// F2mFieldElement aF2m = (F2mFieldElement)a;
+// F2mFieldElement bF2m = (F2mFieldElement)b;
+//
+// if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+// || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+// {
+// throw new ArgumentException("Field elements are not "
+// + "elements of the same field F2m");
+// }
+//
+// if (aF2m.representation != bF2m.representation)
+// {
+// // Should never occur
+// throw new ArgumentException(
+// "One of the field "
+// + "elements are not elements has incorrect representation");
+// }
+// }
+//
+// /**
+// * Computes z * a(z) mod f(z)
, where f(z)
is
+// * the reduction polynomial of this
.
+// * @param a The polynomial a(z)
to be multiplied by
+// * z mod f(z)
.
+// * @return z * a(z) mod f(z)
+// */
+// private BigInteger multZModF(
+// BigInteger a)
+// {
+// // Left-shift of a(z)
+// BigInteger az = a.ShiftLeft(1);
+// if (az.TestBit(this.m))
+// {
+// // If the coefficient of z^m in a(z) Equals 1, reduction
+// // modulo f(z) is performed: Add f(z) to to a(z):
+// // Step 1: Unset mth coeffient of a(z)
+// az = az.ClearBit(this.m);
+//
+// // Step 2: Add r(z) to a(z), where r(z) is defined as
+// // f(z) = z^m + r(z), and k1, k2, k3 are the positions of
+// // the non-zero coefficients in r(z)
+// az = az.FlipBit(0);
+// az = az.FlipBit(this.k1);
+// if (this.representation == Ppb)
+// {
+// az = az.FlipBit(this.k2);
+// az = az.FlipBit(this.k3);
+// }
+// }
+// return az;
+// }
+//
+// public override ECFieldElement Add(
+// ECFieldElement b)
+// {
+// // No check performed here for performance reasons. Instead the
+// // elements involved are checked in ECPoint.F2m
+// // checkFieldElements(this, b);
+// if (b.x.SignValue == 0)
+// return this;
+//
+// return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, this.x.Xor(b.x));
+// }
+//
+// public override ECFieldElement Subtract(
+// ECFieldElement b)
+// {
+// // Addition and subtraction are the same in F2m
+// return Add(b);
+// }
+//
+// public override ECFieldElement Multiply(
+// ECFieldElement b)
+// {
+// // Left-to-right shift-and-add field multiplication in F2m
+// // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+// // Output: c(z) = a(z) * b(z) mod f(z)
+//
+// // No check performed here for performance reasons. Instead the
+// // elements involved are checked in ECPoint.F2m
+// // checkFieldElements(this, b);
+// BigInteger az = this.x;
+// BigInteger bz = b.x;
+// BigInteger cz;
+//
+// // Compute c(z) = a(z) * b(z) mod f(z)
+// if (az.TestBit(0))
+// {
+// cz = bz;
+// }
+// else
+// {
+// cz = BigInteger.Zero;
+// }
+//
+// for (int i = 1; i < this.m; i++)
+// {
+// // b(z) := z * b(z) mod f(z)
+// bz = multZModF(bz);
+//
+// if (az.TestBit(i))
+// {
+// // If the coefficient of x^i in a(z) Equals 1, b(z) is added
+// // to c(z)
+// cz = cz.Xor(bz);
+// }
+// }
+// return new F2mFieldElement(m, this.k1, this.k2, this.k3, cz);
+// }
+//
+//
+// public override ECFieldElement Divide(
+// ECFieldElement b)
+// {
+// // There may be more efficient implementations
+// ECFieldElement bInv = b.Invert();
+// return Multiply(bInv);
+// }
+//
+// public override ECFieldElement Negate()
+// {
+// // -x == x holds for all x in F2m
+// return this;
+// }
+//
+// public override ECFieldElement Square()
+// {
+// // Naive implementation, can probably be speeded up using modular
+// // reduction
+// return Multiply(this);
+// }
+//
+// public override ECFieldElement Invert()
+// {
+// // Inversion in F2m using the extended Euclidean algorithm
+// // Input: A nonzero polynomial a(z) of degree at most m-1
+// // Output: a(z)^(-1) mod f(z)
+//
+// // u(z) := a(z)
+// BigInteger uz = this.x;
+// if (uz.SignValue <= 0)
+// {
+// throw new ArithmeticException("x is zero or negative, " +
+// "inversion is impossible");
+// }
+//
+// // v(z) := f(z)
+// BigInteger vz = BigInteger.One.ShiftLeft(m);
+// vz = vz.SetBit(0);
+// vz = vz.SetBit(this.k1);
+// if (this.representation == Ppb)
+// {
+// vz = vz.SetBit(this.k2);
+// vz = vz.SetBit(this.k3);
+// }
+//
+// // g1(z) := 1, g2(z) := 0
+// BigInteger g1z = BigInteger.One;
+// BigInteger g2z = BigInteger.Zero;
+//
+// // while u != 1
+// while (uz.SignValue != 0)
+// {
+// // j := deg(u(z)) - deg(v(z))
+// int j = uz.BitLength - vz.BitLength;
+//
+// // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+// if (j < 0)
+// {
+// BigInteger uzCopy = uz;
+// uz = vz;
+// vz = uzCopy;
+//
+// BigInteger g1zCopy = g1z;
+// g1z = g2z;
+// g2z = g1zCopy;
+//
+// j = -j;
+// }
+//
+// // u(z) := u(z) + z^j * v(z)
+// // Note, that no reduction modulo f(z) is required, because
+// // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+// // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+// // = deg(u(z))
+// uz = uz.Xor(vz.ShiftLeft(j));
+//
+// // g1(z) := g1(z) + z^j * g2(z)
+// g1z = g1z.Xor(g2z.ShiftLeft(j));
+// // if (g1z.BitLength() > this.m) {
+// // throw new ArithmeticException(
+// // "deg(g1z) >= m, g1z = " + g1z.ToString(2));
+// // }
+// }
+// return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z);
+// }
+//
+// public override ECFieldElement Sqrt()
+// {
+// throw new ArithmeticException("Not implemented");
+// }
+//
+// /**
+// * @return the representation of the field
+// * F2m
, either of
+// * {@link F2mFieldElement.Tpb} (trinomial
+// * basis representation) or
+// * {@link F2mFieldElement.Ppb} (pentanomial
+// * basis representation).
+// */
+// public int Representation
+// {
+// get { return this.representation; }
+// }
+//
+// /**
+// * @return the degree m
of the reduction polynomial
+// * f(z)
.
+// */
+// public int M
+// {
+// get { return this.m; }
+// }
+//
+// /**
+// * @return Tpb: The integer k
where xm +
+// * xk + 1
represents the reduction polynomial
+// * f(z)
.
+// * Ppb: The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int K1
+// {
+// get { return this.k1; }
+// }
+//
+// /**
+// * @return Tpb: Always returns 0
+// * Ppb: The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int K2
+// {
+// get { return this.k2; }
+// }
+//
+// /**
+// * @return Tpb: Always set to 0
+// * Ppb: The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int K3
+// {
+// get { return this.k3; }
+// }
+//
+// public override bool Equals(
+// object obj)
+// {
+// if (obj == this)
+// return true;
+//
+// F2mFieldElement other = obj as F2mFieldElement;
+//
+// if (other == null)
+// return false;
+//
+// return Equals(other);
+// }
+//
+// protected bool Equals(
+// F2mFieldElement other)
+// {
+// return m == other.m
+// && k1 == other.k1
+// && k2 == other.k2
+// && k3 == other.k3
+// && representation == other.representation
+// && base.Equals(other);
+// }
+//
+// public override int GetHashCode()
+// {
+// return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3;
+// }
+// }
+
+ /**
+ * Class representing the Elements of the finite field
+ * F2m
in polynomial basis (PB)
+ * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial
+ * basis representations are supported. Gaussian normal basis (GNB)
+ * representation is not supported.
+ */
+ public class F2mFieldElement
+ : ECFieldElement
+ {
+ /**
+ * Indicates gaussian normal basis representation (GNB). Number chosen
+ * according to X9.62. GNB is not implemented at present.
+ */
+ public const int Gnb = 1;
+
+ /**
+ * Indicates trinomial basis representation (Tpb). Number chosen
+ * according to X9.62.
+ */
+ public const int Tpb = 2;
+
+ /**
+ * Indicates pentanomial basis representation (Ppb). Number chosen
+ * according to X9.62.
+ */
+ public const int Ppb = 3;
+
+ /**
+ * Tpb or Ppb.
+ */
+ private int representation;
+
+ /**
+ * The exponent m
of F2m
.
+ */
+ private int m;
+
+ /**
+ * Tpb: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * Ppb: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k1;
+
+ /**
+ * Tpb: Always set to 0
+ * Ppb: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k2;
+
+ /**
+ * Tpb: Always set to 0
+ * Ppb: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k3;
+
+ /**
+ * The IntArray
holding the bits.
+ */
+ private IntArray x;
+
+ /**
+ * The number of int
s required to hold m
bits.
+ */
+ private readonly int t;
+
+ /**
+ * Constructor for Ppb.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2mFieldElement(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger x)
+ {
+ // t = m / 32 rounded up to the next integer
+ this.t = (m + 31) >> 5;
+ this.x = new IntArray(x, t);
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = Tpb;
+ }
+ else
+ {
+ if (k2 >= k3)
+ throw new ArgumentException("k2 must be smaller than k3");
+ if (k2 <= 0)
+ throw new ArgumentException("k2 must be larger than 0");
+
+ this.representation = Ppb;
+ }
+
+ if (x.SignValue < 0)
+ throw new ArgumentException("x value cannot be negative");
+
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ }
+
+ /**
+ * Constructor for Tpb.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2mFieldElement(
+ int m,
+ int k,
+ BigInteger x)
+ : this(m, k, 0, 0, x)
+ {
+ // Set k1 to k, and set k2 and k3 to 0
+ }
+
+ private F2mFieldElement(int m, int k1, int k2, int k3, IntArray x)
+ {
+ t = (m + 31) >> 5;
+ this.x = x;
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = Tpb;
+ }
+ else
+ {
+ this.representation = Ppb;
+ }
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return x.ToBigInteger();
+ }
+
+ public override string FieldName
+ {
+ get { return "F2m"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return m; }
+ }
+
+ /**
+ * Checks, if the ECFieldElements a
and b
+ * are elements of the same field F2m
+ * (having the same representation).
+ * @param a field element.
+ * @param b field element to be compared.
+ * @throws ArgumentException if a
and b
+ * are not elements of the same field
+ * F2m
(having the same
+ * representation).
+ */
+ public static void CheckFieldElements(
+ ECFieldElement a,
+ ECFieldElement b)
+ {
+ if (!(a is F2mFieldElement) || !(b is F2mFieldElement))
+ {
+ throw new ArgumentException("Field elements are not "
+ + "both instances of F2mFieldElement");
+ }
+
+ F2mFieldElement aF2m = (F2mFieldElement)a;
+ F2mFieldElement bF2m = (F2mFieldElement)b;
+
+ if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+ || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+ {
+ throw new ArgumentException("Field elements are not "
+ + "elements of the same field F2m");
+ }
+
+ if (aF2m.representation != bF2m.representation)
+ {
+ // Should never occur
+ throw new ArgumentException(
+ "One of the field "
+ + "elements are not elements has incorrect representation");
+ }
+ }
+
+ public override ECFieldElement Add(
+ ECFieldElement b)
+ {
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ IntArray iarrClone = (IntArray) this.x.Clone();
+ F2mFieldElement bF2m = (F2mFieldElement) b;
+ iarrClone.AddShifted(bF2m.x, 0);
+ return new F2mFieldElement(m, k1, k2, k3, iarrClone);
+ }
+
+ public override ECFieldElement Subtract(
+ ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(
+ ECFieldElement b)
+ {
+ // Right-to-left comb multiplication in the IntArray
+ // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+ // Output: c(z) = a(z) * b(z) mod f(z)
+
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ F2mFieldElement bF2m = (F2mFieldElement) b;
+ IntArray mult = x.Multiply(bF2m.x, m);
+ mult.Reduce(m, new int[]{k1, k2, k3});
+ return new F2mFieldElement(m, k1, k2, k3, mult);
+ }
+
+ public override ECFieldElement Divide(
+ ECFieldElement b)
+ {
+ // There may be more efficient implementations
+ ECFieldElement bInv = b.Invert();
+ return Multiply(bInv);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ // -x == x holds for all x in F2m
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ IntArray squared = x.Square(m);
+ squared.Reduce(m, new int[]{k1, k2, k3});
+ return new F2mFieldElement(m, k1, k2, k3, squared);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // Inversion in F2m using the extended Euclidean algorithm
+ // Input: A nonzero polynomial a(z) of degree at most m-1
+ // Output: a(z)^(-1) mod f(z)
+
+ // u(z) := a(z)
+ IntArray uz = (IntArray)this.x.Clone();
+
+ // v(z) := f(z)
+ IntArray vz = new IntArray(t);
+ vz.SetBit(m);
+ vz.SetBit(0);
+ vz.SetBit(this.k1);
+ if (this.representation == Ppb)
+ {
+ vz.SetBit(this.k2);
+ vz.SetBit(this.k3);
+ }
+
+ // g1(z) := 1, g2(z) := 0
+ IntArray g1z = new IntArray(t);
+ g1z.SetBit(0);
+ IntArray g2z = new IntArray(t);
+
+ // while u != 0
+ while (uz.GetUsedLength() > 0)
+// while (uz.bitLength() > 1)
+ {
+ // j := deg(u(z)) - deg(v(z))
+ int j = uz.BitLength - vz.BitLength;
+
+ // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+ if (j < 0)
+ {
+ IntArray uzCopy = uz;
+ uz = vz;
+ vz = uzCopy;
+
+ IntArray g1zCopy = g1z;
+ g1z = g2z;
+ g2z = g1zCopy;
+
+ j = -j;
+ }
+
+ // u(z) := u(z) + z^j * v(z)
+ // Note, that no reduction modulo f(z) is required, because
+ // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+ // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+ // = deg(u(z))
+ // uz = uz.xor(vz.ShiftLeft(j));
+ // jInt = n / 32
+ int jInt = j >> 5;
+ // jInt = n % 32
+ int jBit = j & 0x1F;
+ IntArray vzShift = vz.ShiftLeft(jBit);
+ uz.AddShifted(vzShift, jInt);
+
+ // g1(z) := g1(z) + z^j * g2(z)
+// g1z = g1z.xor(g2z.ShiftLeft(j));
+ IntArray g2zShift = g2z.ShiftLeft(jBit);
+ g1z.AddShifted(g2zShift, jInt);
+ }
+ return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ throw new ArithmeticException("Not implemented");
+ }
+
+ /**
+ * @return the representation of the field
+ * F2m
, either of
+ * {@link F2mFieldElement.Tpb} (trinomial
+ * basis representation) or
+ * {@link F2mFieldElement.Ppb} (pentanomial
+ * basis representation).
+ */
+ public int Representation
+ {
+ get { return this.representation; }
+ }
+
+ /**
+ * @return the degree m
of the reduction polynomial
+ * f(z)
.
+ */
+ public int M
+ {
+ get { return this.m; }
+ }
+
+ /**
+ * @return Tpb: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * Ppb: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K1
+ {
+ get { return this.k1; }
+ }
+
+ /**
+ * @return Tpb: Always returns 0
+ * Ppb: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K2
+ {
+ get { return this.k2; }
+ }
+
+ /**
+ * @return Tpb: Always set to 0
+ * Ppb: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K3
+ {
+ get { return this.k3; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ F2mFieldElement other = obj as F2mFieldElement;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ F2mFieldElement other)
+ {
+ return m == other.m
+ && k1 == other.k1
+ && k2 == other.k2
+ && k3 == other.k3
+ && representation == other.representation
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return m.GetHashCode()
+ ^ k1.GetHashCode()
+ ^ k2.GetHashCode()
+ ^ k3.GetHashCode()
+ ^ representation.GetHashCode()
+ ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/ECPoint.cs b/src/core/srcbc/math/ec/ECPoint.cs
new file mode 100644
index 0000000..4792e70
--- /dev/null
+++ b/src/core/srcbc/math/ec/ECPoint.cs
@@ -0,0 +1,566 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Asn1.X9;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ /**
+ * base class for points on elliptic curves.
+ */
+ public abstract class ECPoint
+ {
+ internal readonly ECCurve curve;
+ internal readonly ECFieldElement x, y;
+ internal readonly bool withCompression;
+ internal ECMultiplier multiplier = null;
+ internal PreCompInfo preCompInfo = null;
+
+ protected internal ECPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ {
+ if (curve == null)
+ throw new ArgumentNullException("curve");
+
+ this.curve = curve;
+ this.x = x;
+ this.y = y;
+ this.withCompression = withCompression;
+ }
+
+ public ECCurve Curve
+ {
+ get { return curve; }
+ }
+
+ public ECFieldElement X
+ {
+ get { return x; }
+ }
+
+ public ECFieldElement Y
+ {
+ get { return y; }
+ }
+
+ public bool IsInfinity
+ {
+ get { return x == null && y == null; }
+ }
+
+ public bool IsCompressed
+ {
+ get { return withCompression; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECPoint o = obj as ECPoint;
+
+ if (o == null)
+ return false;
+
+ if (this.IsInfinity)
+ return o.IsInfinity;
+
+ return x.Equals(o.x) && y.Equals(o.y);
+ }
+
+ public override int GetHashCode()
+ {
+ if (this.IsInfinity)
+ return 0;
+
+ return x.GetHashCode() ^ y.GetHashCode();
+ }
+
+// /**
+// * Mainly for testing. Explicitly set the ECMultiplier
.
+// * @param multiplier The ECMultiplier
to be used to multiply
+// * this ECPoint
.
+// */
+// internal void SetECMultiplier(
+// ECMultiplier multiplier)
+// {
+// this.multiplier = multiplier;
+// }
+
+ /**
+ * Sets the PreCompInfo
. Used by ECMultiplier
s
+ * to save the precomputation for this ECPoint
to store the
+ * precomputation result for use by subsequent multiplication.
+ * @param preCompInfo The values precomputed by the
+ * ECMultiplier
.
+ */
+ internal void SetPreCompInfo(
+ PreCompInfo preCompInfo)
+ {
+ this.preCompInfo = preCompInfo;
+ }
+
+ public abstract byte[] GetEncoded();
+
+ public abstract ECPoint Add(ECPoint b);
+ public abstract ECPoint Subtract(ECPoint b);
+ public abstract ECPoint Negate();
+ public abstract ECPoint Twice();
+ public abstract ECPoint Multiply(BigInteger b);
+
+ /**
+ * Sets the appropriate ECMultiplier
, unless already set.
+ */
+ internal virtual void AssertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ lock (this)
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new FpNafMultiplier();
+ }
+ }
+ }
+ }
+ }
+
+ public abstract class ECPointBase
+ : ECPoint
+ {
+ protected internal ECPointBase(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected internal abstract bool YTilde { get; }
+
+ /**
+ * return the field element encoded with point compression. (S 4.3.6)
+ */
+ public override byte[] GetEncoded()
+ {
+ if (this.IsInfinity)
+ return new byte[1];
+
+ // Note: some of the tests rely on calculating byte length from the field element
+ // (since the test cases use mismatching fields for curve/elements)
+ int byteLength = X9IntegerConverter.GetByteLength(x);
+ byte[] X = X9IntegerConverter.IntegerToBytes(this.X.ToBigInteger(), byteLength);
+ byte[] PO;
+
+ if (withCompression)
+ {
+ PO = new byte[1 + X.Length];
+
+ PO[0] = (byte)(YTilde ? 0x03 : 0x02);
+ }
+ else
+ {
+ byte[] Y = X9IntegerConverter.IntegerToBytes(this.Y.ToBigInteger(), byteLength);
+ PO = new byte[1 + X.Length + Y.Length];
+
+ PO[0] = 0x04;
+
+ Y.CopyTo(PO, 1 + X.Length);
+ }
+
+ X.CopyTo(PO, 1);
+
+ return PO;
+ }
+
+ /**
+ * Multiplies this ECPoint
by the given number.
+ * @param k The multiplicator.
+ * @return k * this
.
+ */
+ public override ECPoint Multiply(
+ BigInteger k)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ if (k.SignValue == 0)
+ return this.curve.Infinity;
+
+ AssertECMultiplier();
+ return this.multiplier.Multiply(this, k, preCompInfo);
+ }
+ }
+
+ /**
+ * Elliptic curve points over Fp
+ */
+ public class FpPoint
+ : ECPointBase
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ */
+ public FpPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ * @param withCompression if true encode with point compression
+ */
+ public FpPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x != null && y == null) || (x == null && y != null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ protected internal override bool YTilde
+ {
+ get
+ {
+ return this.Y.ToBigInteger().TestBit(0);
+ }
+ }
+
+ // B.3 pg 62
+ public override ECPoint Add(
+ ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+
+ if (b.IsInfinity)
+ return this;
+
+ // Check if b = this or b = -this
+ if (this.x.Equals(b.x))
+ {
+ if (this.y.Equals(b.y))
+ {
+ // this = b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ Debug.Assert(this.y.Equals(b.y.Negate()));
+
+ // this = -b, i.e. the result is the point at infinity
+ return this.curve.Infinity;
+ }
+
+ ECFieldElement gamma = b.y.Subtract(this.y).Divide(b.x.Subtract(this.x));
+
+ ECFieldElement x3 = gamma.Square().Subtract(this.x).Subtract(b.x);
+ ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y);
+
+ return new FpPoint(curve, x3, y3);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Twice()
+ {
+ // Twice identity element (point at infinity) is identity
+ if (this.IsInfinity)
+ return this;
+
+ // if y1 == 0, then (x1, y1) == (x1, -y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ if (this.y.ToBigInteger().SignValue == 0)
+ return this.curve.Infinity;
+
+ ECFieldElement TWO = this.curve.FromBigInteger(BigInteger.Two);
+ ECFieldElement THREE = this.curve.FromBigInteger(BigInteger.Three);
+ ECFieldElement gamma = this.x.Square().Multiply(THREE).Add(curve.a).Divide(y.Multiply(TWO));
+
+ ECFieldElement x3 = gamma.Square().Subtract(this.x.Multiply(TWO));
+ ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y);
+
+ return new FpPoint(curve, x3, y3, this.withCompression);
+ }
+
+ // D.3.2 pg 102 (see Note:)
+ public override ECPoint Subtract(
+ ECPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return Add(b.Negate());
+ }
+
+ public override ECPoint Negate()
+ {
+ return new FpPoint(this.curve, this.x, this.y.Negate(), this.withCompression);
+ }
+
+ // TODO Uncomment this to enable WNAF Fp point multiplication
+// /**
+// * Sets the default ECMultiplier
, unless already set.
+// */
+// internal override void AssertECMultiplier()
+// {
+// if (this.multiplier == null)
+// {
+// lock (this)
+// {
+// if (this.multiplier == null)
+// {
+// this.multiplier = new WNafMultiplier();
+// }
+// }
+// }
+// }
+ }
+
+ /**
+ * Elliptic curve points over F2m
+ */
+ public class F2mPoint
+ : ECPointBase
+ {
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ */
+ public F2mPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ * @param withCompression true if encode with point compression.
+ */
+ public F2mPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ if (x != null)
+ {
+ // Check if x and y are elements of the same field
+ F2mFieldElement.CheckFieldElements(this.x, this.y);
+
+ // Check if x and a are elements of the same field
+ F2mFieldElement.CheckFieldElements(this.x, this.curve.A);
+ }
+ }
+
+ /**
+ * Constructor for point at infinity
+ */
+ [Obsolete("Use ECCurve.Infinity property")]
+ public F2mPoint(
+ ECCurve curve)
+ : this(curve, null, null)
+ {
+ }
+
+ protected internal override bool YTilde
+ {
+ get
+ {
+ // X9.62 4.2.2 and 4.3.6:
+ // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
+ // bit of y * x^(-1)
+ return this.X.ToBigInteger().SignValue != 0
+ && this.Y.Multiply(this.X.Invert()).ToBigInteger().TestBit(0);
+ }
+ }
+
+ /**
+ * Check, if two ECPoint
s can be added or subtracted.
+ * @param a The first ECPoint
to check.
+ * @param b The second ECPoint
to check.
+ * @throws IllegalArgumentException if a
and b
+ * cannot be added.
+ */
+ private static void CheckPoints(
+ ECPoint a,
+ ECPoint b)
+ {
+ // Check, if points are on the same curve
+ if (!a.curve.Equals(b.curve))
+ throw new ArgumentException("Only points on the same curve can be added or subtracted");
+
+// F2mFieldElement.CheckFieldElements(a.x, b.x);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
+ */
+ public override ECPoint Add(ECPoint b)
+ {
+ CheckPoints(this, b);
+ return AddSimple((F2mPoint) b);
+ }
+
+ /**
+ * Adds another ECPoints.F2m
to this
without
+ * checking if both points are on the same curve. Used by multiplication
+ * algorithms, because there all points are a multiple of the same point
+ * and hence the checks can be omitted.
+ * @param b The other ECPoints.F2m
to add to
+ * this
.
+ * @return this + b
+ */
+ internal F2mPoint AddSimple(F2mPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+
+ if (b.IsInfinity)
+ return this;
+
+ F2mFieldElement x2 = (F2mFieldElement) b.X;
+ F2mFieldElement y2 = (F2mFieldElement) b.Y;
+
+ // Check if b == this or b == -this
+ if (this.x.Equals(x2))
+ {
+ // this == b, i.e. this must be doubled
+ if (this.y.Equals(y2))
+ return (F2mPoint) this.Twice();
+
+ // this = -other, i.e. the result is the point at infinity
+ return (F2mPoint) this.curve.Infinity;
+ }
+
+ ECFieldElement xSum = this.x.Add(x2);
+
+ F2mFieldElement lambda
+ = (F2mFieldElement)(this.y.Add(y2)).Divide(xSum);
+
+ F2mFieldElement x3
+ = (F2mFieldElement)lambda.Square().Add(lambda).Add(xSum).Add(this.curve.A);
+
+ F2mFieldElement y3
+ = (F2mFieldElement)lambda.Multiply(this.x.Add(x3)).Add(x3).Add(this.y);
+
+ return new F2mPoint(curve, x3, y3, withCompression);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
+ */
+ public override ECPoint Subtract(
+ ECPoint b)
+ {
+ CheckPoints(this, b);
+ return SubtractSimple((F2mPoint) b);
+ }
+
+ /**
+ * Subtracts another ECPoints.F2m
from this
+ * without checking if both points are on the same curve. Used by
+ * multiplication algorithms, because there all points are a multiple
+ * of the same point and hence the checks can be omitted.
+ * @param b The other ECPoints.F2m
to subtract from
+ * this
.
+ * @return this - b
+ */
+ internal F2mPoint SubtractSimple(
+ F2mPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return AddSimple((F2mPoint) b.Negate());
+ }
+
+ /* (non-Javadoc)
+ * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
+ */
+ public override ECPoint Twice()
+ {
+ // Twice identity element (point at infinity) is identity
+ if (this.IsInfinity)
+ return this;
+
+ // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ if (this.x.ToBigInteger().SignValue == 0)
+ return this.curve.Infinity;
+
+ F2mFieldElement lambda = (F2mFieldElement) this.x.Add(this.y.Divide(this.x));
+ F2mFieldElement x2 = (F2mFieldElement)lambda.Square().Add(lambda).Add(this.curve.A);
+ ECFieldElement ONE = this.curve.FromBigInteger(BigInteger.One);
+ F2mFieldElement y2 = (F2mFieldElement)this.x.Square().Add(
+ x2.Multiply(lambda.Add(ONE)));
+
+ return new F2mPoint(this.curve, x2, y2, withCompression);
+ }
+
+ public override ECPoint Negate()
+ {
+ return new F2mPoint(curve, this.x, this.x.Add(this.y), withCompression);
+ }
+
+ // TODO Uncomment this to enable WNAF/WTNAF F2m point multiplication
+// /**
+// * Sets the appropriate ECMultiplier
, unless already set.
+// */
+// internal override void AssertECMultiplier()
+// {
+// if (this.multiplier == null)
+// {
+// lock (this)
+// {
+// if (this.multiplier == null)
+// {
+// if (((F2mCurve) this.curve).IsKoblitz)
+// {
+// this.multiplier = new WTauNafMultiplier();
+// }
+// else
+// {
+// this.multiplier = new WNafMultiplier();
+// }
+// }
+// }
+// }
+// }
+ }
+}
diff --git a/src/core/srcbc/math/ec/IntArray.cs b/src/core/srcbc/math/ec/IntArray.cs
new file mode 100644
index 0000000..d16197d
--- /dev/null
+++ b/src/core/srcbc/math/ec/IntArray.cs
@@ -0,0 +1,486 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ internal class IntArray
+ : ICloneable
+ {
+ // TODO make m fixed for the IntArray, and hence compute T once and for all
+
+ // TODO Use uint's internally?
+ private int[] m_ints;
+
+ public IntArray(int intLen)
+ {
+ m_ints = new int[intLen];
+ }
+
+ private IntArray(int[] ints)
+ {
+ m_ints = ints;
+ }
+
+ public IntArray(BigInteger bigInt)
+ : this(bigInt, 0)
+ {
+ }
+
+ public IntArray(BigInteger bigInt, int minIntLen)
+ {
+ if (bigInt.SignValue == -1)
+ throw new ArgumentException("Only positive Integers allowed", "bigint");
+
+ if (bigInt.SignValue == 0)
+ {
+ m_ints = new int[] { 0 };
+ return;
+ }
+
+ byte[] barr = bigInt.ToByteArrayUnsigned();
+ int barrLen = barr.Length;
+
+ int intLen = (barrLen + 3) / 4;
+ m_ints = new int[System.Math.Max(intLen, minIntLen)];
+
+ int rem = barrLen % 4;
+ int barrI = 0;
+
+ if (0 < rem)
+ {
+ int temp = (int) barr[barrI++];
+ while (barrI < rem)
+ {
+ temp = temp << 8 | (int) barr[barrI++];
+ }
+ m_ints[--intLen] = temp;
+ }
+
+ while (intLen > 0)
+ {
+ int temp = (int) barr[barrI++];
+ for (int i = 1; i < 4; i++)
+ {
+ temp = temp << 8 | (int) barr[barrI++];
+ }
+ m_ints[--intLen] = temp;
+ }
+ }
+
+ public int GetUsedLength()
+ {
+ int highestIntPos = m_ints.Length;
+
+ if (highestIntPos < 1)
+ return 0;
+
+ // Check if first element will act as sentinel
+ if (m_ints[0] != 0)
+ {
+ while (m_ints[--highestIntPos] == 0)
+ {
+ }
+ return highestIntPos + 1;
+ }
+
+ do
+ {
+ if (m_ints[--highestIntPos] != 0)
+ {
+ return highestIntPos + 1;
+ }
+ }
+ while (highestIntPos > 0);
+
+ return 0;
+ }
+
+ public int BitLength
+ {
+ get
+ {
+ // JDK 1.5: see Integer.numberOfLeadingZeros()
+ int intLen = GetUsedLength();
+ if (intLen == 0)
+ return 0;
+
+ int last = intLen - 1;
+ uint highest = (uint) m_ints[last];
+ int bits = (last << 5) + 1;
+
+ // A couple of binary search steps
+ if (highest > 0x0000ffff)
+ {
+ if (highest > 0x00ffffff)
+ {
+ bits += 24;
+ highest >>= 24;
+ }
+ else
+ {
+ bits += 16;
+ highest >>= 16;
+ }
+ }
+ else if (highest > 0x000000ff)
+ {
+ bits += 8;
+ highest >>= 8;
+ }
+
+ while (highest > 1)
+ {
+ ++bits;
+ highest >>= 1;
+ }
+
+ return bits;
+ }
+ }
+
+ private int[] resizedInts(int newLen)
+ {
+ int[] newInts = new int[newLen];
+ int oldLen = m_ints.Length;
+ int copyLen = oldLen < newLen ? oldLen : newLen;
+ Array.Copy(m_ints, 0, newInts, 0, copyLen);
+ return newInts;
+ }
+
+ public BigInteger ToBigInteger()
+ {
+ int usedLen = GetUsedLength();
+ if (usedLen == 0)
+ {
+ return BigInteger.Zero;
+ }
+
+ int highestInt = m_ints[usedLen - 1];
+ byte[] temp = new byte[4];
+ int barrI = 0;
+ bool trailingZeroBytesDone = false;
+ for (int j = 3; j >= 0; j--)
+ {
+ byte thisByte = (byte)((int)((uint) highestInt >> (8 * j)));
+ if (trailingZeroBytesDone || (thisByte != 0))
+ {
+ trailingZeroBytesDone = true;
+ temp[barrI++] = thisByte;
+ }
+ }
+
+ int barrLen = 4 * (usedLen - 1) + barrI;
+ byte[] barr = new byte[barrLen];
+ for (int j = 0; j < barrI; j++)
+ {
+ barr[j] = temp[j];
+ }
+ // Highest value int is done now
+
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ for (int j = 3; j >= 0; j--)
+ {
+ barr[barrI++] = (byte)((int)((uint)m_ints[iarrJ] >> (8 * j)));
+ }
+ }
+ return new BigInteger(1, barr);
+ }
+
+ public void ShiftLeft()
+ {
+ int usedLen = GetUsedLength();
+ if (usedLen == 0)
+ {
+ return;
+ }
+ if (m_ints[usedLen - 1] < 0)
+ {
+ // highest bit of highest used byte is set, so shifting left will
+ // make the IntArray one byte longer
+ usedLen++;
+ if (usedLen > m_ints.Length)
+ {
+ // make the m_ints one byte longer, because we need one more
+ // byte which is not available in m_ints
+ m_ints = resizedInts(m_ints.Length + 1);
+ }
+ }
+
+ bool carry = false;
+ for (int i = 0; i < usedLen; i++)
+ {
+ // nextCarry is true if highest bit is set
+ bool nextCarry = m_ints[i] < 0;
+ m_ints[i] <<= 1;
+ if (carry)
+ {
+ // set lowest bit
+ m_ints[i] |= 1;
+ }
+ carry = nextCarry;
+ }
+ }
+
+ public IntArray ShiftLeft(int n)
+ {
+ int usedLen = GetUsedLength();
+ if (usedLen == 0)
+ {
+ return this;
+ }
+
+ if (n == 0)
+ {
+ return this;
+ }
+
+ if (n > 31)
+ {
+ throw new ArgumentException("shiftLeft() for max 31 bits "
+ + ", " + n + "bit shift is not possible", "n");
+ }
+
+ int[] newInts = new int[usedLen + 1];
+
+ int nm32 = 32 - n;
+ newInts[0] = m_ints[0] << n;
+ for (int i = 1; i < usedLen; i++)
+ {
+ newInts[i] = (m_ints[i] << n) | (int)((uint)m_ints[i - 1] >> nm32);
+ }
+ newInts[usedLen] = (int)((uint)m_ints[usedLen - 1] >> nm32);
+
+ return new IntArray(newInts);
+ }
+
+ public void AddShifted(IntArray other, int shift)
+ {
+ int usedLenOther = other.GetUsedLength();
+ int newMinUsedLen = usedLenOther + shift;
+ if (newMinUsedLen > m_ints.Length)
+ {
+ m_ints = resizedInts(newMinUsedLen);
+ //Console.WriteLine("Resize required");
+ }
+
+ for (int i = 0; i < usedLenOther; i++)
+ {
+ m_ints[i + shift] ^= other.m_ints[i];
+ }
+ }
+
+ public int Length
+ {
+ get { return m_ints.Length; }
+ }
+
+ public bool TestBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int tester = 1 << theBit;
+ return ((m_ints[theInt] & tester) != 0);
+ }
+
+ public void FlipBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int flipper = 1 << theBit;
+ m_ints[theInt] ^= flipper;
+ }
+
+ public void SetBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int setter = 1 << theBit;
+ m_ints[theInt] |= setter;
+ }
+
+ public IntArray Multiply(IntArray other, int m)
+ {
+ // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ int t = (m + 31) >> 5;
+ if (m_ints.Length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray b = new IntArray(other.resizedInts(other.Length + 1));
+ IntArray c = new IntArray((m + m + 31) >> 5);
+ // IntArray c = new IntArray(t + t);
+ int testBit = 1;
+ for (int k = 0; k < 32; k++)
+ {
+ for (int j = 0; j < t; j++)
+ {
+ if ((m_ints[j] & testBit) != 0)
+ {
+ // The kth bit of m_ints[j] is set
+ c.AddShifted(b, j);
+ }
+ }
+ testBit <<= 1;
+ b.ShiftLeft();
+ }
+ return c;
+ }
+
+ // public IntArray multiplyLeftToRight(IntArray other, int m) {
+ // // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ // int t = (m + 31) / 32;
+ // if (m_ints.Length < t) {
+ // m_ints = resizedInts(t);
+ // }
+ //
+ // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+ // IntArray c = new IntArray((m + m + 31) / 32);
+ // // IntArray c = new IntArray(t + t);
+ // int testBit = 1 << 31;
+ // for (int k = 31; k >= 0; k--) {
+ // for (int j = 0; j < t; j++) {
+ // if ((m_ints[j] & testBit) != 0) {
+ // // The kth bit of m_ints[j] is set
+ // c.addShifted(b, j);
+ // }
+ // }
+ // testBit >>>= 1;
+ // if (k > 0) {
+ // c.shiftLeft();
+ // }
+ // }
+ // return c;
+ // }
+
+ // TODO note, redPol.Length must be 3 for TPB and 5 for PPB
+ public void Reduce(int m, int[] redPol)
+ {
+ for (int i = m + m - 2; i >= m; i--)
+ {
+ if (TestBit(i))
+ {
+ int bit = i - m;
+ FlipBit(bit);
+ FlipBit(i);
+ int l = redPol.Length;
+ while (--l >= 0)
+ {
+ FlipBit(redPol[l] + bit);
+ }
+ }
+ }
+ m_ints = resizedInts((m + 31) >> 5);
+ }
+
+ public IntArray Square(int m)
+ {
+ // TODO make the table static readonly
+ int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
+ 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
+
+ int t = (m + 31) >> 5;
+ if (m_ints.Length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray c = new IntArray(t + t);
+
+ // TODO twice the same code, put in separate private method
+ for (int i = 0; i < t; i++)
+ {
+ int v0 = 0;
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = (int)((uint) v0 >> 8);
+ int u = (int)((uint)m_ints[i] >> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i] = v0;
+
+ v0 = 0;
+ int upper = (int)((uint) m_ints[i] >> 16);
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = (int)((uint) v0 >> 8);
+ int u = (int)((uint)upper >> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i + 1] = v0;
+ }
+ return c;
+ }
+
+ public override bool Equals(object o)
+ {
+ if (!(o is IntArray))
+ {
+ return false;
+ }
+ IntArray other = (IntArray) o;
+ int usedLen = GetUsedLength();
+ if (other.GetUsedLength() != usedLen)
+ {
+ return false;
+ }
+ for (int i = 0; i < usedLen; i++)
+ {
+ if (m_ints[i] != other.m_ints[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int i = GetUsedLength();
+ int hc = i;
+ while (--i >= 0)
+ {
+ hc *= 17;
+ hc ^= m_ints[i];
+ }
+ return hc;
+ }
+
+ public object Clone()
+ {
+ return new IntArray((int[]) m_ints.Clone());
+ }
+
+ public override string ToString()
+ {
+ int usedLen = GetUsedLength();
+ if (usedLen == 0)
+ {
+ return "0";
+ }
+
+ StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[usedLen - 1], 2));
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ string hexString = Convert.ToString(m_ints[iarrJ], 2);
+
+ // Add leading zeroes, except for highest significant int
+ for (int i = hexString.Length; i < 8; i++)
+ {
+ hexString = "0" + hexString;
+ }
+ sb.Append(hexString);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/abc/SimpleBigDecimal.cs b/src/core/srcbc/math/ec/abc/SimpleBigDecimal.cs
new file mode 100644
index 0000000..47c165e
--- /dev/null
+++ b/src/core/srcbc/math/ec/abc/SimpleBigDecimal.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class representing a simple version of a big decimal. A
+ * SimpleBigDecimal
is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the scale
of the SimpleBigDecimal
.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All SimpleBigDecimal
s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two SimpleBigDecimal
s returns a
+ * SimpleBigDecimal
with double scale.
+ */
+ internal class SimpleBigDecimal
+ // : Number
+ {
+ // private static final long serialVersionUID = 1L;
+
+ private readonly BigInteger bigInt;
+ private readonly int scale;
+
+ /**
+ * Returns a SimpleBigDecimal
representing the same numerical
+ * value as value
.
+ * @param value The value of the SimpleBigDecimal
to be
+ * created.
+ * @param scale The scale of the SimpleBigDecimal
to be
+ * created.
+ * @return The such created SimpleBigDecimal
.
+ */
+ public static SimpleBigDecimal GetInstance(BigInteger val, int scale)
+ {
+ return new SimpleBigDecimal(val.ShiftLeft(scale), scale);
+ }
+
+ /**
+ * Constructor for SimpleBigDecimal
. The value of the
+ * constructed SimpleBigDecimal
Equals bigInt /
+ * 2scale
.
+ * @param bigInt The bigInt
value parameter.
+ * @param scale The scale of the constructed SimpleBigDecimal
.
+ */
+ public SimpleBigDecimal(BigInteger bigInt, int scale)
+ {
+ if (scale < 0)
+ throw new ArgumentException("scale may not be negative");
+
+ this.bigInt = bigInt;
+ this.scale = scale;
+ }
+
+ private SimpleBigDecimal(SimpleBigDecimal limBigDec)
+ {
+ bigInt = limBigDec.bigInt;
+ scale = limBigDec.scale;
+ }
+
+ private void CheckScale(SimpleBigDecimal b)
+ {
+ if (scale != b.scale)
+ throw new ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations");
+ }
+
+ public SimpleBigDecimal AdjustScale(int newScale)
+ {
+ if (newScale < 0)
+ throw new ArgumentException("scale may not be negative");
+
+ if (newScale == scale)
+ return this;
+
+ return new SimpleBigDecimal(bigInt.ShiftLeft(newScale - scale), newScale);
+ }
+
+ public SimpleBigDecimal Add(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ return new SimpleBigDecimal(bigInt.Add(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal Add(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Add(b.ShiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal Negate()
+ {
+ return new SimpleBigDecimal(bigInt.Negate(), scale);
+ }
+
+ public SimpleBigDecimal Subtract(SimpleBigDecimal b)
+ {
+ return Add(b.Negate());
+ }
+
+ public SimpleBigDecimal Subtract(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Subtract(b.ShiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal Multiply(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ return new SimpleBigDecimal(bigInt.Multiply(b.bigInt), scale + scale);
+ }
+
+ public SimpleBigDecimal Multiply(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Multiply(b), scale);
+ }
+
+ public SimpleBigDecimal Divide(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ BigInteger dividend = bigInt.ShiftLeft(scale);
+ return new SimpleBigDecimal(dividend.Divide(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal Divide(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Divide(b), scale);
+ }
+
+ public SimpleBigDecimal ShiftLeft(int n)
+ {
+ return new SimpleBigDecimal(bigInt.ShiftLeft(n), scale);
+ }
+
+ public int CompareTo(SimpleBigDecimal val)
+ {
+ CheckScale(val);
+ return bigInt.CompareTo(val.bigInt);
+ }
+
+ public int CompareTo(BigInteger val)
+ {
+ return bigInt.CompareTo(val.ShiftLeft(scale));
+ }
+
+ public BigInteger Floor()
+ {
+ return bigInt.ShiftRight(scale);
+ }
+
+ public BigInteger Round()
+ {
+ SimpleBigDecimal oneHalf = new SimpleBigDecimal(BigInteger.One, 1);
+ return Add(oneHalf.AdjustScale(scale)).Floor();
+ }
+
+ public int IntValue
+ {
+ get { return Floor().IntValue; }
+ }
+
+ public long LongValue
+ {
+ get { return Floor().LongValue; }
+ }
+
+// public double doubleValue()
+// {
+// return new Double(ToString()).doubleValue();
+// }
+//
+// public float floatValue()
+// {
+// return new Float(ToString()).floatValue();
+// }
+
+ public int Scale
+ {
+ get { return scale; }
+ }
+
+ public override string ToString()
+ {
+ if (scale == 0)
+ return bigInt.ToString();
+
+ BigInteger floorBigInt = Floor();
+
+ BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale));
+ if (bigInt.SignValue < 0)
+ {
+ fract = BigInteger.One.ShiftLeft(scale).Subtract(fract);
+ }
+
+ if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero))))
+ {
+ floorBigInt = floorBigInt.Add(BigInteger.One);
+ }
+ string leftOfPoint = floorBigInt.ToString();
+
+ char[] fractCharArr = new char[scale];
+ string fractStr = fract.ToString(2);
+ int fractLen = fractStr.Length;
+ int zeroes = scale - fractLen;
+ for (int i = 0; i < zeroes; i++)
+ {
+ fractCharArr[i] = '0';
+ }
+ for (int j = 0; j < fractLen; j++)
+ {
+ fractCharArr[zeroes + j] = fractStr[j];
+ }
+ string rightOfPoint = new string(fractCharArr);
+
+ StringBuilder sb = new StringBuilder(leftOfPoint);
+ sb.Append(".");
+ sb.Append(rightOfPoint);
+
+ return sb.ToString();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (this == obj)
+ return true;
+
+ SimpleBigDecimal other = obj as SimpleBigDecimal;
+
+ if (other == null)
+ return false;
+
+ return bigInt.Equals(other.bigInt)
+ && scale == other.scale;
+ }
+
+ public override int GetHashCode()
+ {
+ return bigInt.GetHashCode() ^ scale;
+ }
+
+ }
+}
diff --git a/src/core/srcbc/math/ec/abc/Tnaf.cs b/src/core/srcbc/math/ec/abc/Tnaf.cs
new file mode 100644
index 0000000..b73bcd1
--- /dev/null
+++ b/src/core/srcbc/math/ec/abc/Tnaf.cs
@@ -0,0 +1,834 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class holding methods for point multiplication based on the window
+ * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+ internal class Tnaf
+ {
+ private static readonly BigInteger MinusOne = BigInteger.One.Negate();
+ private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
+ private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
+ private static readonly BigInteger Four = BigInteger.ValueOf(4);
+
+ /**
+ * The window width of WTNAF. The standard value of 4 is slightly less
+ * than optimal for running time, but keeps space requirements for
+ * precomputation low. For typical curves, a value of 5 or 6 results in
+ * a better running time. When changing this value, the
+ * αu
's must be computed differently, see
+ * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+ * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+ * p. 121-122
+ */
+ public const sbyte Width = 4;
+
+ /**
+ * 24
+ */
+ public const sbyte Pow2Width = 16;
+
+ /**
+ * The αu
's for a=0
as an array
+ * of ZTauElement
s.
+ */
+ public static readonly ZTauElement[] Alpha0 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, MinusOne), null,
+ new ZTauElement(MinusOne, MinusOne), null,
+ new ZTauElement(BigInteger.One, MinusOne), null
+ };
+
+ /**
+ * The αu
's for a=0
as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha0Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of ZTauElement
s.
+ */
+ public static readonly ZTauElement[] Alpha1 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, BigInteger.One), null,
+ new ZTauElement(MinusOne, BigInteger.One), null,
+ new ZTauElement(BigInteger.One, BigInteger.One), null
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha1Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
+ };
+
+ /**
+ * Computes the norm of an element λ
of
+ * Z[τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return The norm of λ
.
+ */
+ public static BigInteger Norm(sbyte mu, ZTauElement lambda)
+ {
+ BigInteger norm;
+
+ // s1 = u^2
+ BigInteger s1 = lambda.u.Multiply(lambda.u);
+
+ // s2 = u * v
+ BigInteger s2 = lambda.u.Multiply(lambda.v);
+
+ // s3 = 2 * v^2
+ BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Computes the norm of an element λ
of
+ * R[τ]
, where λ = u + vτ
+ * and u
and u
are real numbers (elements of
+ * R
).
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param u The real part of the element λ
of
+ * R[τ]
.
+ * @param v The τ
-adic part of the element
+ * λ
of R[τ]
.
+ * @return The norm of λ
.
+ */
+ public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v)
+ {
+ SimpleBigDecimal norm;
+
+ // s1 = u^2
+ SimpleBigDecimal s1 = u.Multiply(u);
+
+ // s2 = u * v
+ SimpleBigDecimal s2 = u.Multiply(v);
+
+ // s3 = 2 * v^2
+ SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Rounds an element λ
of R[τ]
+ * to an element of Z[τ]
, such that their difference
+ * has minimal norm. λ
is given as
+ * λ = λ0 + λ1τ
.
+ * @param lambda0 The component λ0
.
+ * @param lambda1 The component λ1
.
+ * @param mu The parameter μ
of the elliptic curve. Must
+ * equal 1 or -1.
+ * @return The rounded element of Z[τ]
.
+ * @throws ArgumentException if lambda0
and
+ * lambda1
do not have same scale.
+ */
+ public static ZTauElement Round(SimpleBigDecimal lambda0,
+ SimpleBigDecimal lambda1, sbyte mu)
+ {
+ int scale = lambda0.Scale;
+ if (lambda1.Scale != scale)
+ throw new ArgumentException("lambda0 and lambda1 do not have same scale");
+
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger f0 = lambda0.Round();
+ BigInteger f1 = lambda1.Round();
+
+ SimpleBigDecimal eta0 = lambda0.Subtract(f0);
+ SimpleBigDecimal eta1 = lambda1.Subtract(f1);
+
+ // eta = 2*eta0 + mu*eta1
+ SimpleBigDecimal eta = eta0.Add(eta0);
+ if (mu == 1)
+ {
+ eta = eta.Add(eta1);
+ }
+ else
+ {
+ // mu == -1
+ eta = eta.Subtract(eta1);
+ }
+
+ // check1 = eta0 - 3*mu*eta1
+ // check2 = eta0 + 4*mu*eta1
+ SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1);
+ SimpleBigDecimal fourEta1 = threeEta1.Add(eta1);
+ SimpleBigDecimal check1;
+ SimpleBigDecimal check2;
+ if (mu == 1)
+ {
+ check1 = eta0.Subtract(threeEta1);
+ check2 = eta0.Add(fourEta1);
+ }
+ else
+ {
+ // mu == -1
+ check1 = eta0.Add(threeEta1);
+ check2 = eta0.Subtract(fourEta1);
+ }
+
+ sbyte h0 = 0;
+ sbyte h1 = 0;
+
+ // if eta >= 1
+ if (eta.CompareTo(BigInteger.One) >= 0)
+ {
+ if (check1.CompareTo(MinusOne) < 0)
+ {
+ h1 = mu;
+ }
+ else
+ {
+ h0 = 1;
+ }
+ }
+ else
+ {
+ // eta < 1
+ if (check2.CompareTo(BigInteger.Two) >= 0)
+ {
+ h1 = mu;
+ }
+ }
+
+ // if eta < -1
+ if (eta.CompareTo(MinusOne) < 0)
+ {
+ if (check1.CompareTo(BigInteger.One) >= 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ else
+ {
+ h0 = -1;
+ }
+ }
+ else
+ {
+ // eta >= -1
+ if (check2.CompareTo(MinusTwo) < 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ }
+
+ BigInteger q0 = f0.Add(BigInteger.ValueOf(h0));
+ BigInteger q1 = f1.Add(BigInteger.ValueOf(h1));
+ return new ZTauElement(q0, q1);
+ }
+
+ /**
+ * Approximate division by n
. For an integer
+ * k
, the value λ = s k / n
is
+ * computed to c
bits of accuracy.
+ * @param k The parameter k
.
+ * @param s The curve parameter s0
or
+ * s1
.
+ * @param vm The Lucas Sequence element Vm
.
+ * @param a The parameter a
of the elliptic curve.
+ * @param m The bit length of the finite field
+ * Fm
.
+ * @param c The number of bits of accuracy, i.e. the scale of the returned
+ * SimpleBigDecimal
.
+ * @return The value λ = s k / n
computed to
+ * c
bits of accuracy.
+ */
+ public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
+ BigInteger s, BigInteger vm, sbyte a, int m, int c)
+ {
+ int _k = (m + 5)/2 + c;
+ BigInteger ns = k.ShiftRight(m - _k - 2 + a);
+
+ BigInteger gs = s.Multiply(ns);
+
+ BigInteger hs = gs.ShiftRight(m);
+
+ BigInteger js = vm.Multiply(hs);
+
+ BigInteger gsPlusJs = gs.Add(js);
+ BigInteger ls = gsPlusJs.ShiftRight(_k-c);
+ if (gsPlusJs.TestBit(_k-c-1))
+ {
+ // round up
+ ls = ls.Add(BigInteger.One);
+ }
+
+ return new SimpleBigDecimal(ls, c);
+ }
+
+ /**
+ * Computes the τ
-adic NAF (non-adjacent form) of an
+ * element λ
of Z[τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return The τ
-adic NAF of λ
.
+ */
+ public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+ int i = 0;
+
+ // The actual length of the TNAF
+ int length = 0;
+
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+
+ while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
+ {
+ // If r0 is odd
+ if (r0.TestBit(0))
+ {
+ u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
+
+ // r0 = r0 - u[i]
+ if (u[i] == 1)
+ {
+ r0 = r0.ClearBit(0);
+ }
+ else
+ {
+ // u[i] == -1
+ r0 = r0.Add(BigInteger.One);
+ }
+ length = i;
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+ BigInteger s = r0.ShiftRight(1);
+ if (mu == 1)
+ {
+ r0 = r1.Add(s);
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(s);
+ }
+
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+
+ length++;
+
+ // Reduce the TNAF array to its actual length
+ sbyte[] tnaf = new sbyte[length];
+ Array.Copy(u, 0, tnaf, 0, length);
+ return tnaf;
+ }
+
+ /**
+ * Applies the operation τ()
to an
+ * F2mPoint
.
+ * @param p The F2mPoint to which τ()
is applied.
+ * @return τ(p)
+ */
+ public static F2mPoint Tau(F2mPoint p)
+ {
+ if (p.IsInfinity)
+ return p;
+
+ ECFieldElement x = p.X;
+ ECFieldElement y = p.Y;
+
+ return new F2mPoint(p.Curve, x.Square(), y.Square(), p.IsCompressed);
+ }
+
+ /**
+ * Returns the parameter μ
of the elliptic curve.
+ * @param curve The elliptic curve from which to obtain μ
.
+ * The curve must be a Koblitz curve, i.e. a
Equals
+ * 0
or 1
and b
Equals
+ * 1
.
+ * @return μ
of the elliptic curve.
+ * @throws ArgumentException if the given ECCurve is not a Koblitz
+ * curve.
+ */
+ public static sbyte GetMu(F2mCurve curve)
+ {
+ BigInteger a = curve.A.ToBigInteger();
+
+ sbyte mu;
+ if (a.SignValue == 0)
+ {
+ mu = -1;
+ }
+ else if (a.Equals(BigInteger.One))
+ {
+ mu = 1;
+ }
+ else
+ {
+ throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
+ }
+ return mu;
+ }
+
+ /**
+ * Calculates the Lucas Sequence elements Uk-1
and
+ * Uk
or Vk-1
and
+ * Vk
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param k The index of the second element of the Lucas Sequence to be
+ * returned.
+ * @param doV If set to true, computes Vk-1
and
+ * Vk
, otherwise Uk-1
and
+ * Uk
.
+ * @return An array with 2 elements, containing Uk-1
+ * and Uk
or Vk-1
+ * and Vk
.
+ */
+ public static BigInteger[] GetLucas(sbyte mu, int k, bool doV)
+ {
+ if (!(mu == 1 || mu == -1))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger u0;
+ BigInteger u1;
+ BigInteger u2;
+
+ if (doV)
+ {
+ u0 = BigInteger.Two;
+ u1 = BigInteger.ValueOf(mu);
+ }
+ else
+ {
+ u0 = BigInteger.Zero;
+ u1 = BigInteger.One;
+ }
+
+ for (int i = 1; i < k; i++)
+ {
+ // u2 = mu*u1 - 2*u0;
+ BigInteger s = null;
+ if (mu == 1)
+ {
+ s = u1;
+ }
+ else
+ {
+ // mu == -1
+ s = u1.Negate();
+ }
+
+ u2 = s.Subtract(u0.ShiftLeft(1));
+ u0 = u1;
+ u1 = u2;
+ // System.out.println(i + ": " + u2);
+ // System.out.println();
+ }
+
+ BigInteger[] retVal = {u0, u1};
+ return retVal;
+ }
+
+ /**
+ * Computes the auxiliary value tw
. If the width is
+ * 4, then for mu = 1
, tw = 6
and for
+ * mu = -1
, tw = 10
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param w The window width of the WTNAF.
+ * @return the auxiliary value tw
+ */
+ public static BigInteger GetTw(sbyte mu, int w)
+ {
+ if (w == 4)
+ {
+ if (mu == 1)
+ {
+ return BigInteger.ValueOf(6);
+ }
+ else
+ {
+ // mu == -1
+ return BigInteger.ValueOf(10);
+ }
+ }
+ else
+ {
+ // For w <> 4, the values must be computed
+ BigInteger[] us = GetLucas(mu, w, false);
+ BigInteger twoToW = BigInteger.Zero.SetBit(w);
+ BigInteger u1invert = us[1].ModInverse(twoToW);
+ BigInteger tw;
+ tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW);
+ //System.out.println("mu = " + mu);
+ //System.out.println("tw = " + tw);
+ return tw;
+ }
+ }
+
+ /**
+ * Computes the auxiliary values s0
and
+ * s1
used for partial modular reduction.
+ * @param curve The elliptic curve for which to compute
+ * s0
and s1
.
+ * @throws ArgumentException if curve
is not a
+ * Koblitz curve (Anomalous Binary Curve, ABC).
+ */
+ public static BigInteger[] GetSi(F2mCurve curve)
+ {
+ if (!curve.IsKoblitz)
+ throw new ArgumentException("si is defined for Koblitz curves only");
+
+ int m = curve.M;
+ int a = curve.A.ToBigInteger().IntValue;
+ sbyte mu = curve.GetMu();
+ int h = curve.H.IntValue;
+ int index = m + 3 - a;
+ BigInteger[] ui = GetLucas(mu, index, false);
+
+ BigInteger dividend0;
+ BigInteger dividend1;
+ if (mu == 1)
+ {
+ dividend0 = BigInteger.One.Subtract(ui[1]);
+ dividend1 = BigInteger.One.Subtract(ui[0]);
+ }
+ else if (mu == -1)
+ {
+ dividend0 = BigInteger.One.Add(ui[1]);
+ dividend1 = BigInteger.One.Add(ui[0]);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger[] si = new BigInteger[2];
+
+ if (h == 2)
+ {
+ si[0] = dividend0.ShiftRight(1);
+ si[1] = dividend1.ShiftRight(1).Negate();
+ }
+ else if (h == 4)
+ {
+ si[0] = dividend0.ShiftRight(2);
+ si[1] = dividend1.ShiftRight(2).Negate();
+ }
+ else
+ {
+ throw new ArgumentException("h (Cofactor) must be 2 or 4");
+ }
+
+ return si;
+ }
+
+ /**
+ * Partial modular reduction modulo
+ * (τm - 1)/(τ - 1)
.
+ * @param k The integer to be reduced.
+ * @param m The bitlength of the underlying finite field.
+ * @param a The parameter a
of the elliptic curve.
+ * @param s The auxiliary values s0
and
+ * s1
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param c The precision (number of bits of accuracy) of the partial
+ * modular reduction.
+ * @return ρ := k partmod (τm - 1)/(τ - 1)
+ */
+ public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
+ BigInteger[] s, sbyte mu, sbyte c)
+ {
+ // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+ BigInteger d0;
+ if (mu == 1)
+ {
+ d0 = s[0].Add(s[1]);
+ }
+ else
+ {
+ d0 = s[0].Subtract(s[1]);
+ }
+
+ BigInteger[] v = GetLucas(mu, m, true);
+ BigInteger vm = v[1];
+
+ SimpleBigDecimal lambda0 = ApproximateDivisionByN(
+ k, s[0], vm, a, m, c);
+
+ SimpleBigDecimal lambda1 = ApproximateDivisionByN(
+ k, s[1], vm, a, m, c);
+
+ ZTauElement q = Round(lambda0, lambda1, mu);
+
+ // r0 = n - d0*q0 - 2*s1*q1
+ BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract(
+ BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v));
+
+ // r1 = s1*q0 - s0*q1
+ BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v));
+
+ return new ZTauElement(r0, r1);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by a BigInteger
using the reduced τ
-adic
+ * NAF (RTNAF) method.
+ * @param p The F2mPoint to Multiply.
+ * @param k The BigInteger
by which to Multiply p
.
+ * @return k * p
+ */
+ public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
+ {
+ F2mCurve curve = (F2mCurve) p.Curve;
+ int m = curve.M;
+ sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+ sbyte mu = curve.GetMu();
+ BigInteger[] s = curve.GetSi();
+ ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
+
+ return MultiplyTnaf(p, rho);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element λ
of Z[τ]
+ * using the τ
-adic NAF (TNAF) method.
+ * @param p The F2mPoint to Multiply.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return λ * p
+ */
+ public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
+ {
+ F2mCurve curve = (F2mCurve)p.Curve;
+ sbyte mu = curve.GetMu();
+ sbyte[] u = TauAdicNaf(mu, lambda);
+
+ F2mPoint q = MultiplyFromTnaf(p, u);
+
+ return q;
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element λ
of Z[τ]
+ * using the τ
-adic NAF (TNAF) method, given the TNAF
+ * of λ
.
+ * @param p The F2mPoint to Multiply.
+ * @param u The the TNAF of λ
..
+ * @return λ * p
+ */
+ public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
+ {
+ F2mCurve curve = (F2mCurve)p.Curve;
+ F2mPoint q = (F2mPoint) curve.Infinity;
+ for (int i = u.Length - 1; i >= 0; i--)
+ {
+ q = Tau(q);
+ if (u[i] == 1)
+ {
+ q = (F2mPoint)q.AddSimple(p);
+ }
+ else if (u[i] == -1)
+ {
+ q = (F2mPoint)q.SubtractSimple(p);
+ }
+ }
+ return q;
+ }
+
+ /**
+ * Computes the [τ]
-adic window NAF of an element
+ * λ
of Z[τ]
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @param width The window width of the resulting WNAF.
+ * @param pow2w 2width.
+ * @param tw The auxiliary value tw
.
+ * @param alpha The αu
's for the window width.
+ * @return The [τ]
-adic window NAF of
+ * λ
.
+ */
+ public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
+ sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+
+ // 2^(width - 1)
+ BigInteger pow2wMin1 = pow2w.ShiftRight(1);
+
+ // Split lambda into two BigIntegers to simplify calculations
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+ int i = 0;
+
+ // while lambda <> (0, 0)
+ while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero))))
+ {
+ // if r0 is odd
+ if (r0.TestBit(0))
+ {
+ // uUnMod = r0 + r1*tw Mod 2^width
+ BigInteger uUnMod
+ = r0.Add(r1.Multiply(tw)).Mod(pow2w);
+
+ sbyte uLocal;
+ // if uUnMod >= 2^(width - 1)
+ if (uUnMod.CompareTo(pow2wMin1) >= 0)
+ {
+ uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
+ }
+ else
+ {
+ uLocal = (sbyte) uUnMod.IntValue;
+ }
+ // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+ u[i] = uLocal;
+ bool s = true;
+ if (uLocal < 0)
+ {
+ s = false;
+ uLocal = (sbyte)-uLocal;
+ }
+ // uLocal is now >= 0
+
+ if (s)
+ {
+ r0 = r0.Subtract(alpha[uLocal].u);
+ r1 = r1.Subtract(alpha[uLocal].v);
+ }
+ else
+ {
+ r0 = r0.Add(alpha[uLocal].u);
+ r1 = r1.Add(alpha[uLocal].v);
+ }
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+
+ if (mu == 1)
+ {
+ r0 = r1.Add(r0.ShiftRight(1));
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(r0.ShiftRight(1));
+ }
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+ return u;
+ }
+
+ /**
+ * Does the precomputation for WTNAF multiplication.
+ * @param p The ECPoint
for which to do the precomputation.
+ * @param a The parameter a
of the elliptic curve.
+ * @return The precomputation array for p
.
+ */
+ public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
+ {
+ F2mPoint[] pu;
+ pu = new F2mPoint[16];
+ pu[1] = p;
+ sbyte[][] alphaTnaf;
+ if (a == 0)
+ {
+ alphaTnaf = Tnaf.Alpha0Tnaf;
+ }
+ else
+ {
+ // a == 1
+ alphaTnaf = Tnaf.Alpha1Tnaf;
+ }
+
+ int precompLen = alphaTnaf.Length;
+ for (int i = 3; i < precompLen; i = i + 2)
+ {
+ pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
+ }
+
+ return pu;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/abc/ZTauElement.cs b/src/core/srcbc/math/ec/abc/ZTauElement.cs
new file mode 100644
index 0000000..3ed67ee
--- /dev/null
+++ b/src/core/srcbc/math/ec/abc/ZTauElement.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class representing an element of Z[τ]
. Let
+ * λ
be an element of Z[τ]
. Then
+ * λ
is given as λ = u + vτ
. The
+ * components u
and v
may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+ internal class ZTauElement
+ {
+ /**
+ * The "real" part of λ
.
+ */
+ public readonly BigInteger u;
+
+ /**
+ * The "τ
-adic" part of λ
.
+ */
+ public readonly BigInteger v;
+
+ /**
+ * Constructor for an element λ
of
+ * Z[τ]
.
+ * @param u The "real" part of λ
.
+ * @param v The "τ
-adic" part of
+ * λ
.
+ */
+ public ZTauElement(BigInteger u, BigInteger v)
+ {
+ this.u = u;
+ this.v = v;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/ECMultiplier.cs b/src/core/srcbc/math/ec/multiplier/ECMultiplier.cs
new file mode 100644
index 0000000..6affc37
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/ECMultiplier.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for ECPoint
s.
+ */
+ internal interface ECMultiplier
+ {
+ /**
+ * Multiplies the ECPoint p
by k
, i.e.
+ * p
is added k
times to itself.
+ * @param p The ECPoint
to be multiplied.
+ * @param k The factor by which p
i multiplied.
+ * @return p
multiplied by k
.
+ */
+ ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/FpNafMultiplier.cs b/src/core/srcbc/math/ec/multiplier/FpNafMultiplier.cs
new file mode 100644
index 0000000..30f8242
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/FpNafMultiplier.cs
@@ -0,0 +1,39 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+ */
+ internal class FpNafMultiplier
+ : ECMultiplier
+ {
+ /**
+ * D.3.2 pg 101
+ * @see org.bouncycastle.math.ec.multiplier.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+ */
+ public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ // TODO Probably should try to add this
+ // BigInteger e = k.Mod(n); // n == order of p
+ BigInteger e = k;
+ BigInteger h = e.Multiply(BigInteger.Three);
+
+ ECPoint neg = p.Negate();
+ ECPoint R = p;
+
+ for (int i = h.BitLength - 2; i > 0; --i)
+ {
+ R = R.Twice();
+
+ bool hBit = h.TestBit(i);
+ bool eBit = e.TestBit(i);
+
+ if (hBit != eBit)
+ {
+ R = R.Add(hBit ? p : neg);
+ }
+ }
+
+ return R;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/PreCompInfo.cs b/src/core/srcbc/math/ec/multiplier/PreCompInfo.cs
new file mode 100644
index 0000000..77b90a2
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/PreCompInfo.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) for
+ * WNafMultiplier
.
+ */
+ internal interface PreCompInfo
+ {
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/ReferenceMultiplier.cs b/src/core/srcbc/math/ec/multiplier/ReferenceMultiplier.cs
new file mode 100644
index 0000000..16c8778
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/ReferenceMultiplier.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ internal class ReferenceMultiplier
+ : ECMultiplier
+ {
+ /**
+ * Simple shift-and-add multiplication. Serves as reference implementation
+ * to verify (possibly faster) implementations in
+ * {@link org.bouncycastle.math.ec.ECPoint ECPoint}.
+ *
+ * @param p The point to multiply.
+ * @param k The factor by which to multiply.
+ * @return The result of the point multiplication k * p
.
+ */
+ public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ ECPoint q = p.Curve.Infinity;
+ int t = k.BitLength;
+ for (int i = 0; i < t; i++)
+ {
+ if (k.TestBit(i))
+ {
+ q = q.Add(p);
+ }
+ p = p.Twice();
+ }
+ return q;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/WNafMultiplier.cs b/src/core/srcbc/math/ec/multiplier/WNafMultiplier.cs
new file mode 100644
index 0000000..7a08169
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/WNafMultiplier.cs
@@ -0,0 +1,241 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+ internal class WNafMultiplier
+ : ECMultiplier
+ {
+ /**
+ * Computes the Window NAF (non-adjacent Form) of an integer.
+ * @param width The width w
of the Window NAF. The width is
+ * defined as the minimal number w
, such that for any
+ * w
consecutive digits in the resulting representation, at
+ * most one is non-zero.
+ * @param k The integer of which the Window NAF is computed.
+ * @return The Window NAF of the given width, such that the following holds:
+ * k = −i=0l-1 ki2i
+ *
, where the ki
denote the elements of the
+ * returned sbyte[]
.
+ */
+ public sbyte[] WindowNaf(sbyte width, BigInteger k)
+ {
+ // The window NAF is at most 1 element longer than the binary
+ // representation of the integer k. sbyte can be used instead of short or
+ // int unless the window width is larger than 8. For larger width use
+ // short or int. However, a width of more than 8 is not efficient for
+ // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
+ // 1000 Bits are currently not used in practice.
+ sbyte[] wnaf = new sbyte[k.BitLength + 1];
+
+ // 2^width as short and BigInteger
+ short pow2wB = (short)(1 << width);
+ BigInteger pow2wBI = BigInteger.ValueOf(pow2wB);
+
+ int i = 0;
+
+ // The actual length of the WNAF
+ int length = 0;
+
+ // while k >= 1
+ while (k.SignValue > 0)
+ {
+ // if k is odd
+ if (k.TestBit(0))
+ {
+ // k Mod 2^width
+ BigInteger remainder = k.Mod(pow2wBI);
+
+ // if remainder > 2^(width - 1) - 1
+ if (remainder.TestBit(width - 1))
+ {
+ wnaf[i] = (sbyte)(remainder.IntValue - pow2wB);
+ }
+ else
+ {
+ wnaf[i] = (sbyte)remainder.IntValue;
+ }
+ // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
+
+ k = k.Subtract(BigInteger.ValueOf(wnaf[i]));
+ length = i;
+ }
+ else
+ {
+ wnaf[i] = 0;
+ }
+
+ // k = k/2
+ k = k.ShiftRight(1);
+ i++;
+ }
+
+ length++;
+
+ // Reduce the WNAF array to its actual length
+ sbyte[] wnafShort = new sbyte[length];
+ Array.Copy(wnaf, 0, wnafShort, 0, length);
+ return wnafShort;
+ }
+
+ /**
+ * Multiplies this
by an integer k
using the
+ * Window NAF method.
+ * @param k The integer by which this
is multiplied.
+ * @return A new ECPoint
which equals this
+ * multiplied by k
.
+ */
+ public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ WNafPreCompInfo wnafPreCompInfo;
+
+ if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
+ {
+ wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
+ }
+ else
+ {
+ // Ignore empty PreCompInfo or PreCompInfo of incorrect type
+ wnafPreCompInfo = new WNafPreCompInfo();
+ }
+
+ // floor(log2(k))
+ int m = k.BitLength;
+
+ // width of the Window NAF
+ sbyte width;
+
+ // Required length of precomputation array
+ int reqPreCompLen;
+
+ // Determine optimal width and corresponding length of precomputation
+ // array based on literature values
+ if (m < 13)
+ {
+ width = 2;
+ reqPreCompLen = 1;
+ }
+ else
+ {
+ if (m < 41)
+ {
+ width = 3;
+ reqPreCompLen = 2;
+ }
+ else
+ {
+ if (m < 121)
+ {
+ width = 4;
+ reqPreCompLen = 4;
+ }
+ else
+ {
+ if (m < 337)
+ {
+ width = 5;
+ reqPreCompLen = 8;
+ }
+ else
+ {
+ if (m < 897)
+ {
+ width = 6;
+ reqPreCompLen = 16;
+ }
+ else
+ {
+ if (m < 2305)
+ {
+ width = 7;
+ reqPreCompLen = 32;
+ }
+ else
+ {
+ width = 8;
+ reqPreCompLen = 127;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // The length of the precomputation array
+ int preCompLen = 1;
+
+ ECPoint[] preComp = wnafPreCompInfo.GetPreComp();
+ ECPoint twiceP = wnafPreCompInfo.GetTwiceP();
+
+ // Check if the precomputed ECPoints already exist
+ if (preComp == null)
+ {
+ // Precomputation must be performed from scratch, create an empty
+ // precomputation array of desired length
+ preComp = new ECPoint[]{ p };
+ }
+ else
+ {
+ // Take the already precomputed ECPoints to start with
+ preCompLen = preComp.Length;
+ }
+
+ if (twiceP == null)
+ {
+ // Compute twice(p)
+ twiceP = p.Twice();
+ }
+
+ if (preCompLen < reqPreCompLen)
+ {
+ // Precomputation array must be made bigger, copy existing preComp
+ // array into the larger new preComp array
+ ECPoint[] oldPreComp = preComp;
+ preComp = new ECPoint[reqPreCompLen];
+ Array.Copy(oldPreComp, 0, preComp, 0, preCompLen);
+
+ for (int i = preCompLen; i < reqPreCompLen; i++)
+ {
+ // Compute the new ECPoints for the precomputation array.
+ // The values 1, 3, 5, ..., 2^(width-1)-1 times p are
+ // computed
+ preComp[i] = twiceP.Add(preComp[i - 1]);
+ }
+ }
+
+ // Compute the Window NAF of the desired width
+ sbyte[] wnaf = WindowNaf(width, k);
+ int l = wnaf.Length;
+
+ // Apply the Window NAF to p using the precomputed ECPoint values.
+ ECPoint q = p.Curve.Infinity;
+ for (int i = l - 1; i >= 0; i--)
+ {
+ q = q.Twice();
+
+ if (wnaf[i] != 0)
+ {
+ if (wnaf[i] > 0)
+ {
+ q = q.Add(preComp[(wnaf[i] - 1)/2]);
+ }
+ else
+ {
+ // wnaf[i] < 0
+ q = q.Subtract(preComp[(-wnaf[i] - 1)/2]);
+ }
+ }
+ }
+
+ // Set PreCompInfo in ECPoint, such that it is available for next
+ // multiplication.
+ wnafPreCompInfo.SetPreComp(preComp);
+ wnafPreCompInfo.SetTwiceP(twiceP);
+ p.SetPreCompInfo(wnafPreCompInfo);
+ return q;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/WNafPreCompInfo.cs b/src/core/srcbc/math/ec/multiplier/WNafPreCompInfo.cs
new file mode 100644
index 0000000..f7eed6c
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/WNafPreCompInfo.cs
@@ -0,0 +1,46 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ */
+ internal class WNafPreCompInfo
+ : PreCompInfo
+ {
+ /**
+ * Array holding the precomputed ECPoint
s used for the Window
+ * NAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}
.
+ */
+ private ECPoint[] preComp = null;
+
+ /**
+ * Holds an ECPoint
representing twice(this). Used for the
+ * Window NAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}
.
+ */
+ private ECPoint twiceP = null;
+
+ internal ECPoint[] GetPreComp()
+ {
+ return preComp;
+ }
+
+ internal void SetPreComp(ECPoint[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ internal ECPoint GetTwiceP()
+ {
+ return twiceP;
+ }
+
+ internal void SetTwiceP(ECPoint twiceThis)
+ {
+ this.twiceP = twiceThis;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/WTauNafMultiplier.cs b/src/core/srcbc/math/ec/multiplier/WTauNafMultiplier.cs
new file mode 100644
index 0000000..d005397
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/WTauNafMultiplier.cs
@@ -0,0 +1,120 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Abc;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+ internal class WTauNafMultiplier
+ : ECMultiplier
+ {
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by k
using the reduced τ
-adic NAF (RTNAF)
+ * method.
+ * @param p The F2mPoint to multiply.
+ * @param k The integer by which to multiply k
.
+ * @return p
multiplied by k
.
+ */
+ public ECPoint Multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)
+ {
+ if (!(point is F2mPoint))
+ throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier");
+
+ F2mPoint p = (F2mPoint)point;
+
+ F2mCurve curve = (F2mCurve) p.Curve;
+ int m = curve.M;
+ sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+ sbyte mu = curve.GetMu();
+ BigInteger[] s = curve.GetSi();
+
+ ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
+
+ return MultiplyWTnaf(p, rho, preCompInfo, a, mu);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element λ
of Z[τ]
using
+ * the τ
-adic NAF (TNAF) method.
+ * @param p The F2mPoint to multiply.
+ * @param lambda The element λ
of
+ * Z[τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @return p
multiplied by λ
.
+ */
+ private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda,
+ PreCompInfo preCompInfo, sbyte a, sbyte mu)
+ {
+ ZTauElement[] alpha;
+ if (a == 0)
+ {
+ alpha = Tnaf.Alpha0;
+ }
+ else
+ {
+ // a == 1
+ alpha = Tnaf.Alpha1;
+ }
+
+ BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width);
+
+ sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width,
+ BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha);
+
+ return MultiplyFromWTnaf(p, u, preCompInfo);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element λ
of Z[τ]
+ * using the window τ
-adic NAF (TNAF) method, given the
+ * WTNAF of λ
.
+ * @param p The F2mPoint to multiply.
+ * @param u The the WTNAF of λ
..
+ * @return λ * p
+ */
+ private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u,
+ PreCompInfo preCompInfo)
+ {
+ F2mCurve curve = (F2mCurve)p.Curve;
+ sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+
+ F2mPoint[] pu;
+ if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
+ {
+ pu = Tnaf.GetPreComp(p, a);
+ p.SetPreCompInfo(new WTauNafPreCompInfo(pu));
+ }
+ else
+ {
+ pu = ((WTauNafPreCompInfo)preCompInfo).GetPreComp();
+ }
+
+ // q = infinity
+ F2mPoint q = (F2mPoint) p.Curve.Infinity;
+ for (int i = u.Length - 1; i >= 0; i--)
+ {
+ q = Tnaf.Tau(q);
+ if (u[i] != 0)
+ {
+ if (u[i] > 0)
+ {
+ q = q.AddSimple(pu[u[i]]);
+ }
+ else
+ {
+ // u[i] < 0
+ q = q.SubtractSimple(pu[-u[i]]);
+ }
+ }
+ }
+
+ return q;
+ }
+ }
+}
diff --git a/src/core/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs b/src/core/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs
new file mode 100644
index 0000000..07698f2
--- /dev/null
+++ b/src/core/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -0,0 +1,41 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class holding precomputation data for the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+ internal class WTauNafPreCompInfo
+ : PreCompInfo
+ {
+ /**
+ * Array holding the precomputed F2mPoint
s used for the
+ * WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ private readonly F2mPoint[] preComp;
+
+ /**
+ * Constructor for WTauNafPreCompInfo
+ * @param preComp Array holding the precomputed F2mPoint
s
+ * used for the WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ internal WTauNafPreCompInfo(F2mPoint[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ /**
+ * @return the array holding the precomputed F2mPoint
s
+ * used for the WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ internal F2mPoint[] GetPreComp()
+ {
+ return preComp;
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/BasicOCSPResp.cs b/src/core/srcbc/ocsp/BasicOCSPResp.cs
new file mode 100644
index 0000000..058a5fb
--- /dev/null
+++ b/src/core/srcbc/ocsp/BasicOCSPResp.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ ///
+ ///
+ /// BasicOcspResponse ::= SEQUENCE {
+ /// tbsResponseData ResponseData,
+ /// signatureAlgorithm AlgorithmIdentifier,
+ /// signature BIT STRING,
+ /// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+ /// }
+ ///
+ ///
+ public class BasicOcspResp
+ : X509ExtensionBase
+ {
+ private readonly BasicOcspResponse resp;
+ private readonly ResponseData data;
+// private readonly X509Certificate[] chain;
+
+ public BasicOcspResp(
+ BasicOcspResponse resp)
+ {
+ this.resp = resp;
+ this.data = resp.TbsResponseData;
+ }
+
+ /// The DER encoding of the tbsResponseData field.
+ /// In the event of an encoding error.
+ public byte[] GetTbsResponseData()
+ {
+ try
+ {
+ return data.GetDerEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("problem encoding tbsResponseData", e);
+ }
+ }
+
+ public int Version
+ {
+ get { return data.Version.Value.IntValue + 1; }
+ }
+
+ public RespID ResponderId
+ {
+ get { return new RespID(data.ResponderID); }
+ }
+
+ public DateTime ProducedAt
+ {
+ get { return data.ProducedAt.ToDateTime(); }
+ }
+
+ public SingleResp[] Responses
+ {
+ get
+ {
+ Asn1Sequence s = data.Responses;
+ SingleResp[] rs = new SingleResp[s.Count];
+
+ for (int i = 0; i != rs.Length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+ }
+
+ return rs;
+ }
+ }
+
+ public X509Extensions ResponseExtensions
+ {
+ get { return data.ResponseExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return ResponseExtensions;
+ }
+
+ public string SignatureAlgName
+ {
+ get { return OcspUtilities.GetAlgorithmName(resp.SignatureAlgorithm.ObjectID); }
+ }
+
+ public string SignatureAlgOid
+ {
+ get { return resp.SignatureAlgorithm.ObjectID.Id; }
+ }
+
+ [Obsolete("RespData class is no longer required as all functionality is available on this class")]
+ public RespData GetResponseData()
+ {
+ return new RespData(data);
+ }
+
+ public byte[] GetSignature()
+ {
+ return resp.Signature.GetBytes();
+ }
+
+ private ArrayList GetCertList()
+ {
+ // load the certificates and revocation lists if we have any
+
+ ArrayList certs = new ArrayList();
+ Asn1Sequence s = resp.Certs;
+
+ if (s != null)
+ {
+ foreach (Asn1Encodable ae in s)
+ {
+ try
+ {
+ certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+ }
+ catch (IOException ex)
+ {
+ throw new OcspException("can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OcspException("can't re-encode certificate!", ex);
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] GetCerts()
+ {
+ ArrayList certs = GetCertList();
+
+ return (X509Certificate[]) certs.ToArray(typeof(X509Certificate));
+ }
+
+ /// The certificates, if any, associated with the response.
+ /// In the event of an encoding error.
+ public IX509Store GetCertificates(
+ string type)
+ {
+ try
+ {
+ return X509StoreFactory.Create(
+ "Certificate/" + type,
+ new X509CollectionStoreParameters(this.GetCertList()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't setup the CertStore", e);
+ }
+ }
+
+ ///
+ /// Verify the signature against the tbsResponseData object we contain.
+ ///
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgName);
+ signature.Init(false, publicKey);
+ byte[] bs = data.GetDerEncoded();
+ signature.BlockUpdate(bs, 0, bs.Length);
+
+ return signature.VerifySignature(this.GetSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing sig: " + e, e);
+ }
+ }
+
+ /// The ASN.1 encoded representation of this object.
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ BasicOcspResp other = obj as BasicOcspResp;
+
+ if (other == null)
+ return false;
+
+ return resp.Equals(other.resp);
+ }
+
+ public override int GetHashCode()
+ {
+ return resp.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/BasicOCSPRespGenerator.cs b/src/core/srcbc/ocsp/BasicOCSPRespGenerator.cs
new file mode 100644
index 0000000..afa8970
--- /dev/null
+++ b/src/core/srcbc/ocsp/BasicOCSPRespGenerator.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * Generator for basic OCSP response objects.
+ */
+ public class BasicOcspRespGenerator
+ {
+ private readonly IList list = new ArrayList();
+
+ private X509Extensions responseExtensions;
+ private RespID responderID;
+
+ private class ResponseObject
+ {
+ internal CertificateID certId;
+ internal CertStatus certStatus;
+ internal DerGeneralizedTime thisUpdate;
+ internal DerGeneralizedTime nextUpdate;
+ internal X509Extensions extensions;
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ X509Extensions extensions)
+ : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions)
+ {
+ }
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ DateTime nextUpdate,
+ X509Extensions extensions)
+ : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions)
+ {
+ }
+
+ private ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DerGeneralizedTime thisUpdate,
+ DerGeneralizedTime nextUpdate,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+
+ if (certStatus == null)
+ {
+ this.certStatus = new CertStatus();
+ }
+ else if (certStatus is UnknownStatus)
+ {
+ this.certStatus = new CertStatus(2, DerNull.Instance);
+ }
+ else
+ {
+ RevokedStatus rs = (RevokedStatus) certStatus;
+ CrlReason revocationReason = rs.HasRevocationReason
+ ? new CrlReason(rs.RevocationReason)
+ : null;
+
+ this.certStatus = new CertStatus(
+ new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason));
+ }
+
+ this.thisUpdate = thisUpdate;
+ this.nextUpdate = nextUpdate;
+
+ this.extensions = extensions;
+ }
+
+ public SingleResponse ToResponse()
+ {
+ return new SingleResponse(certId.ToAsn1Object(), certStatus, thisUpdate, nextUpdate, extensions);
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public BasicOcspRespGenerator(
+ RespID responderID)
+ {
+ this.responderID = responderID;
+ }
+
+ /**
+ * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+ */
+ public BasicOcspRespGenerator(
+ AsymmetricKeyParameter publicKey)
+ {
+ this.responderID = new RespID(publicKey);
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ DateTime nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param thisUpdate date this response was valid on
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ DateTime nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Set the extensions for the response.
+ *
+ * @param responseExtensions the extension object to carry.
+ */
+ public void SetResponseExtensions(
+ X509Extensions responseExtensions)
+ {
+ this.responseExtensions = responseExtensions;
+ }
+
+ private BasicOcspResp GenerateResponse(
+ string signatureName,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ DateTime producedAt,
+ SecureRandom random)
+ {
+ DerObjectIdentifier signingAlgorithm;
+ try
+ {
+ signingAlgorithm = OcspUtilities.GetAlgorithmOid(signatureName);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("unknown signing algorithm specified", e);
+ }
+
+ Asn1EncodableVector responses = new Asn1EncodableVector();
+
+ foreach (ResponseObject respObj in list)
+ {
+ try
+ {
+ responses.Add(respObj.ToResponse());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating Request", e);
+ }
+ }
+
+ ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt), new DerSequence(responses), responseExtensions);
+
+ ISigner sig = null;
+
+ try
+ {
+ sig = SignerUtilities.GetSigner(signatureName);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating signature: " + e, e);
+ }
+
+ DerBitString bitSig = null;
+
+ try
+ {
+ byte[] encoded = tbsResp.GetDerEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ bitSig = new DerBitString(sig.GenerateSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm);
+
+ if (chain != null && chain.Length > 0)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.Length; i++)
+ {
+ v.Add(
+ X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(chain[i].GetEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OcspException("error encoding certs", e);
+ }
+
+ return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, new DerSequence(v)));
+ }
+ else
+ {
+ return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, null));
+ }
+ }
+
+ public BasicOcspResp Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ DateTime thisUpdate)
+ {
+ return Generate(signingAlgorithm, privateKey, chain, thisUpdate, null);
+ }
+
+ public BasicOcspResp Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ DateTime producedAt,
+ SecureRandom random)
+ {
+ if (signingAlgorithm == null)
+ {
+ throw new ArgumentException("no signing algorithm specified");
+ }
+
+ return GenerateResponse(signingAlgorithm, privateKey, chain, producedAt, random);
+ }
+
+ /**
+ * Return an IEnumerable of the signature names supported by the generator.
+ *
+ * @return an IEnumerable containing recognised names.
+ */
+ public IEnumerable SignatureAlgNames
+ {
+ get { return OcspUtilities.AlgNames; }
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/CertificateID.cs b/src/core/srcbc/ocsp/CertificateID.cs
new file mode 100644
index 0000000..883cdfd
--- /dev/null
+++ b/src/core/srcbc/ocsp/CertificateID.cs
@@ -0,0 +1,118 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class CertificateID
+ {
+ public const string HashSha1 = "1.3.14.3.2.26";
+
+ private readonly CertID id;
+
+ public CertificateID(
+ CertID id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * create from an issuer certificate and the serial number of the
+ * certificate it signed.
+ * @exception OcspException if any problems occur creating the id fields.
+ */
+ public CertificateID(
+ string hashAlgorithm,
+ X509Certificate issuerCert,
+ BigInteger number)
+ {
+ try
+ {
+ IDigest digest = DigestUtilities.GetDigest(hashAlgorithm);
+ AlgorithmIdentifier hashAlg = new AlgorithmIdentifier(
+ new DerObjectIdentifier(hashAlgorithm), DerNull.Instance);
+
+ X509Name issuerName = PrincipalUtilities.GetSubjectX509Principal(issuerCert);
+
+ byte[] encodedIssuerName = issuerName.GetEncoded();
+ digest.BlockUpdate(encodedIssuerName, 0, encodedIssuerName.Length);
+
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ Asn1OctetString issuerNameHash = new DerOctetString(hash);
+ AsymmetricKeyParameter issuerKey = issuerCert.GetPublicKey();
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKey);
+
+ byte[] encodedPublicKey = info.PublicKeyData.GetBytes();
+ digest.BlockUpdate(encodedPublicKey, 0, encodedPublicKey.Length);
+
+ hash = DigestUtilities.DoFinal(digest);
+
+ Asn1OctetString issuerKeyHash = new DerOctetString(hash);
+
+ DerInteger serialNumber = new DerInteger(number);
+
+ this.id = new CertID(hashAlg, issuerNameHash, issuerKeyHash, serialNumber);
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem creating ID: " + e, e);
+ }
+ }
+
+ public string HashAlgOid
+ {
+ get { return id.HashAlgorithm.ObjectID.Id; }
+ }
+
+ public byte[] GetIssuerNameHash()
+ {
+ return id.IssuerNameHash.GetOctets();
+ }
+
+ public byte[] GetIssuerKeyHash()
+ {
+ return id.IssuerKeyHash.GetOctets();
+ }
+
+ /**
+ * return the serial number for the certificate associated
+ * with this request.
+ */
+ public BigInteger SerialNumber
+ {
+ get { return id.SerialNumber.Value; }
+ }
+
+ public CertID ToAsn1Object()
+ {
+ return id;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ CertificateID other = obj as CertificateID;
+
+ if (other == null)
+ return false;
+
+ return id.ToAsn1Object().Equals(other.id.ToAsn1Object());
+ }
+
+ public override int GetHashCode()
+ {
+ return id.ToAsn1Object().GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/CertificateStatus.cs b/src/core/srcbc/ocsp/CertificateStatus.cs
new file mode 100644
index 0000000..3b09f20
--- /dev/null
+++ b/src/core/srcbc/ocsp/CertificateStatus.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public abstract class CertificateStatus
+ {
+ public static readonly CertificateStatus Good = null;
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPException.cs b/src/core/srcbc/ocsp/OCSPException.cs
new file mode 100644
index 0000000..34a9ac5
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class OcspException
+ : Exception
+ {
+ public OcspException()
+ {
+ }
+
+ public OcspException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public OcspException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPReq.cs b/src/core/srcbc/ocsp/OCSPReq.cs
new file mode 100644
index 0000000..2ce7286
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPReq.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ *
+ * OcspRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+ *
+ * Version ::= INTEGER { v1(0) }
+ *
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ *
+ */
+ public class OcspReq
+ : X509ExtensionBase
+ {
+ private OcspRequest req;
+
+ public OcspReq(
+ OcspRequest req)
+ {
+ this.req = req;
+ }
+
+ public OcspReq(
+ byte[] req)
+ : this(new Asn1InputStream(req))
+ {
+ }
+
+ public OcspReq(
+ Stream inStr)
+ : this(new Asn1InputStream(inStr))
+ {
+ }
+
+ private OcspReq(
+ Asn1InputStream aIn)
+ {
+ try
+ {
+ this.req = OcspRequest.GetInstance(aIn.ReadObject());
+ }
+ catch (ArgumentException e)
+ {
+ throw new IOException("malformed request: " + e.Message);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new IOException("malformed request: " + e.Message);
+ }
+ }
+
+ /**
+ * Return the DER encoding of the tbsRequest field.
+ * @return DER encoding of tbsRequest
+ * @throws OcspException in the event of an encoding error.
+ */
+ public byte[] GetTbsRequest()
+ {
+ try
+ {
+ return req.TbsRequest.GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("problem encoding tbsRequest", e);
+ }
+ }
+
+ public int Version
+ {
+ get { return req.TbsRequest.Version.Value.IntValue + 1; }
+ }
+
+ public GeneralName RequestorName
+ {
+ get { return GeneralName.GetInstance(req.TbsRequest.RequestorName); }
+ }
+
+ public Req[] GetRequestList()
+ {
+ Asn1Sequence seq = req.TbsRequest.RequestList;
+ Req[] requests = new Req[seq.Count];
+
+ for (int i = 0; i != requests.Length; i++)
+ {
+ requests[i] = new Req(Request.GetInstance(seq[i]));
+ }
+
+ return requests;
+ }
+
+ public X509Extensions RequestExtensions
+ {
+ get { return X509Extensions.GetInstance(req.TbsRequest.RequestExtensions); }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return RequestExtensions;
+ }
+
+ /**
+ * return the object identifier representing the signature algorithm
+ */
+ public string SignatureAlgOid
+ {
+ get
+ {
+ if (!this.IsSigned)
+ return null;
+
+ return req.OptionalSignature.SignatureAlgorithm.ObjectID.Id;
+ }
+ }
+
+ public byte[] GetSignature()
+ {
+ if (!this.IsSigned)
+ return null;
+
+ return req.OptionalSignature.SignatureValue.GetBytes();
+ }
+
+ private ArrayList GetCertList()
+ {
+ // load the certificates if we have any
+
+ ArrayList certs = new ArrayList();
+ Asn1Sequence s = req.OptionalSignature.Certs;
+
+ if (s != null)
+ {
+ foreach (Asn1Encodable ae in s)
+ {
+ try
+ {
+ certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't re-encode certificate!", e);
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] GetCerts()
+ {
+ if (!this.IsSigned)
+ return null;
+
+ ArrayList certs = this.GetCertList();
+
+ return (X509Certificate[]) certs.ToArray(typeof(X509Certificate));
+ }
+
+ /**
+ * If the request is signed return a possibly empty CertStore containing the certificates in the
+ * request. If the request is not signed the method returns null.
+ *
+ * @return null if not signed, a CertStore otherwise
+ * @throws OcspException
+ */
+ public IX509Store GetCertificates(
+ string type)
+ {
+ if (!this.IsSigned)
+ return null;
+
+ try
+ {
+ return X509StoreFactory.Create(
+ "Certificate/" + type,
+ new X509CollectionStoreParameters(this.GetCertList()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * Return whether or not this request is signed.
+ *
+ * @return true if signed false otherwise.
+ */
+ public bool IsSigned
+ {
+ get { return req.OptionalSignature != null; }
+ }
+
+ /**
+ * Verify the signature against the TBSRequest object we contain.
+ */
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!this.IsSigned)
+ throw new OcspException("attempt to Verify signature on unsigned object");
+
+ try
+ {
+ ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgOid);
+
+ signature.Init(false, publicKey);
+
+ byte[] encoded = req.TbsRequest.GetEncoded();
+
+ signature.BlockUpdate(encoded, 0, encoded.Length);
+
+ return signature.VerifySignature(this.GetSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return req.GetEncoded();
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPReqGenerator.cs b/src/core/srcbc/ocsp/OCSPReqGenerator.cs
new file mode 100644
index 0000000..62bb13a
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPReqGenerator.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class OcspReqGenerator
+ {
+ private IList list = new ArrayList();
+ private GeneralName requestorName = null;
+ private X509Extensions requestExtensions = null;
+
+ private class RequestObject
+ {
+ internal CertificateID certId;
+ internal X509Extensions extensions;
+
+ public RequestObject(
+ CertificateID certId,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+ this.extensions = extensions;
+ }
+
+ public Request ToRequest()
+ {
+ return new Request(certId.ToAsn1Object(), extensions);
+ }
+ }
+
+ /**
+ * Add a request for the given CertificateID.
+ *
+ * @param certId certificate ID of interest
+ */
+ public void AddRequest(
+ CertificateID certId)
+ {
+ list.Add(new RequestObject(certId, null));
+ }
+
+ /**
+ * Add a request with extensions
+ *
+ * @param certId certificate ID of interest
+ * @param singleRequestExtensions the extensions to attach to the request
+ */
+ public void AddRequest(
+ CertificateID certId,
+ X509Extensions singleRequestExtensions)
+ {
+ list.Add(new RequestObject(certId, singleRequestExtensions));
+ }
+
+ /**
+ * Set the requestor name to the passed in X509Principal
+ *
+ * @param requestorName a X509Principal representing the requestor name.
+ */
+ public void SetRequestorName(
+ X509Name requestorName)
+ {
+ try
+ {
+ this.requestorName = new GeneralName(GeneralName.DirectoryName, requestorName);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("cannot encode principal", e);
+ }
+ }
+
+ public void SetRequestorName(
+ GeneralName requestorName)
+ {
+ this.requestorName = requestorName;
+ }
+
+ public void SetRequestExtensions(
+ X509Extensions requestExtensions)
+ {
+ this.requestExtensions = requestExtensions;
+ }
+
+ private OcspReq GenerateRequest(
+ DerObjectIdentifier signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ SecureRandom random)
+ {
+ Asn1EncodableVector requests = new Asn1EncodableVector();
+
+ foreach (RequestObject reqObj in list)
+ {
+ try
+ {
+ requests.Add(reqObj.ToRequest());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating Request", e);
+ }
+ }
+
+ TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions);
+
+ ISigner sig = null;
+ Signature signature = null;
+
+ if (signingAlgorithm != null)
+ {
+ if (requestorName == null)
+ {
+ throw new OcspException("requestorName must be specified if request is signed.");
+ }
+
+ try
+ {
+ sig = SignerUtilities.GetSigner(signingAlgorithm.Id);
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating signature: " + e, e);
+ }
+
+ DerBitString bitSig = null;
+
+ try
+ {
+ byte[] encoded = tbsReq.GetEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ bitSig = new DerBitString(sig.GenerateSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance);
+
+ if (chain != null && chain.Length > 0)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.Length; i++)
+ {
+ v.Add(
+ X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(chain[i].GetEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OcspException("error encoding certs", e);
+ }
+
+ signature = new Signature(sigAlgId, bitSig, new DerSequence(v));
+ }
+ else
+ {
+ signature = new Signature(sigAlgId, bitSig);
+ }
+ }
+
+ return new OcspReq(new OcspRequest(tbsReq, signature));
+ }
+
+ /**
+ * Generate an unsigned request
+ *
+ * @return the OcspReq
+ * @throws OcspException
+ */
+ public OcspReq Generate()
+ {
+ return GenerateRequest(null, null, null, null);
+ }
+
+ public OcspReq Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain)
+ {
+ return Generate(signingAlgorithm, privateKey, chain, null);
+ }
+
+ public OcspReq Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ SecureRandom random)
+ {
+ if (signingAlgorithm == null)
+ throw new ArgumentException("no signing algorithm specified");
+
+ try
+ {
+ DerObjectIdentifier oid = OcspUtilities.GetAlgorithmOid(signingAlgorithm);
+
+ return GenerateRequest(oid, privateKey, chain, random);
+ }
+ catch (ArgumentException)
+ {
+ throw new ArgumentException("unknown signing algorithm specified: " + signingAlgorithm);
+ }
+ }
+
+ /**
+ * Return an IEnumerable of the signature names supported by the generator.
+ *
+ * @return an IEnumerable containing recognised names.
+ */
+ public IEnumerable SignatureAlgNames
+ {
+ get { return OcspUtilities.AlgNames; }
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPResp.cs b/src/core/srcbc/ocsp/OCSPResp.cs
new file mode 100644
index 0000000..13e3f72
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPResp.cs
@@ -0,0 +1,100 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class OcspResp
+ {
+ private OcspResponse resp;
+
+ public OcspResp(
+ OcspResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public OcspResp(
+ byte[] resp)
+ : this(new Asn1InputStream(resp))
+ {
+ }
+
+ public OcspResp(
+ Stream inStr)
+ : this(new Asn1InputStream(inStr))
+ {
+ }
+
+ private OcspResp(
+ Asn1InputStream aIn)
+ {
+ try
+ {
+ this.resp = OcspResponse.GetInstance(aIn.ReadObject());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("malformed response: " + e.Message, e);
+ }
+ }
+
+ public int Status
+ {
+ get { return this.resp.ResponseStatus.Value.IntValue; }
+ }
+
+ public object GetResponseObject()
+ {
+ ResponseBytes rb = this.resp.ResponseBytes;
+
+ if (rb == null)
+ return null;
+
+ if (rb.ResponseType.Equals(OcspObjectIdentifiers.PkixOcspBasic))
+ {
+ try
+ {
+ return new BasicOcspResp(
+ BasicOcspResponse.GetInstance(
+ Asn1Object.FromByteArray(rb.Response.GetOctets())));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem decoding object: " + e, e);
+ }
+ }
+
+ return rb.Response;
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ OcspResp other = obj as OcspResp;
+
+ if (other == null)
+ return false;
+
+ return resp.Equals(other.resp);
+ }
+
+ public override int GetHashCode()
+ {
+ return resp.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPRespGenerator.cs b/src/core/srcbc/ocsp/OCSPRespGenerator.cs
new file mode 100644
index 0000000..61d6f5f
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPRespGenerator.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * base generator for an OCSP response - at the moment this only supports the
+ * generation of responses containing BasicOCSP responses.
+ */
+ public class OCSPRespGenerator
+ {
+ public const int Successful = 0; // Response has valid confirmations
+ public const int MalformedRequest = 1; // Illegal confirmation request
+ public const int InternalError = 2; // Internal error in issuer
+ public const int TryLater = 3; // Try again later
+ // (4) is not used
+ public const int SigRequired = 5; // Must sign the request
+ public const int Unauthorized = 6; // Request unauthorized
+
+ public OcspResp Generate(
+ int status,
+ object response)
+ {
+ if (response == null)
+ {
+ return new OcspResp(new OcspResponse(new OcspResponseStatus(status),null));
+ }
+ if (response is BasicOcspResp)
+ {
+ BasicOcspResp r = (BasicOcspResp)response;
+ Asn1OctetString octs;
+
+ try
+ {
+ octs = new DerOctetString(r.GetEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't encode object.", e);
+ }
+
+ ResponseBytes rb = new ResponseBytes(
+ OcspObjectIdentifiers.PkixOcspBasic, octs);
+
+ return new OcspResp(new OcspResponse(
+ new OcspResponseStatus(status), rb));
+ }
+
+ throw new OcspException("unknown response object");
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPRespStatus.cs b/src/core/srcbc/ocsp/OCSPRespStatus.cs
new file mode 100644
index 0000000..bef915e
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPRespStatus.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ [Obsolete("Use version with correct spelling 'OcspRespStatus'")]
+ public abstract class OcscpRespStatus : OcspRespStatus
+ {
+ }
+
+ public abstract class OcspRespStatus
+ {
+ /**
+ * note 4 is not used.
+ */
+ public const int Successful = 0; // --Response has valid confirmations
+ public const int MalformedRequest = 1; // --Illegal confirmation request
+ public const int InternalError = 2; // --Internal error in issuer
+ public const int TryLater = 3; // --Try again later
+ public const int SigRequired = 5; // --Must sign the request
+ public const int Unauthorized = 6; // --Request unauthorized
+ }
+}
diff --git a/src/core/srcbc/ocsp/OCSPUtil.cs b/src/core/srcbc/ocsp/OCSPUtil.cs
new file mode 100644
index 0000000..8704c74
--- /dev/null
+++ b/src/core/srcbc/ocsp/OCSPUtil.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ class OcspUtilities
+ {
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable oids = new Hashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static OcspUtilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+
+ oids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, "RIPEMD160WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, "RIPEMD128WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, "RIPEMD256WITHRSA");
+ oids.Add(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture);
+
+ if (algorithms.ContainsKey(algorithmName))
+ {
+ return (DerObjectIdentifier)algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+
+ internal static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ if (oids.ContainsKey(oid))
+ {
+ return (string)oids[oid];
+ }
+
+ return oid.Id;
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable AlgNames
+ {
+ get { return new EnumerableProxy(algorithms.Keys); }
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/Req.cs b/src/core/srcbc/ocsp/Req.cs
new file mode 100644
index 0000000..df66e0a
--- /dev/null
+++ b/src/core/srcbc/ocsp/Req.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class Req
+ : X509ExtensionBase
+ {
+ private Request req;
+
+ public Req(
+ Request req)
+ {
+ this.req = req;
+ }
+
+ public CertificateID GetCertID()
+ {
+ return new CertificateID(req.ReqCert);
+ }
+
+ public X509Extensions SingleRequestExtensions
+ {
+ get { return req.SingleRequestExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return SingleRequestExtensions;
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/RespData.cs b/src/core/srcbc/ocsp/RespData.cs
new file mode 100644
index 0000000..f1ee2e9
--- /dev/null
+++ b/src/core/srcbc/ocsp/RespData.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class RespData
+ : X509ExtensionBase
+ {
+ internal readonly ResponseData data;
+
+ public RespData(
+ ResponseData data)
+ {
+ this.data = data;
+ }
+
+ public int Version
+ {
+ get { return data.Version.Value.IntValue + 1; }
+ }
+
+ public RespID GetResponderId()
+ {
+ return new RespID(data.ResponderID);
+ }
+
+ public DateTime ProducedAt
+ {
+ get { return data.ProducedAt.ToDateTime(); }
+ }
+
+ public SingleResp[] GetResponses()
+ {
+ Asn1Sequence s = data.Responses;
+ SingleResp[] rs = new SingleResp[s.Count];
+
+ for (int i = 0; i != rs.Length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+ }
+
+ return rs;
+ }
+
+ public X509Extensions ResponseExtensions
+ {
+ get { return data.ResponseExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return ResponseExtensions;
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/RespID.cs b/src/core/srcbc/ocsp/RespID.cs
new file mode 100644
index 0000000..56018a8
--- /dev/null
+++ b/src/core/srcbc/ocsp/RespID.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * Carrier for a ResponderID.
+ */
+ public class RespID
+ {
+ internal readonly ResponderID id;
+
+ public RespID(
+ ResponderID id)
+ {
+ this.id = id;
+ }
+
+ public RespID(
+ X509Name name)
+ {
+ try
+ {
+ this.id = new ResponderID(name);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("can't decode name.", e);
+ }
+ }
+
+ public RespID(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ IDigest digest = DigestUtilities.GetDigest("SHA1");
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+ byte[] encoded = info.PublicKeyData.GetBytes();
+ digest.BlockUpdate(encoded, 0, encoded.Length);
+
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ Asn1OctetString keyHash = new DerOctetString(hash);
+
+ this.id = new ResponderID(keyHash);
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem creating ID: " + e, e);
+ }
+ }
+
+ public ResponderID ToAsn1Object()
+ {
+ return id;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RespID other = obj as RespID;
+
+ if (other == null)
+ return false;
+
+ return id.Equals(other.id);
+ }
+
+ public override int GetHashCode()
+ {
+ return id.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/RevokedStatus.cs b/src/core/srcbc/ocsp/RevokedStatus.cs
new file mode 100644
index 0000000..07925af
--- /dev/null
+++ b/src/core/srcbc/ocsp/RevokedStatus.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * wrapper for the RevokedInfo object
+ */
+ public class RevokedStatus
+ : CertificateStatus
+ {
+ internal readonly RevokedInfo info;
+
+ public RevokedStatus(
+ RevokedInfo info)
+ {
+ this.info = info;
+ }
+
+ public RevokedStatus(
+ DateTime revocationDate,
+ int reason)
+ {
+ this.info = new RevokedInfo(new DerGeneralizedTime(revocationDate), new CrlReason(reason));
+ }
+
+ public DateTime RevocationTime
+ {
+ get { return info.RevocationTime.ToDateTime(); }
+ }
+
+ public bool HasRevocationReason
+ {
+ get { return (info.RevocationReason != null); }
+ }
+
+ /**
+ * return the revocation reason. Note: this field is optional, test for it
+ * with hasRevocationReason() first.
+ * @exception InvalidOperationException if a reason is asked for and none is avaliable
+ */
+ public int RevocationReason
+ {
+ get
+ {
+ if (info.RevocationReason == null)
+ {
+ throw new InvalidOperationException("attempt to get a reason where none is available");
+ }
+
+ return info.RevocationReason.Value.IntValue;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/SingleResp.cs b/src/core/srcbc/ocsp/SingleResp.cs
new file mode 100644
index 0000000..c02390e
--- /dev/null
+++ b/src/core/srcbc/ocsp/SingleResp.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class SingleResp
+ : X509ExtensionBase
+ {
+ internal readonly SingleResponse resp;
+
+ public SingleResp(
+ SingleResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public CertificateID GetCertID()
+ {
+ return new CertificateID(resp.CertId);
+ }
+
+ /**
+ * Return the status object for the response - null indicates good.
+ *
+ * @return the status object for the response, null if it is good.
+ */
+ public object GetCertStatus()
+ {
+ CertStatus s = resp.CertStatus;
+
+ if (s.TagNo == 0)
+ {
+ return null; // good
+ }
+
+ if (s.TagNo == 1)
+ {
+ return new RevokedStatus(RevokedInfo.GetInstance(s.Status));
+ }
+
+ return new UnknownStatus();
+ }
+
+ public DateTime ThisUpdate
+ {
+ get { return resp.ThisUpdate.ToDateTime(); }
+ }
+
+ /**
+ * return the NextUpdate value - note: this is an optional field so may
+ * be returned as null.
+ *
+ * @return nextUpdate, or null if not present.
+ */
+ public DateTimeObject NextUpdate
+ {
+ get
+ {
+ return resp.NextUpdate == null
+ ? null
+ : new DateTimeObject(resp.NextUpdate.ToDateTime());
+ }
+ }
+
+ public X509Extensions SingleExtensions
+ {
+ get { return resp.SingleExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return SingleExtensions;
+ }
+ }
+}
diff --git a/src/core/srcbc/ocsp/UnknownStatus.cs b/src/core/srcbc/ocsp/UnknownStatus.cs
new file mode 100644
index 0000000..e120b48
--- /dev/null
+++ b/src/core/srcbc/ocsp/UnknownStatus.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * wrapper for the UnknownInfo object
+ */
+ public class UnknownStatus
+ : CertificateStatus
+ {
+ public UnknownStatus()
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/IStreamGenerator.cs b/src/core/srcbc/openpgp/IStreamGenerator.cs
new file mode 100644
index 0000000..ebaf7ff
--- /dev/null
+++ b/src/core/srcbc/openpgp/IStreamGenerator.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public interface IStreamGenerator
+ {
+ void Close();
+ }
+}
diff --git a/src/core/srcbc/openpgp/PGPKeyRing.cs b/src/core/srcbc/openpgp/PGPKeyRing.cs
new file mode 100644
index 0000000..a919e22
--- /dev/null
+++ b/src/core/srcbc/openpgp/PGPKeyRing.cs
@@ -0,0 +1,77 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpKeyRing
+ : PgpObject
+ {
+ internal PgpKeyRing()
+ {
+ }
+
+ internal static TrustPacket ReadOptionalTrustPacket(
+ BcpgInputStream bcpgInput)
+ {
+ return (bcpgInput.NextPacketTag() == PacketTag.Trust)
+ ? (TrustPacket) bcpgInput.ReadPacket()
+ : null;
+ }
+
+ internal static ArrayList ReadSignaturesAndTrust(
+ BcpgInputStream bcpgInput)
+ {
+ try
+ {
+ ArrayList sigList = new ArrayList();
+
+ while (bcpgInput.NextPacketTag() == PacketTag.Signature)
+ {
+ SignaturePacket signaturePacket = (SignaturePacket) bcpgInput.ReadPacket();
+ TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
+
+ sigList.Add(new PgpSignature(signaturePacket, trustPacket));
+ }
+
+ return sigList;
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create signature object: " + e.Message, e);
+ }
+ }
+
+ internal static void ReadUserIDs(
+ BcpgInputStream bcpgInput,
+ out ArrayList ids,
+ out ArrayList idTrusts,
+ out ArrayList idSigs)
+ {
+ ids = new ArrayList();
+ idTrusts = new ArrayList();
+ idSigs = new ArrayList();
+
+ while (bcpgInput.NextPacketTag() == PacketTag.UserId
+ || bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
+ {
+ Packet obj = bcpgInput.ReadPacket();
+ if (obj is UserIdPacket)
+ {
+ UserIdPacket id = (UserIdPacket)obj;
+ ids.Add(id.GetId());
+ }
+ else
+ {
+ UserAttributePacket user = (UserAttributePacket) obj;
+ ids.Add(new PgpUserAttributeSubpacketVector(user.GetSubpackets()));
+ }
+
+ idTrusts.Add(
+ ReadOptionalTrustPacket(bcpgInput));
+
+ idSigs.Add(
+ ReadSignaturesAndTrust(bcpgInput));
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PGPObject.cs b/src/core/srcbc/openpgp/PGPObject.cs
new file mode 100644
index 0000000..624f8d0
--- /dev/null
+++ b/src/core/srcbc/openpgp/PGPObject.cs
@@ -0,0 +1,9 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpObject
+ {
+ internal PgpObject()
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs b/src/core/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
new file mode 100644
index 0000000..e8fc515
--- /dev/null
+++ b/src/core/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Attr;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class PgpUserAttributeSubpacketVectorGenerator
+ {
+ private ArrayList list = new ArrayList();
+
+ public virtual void SetImageAttribute(
+ ImageAttrib.Format imageType,
+ byte[] imageData)
+ {
+ if (imageData == null)
+ throw new ArgumentException("attempt to set null image", "imageData");
+
+ list.Add(new ImageAttrib(imageType, imageData));
+ }
+
+ public virtual PgpUserAttributeSubpacketVector Generate()
+ {
+ return new PgpUserAttributeSubpacketVector(
+ (UserAttributeSubpacket[]) list.ToArray(typeof(UserAttributeSubpacket)));
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpCompressedData.cs b/src/core/srcbc/openpgp/PgpCompressedData.cs
new file mode 100644
index 0000000..5fbfaff
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpCompressedData.cs
@@ -0,0 +1,50 @@
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Compressed data objects
+ public class PgpCompressedData
+ : PgpObject
+ {
+ private readonly CompressedDataPacket data;
+
+ public PgpCompressedData(
+ BcpgInputStream bcpgInput)
+ {
+ data = (CompressedDataPacket) bcpgInput.ReadPacket();
+ }
+
+ /// The algorithm used for compression
+ public CompressionAlgorithmTag Algorithm
+ {
+ get { return data.Algorithm; }
+ }
+
+ /// Get the raw input stream contained in the object.
+ public Stream GetInputStream()
+ {
+ return data.GetInputStream();
+ }
+
+ /// Return an uncompressed input stream which allows reading of the compressed data.
+ public Stream GetDataStream()
+ {
+ switch (Algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ return GetInputStream();
+ case CompressionAlgorithmTag.Zip:
+ return new ZInflaterInputStream(GetInputStream(), true);
+ case CompressionAlgorithmTag.ZLib:
+ return new ZInflaterInputStream(GetInputStream());
+ case CompressionAlgorithmTag.BZip2:
+ return new CBZip2InputStream(GetInputStream());
+ default:
+ throw new PgpException("can't recognise compression algorithm: " + Algorithm);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpCompressedDataGenerator.cs b/src/core/srcbc/openpgp/PgpCompressedDataGenerator.cs
new file mode 100644
index 0000000..a4c0ed8
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpCompressedDataGenerator.cs
@@ -0,0 +1,177 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for producing compressed data packets.
+ public class PgpCompressedDataGenerator
+ : IStreamGenerator
+ {
+ private readonly CompressionAlgorithmTag algorithm;
+ private readonly int compression;
+
+ private Stream dOut;
+ private BcpgOutputStream pkOut;
+
+ public PgpCompressedDataGenerator(
+ CompressionAlgorithmTag algorithm)
+ : this(algorithm, JZlib.Z_DEFAULT_COMPRESSION)
+ {
+ }
+
+ public PgpCompressedDataGenerator(
+ CompressionAlgorithmTag algorithm,
+ int compression)
+ {
+ switch (algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ case CompressionAlgorithmTag.Zip:
+ case CompressionAlgorithmTag.ZLib:
+ case CompressionAlgorithmTag.BZip2:
+ break;
+ default:
+ throw new ArgumentException("unknown compression algorithm", "algorithm");
+ }
+
+ if (compression != JZlib.Z_DEFAULT_COMPRESSION)
+ {
+ if ((compression < JZlib.Z_NO_COMPRESSION) || (compression > JZlib.Z_BEST_COMPRESSION))
+ {
+ throw new ArgumentException("unknown compression level: " + compression);
+ }
+ }
+
+ this.algorithm = algorithm;
+ this.compression = compression;
+ }
+
+ ///
+ ///
+ /// Return an output stream which will save the data being written to
+ /// the compressed object.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// Stream to be used for output.
+ /// A Stream for output of the compressed data.
+ ///
+ ///
+ ///
+ public Stream Open(
+ Stream outStr)
+ {
+ if (dOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
+
+ doOpen();
+
+ return new WrappedGeneratorStream(this, dOut);
+ }
+
+ ///
+ ///
+ /// Return an output stream which will compress the data as it is written to it.
+ /// The stream will be written out in chunks according to the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// Note: if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ ///
+ /// Note: using this may break compatibility with RFC 1991 compliant tools.
+ /// Only recent OpenPGP implementations are capable of accepting these streams.
+ ///
+ ///
+ /// Stream to be used for output.
+ /// The buffer to use.
+ /// A Stream for output of the compressed data.
+ ///
+ ///
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ byte[] buffer)
+ {
+ if (dOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+
+ this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer);
+
+ doOpen();
+
+ return new WrappedGeneratorStream(this, dOut);
+ }
+
+ private void doOpen()
+ {
+ pkOut.WriteByte((byte) algorithm);
+
+ switch (algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ dOut = pkOut;
+ break;
+ case CompressionAlgorithmTag.Zip:
+ dOut = new ZDeflaterOutputStream(pkOut, compression, true);
+ break;
+ case CompressionAlgorithmTag.ZLib:
+ dOut = new ZDeflaterOutputStream(pkOut, compression, false);
+ break;
+ case CompressionAlgorithmTag.BZip2:
+ dOut = new CBZip2OutputStream(pkOut);
+ break;
+ default:
+ // Constructor should guard against this possibility
+ throw new InvalidOperationException();
+ }
+ }
+
+ /// Close the compressed object.summary>
+ public void Close()
+ {
+ if (dOut != null)
+ {
+ switch (algorithm)
+ {
+ case CompressionAlgorithmTag.BZip2:
+ ((CBZip2OutputStream) dOut).Finish();
+ break;
+ case CompressionAlgorithmTag.Zip:
+ case CompressionAlgorithmTag.ZLib:
+ ((ZDeflaterOutputStream) dOut).Finish();
+ break;
+ }
+
+ dOut.Flush();
+
+ pkOut.Finish();
+ pkOut.Flush();
+
+ dOut = null;
+ pkOut = null;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpDataValidationException.cs b/src/core/srcbc/openpgp/PgpDataValidationException.cs
new file mode 100644
index 0000000..a38c368
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpDataValidationException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Thrown if the IV at the start of a data stream indicates the wrong key is being used.
+ ///
+ public class PgpDataValidationException
+ : PgpException
+ {
+ public PgpDataValidationException() : base() {}
+ public PgpDataValidationException(string message) : base(message) {}
+ public PgpDataValidationException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpEncryptedData.cs b/src/core/srcbc/openpgp/PgpEncryptedData.cs
new file mode 100644
index 0000000..982ad72
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpEncryptedData.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpEncryptedData
+ {
+ internal class TruncatedStream
+ : BaseInputStream
+ {
+ private const int LookAheadSize = 22;
+ private const int LookAheadBufSize = 512;
+ private const int LookAheadBufLimit = LookAheadBufSize - LookAheadSize;
+
+ private readonly Stream inStr;
+ private readonly byte[] lookAhead = new byte[LookAheadBufSize];
+ private int bufStart, bufEnd;
+
+ internal TruncatedStream(
+ Stream inStr)
+ {
+ int numRead = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
+
+ if (numRead < LookAheadSize)
+ throw new EndOfStreamException();
+
+ this.inStr = inStr;
+ this.bufStart = 0;
+ this.bufEnd = numRead - LookAheadSize;
+ }
+
+ private int FillBuffer()
+ {
+ if (bufEnd < LookAheadBufLimit)
+ return 0;
+
+ Debug.Assert(bufStart == LookAheadBufLimit);
+ Debug.Assert(bufEnd == LookAheadBufLimit);
+
+ Array.Copy(lookAhead, LookAheadBufLimit, lookAhead, 0, LookAheadSize);
+ bufEnd = Streams.ReadFully(inStr, lookAhead, LookAheadSize, LookAheadBufLimit);
+ bufStart = 0;
+ return bufEnd;
+ }
+
+ public override int ReadByte()
+ {
+ if (bufStart < bufEnd)
+ return lookAhead[bufStart++];
+
+ if (FillBuffer() < 1)
+ return -1;
+
+ return lookAhead[bufStart++];
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ int avail = bufEnd - bufStart;
+
+ int pos = off;
+ while (len > avail)
+ {
+ Array.Copy(lookAhead, bufStart, buf, pos, avail);
+
+ bufStart += avail;
+ pos += avail;
+ len -= avail;
+
+ if ((avail = FillBuffer()) < 1)
+ return pos - off;
+ }
+
+ Array.Copy(lookAhead, bufStart, buf, pos, len);
+ bufStart += len;
+
+ return pos + len - off;;
+ }
+
+ internal byte[] GetLookAhead()
+ {
+ byte[] temp = new byte[LookAheadSize];
+ Array.Copy(lookAhead, bufStart, temp, 0, LookAheadSize);
+ return temp;
+ }
+ }
+
+ internal InputStreamPacket encData;
+ internal Stream encStream;
+ internal TruncatedStream truncStream;
+
+ internal PgpEncryptedData(
+ InputStreamPacket encData)
+ {
+ this.encData = encData;
+ }
+
+ /// Return the raw input stream for the data stream.
+ public virtual Stream GetInputStream()
+ {
+ return encData.GetInputStream();
+ }
+
+ /// Return true if the message is integrity protected.
+ /// True, if there is a modification detection code namespace associated
+ /// with this stream.
+ public bool IsIntegrityProtected()
+ {
+ return encData is SymmetricEncIntegrityPacket;
+ }
+
+ /// Note: This can only be called after the message has been read.
+ /// True, if the message verifies, false otherwise
+ public bool Verify()
+ {
+ if (!IsIntegrityProtected())
+ throw new PgpException("data not integrity protected.");
+
+ DigestStream dIn = (DigestStream) encStream;
+
+ //
+ // make sure we are at the end.
+ //
+ while (encStream.ReadByte() >= 0)
+ {
+ // do nothing
+ }
+
+ //
+ // process the MDC packet
+ //
+ byte[] lookAhead = truncStream.GetLookAhead();
+
+ IDigest hash = dIn.ReadDigest();
+ hash.BlockUpdate(lookAhead, 0, 2);
+ byte[] digest = DigestUtilities.DoFinal(hash);
+
+ byte[] streamDigest = new byte[digest.Length];
+ Array.Copy(lookAhead, 2, streamDigest, 0, streamDigest.Length);
+
+ return Arrays.AreEqual(digest, streamDigest);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpEncryptedDataGenerator.cs b/src/core/srcbc/openpgp/PgpEncryptedDataGenerator.cs
new file mode 100644
index 0000000..72907f2
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpEncryptedDataGenerator.cs
@@ -0,0 +1,495 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for encrypted objects.
+ public class PgpEncryptedDataGenerator
+ : IStreamGenerator
+ {
+ private BcpgOutputStream pOut;
+ private CipherStream cOut;
+ private IBufferedCipher c;
+ private bool withIntegrityPacket;
+ private bool oldFormat;
+ private DigestStream digestOut;
+
+ private abstract class EncMethod
+ : ContainedPacket
+ {
+ protected byte[] sessionInfo;
+ protected SymmetricKeyAlgorithmTag encAlgorithm;
+ protected KeyParameter key;
+
+ public abstract void AddSessionInfo(byte[] si, SecureRandom random);
+ }
+
+ private class PbeMethod
+ : EncMethod
+ {
+ private S2k s2k;
+
+ internal PbeMethod(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ S2k s2k,
+ KeyParameter key)
+ {
+ this.encAlgorithm = encAlgorithm;
+ this.s2k = s2k;
+ this.key = key;
+ }
+
+ public KeyParameter GetKey()
+ {
+ return key;
+ }
+
+ public override void AddSessionInfo(
+ byte[] si,
+ SecureRandom random)
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+
+ byte[] iv = new byte[c.GetBlockSize()];
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
+
+ this.sessionInfo = c.DoFinal(si, 0, si.Length - 2);
+ }
+
+ public override void Encode(BcpgOutputStream pOut)
+ {
+ SymmetricKeyEncSessionPacket pk = new SymmetricKeyEncSessionPacket(
+ encAlgorithm, s2k, sessionInfo);
+
+ pOut.WritePacket(pk);
+ }
+ }
+
+ private class PubMethod
+ : EncMethod
+ {
+ internal PgpPublicKey pubKey;
+ internal BigInteger[] data;
+
+ internal PubMethod(
+ PgpPublicKey pubKey)
+ {
+ this.pubKey = pubKey;
+ }
+
+ public override void AddSessionInfo(
+ byte[] si,
+ SecureRandom random)
+ {
+ IBufferedCipher c;
+
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ throw new PgpException("Can't use DSA for encryption.");
+ case PublicKeyAlgorithmTag.ECDsa:
+ throw new PgpException("Can't use ECDSA for encryption.");
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+ }
+
+ AsymmetricKeyParameter akp = pubKey.GetKey();
+
+ c.Init(true, new ParametersWithRandom(akp, random));
+
+ byte[] encKey = c.DoFinal(si);
+
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ data = new BigInteger[]{ new BigInteger(1, encKey) };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ int halfLength = encKey.Length / 2;
+ data = new BigInteger[]
+ {
+ new BigInteger(1, encKey, 0, halfLength),
+ new BigInteger(1, encKey, halfLength, halfLength)
+ };
+ break;
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm);
+ }
+ }
+
+ public override void Encode(BcpgOutputStream pOut)
+ {
+ PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(
+ pubKey.KeyId, pubKey.Algorithm, data);
+
+ pOut.WritePacket(pk);
+ }
+ }
+
+ private readonly ArrayList methods = new ArrayList();
+ private readonly SymmetricKeyAlgorithmTag defAlgorithm;
+ private readonly SecureRandom rand;
+
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = new SecureRandom();
+ }
+
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool withIntegrityPacket)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.withIntegrityPacket = withIntegrityPacket;
+ this.rand = new SecureRandom();
+ }
+
+ /// Existing SecureRandom constructor.
+ /// The symmetric algorithm to use.
+ /// Source of randomness.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ SecureRandom rand)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ }
+
+ /// Creates a cipher stream which will have an integrity packet associated with it.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool withIntegrityPacket,
+ SecureRandom rand)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ this.withIntegrityPacket = withIntegrityPacket;
+ }
+
+ /// Base constructor.
+ /// The symmetric algorithm to use.
+ /// Source of randomness.
+ /// PGP 2.6.x compatibility required.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ SecureRandom rand,
+ bool oldFormat)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ this.oldFormat = oldFormat;
+ }
+
+ /// Add a PBE encryption method to the encrypted object.
+ public void AddMethod(
+ char[] passPhrase)
+ {
+ byte[] iv = new byte[8];
+ rand.NextBytes(iv);
+
+ S2k s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
+
+ methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase)));
+ }
+
+ /// Add a public key encrypted session key to the encrypted object.
+ public void AddMethod(
+ PgpPublicKey key)
+ {
+ if (!key.IsEncryptionKey)
+ {
+ throw new ArgumentException("passed in key not an encryption key!");
+ }
+
+ methods.Add(new PubMethod(key));
+ }
+
+ private void AddCheckSum(
+ byte[] sessionInfo)
+ {
+ Debug.Assert(sessionInfo != null);
+ Debug.Assert(sessionInfo.Length >= 3);
+
+ int check = 0;
+
+ for (int i = 1; i < sessionInfo.Length - 2; i++)
+ {
+ check += sessionInfo[i];
+ }
+
+ sessionInfo[sessionInfo.Length - 2] = (byte)(check >> 8);
+ sessionInfo[sessionInfo.Length - 1] = (byte)(check);
+ }
+
+ private byte[] CreateSessionInfo(
+ SymmetricKeyAlgorithmTag algorithm,
+ KeyParameter key)
+ {
+ byte[] keyBytes = key.GetKey();
+ byte[] sessionInfo = new byte[keyBytes.Length + 3];
+ sessionInfo[0] = (byte) algorithm;
+ keyBytes.CopyTo(sessionInfo, 1);
+ AddCheckSum(sessionInfo);
+ return sessionInfo;
+ }
+
+ ///
+ ///
+ /// If buffer is non null stream assumed to be partial, otherwise the length will be used
+ /// to output a fixed length packet.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ private Stream Open(
+ Stream outStr,
+ long length,
+ byte[] buffer)
+ {
+ if (cOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (methods.Count == 0)
+ throw new InvalidOperationException("No encryption methods specified");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ pOut = new BcpgOutputStream(outStr);
+
+ KeyParameter key;
+
+ if (methods.Count == 1)
+ {
+ if (methods[0] is PbeMethod)
+ {
+ PbeMethod m = (PbeMethod)methods[0];
+
+ key = m.GetKey();
+ }
+ else
+ {
+ key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+
+ byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+ PubMethod m = (PubMethod)methods[0];
+
+ try
+ {
+ m.AddSessionInfo(sessionInfo, rand);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception encrypting session key", e);
+ }
+ }
+
+ pOut.WritePacket((ContainedPacket)methods[0]);
+ }
+ else // multiple methods
+ {
+ key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+ byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+
+ for (int i = 0; i != methods.Count; i++)
+ {
+ EncMethod m = (EncMethod)methods[i];
+
+ try
+ {
+ m.AddSessionInfo(sessionInfo, rand);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception encrypting session key", e);
+ }
+
+ pOut.WritePacket(m);
+ }
+ }
+
+ string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
+ if (cName == null)
+ {
+ throw new PgpException("null cipher specified");
+ }
+
+ try
+ {
+ if (withIntegrityPacket)
+ {
+ cName += "/CFB/NoPadding";
+ }
+ else
+ {
+ cName += "/OpenPGPCFB/NoPadding";
+ }
+
+ c = CipherUtilities.GetCipher(cName);
+
+ // TODO Confirm the IV should be all zero bytes (not inLineIv - see below)
+ byte[] iv = new byte[c.GetBlockSize()];
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand));
+
+ if (buffer == null)
+ {
+ //
+ // we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected
+ //
+ if (withIntegrityPacket)
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
+ pOut.WriteByte(1); // version number
+ }
+ else
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat);
+ }
+ }
+ else
+ {
+ if (withIntegrityPacket)
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer);
+ pOut.WriteByte(1); // version number
+ }
+ else
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
+ }
+ }
+
+ int blockSize = c.GetBlockSize();
+ byte[] inLineIv = new byte[blockSize + 2];
+ rand.NextBytes(inLineIv, 0, blockSize);
+ Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2);
+
+ Stream myOut = cOut = new CipherStream(pOut, null, c);
+
+ if (withIntegrityPacket)
+ {
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+ myOut = digestOut = new DigestStream(myOut, null, digest);
+ }
+
+ myOut.Write(inLineIv, 0, inLineIv.Length);
+
+ return new WrappedGeneratorStream(this, myOut);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ ///
+ ///
+ /// Return an output stream which will encrypt the data as it is written to it.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ long length)
+ {
+ return Open(outStr, length, null);
+ }
+
+ ///
+ ///
+ /// Return an output stream which will encrypt the data as it is written to it.
+ /// The stream will be written out in chunks according to the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// Note: if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ byte[] buffer)
+ {
+ return Open(outStr, 0, buffer);
+ }
+
+ ///
+ ///
+ /// Close off the encrypted object - this is equivalent to calling Close() on the stream
+ /// returned by the Open() method.
+ ///
+ ///
+ /// Note: This does not close the underlying output stream, only the stream on top of
+ /// it created by the Open() method.
+ ///
+ ///
+ public void Close()
+ {
+ if (cOut != null)
+ {
+ // TODO Should this all be under the try/catch block?
+ if (digestOut != null)
+ {
+ //
+ // hand code a mod detection packet
+ //
+ BcpgOutputStream bOut = new BcpgOutputStream(
+ digestOut, PacketTag.ModificationDetectionCode, 20);
+
+ bOut.Flush();
+ digestOut.Flush();
+
+ // TODO
+ byte[] dig = DigestUtilities.DoFinal(digestOut.WriteDigest());
+ cOut.Write(dig, 0, dig.Length);
+ }
+
+ cOut.Flush();
+
+ try
+ {
+ pOut.Write(c.DoFinal());
+ pOut.Finish();
+ }
+ catch (Exception e)
+ {
+ throw new IOException(e.Message, e);
+ }
+
+ cOut = null;
+ pOut = null;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpEncryptedDataList.cs b/src/core/srcbc/openpgp/PgpEncryptedDataList.cs
new file mode 100644
index 0000000..315e1c5
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpEncryptedDataList.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A holder for a list of PGP encryption method packets.
+ public class PgpEncryptedDataList
+ : PgpObject
+ {
+ private ArrayList list = new ArrayList();
+ private InputStreamPacket data;
+
+ public PgpEncryptedDataList(
+ BcpgInputStream bcpgInput)
+ {
+ while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession
+ || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey)
+ {
+ list.Add(bcpgInput.ReadPacket());
+ }
+
+ data = (InputStreamPacket)bcpgInput.ReadPacket();
+
+ for (int i = 0; i != list.Count; i++)
+ {
+ if (list[i] is SymmetricKeyEncSessionPacket)
+ {
+ list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket) list[i], data);
+ }
+ else
+ {
+ list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket) list[i], data);
+ }
+ }
+ }
+
+ public PgpEncryptedData this[int index]
+ {
+ get { return (PgpEncryptedData) list[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public object Get(int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return list.Count; }
+ }
+
+ public int Count
+ {
+ get { return list.Count; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return list.Count == 0; }
+ }
+
+ public IEnumerable GetEncryptedDataObjects()
+ {
+ return new EnumerableProxy(list);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpException.cs b/src/core/srcbc/openpgp/PgpException.cs
new file mode 100644
index 0000000..067ade9
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpException.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generic exception class for PGP encoding/decoding problems.
+ public class PgpException
+ : Exception
+ {
+ public PgpException() : base() {}
+ public PgpException(string message) : base(message) {}
+ public PgpException(string message, Exception exception) : base(message, exception) {}
+
+ [Obsolete("Use InnerException property")]
+ public Exception UnderlyingException
+ {
+ get { return InnerException; }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpExperimental.cs b/src/core/srcbc/openpgp/PgpExperimental.cs
new file mode 100644
index 0000000..8cfac3e
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpExperimental.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class PgpExperimental
+ : PgpObject
+ {
+ private readonly ExperimentalPacket p;
+
+ public PgpExperimental(
+ BcpgInputStream bcpgIn)
+ {
+ p = (ExperimentalPacket) bcpgIn.ReadPacket();
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpKeyFlags.cs b/src/core/srcbc/openpgp/PgpKeyFlags.cs
new file mode 100644
index 0000000..49cb7cb
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpKeyFlags.cs
@@ -0,0 +1,13 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Key flag values for the KeyFlags subpacket.
+ public abstract class PgpKeyFlags
+ {
+ public const int CanCertify = 0x01; // This key may be used to certify other keys.
+ public const int CanSign = 0x02; // This key may be used to sign data.
+ public const int CanEncryptCommunications = 0x04; // This key may be used to encrypt communications.
+ public const int CanEncryptStorage = 0x08; // This key may be used to encrypt storage.
+ public const int MaybeSplit = 0x10; // The private component of this key may have been split by a secret-sharing mechanism.
+ public const int MaybeShared = 0x80; // The private component of this key may be in the possession of more than one person.
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpKeyPair.cs b/src/core/srcbc/openpgp/PgpKeyPair.cs
new file mode 100644
index 0000000..d4aa9ad
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpKeyPair.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// General class to handle JCA key pairs and convert them into OpenPGP ones.
+ ///
+ /// A word for the unwary, the KeyId for an OpenPGP public key is calculated from
+ /// a hash that includes the time of creation, if you pass a different date to the
+ /// constructor below with the same public private key pair the KeyIs will not be the
+ /// same as for previous generations of the key, so ideally you only want to do
+ /// this once.
+ ///
+ ///
+ public class PgpKeyPair
+ {
+ private readonly PgpPublicKey pub;
+ private readonly PgpPrivateKey priv;
+
+ public PgpKeyPair(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricCipherKeyPair keyPair,
+ DateTime time)
+ : this(algorithm, keyPair.Public, keyPair.Private, time)
+ {
+ }
+
+ public PgpKeyPair(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time)
+ {
+ this.pub = new PgpPublicKey(algorithm, pubKey, time);
+ this.priv = new PgpPrivateKey(privKey, pub.KeyId);
+ }
+
+ /// Create a key pair from a PgpPrivateKey and a PgpPublicKey.
+ /// The public key.
+ /// The private key.
+ public PgpKeyPair(
+ PgpPublicKey pub,
+ PgpPrivateKey priv)
+ {
+ this.pub = pub;
+ this.priv = priv;
+ }
+
+ /// The keyId associated with this key pair.
+ public long KeyId
+ {
+ get { return pub.KeyId; }
+ }
+
+ public PgpPublicKey PublicKey
+ {
+ get { return pub; }
+ }
+
+ public PgpPrivateKey PrivateKey
+ {
+ get { return priv; }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs b/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs
new file mode 100644
index 0000000..a423762
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Generator for a PGP master and subkey ring.
+ /// This class will generate both the secret and public key rings
+ ///
+ public class PgpKeyRingGenerator
+ {
+ private ArrayList keys = new ArrayList();
+ private string id;
+ private SymmetricKeyAlgorithmTag encAlgorithm;
+ private int certificationLevel;
+ private char[] passPhrase;
+ private bool useSha1;
+ private PgpKeyPair masterKey;
+ private PgpSignatureSubpacketVector hashedPacketVector;
+ private PgpSignatureSubpacketVector unhashedPacketVector;
+ private SecureRandom rand;
+
+ ///
+ /// Create a new key ring generator using old style checksumming. It is recommended to use
+ /// SHA1 checksumming where possible.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The passPhrase to be used to protect secret keys.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ {
+ this.certificationLevel = certificationLevel;
+ this.masterKey = masterKey;
+ this.id = id;
+ this.encAlgorithm = encAlgorithm;
+ this.passPhrase = passPhrase;
+ this.useSha1 = useSha1;
+ this.hashedPacketVector = hashedPackets;
+ this.unhashedPacketVector = unhashedPackets;
+ this.rand = rand;
+
+ keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
+ }
+
+ /// Add a subkey to the key ring to be generated with default certification.
+ public void AddSubKey(
+ PgpKeyPair keyPair)
+ {
+ AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
+ }
+
+ ///
+ /// Add a subkey with specific hashed and unhashed packets associated with it and
+ /// default certification.
+ ///
+ /// Public/private key pair.
+ /// Hashed packet values to be included in certification.
+ /// Unhashed packets values to be included in certification.
+ ///
+ public void AddSubKey(
+ PgpKeyPair keyPair,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets)
+ {
+ try
+ {
+ PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+ masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ ArrayList subSigs = new ArrayList();
+
+ subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+
+ keys.Add(new PgpSecretKey(keyPair, null, subSigs, encAlgorithm, passPhrase, useSha1, rand));
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception adding subkey: ", e);
+ }
+ }
+
+ /// Return the secret key ring.
+ public PgpSecretKeyRing GenerateSecretKeyRing()
+ {
+ return new PgpSecretKeyRing(keys);
+ }
+
+ /// Return the public key ring that corresponds to the secret key ring.
+ public PgpPublicKeyRing GeneratePublicKeyRing()
+ {
+ ArrayList pubKeys = new ArrayList();
+
+ IEnumerator enumerator = keys.GetEnumerator();
+ enumerator.MoveNext();
+
+ PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current;
+ pubKeys.Add(pgpSecretKey.PublicKey);
+
+ while (enumerator.MoveNext())
+ {
+ pgpSecretKey = (PgpSecretKey) enumerator.Current;
+
+ PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey);
+ k.publicPk = new PublicSubkeyPacket(
+ k.Algorithm, k.CreationTime, k.publicPk.Key);
+
+ pubKeys.Add(k);
+ }
+
+ return new PgpPublicKeyRing(pubKeys);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpKeyValidationException.cs b/src/core/srcbc/openpgp/PgpKeyValidationException.cs
new file mode 100644
index 0000000..81bb818
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpKeyValidationException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Thrown if the key checksum is invalid.
+ ///
+ public class PgpKeyValidationException
+ : PgpException
+ {
+ public PgpKeyValidationException() : base() {}
+ public PgpKeyValidationException(string message) : base(message) {}
+ public PgpKeyValidationException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpLiteralData.cs b/src/core/srcbc/openpgp/PgpLiteralData.cs
new file mode 100644
index 0000000..10b7fc0
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpLiteralData.cs
@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for processing literal data objects.
+ public class PgpLiteralData
+ : PgpObject
+ {
+ public const char Binary = 'b';
+ public const char Text = 't';
+
+ /// The special name indicating a "for your eyes only" packet.
+ public const string Console = "_CONSOLE";
+
+ private LiteralDataPacket data;
+
+ public PgpLiteralData(
+ BcpgInputStream bcpgInput)
+ {
+ data = (LiteralDataPacket) bcpgInput.ReadPacket();
+ }
+
+ /// The format of the data stream - Binary or Text
+ public int Format
+ {
+ get { return data.Format; }
+ }
+
+ /// The file name that's associated with the data stream.
+ public string FileName
+ {
+ get { return data.FileName; }
+ }
+
+ /// The modification time for the file.
+ public DateTime ModificationTime
+ {
+ get { return DateTimeUtilities.UnixMsToDateTime(data.ModificationTime); }
+ }
+
+ /// The raw input stream for the data stream.
+ public Stream GetInputStream()
+ {
+ return data.GetInputStream();
+ }
+
+ /// The input stream representing the data stream.
+ public Stream GetDataStream()
+ {
+ return GetInputStream();
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpLiteralDataGenerator.cs b/src/core/srcbc/openpgp/PgpLiteralDataGenerator.cs
new file mode 100644
index 0000000..e00394d
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpLiteralDataGenerator.cs
@@ -0,0 +1,177 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for producing literal data packets.
+ public class PgpLiteralDataGenerator
+ : IStreamGenerator
+ {
+ public const char Binary = PgpLiteralData.Binary;
+ public const char Text = PgpLiteralData.Text;
+
+ /// The special name indicating a "for your eyes only" packet.
+ public const string Console = PgpLiteralData.Console;
+
+ private BcpgOutputStream pkOut;
+ private bool oldFormat;
+
+ public PgpLiteralDataGenerator()
+ {
+ }
+
+ ///
+ /// Generates literal data objects in the old format.
+ /// This is important if you need compatibility with PGP 2.6.x.
+ ///
+ /// If true, uses old format.
+ public PgpLiteralDataGenerator(
+ bool oldFormat)
+ {
+ this.oldFormat = oldFormat;
+ }
+
+ private void WriteHeader(
+ BcpgOutputStream outStr,
+ char format,
+ string name,
+ long modificationTime)
+ {
+ byte[] asciiName = Strings.ToByteArray(name);
+
+ outStr.Write(
+ (byte) format,
+ (byte) asciiName.Length);
+
+ outStr.Write(asciiName);
+
+ long modDate = modificationTime / 1000L;
+
+ outStr.Write(
+ (byte)(modDate >> 24),
+ (byte)(modDate >> 16),
+ (byte)(modDate >> 8),
+ (byte)modDate);
+ }
+
+ ///
+ ///
+ /// Open a literal data packet, returning a stream to store the data inside the packet.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The name of the 'file'.
+ /// The length of the data we will write.
+ /// The time of last modification we want stored.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ string name,
+ long length,
+ DateTime modificationTime)
+ {
+ if (pkOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ // Do this first, since it might throw an exception
+ long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
+
+ pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData,
+ length + 2 + name.Length + 4, oldFormat);
+
+ WriteHeader(pkOut, format, name, unixMs);
+
+ return new WrappedGeneratorStream(this, pkOut);
+ }
+
+ ///
+ ///
+ /// Open a literal data packet, returning a stream to store the data inside the packet,
+ /// as an indefinite length stream. The stream is written out as a series of partial
+ /// packets with a chunk size determined by the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// Note: if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The name of the 'file'.
+ /// The time of last modification we want stored.
+ /// The buffer to use for collecting data to put into chunks.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ string name,
+ DateTime modificationTime,
+ byte[] buffer)
+ {
+ if (pkOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ // Do this first, since it might throw an exception
+ long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
+
+ pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
+
+ WriteHeader(pkOut, format, name, unixMs);
+
+ return new WrappedGeneratorStream(this, pkOut);
+ }
+
+ ///
+ ///
+ /// Open a literal data packet for the passed in FileInfo object, returning
+ /// an output stream for saving the file contents.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr.
+ ///
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The FileInfo object containg the packet details.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ FileInfo file)
+ {
+ return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
+ }
+
+ ///
+ /// Close the literal data packet - this is equivalent to calling Close()
+ /// on the stream returned by the Open() method.
+ ///
+ public void Close()
+ {
+ if (pkOut != null)
+ {
+ pkOut.Finish();
+ pkOut.Flush();
+ pkOut = null;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpMarker.cs b/src/core/srcbc/openpgp/PgpMarker.cs
new file mode 100644
index 0000000..3e8f27f
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpMarker.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// A PGP marker packet - in general these should be ignored other than where
+ /// the idea is to preserve the original input stream.
+ ///
+ public class PgpMarker
+ : PgpObject
+ {
+ private readonly MarkerPacket p;
+
+ public PgpMarker(
+ BcpgInputStream bcpgIn)
+ {
+ p = (MarkerPacket) bcpgIn.ReadPacket();
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpObjectFactory.cs b/src/core/srcbc/openpgp/PgpObjectFactory.cs
new file mode 100644
index 0000000..ae23754
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpObjectFactory.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// General class for reading a PGP object stream.
+ ///
+ /// Note: if this class finds a PgpPublicKey or a PgpSecretKey it
+ /// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each
+ /// key found. If all you are trying to do is read a key ring file use
+ /// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.
+ ///
+ public class PgpObjectFactory
+ {
+ private readonly BcpgInputStream bcpgIn;
+
+ public PgpObjectFactory(
+ Stream inputStream)
+ {
+ this.bcpgIn = BcpgInputStream.Wrap(inputStream);
+ }
+
+ public PgpObjectFactory(
+ byte[] bytes)
+ : this(new MemoryStream(bytes, false))
+ {
+ }
+
+ /// Return the next object in the stream, or null if the end is reached.
+ /// On a parse error
+ public PgpObject NextPgpObject()
+ {
+ PacketTag tag = bcpgIn.NextPacketTag();
+
+ if ((int) tag == -1) return null;
+
+ switch (tag)
+ {
+ case PacketTag.Signature:
+ {
+ ArrayList l = new ArrayList();
+
+ while (bcpgIn.NextPacketTag() == PacketTag.Signature)
+ {
+ try
+ {
+ l.Add(new PgpSignature(bcpgIn));
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create signature object: " + e);
+ }
+ }
+
+ return new PgpSignatureList(
+ (PgpSignature[]) l.ToArray(typeof(PgpSignature)));
+ }
+ case PacketTag.SecretKey:
+ try
+ {
+ return new PgpSecretKeyRing(bcpgIn);
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create secret key object: " + e);
+ }
+ case PacketTag.PublicKey:
+ return new PgpPublicKeyRing(bcpgIn);
+ case PacketTag.CompressedData:
+ return new PgpCompressedData(bcpgIn);
+ case PacketTag.LiteralData:
+ return new PgpLiteralData(bcpgIn);
+ case PacketTag.PublicKeyEncryptedSession:
+ case PacketTag.SymmetricKeyEncryptedSessionKey:
+ return new PgpEncryptedDataList(bcpgIn);
+ case PacketTag.OnePassSignature:
+ {
+ ArrayList l = new ArrayList();
+
+ while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
+ {
+ try
+ {
+ l.Add(new PgpOnePassSignature(bcpgIn));
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create one pass signature object: " + e);
+ }
+ }
+
+ return new PgpOnePassSignatureList(
+ (PgpOnePassSignature[]) l.ToArray(typeof(PgpOnePassSignature)));
+ }
+ case PacketTag.Marker:
+ return new PgpMarker(bcpgIn);
+ case PacketTag.Experimental1:
+ case PacketTag.Experimental2:
+ case PacketTag.Experimental3:
+ case PacketTag.Experimental4:
+ return new PgpExperimental(bcpgIn);
+ }
+
+ throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
+ }
+
+ [Obsolete("Use NextPgpObject() instead")]
+ public object NextObject()
+ {
+ return NextPgpObject();
+ }
+
+ ///
+ /// Return all available objects in a list.
+ ///
+ /// An IList containing all objects from this factory, in order.
+ public IList AllPgpObjects()
+ {
+ ArrayList result = new ArrayList();
+ PgpObject pgpObject;
+ while ((pgpObject = NextPgpObject()) != null)
+ {
+ result.Add(pgpObject);
+ }
+ return result;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpOnePassSignature.cs b/src/core/srcbc/openpgp/PgpOnePassSignature.cs
new file mode 100644
index 0000000..c8c4128
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpOnePassSignature.cs
@@ -0,0 +1,179 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A one pass signature object.
+ public class PgpOnePassSignature
+ {
+ private OnePassSignaturePacket sigPack;
+ private int signatureType;
+ private ISigner sig;
+ private byte lastb;
+
+ internal PgpOnePassSignature(
+ BcpgInputStream bcpgInput)
+ : this((OnePassSignaturePacket) bcpgInput.ReadPacket())
+ {
+ }
+
+ internal PgpOnePassSignature(
+ OnePassSignaturePacket sigPack)
+ {
+ this.sigPack = sigPack;
+ this.signatureType = sigPack.SignatureType;
+
+ try
+ {
+ this.sig = SignerUtilities.GetSigner(
+ PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't set up signature object.", e);
+ }
+ }
+
+ /// Initialise the signature object for verification.
+ public void InitVerify(
+ PgpPublicKey pubKey)
+ {
+ lastb = 0;
+
+ try
+ {
+ sig.Init(false, pubKey.GetKey());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ sig.Update(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ sig.Update(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ sig.Update((byte)'\r');
+ sig.Update((byte)'\n');
+ }
+
+ public void Update(
+ byte[] bytes)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ for (int i = 0; i != bytes.Length; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, 0, bytes.Length);
+ }
+ }
+
+ public void Update(
+ byte[] bytes,
+ int off,
+ int length)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + length;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, off, length);
+ }
+ }
+
+ /// Verify the calculated signature against the passed in PgpSignature.
+ public bool Verify(
+ PgpSignature pgpSig)
+ {
+ byte[] trailer = pgpSig.GetSignatureTrailer();
+
+ sig.BlockUpdate(trailer, 0, trailer.Length);
+
+ return sig.VerifySignature(pgpSig.GetSignature());
+ }
+
+ public long KeyId
+ {
+ get { return sigPack.KeyId; }
+ }
+
+ public int SignatureType
+ {
+ get { return sigPack.SignatureType; }
+ }
+
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return sigPack.HashAlgorithm; }
+ }
+
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return sigPack.KeyAlgorithm; }
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpOnePassSignatureList.cs b/src/core/srcbc/openpgp/PgpOnePassSignatureList.cs
new file mode 100644
index 0000000..6f15c86
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpOnePassSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Holder for a list of PgpOnePassSignature objects.
+ public class PgpOnePassSignatureList
+ : PgpObject
+ {
+ private readonly PgpOnePassSignature[] sigs;
+
+ public PgpOnePassSignatureList(
+ PgpOnePassSignature[] sigs)
+ {
+ this.sigs = (PgpOnePassSignature[]) sigs.Clone();
+ }
+
+ public PgpOnePassSignatureList(
+ PgpOnePassSignature sig)
+ {
+ this.sigs = new PgpOnePassSignature[]{ sig };
+ }
+
+ public PgpOnePassSignature this[int index]
+ {
+ get { return sigs[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public PgpOnePassSignature Get(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return sigs.Length; }
+ }
+
+ public int Count
+ {
+ get { return sigs.Length; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return (sigs.Length == 0); }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPbeEncryptedData.cs b/src/core/srcbc/openpgp/PgpPbeEncryptedData.cs
new file mode 100644
index 0000000..66cbec4
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPbeEncryptedData.cs
@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A password based encryption object.
+ public class PgpPbeEncryptedData
+ : PgpEncryptedData
+ {
+ private readonly SymmetricKeyEncSessionPacket keyData;
+
+ internal PgpPbeEncryptedData(
+ SymmetricKeyEncSessionPacket keyData,
+ InputStreamPacket encData)
+ : base(encData)
+ {
+ this.keyData = keyData;
+ }
+
+ /// Return the raw input stream for the data stream.
+ public override Stream GetInputStream()
+ {
+ return encData.GetInputStream();
+ }
+
+ /// Return the decrypted input stream, using the passed in passphrase.
+ public Stream GetDataStream(
+ char[] passPhrase)
+ {
+ try
+ {
+ SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
+
+ KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(
+ keyAlgorithm, keyData.S2k, passPhrase);
+
+
+ byte[] secKeyData = keyData.GetSecKeyData();
+ if (secKeyData != null && secKeyData.Length > 0)
+ {
+ IBufferedCipher keyCipher = CipherUtilities.GetCipher(
+ PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding");
+
+ keyCipher.Init(false,
+ new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()]));
+
+ byte[] keyBytes = keyCipher.DoFinal(secKeyData);
+
+ keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0];
+
+ key = ParameterUtilities.CreateKeyParameter(
+ PgpUtilities.GetSymmetricCipherName(keyAlgorithm),
+ keyBytes, 1, keyBytes.Length - 1);
+ }
+
+
+ IBufferedCipher c = CreateStreamCipher(keyAlgorithm);
+
+ byte[] iv = new byte[c.GetBlockSize()];
+
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, null));
+
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ truncStream = new TruncatedStream(encStream);
+
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ encStream = new DigestStream(truncStream, digest, null);
+ }
+
+ if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ int v1 = encStream.ReadByte();
+ int v2 = encStream.ReadByte();
+
+ if (v1 < 0 || v2 < 0)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+
+ // Note: the oracle attack on the "quick check" bytes is not deemed
+ // a security risk for PBE (see PgpPublicKeyEncryptedData)
+
+ bool repeatCheckPassed =
+ iv[iv.Length - 2] == (byte)v1
+ && iv[iv.Length - 1] == (byte)v2;
+
+ // Note: some versions of PGP appear to produce 0 for the extra
+ // bytes rather than repeating the two previous bytes
+ bool zeroesCheckPassed =
+ v1 == 0
+ && v2 == 0;
+
+ if (!repeatCheckPassed && !zeroesCheckPassed)
+ {
+ throw new PgpDataValidationException("quick check failed.");
+ }
+
+
+ return encStream;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ private IBufferedCipher CreateStreamCipher(
+ SymmetricKeyAlgorithmTag keyAlgorithm)
+ {
+ string mode = (encData is SymmetricEncIntegrityPacket)
+ ? "CFB"
+ : "OpenPGPCFB";
+
+ string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm)
+ + "/" + mode + "/NoPadding";
+
+ return CipherUtilities.GetCipher(cName);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPrivateKey.cs b/src/core/srcbc/openpgp/PgpPrivateKey.cs
new file mode 100644
index 0000000..e4f5853
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPrivateKey.cs
@@ -0,0 +1,42 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to contain a private key for use with other OpenPGP objects.
+ public class PgpPrivateKey
+ {
+ private readonly long keyId;
+ private readonly AsymmetricKeyParameter privateKey;
+
+ ///
+ /// Create a PgpPrivateKey from a regular private key and the ID of its
+ /// associated public key.
+ ///
+ /// Private key to use.
+ /// ID of the corresponding public key.
+ public PgpPrivateKey(
+ AsymmetricKeyParameter privateKey,
+ long keyId)
+ {
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("Expected a private key", "privateKey");
+
+ this.privateKey = privateKey;
+ this.keyId = keyId;
+ }
+
+ /// The keyId associated with the contained private key.
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ /// The contained private key.
+ public AsymmetricKeyParameter Key
+ {
+ get { return privateKey; }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPublicKey.cs b/src/core/srcbc/openpgp/PgpPublicKey.cs
new file mode 100644
index 0000000..131ba28
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPublicKey.cs
@@ -0,0 +1,835 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to handle a PGP public key object.
+ public class PgpPublicKey
+ {
+ private static readonly int[] MasterKeyCertificationTypes = new int[]
+ {
+ PgpSignature.PositiveCertification,
+ PgpSignature.CasualCertification,
+ PgpSignature.NoCertification,
+ PgpSignature.DefaultCertification
+ };
+
+ private long keyId;
+ private byte[] fingerprint;
+ private int keyStrength;
+
+ internal PublicKeyPacket publicPk;
+ private TrustPacket trustPk;
+ private ArrayList keySigs = new ArrayList();
+ private ArrayList ids = new ArrayList();
+ private ArrayList idTrusts = new ArrayList();
+ private ArrayList idSigs = new ArrayList();
+ private ArrayList subSigs;
+
+ private void Init()
+ {
+ IBcpgKey key = publicPk.Key;
+
+ if (publicPk.Version <= 3)
+ {
+ RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
+
+ this.keyId = rK.Modulus.LongValue;
+
+ try
+ {
+ IDigest digest = DigestUtilities.GetDigest("MD5");
+
+ byte[] bytes = rK.Modulus.ToByteArrayUnsigned();
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+
+ bytes = rK.PublicExponent.ToByteArrayUnsigned();
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+
+ this.fingerprint = DigestUtilities.DoFinal(digest);
+ }
+ //catch (NoSuchAlgorithmException)
+ catch (Exception)
+ {
+ throw new IOException("can't find MD5");
+ }
+
+ this.keyStrength = rK.Modulus.BitLength;
+ }
+ else
+ {
+ byte[] kBytes = publicPk.GetEncodedContents();
+
+ try
+ {
+ IDigest digest = DigestUtilities.GetDigest("SHA1");
+
+ digest.Update(0x99);
+ digest.Update((byte)(kBytes.Length >> 8));
+ digest.Update((byte)kBytes.Length);
+ digest.BlockUpdate(kBytes, 0, kBytes.Length);
+ this.fingerprint = DigestUtilities.DoFinal(digest);
+ }
+ //catch (NoSuchAlgorithmException)
+ catch (Exception)
+ {
+ throw new IOException("can't find SHA1");
+ }
+
+ this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
+ | ((ulong)fingerprint[fingerprint.Length - 7] << 48)
+ | ((ulong)fingerprint[fingerprint.Length - 6] << 40)
+ | ((ulong)fingerprint[fingerprint.Length - 5] << 32)
+ | ((ulong)fingerprint[fingerprint.Length - 4] << 24)
+ | ((ulong)fingerprint[fingerprint.Length - 3] << 16)
+ | ((ulong)fingerprint[fingerprint.Length - 2] << 8)
+ | (ulong)fingerprint[fingerprint.Length - 1]);
+
+ if (key is RsaPublicBcpgKey)
+ {
+ this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
+ }
+ else if (key is DsaPublicBcpgKey)
+ {
+ this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
+ }
+ else if (key is ElGamalPublicBcpgKey)
+ {
+ this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
+ }
+ }
+ }
+
+ ///
+ /// Create a PgpPublicKey from the passed in lightweight one.
+ ///
+ ///
+ /// Note: the time passed in affects the value of the key's keyId, so you probably only want
+ /// to do this once for a lightweight key, or make sure you keep track of the time you used.
+ ///
+ /// Asymmetric algorithm type representing the public key.
+ /// Actual public key to associate.
+ /// Date of creation.
+ /// If pubKey is not public.
+ /// On key creation problem.
+ public PgpPublicKey(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ DateTime time)
+ {
+ if (pubKey.IsPrivate)
+ throw new ArgumentException("Expected a public key", "pubKey");
+
+ IBcpgKey bcpgKey;
+ if (pubKey is RsaKeyParameters)
+ {
+ RsaKeyParameters rK = (RsaKeyParameters) pubKey;
+
+ bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
+ }
+ else if (pubKey is DsaPublicKeyParameters)
+ {
+ DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey;
+ DsaParameters dP = dK.Parameters;
+
+ bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
+ }
+ else if (pubKey is ElGamalPublicKeyParameters)
+ {
+ ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
+ ElGamalParameters eS = eK.Parameters;
+
+ bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
+ }
+ else
+ {
+ throw new PgpException("unknown key class");
+ }
+
+ this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
+ this.ids = new ArrayList();
+ this.idSigs = new ArrayList();
+
+ try
+ {
+ Init();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception calculating keyId", e);
+ }
+ }
+
+ /// Constructor for a sub-key.
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ TrustPacket trustPk,
+ ArrayList sigs)
+ {
+ this.publicPk = publicPk;
+ this.trustPk = trustPk;
+ this.subSigs = sigs;
+
+ Init();
+ }
+
+ internal PgpPublicKey(
+ PgpPublicKey key,
+ TrustPacket trust,
+ ArrayList subSigs)
+ {
+ this.publicPk = key.publicPk;
+ this.trustPk = trust;
+ this.subSigs = subSigs;
+
+ this.fingerprint = key.fingerprint;
+ this.keyId = key.keyId;
+ this.keyStrength = key.keyStrength;
+ }
+
+ /// Copy constructor.
+ /// The public key to copy.
+ internal PgpPublicKey(
+ PgpPublicKey pubKey)
+ {
+ this.publicPk = pubKey.publicPk;
+
+ this.keySigs = new ArrayList(pubKey.keySigs);
+ this.ids = new ArrayList(pubKey.ids);
+ this.idTrusts = new ArrayList(pubKey.idTrusts);
+ this.idSigs = new ArrayList(pubKey.idSigs.Count);
+ for (int i = 0; i != pubKey.idSigs.Count; i++)
+ {
+ this.idSigs.Add(new ArrayList((ArrayList)pubKey.idSigs[i]));
+ }
+
+ if (pubKey.subSigs != null)
+ {
+ this.subSigs = new ArrayList(pubKey.subSigs.Count);
+ for (int i = 0; i != pubKey.subSigs.Count; i++)
+ {
+ this.subSigs.Add(pubKey.subSigs[i]);
+ }
+ }
+
+ this.fingerprint = pubKey.fingerprint;
+ this.keyId = pubKey.keyId;
+ this.keyStrength = pubKey.keyStrength;
+ }
+
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ TrustPacket trustPk,
+ ArrayList keySigs,
+ ArrayList ids,
+ ArrayList idTrusts,
+ ArrayList idSigs)
+ {
+ this.publicPk = publicPk;
+ this.trustPk = trustPk;
+ this.keySigs = keySigs;
+ this.ids = ids;
+ this.idTrusts = idTrusts;
+ this.idSigs = idSigs;
+
+ Init();
+ }
+
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ ArrayList ids,
+ ArrayList idSigs)
+ {
+ this.publicPk = publicPk;
+ this.ids = ids;
+ this.idSigs = idSigs;
+ Init();
+ }
+
+ /// The version of this key.
+ public int Version
+ {
+ get { return publicPk.Version; }
+ }
+
+ /// The creation time of this key.
+ public DateTime CreationTime
+ {
+ get { return publicPk.GetTime(); }
+ }
+
+ /// The number of valid days from creation time - zero means no expiry.
+ public int ValidDays
+ {
+ get
+ {
+ if (publicPk.Version > 3)
+ {
+ return (int)(GetValidSeconds() / (24 * 60 * 60));
+ }
+
+ return publicPk.ValidDays;
+ }
+ }
+
+ /// Return the trust data associated with the public key, if present.
+ /// A byte array with trust data, null otherwise.
+ public byte[] GetTrustData()
+ {
+ if (trustPk == null)
+ {
+ return null;
+ }
+
+ return trustPk.GetLevelAndTrustAmount();
+ }
+
+ /// The number of valid seconds from creation time - zero means no expiry.
+ public long GetValidSeconds()
+ {
+ if (publicPk.Version > 3)
+ {
+ if (IsMasterKey)
+ {
+ for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
+ {
+ long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
+
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+ }
+ else
+ {
+ long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
+
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+
+ return 0;
+ }
+
+ return (long) publicPk.ValidDays * 24 * 60 * 60;
+ }
+
+ private long GetExpirationTimeFromSig(
+ bool selfSigned,
+ int signatureType)
+ {
+ foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
+ {
+ if (!selfSigned || sig.KeyId == KeyId)
+ {
+ PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+
+ if (hashed != null)
+ {
+ return hashed.GetKeyExpirationTime();
+ }
+
+ return 0;
+ }
+ }
+
+ return -1;
+ }
+
+ /// The keyId associated with the public key.
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ /// The fingerprint of the key
+ public byte[] GetFingerprint()
+ {
+ return (byte[]) fingerprint.Clone();
+ }
+
+
+ /// True, if this key is marked as suitable for encryption
+ /// True, if this key is marked as suitable for using for encryption.
+ public bool IsEncryptionKey
+ {
+ get
+ {
+ switch (publicPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /// True, if this is a master key.
+ public bool IsMasterKey
+ {
+ get { return subSigs == null; }
+ }
+
+ /// The algorithm code associated with the public key.
+ public PublicKeyAlgorithmTag Algorithm
+ {
+ get { return publicPk.Algorithm; }
+ }
+
+ /// The strength of the key in bits.
+ public int BitStrength
+ {
+ get { return keyStrength; }
+ }
+
+ /// The public key contained in the object.
+ /// A lightweight public key.
+ /// If the key algorithm is not recognised.
+ public AsymmetricKeyParameter GetKey()
+ {
+ try
+ {
+ switch (publicPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key;
+ return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key;
+ return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key;
+ return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
+ default:
+ throw new PgpException("unknown public key algorithm encountered");
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception constructing public key", e);
+ }
+ }
+
+ /// Allows enumeration of any user IDs associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable GetUserIds()
+ {
+ ArrayList temp = new ArrayList();
+
+ foreach (object o in ids)
+ {
+ if (o is string)
+ {
+ temp.Add(o);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of any user attribute vectors associated with the key.
+ /// An IEnumerable of PgpUserAttributeSubpacketVector objects.
+ public IEnumerable GetUserAttributes()
+ {
+ ArrayList temp = new ArrayList();
+
+ foreach (object o in ids)
+ {
+ if (o is PgpUserAttributeSubpacketVector)
+ {
+ temp.Add(o);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of any signatures associated with the passed in id.
+ /// The ID to be matched.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesForId(
+ string id)
+ {
+ if (id == null)
+ throw new ArgumentNullException("id");
+
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (id.Equals(ids[i]))
+ {
+ return new EnumerableProxy((ArrayList) idSigs[i]);
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of signatures associated with the passed in user attributes.
+ /// The vector of user attributes to be matched.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesForUserAttribute(
+ PgpUserAttributeSubpacketVector userAttributes)
+ {
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (userAttributes.Equals(ids[i]))
+ {
+ return new EnumerableProxy((ArrayList) idSigs[i]);
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of signatures of the passed in type that are on this key.
+ /// The type of the signature to be returned.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesOfType(
+ int signatureType)
+ {
+ ArrayList temp = new ArrayList();
+
+ foreach (PgpSignature sig in GetSignatures())
+ {
+ if (sig.SignatureType == signatureType)
+ {
+ temp.Add(sig);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of all signatures/certifications associated with this key.
+ /// An IEnumerable with all signatures/certifications.
+ public IEnumerable GetSignatures()
+ {
+ ArrayList sigs;
+ if (subSigs != null)
+ {
+ sigs = subSigs;
+ }
+ else
+ {
+ sigs = new ArrayList(keySigs);
+
+ foreach (ICollection extraSigs in idSigs)
+ {
+ sigs.AddRange(extraSigs);
+ }
+ }
+
+ return new EnumerableProxy(sigs);
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ Encode(bOut);
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ bcpgOut.WritePacket(publicPk);
+ if (trustPk != null)
+ {
+ bcpgOut.WritePacket(trustPk);
+ }
+
+ if (subSigs == null) // not a sub-key
+ {
+ foreach (PgpSignature keySig in keySigs)
+ {
+ keySig.Encode(bcpgOut);
+ }
+
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (ids[i] is string)
+ {
+ string id = (string) ids[i];
+
+ bcpgOut.WritePacket(new UserIdPacket(id));
+ }
+ else
+ {
+ PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
+ bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+ }
+
+ if (idTrusts[i] != null)
+ {
+ bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
+ }
+
+ foreach (PgpSignature sig in (ArrayList) idSigs[i])
+ {
+ sig.Encode(bcpgOut);
+ }
+ }
+ }
+ else
+ {
+ foreach (PgpSignature subSig in subSigs)
+ {
+ subSig.Encode(bcpgOut);
+ }
+ }
+ }
+
+ /// Check whether this (sub)key has a revocation signature on it.
+ /// True, if this (sub)key has been revoked.
+ public bool IsRevoked()
+ {
+ int ns = 0;
+ bool revoked = false;
+ if (IsMasterKey) // Master key
+ {
+ while (!revoked && (ns < keySigs.Count))
+ {
+ if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation)
+ {
+ revoked = true;
+ }
+ }
+ }
+ else // Sub-key
+ {
+ while (!revoked && (ns < subSigs.Count))
+ {
+ if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation)
+ {
+ revoked = true;
+ }
+ }
+ }
+ return revoked;
+ }
+
+ /// Add a certification for an id to the given public key.
+ /// The key the certification is to be added to.
+ /// The ID the certification is associated with.
+ /// The new certification.
+ /// The re-certified key.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ string id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ ArrayList sigList = null;
+
+ for (int i = 0; i != returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ sigList = (ArrayList) returnKey.idSigs[i];
+ }
+ }
+
+ if (sigList != null)
+ {
+ sigList.Add(certification);
+ }
+ else
+ {
+ sigList = new ArrayList();
+
+ sigList.Add(certification);
+ returnKey.ids.Add(id);
+ returnKey.idTrusts.Add(null);
+ returnKey.idSigs.Add(sigList);
+ }
+
+ return returnKey;
+ }
+
+ /// Add a certification for the given UserAttributeSubpackets to the given public key.
+ /// The key the certification is to be added to.
+ /// The attributes the certification is associated with.
+ /// The new certification.
+ /// The re-certified key.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ IList sigList = null;
+
+ for (int i = 0; i != returnKey.ids.Count; i++)
+ {
+ if (userAttributes.Equals(returnKey.ids[i]))
+ {
+ sigList = (IList) returnKey.idSigs[i];
+ }
+ }
+
+ if (sigList != null)
+ {
+ sigList.Add(certification);
+ }
+ else
+ {
+ sigList = new ArrayList();
+ sigList.Add(certification);
+ returnKey.ids.Add(userAttributes);
+ returnKey.idTrusts.Add(null);
+ returnKey.idSigs.Add(sigList);
+ }
+
+ return returnKey;
+ }
+
+ ///
+ /// Remove any certifications associated with a user attribute subpacket on a key.
+ ///
+ /// The key the certifications are to be removed from.
+ /// The attributes to be removed.
+ ///
+ /// The re-certified key, or null if the user attribute subpacket was not found on the key.
+ ///
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ bool found = false;
+
+ for (int i = 0; i < returnKey.ids.Count; i++)
+ {
+ if (userAttributes.Equals(returnKey.ids[i]))
+ {
+ found = true;
+ returnKey.ids.RemoveAt(i);
+ returnKey.idTrusts.RemoveAt(i);
+ returnKey.idSigs.RemoveAt(i);
+ }
+ }
+
+ if (!found)
+ {
+ return null;
+ }
+
+ return returnKey;
+ }
+
+ /// Remove any certifications associated with a given ID on a key.
+ /// The key the certifications are to be removed from.
+ /// The ID that is to be removed.
+ /// The re-certified key, or null if the ID was not found on the key.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ string id)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ bool found = false;
+
+ for (int i = 0; i < returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ found = true;
+ returnKey.ids.RemoveAt(i);
+ returnKey.idTrusts.RemoveAt(i);
+ returnKey.idSigs.RemoveAt(i);
+ }
+ }
+
+ return found ? returnKey : null;
+ }
+
+ /// Remove any certifications associated with a given ID on a key.
+ /// The key the certifications are to be removed from.
+ /// The ID that the certfication is to be removed from.
+ /// The certfication to be removed.
+ /// The re-certified key, or null if the certification was not found.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ string id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ bool found = false;
+
+ for (int i = 0; i < returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ ArrayList certs = (ArrayList) returnKey.idSigs[i];
+ found = certs.Contains(certification);
+
+ if (found)
+ {
+ certs.Remove(certification);
+ }
+ }
+ }
+
+ return found ? returnKey : null;
+ }
+
+ /// Add a revocation or some other key certification to a key.
+ /// The key the revocation is to be added to.
+ /// The key signature to be added.
+ /// The new changed public key object.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ PgpSignature certification)
+ {
+ if (key.IsMasterKey)
+ {
+ if (certification.SignatureType == PgpSignature.SubkeyRevocation)
+ {
+ throw new ArgumentException("signature type incorrect for master key revocation.");
+ }
+ }
+ else
+ {
+ if (certification.SignatureType == PgpSignature.KeyRevocation)
+ {
+ throw new ArgumentException("signature type incorrect for sub-key revocation.");
+ }
+ }
+
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+
+ if (returnKey.subSigs != null)
+ {
+ returnKey.subSigs.Add(certification);
+ }
+ else
+ {
+ returnKey.keySigs.Add(certification);
+ }
+
+ return returnKey;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPublicKeyEncryptedData.cs b/src/core/srcbc/openpgp/PgpPublicKeyEncryptedData.cs
new file mode 100644
index 0000000..d6b0fec
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPublicKeyEncryptedData.cs
@@ -0,0 +1,233 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A public key encrypted data object.
+ public class PgpPublicKeyEncryptedData
+ : PgpEncryptedData
+ {
+ private PublicKeyEncSessionPacket keyData;
+
+ internal PgpPublicKeyEncryptedData(
+ PublicKeyEncSessionPacket keyData,
+ InputStreamPacket encData)
+ : base(encData)
+ {
+ this.keyData = keyData;
+ }
+
+ private static IBufferedCipher GetKeyCipher(
+ PublicKeyAlgorithmTag algorithm)
+ {
+ try
+ {
+ switch (algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ return CipherUtilities.GetCipher("RSA//PKCS1Padding");
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + algorithm);
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ private bool ConfirmCheckSum(
+ byte[] sessionInfo)
+ {
+ int check = 0;
+
+ for (int i = 1; i != sessionInfo.Length - 2; i++)
+ {
+ check += sessionInfo[i] & 0xff;
+ }
+
+ return (sessionInfo[sessionInfo.Length - 2] == (byte)(check >> 8))
+ && (sessionInfo[sessionInfo.Length - 1] == (byte)(check));
+ }
+
+ /// The key ID for the key used to encrypt the data.
+ public long KeyId
+ {
+ get { return keyData.KeyId; }
+ }
+
+ /// Return the decrypted data stream for the packet.
+ public Stream GetDataStream(
+ PgpPrivateKey privKey)
+ {
+ IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm);
+
+ try
+ {
+ c1.Init(false, privKey.Key);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("error setting asymmetric cipher", e);
+ }
+
+ BigInteger[] keyD = keyData.GetEncSessionKey();
+
+ if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
+ || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
+ {
+ c1.ProcessBytes(keyD[0].ToByteArrayUnsigned());
+ }
+ else
+ {
+ ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
+ int size = (k.Parameters.P.BitLength + 7) / 8;
+
+ byte[] bi = keyD[0].ToByteArray();
+
+ int diff = bi.Length - size;
+ if (diff >= 0)
+ {
+ c1.ProcessBytes(bi, diff, size);
+ }
+ else
+ {
+ byte[] zeros = new byte[-diff];
+ c1.ProcessBytes(zeros);
+ c1.ProcessBytes(bi);
+ }
+
+ bi = keyD[1].ToByteArray();
+
+ diff = bi.Length - size;
+ if (diff >= 0)
+ {
+ c1.ProcessBytes(bi, diff, size);
+ }
+ else
+ {
+ byte[] zeros = new byte[-diff];
+ c1.ProcessBytes(zeros);
+ c1.ProcessBytes(bi);
+ }
+ }
+
+ byte[] plain;
+ try
+ {
+ plain = c1.DoFinal();
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception decrypting secret key", e);
+ }
+
+ if (!ConfirmCheckSum(plain))
+ throw new PgpKeyValidationException("key checksum failed");
+
+ IBufferedCipher c2;
+ string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]);
+ string cName = cipherName;
+
+ try
+ {
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ cName += "/CFB/NoPadding";
+ }
+ else
+ {
+ cName += "/OpenPGPCFB/NoPadding";
+ }
+
+ c2 = CipherUtilities.GetCipher(cName);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception creating cipher", e);
+ }
+
+ if (c2 == null)
+ return encData.GetInputStream();
+
+ try
+ {
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(
+ cipherName, plain, 1, plain.Length - 3);
+
+ byte[] iv = new byte[c2.GetBlockSize()];
+
+ c2.Init(false, new ParametersWithIV(key, iv));
+
+ encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null));
+
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ truncStream = new TruncatedStream(encStream);
+
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ encStream = new DigestStream(truncStream, digest, null);
+ }
+
+ if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ int v1 = encStream.ReadByte();
+ int v2 = encStream.ReadByte();
+
+ if (v1 < 0 || v2 < 0)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ // Note: the oracle attack on the "quick check" bytes is deemed
+ // a security risk for typical public key encryption usages,
+ // therefore we do not perform the check.
+
+// bool repeatCheckPassed =
+// iv[iv.Length - 2] == (byte)v1
+// && iv[iv.Length - 1] == (byte)v2;
+//
+// // Note: some versions of PGP appear to produce 0 for the extra
+// // bytes rather than repeating the two previous bytes
+// bool zeroesCheckPassed =
+// v1 == 0
+// && v2 == 0;
+//
+// if (!repeatCheckPassed && !zeroesCheckPassed)
+// {
+// throw new PgpDataValidationException("quick check failed.");
+// }
+
+ return encStream;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception starting decryption", e);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPublicKeyRing.cs b/src/core/srcbc/openpgp/PgpPublicKeyRing.cs
new file mode 100644
index 0000000..631e427
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPublicKeyRing.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Class to hold a single master public key and its subkeys.
+ ///
+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+ /// or construct one of these you should use the PgpPublicKeyRingBundle class.
+ ///
+ ///
+ public class PgpPublicKeyRing
+ : PgpKeyRing
+ {
+ private readonly ArrayList keys;
+
+ public PgpPublicKeyRing(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ internal PgpPublicKeyRing(
+ ArrayList pubKeys)
+ {
+ this.keys = pubKeys;
+ }
+
+ public PgpPublicKeyRing(
+ Stream inputStream)
+ {
+ this.keys = new ArrayList();
+
+ BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+ PacketTag initialTag = bcpgInput.NextPacketTag();
+ if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
+ {
+ throw new IOException("public key ring doesn't start with public key tag: "
+ + "tag 0x" + ((int)initialTag).ToString("X"));
+ }
+
+ PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+ TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+
+ // direct signatures and revocations
+ ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+ ArrayList ids, idTrusts, idSigs;
+ ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+ keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+
+
+ // Read subkeys
+ while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+ {
+ PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket();
+ TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+
+ // PGP 8 actually leaves out the signature.
+ ArrayList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+ keys.Add(new PgpPublicKey(pk, kTrust, sigList));
+ }
+ }
+
+ /// Return the first public key in the ring.
+ public PgpPublicKey GetPublicKey()
+ {
+ return (PgpPublicKey) keys[0];
+ }
+
+ /// Return the public key referred to by the passed in key ID if it is present.
+ public PgpPublicKey GetPublicKey(
+ long keyId)
+ {
+ foreach (PgpPublicKey k in keys)
+ {
+ if (keyId == k.KeyId)
+ {
+ return k;
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of all the public keys.
+ /// An IEnumerable of PgpPublicKey objects.
+ public IEnumerable GetPublicKeys()
+ {
+ return new EnumerableProxy(keys);
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ foreach (PgpPublicKey k in keys)
+ {
+ k.Encode(outStr);
+ }
+ }
+
+ ///
+ /// Returns a new key ring with the public key passed in either added or
+ /// replacing an existing one.
+ ///
+ /// The public key ring to be modified.
+ /// The public key to be inserted.
+ /// A new PgpPublicKeyRing
+ public static PgpPublicKeyRing InsertPublicKey(
+ PgpPublicKeyRing pubRing,
+ PgpPublicKey pubKey)
+ {
+ ArrayList keys = new ArrayList(pubRing.keys);
+ bool found = false;
+ bool masterFound = false;
+
+ for (int i = 0; i != keys.Count; i++)
+ {
+ PgpPublicKey key = (PgpPublicKey) keys[i];
+
+ if (key.KeyId == pubKey.KeyId)
+ {
+ found = true;
+ keys[i] = pubKey;
+ }
+ if (key.IsMasterKey)
+ {
+ masterFound = true;
+ }
+ }
+
+ if (!found)
+ {
+ if (pubKey.IsMasterKey && masterFound)
+ throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+ keys.Add(pubKey);
+ }
+
+ return new PgpPublicKeyRing(keys);
+ }
+
+ /// Returns a new key ring with the public key passed in removed from the key ring.
+ /// The public key ring to be modified.
+ /// The public key to be removed.
+ /// A new PgpPublicKeyRing, or null if pubKey is not found.
+ public static PgpPublicKeyRing RemovePublicKey(
+ PgpPublicKeyRing pubRing,
+ PgpPublicKey pubKey)
+ {
+ ArrayList keys = new ArrayList(pubRing.keys);
+ bool found = false;
+
+ for (int i = 0; i < keys.Count; i++)
+ {
+ PgpPublicKey key = (PgpPublicKey) keys[i];
+
+ if (key.KeyId == pubKey.KeyId)
+ {
+ found = true;
+ keys.RemoveAt(i);
+ }
+ }
+
+ return found ? new PgpPublicKeyRing(keys) : null;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpPublicKeyRingBundle.cs b/src/core/srcbc/openpgp/PgpPublicKeyRingBundle.cs
new file mode 100644
index 0000000..ccb19d6
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpPublicKeyRingBundle.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+ /// If you want to read an entire public key file in one hit this is the class for you.
+ ///
+ public class PgpPublicKeyRingBundle
+ {
+ private readonly IDictionary pubRings;
+ private readonly ArrayList order;
+
+ private PgpPublicKeyRingBundle(
+ IDictionary pubRings,
+ ArrayList order)
+ {
+ this.pubRings = pubRings;
+ this.order = order;
+ }
+
+ public PgpPublicKeyRingBundle(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ /// Build a PgpPublicKeyRingBundle from the passed in input stream.
+ /// Input stream containing data.
+ /// If a problem parsing the stream occurs.
+ /// If an object is encountered which isn't a PgpPublicKeyRing.
+ public PgpPublicKeyRingBundle(
+ Stream inputStream)
+ : this(new PgpObjectFactory(inputStream).AllPgpObjects())
+ {
+ }
+
+ public PgpPublicKeyRingBundle(
+ IEnumerable e)
+ {
+ this.pubRings = new Hashtable();
+ this.order = new ArrayList();
+
+ foreach (object obj in e)
+ {
+ PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing;
+
+ if (pgpPub == null)
+ {
+ throw new PgpException(obj.GetType().FullName + " found where PgpPublicKeyRing expected");
+ }
+
+ long key = pgpPub.GetPublicKey().KeyId;
+ pubRings.Add(key, pgpPub);
+ order.Add(key);
+ }
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return order.Count; }
+ }
+
+ /// Return the number of key rings in this collection.
+ public int Count
+ {
+ get { return order.Count; }
+ }
+
+ /// Allow enumeration of the public key rings making up this collection.
+ public IEnumerable GetKeyRings()
+ {
+ return new EnumerableProxy(pubRings.Values);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId)
+ {
+ return GetKeyRings(userId, false, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial)
+ {
+ return GetKeyRings(userId, matchPartial, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// If true, case is ignored in user ID comparisons.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial,
+ bool ignoreCase)
+ {
+ IList rings = new ArrayList();
+
+ if (ignoreCase)
+ {
+ userId = userId.ToLower(CultureInfo.InvariantCulture);
+ }
+
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds())
+ {
+ string next = nextUserID;
+ if (ignoreCase)
+ {
+ next = next.ToLower(CultureInfo.InvariantCulture);
+ }
+
+ if (matchPartial)
+ {
+ if (next.IndexOf(userId) > -1)
+ {
+ rings.Add(pubRing);
+ }
+ }
+ else
+ {
+ if (next.Equals(userId))
+ {
+ rings.Add(pubRing);
+ }
+ }
+ }
+ }
+
+ return new EnumerableProxy(rings);
+ }
+
+ /// Return the PGP public key associated with the given key id.
+ /// The ID of the public key to return.
+ public PgpPublicKey GetPublicKey(
+ long keyId)
+ {
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+ if (pub != null)
+ {
+ return pub;
+ }
+ }
+
+ return null;
+ }
+
+ /// Return the public key ring which contains the key referred to by keyId
+ /// The ID of the public key
+ public PgpPublicKeyRing GetPublicKeyRing(
+ long keyId)
+ {
+ if (pubRings.Contains(keyId))
+ {
+ return (PgpPublicKeyRing)pubRings[keyId];
+ }
+
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+ if (pub != null)
+ {
+ return pubRing;
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ foreach (long key in order)
+ {
+ PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key];
+
+ sec.Encode(bcpgOut);
+ }
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle and
+ /// the passed in public key ring.
+ ///
+ /// The PgpPublicKeyRingBundle the key ring is to be added to.
+ /// The key ring to be added.
+ /// A new PgpPublicKeyRingBundle merging the current one with the passed in key ring.
+ /// If the keyId for the passed in key ring is already present.
+ public static PgpPublicKeyRingBundle AddPublicKeyRing(
+ PgpPublicKeyRingBundle bundle,
+ PgpPublicKeyRing publicKeyRing)
+ {
+ long key = publicKeyRing.GetPublicKey().KeyId;
+
+ if (bundle.pubRings.Contains(key))
+ {
+ throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newPubRings = new Hashtable(bundle.pubRings);
+ ArrayList newOrder = new ArrayList(bundle.order);
+
+ newPubRings[key] = publicKeyRing;
+
+ newOrder.Add(key);
+
+ return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle with
+ /// the passed in public key ring removed.
+ ///
+ /// The PgpPublicKeyRingBundle the key ring is to be removed from.
+ /// The key ring to be removed.
+ /// A new PgpPublicKeyRingBundle not containing the passed in key ring.
+ /// If the keyId for the passed in key ring is not present.
+ public static PgpPublicKeyRingBundle RemovePublicKeyRing(
+ PgpPublicKeyRingBundle bundle,
+ PgpPublicKeyRing publicKeyRing)
+ {
+ long key = publicKeyRing.GetPublicKey().KeyId;
+
+ if (!bundle.pubRings.Contains(key))
+ {
+ throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newPubRings = new Hashtable(bundle.pubRings);
+ ArrayList newOrder = new ArrayList(bundle.order);
+
+ newPubRings.Remove(key);
+ newOrder.Remove(key);
+
+ return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSecretKey.cs b/src/core/srcbc/openpgp/PgpSecretKey.cs
new file mode 100644
index 0000000..2069da6
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSecretKey.cs
@@ -0,0 +1,707 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to handle a PGP secret key object.
+ public class PgpSecretKey
+ {
+ private SecretKeyPacket secret;
+ private TrustPacket trust;
+ private ArrayList keySigs;
+ private ArrayList ids;
+ private ArrayList idTrusts;
+ private ArrayList idSigs;
+ private PgpPublicKey pub;
+ private ArrayList subSigs;
+
+ /// Copy constructor - master key.
+ private PgpSecretKey(
+ SecretKeyPacket secret,
+ TrustPacket trust,
+ ArrayList keySigs,
+ ArrayList ids,
+ ArrayList idTrusts,
+ ArrayList idSigs,
+ PgpPublicKey pub)
+ {
+ this.secret = secret;
+ this.trust = trust;
+ this.keySigs = keySigs;
+ this.ids = ids;
+ this.idTrusts = idTrusts;
+ this.idSigs = idSigs;
+ this.pub = pub;
+ }
+
+ /// Copy constructor - subkey.
+ private PgpSecretKey(
+ SecretKeyPacket secret,
+ TrustPacket trust,
+ ArrayList subSigs,
+ PgpPublicKey pub)
+ {
+ this.secret = secret;
+ this.trust = trust;
+ this.subSigs = subSigs;
+ this.pub = pub;
+ }
+
+ internal PgpSecretKey(
+ SecretKeyPacket secret,
+ TrustPacket trust,
+ ArrayList keySigs,
+ ArrayList ids,
+ ArrayList idTrusts,
+ ArrayList idSigs)
+ {
+ this.secret = secret;
+ this.trust = trust;
+ this.keySigs = keySigs;
+ this.ids = ids;
+ this.idTrusts = idTrusts;
+ this.idSigs = idSigs;
+ this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs);
+ }
+
+ internal PgpSecretKey(
+ SecretKeyPacket secret,
+ TrustPacket trust,
+ ArrayList subSigs)
+ {
+ this.secret = secret;
+ this.trust = trust;
+ this.subSigs = subSigs;
+ this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, subSigs);
+ }
+
+ /// Create a subkey
+ internal PgpSecretKey(
+ PgpKeyPair keyPair,
+ TrustPacket trust,
+ ArrayList subSigs,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSHA1,
+ SecureRandom rand)
+ : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand)
+ {
+ this.secret = new SecretSubkeyPacket(
+ secret.PublicKeyPacket,
+ secret.EncAlgorithm,
+ secret.S2kUsage,
+ secret.S2k,
+ secret.GetIV(),
+ secret.GetSecretKeyData());
+
+ this.trust = trust;
+ this.subSigs = subSigs;
+ this.pub = new PgpPublicKey(keyPair.PublicKey, trust, subSigs);
+ }
+
+ internal PgpSecretKey(
+ PgpKeyPair keyPair,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSHA1,
+ SecureRandom rand)
+ {
+ PublicKeyPacket pubPk = keyPair.PublicKey.publicPk;
+
+ BcpgObject secKey;
+ switch (keyPair.PublicKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaSign:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) keyPair.PrivateKey.Key;
+ secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) keyPair.PrivateKey.Key;
+ secKey = new DsaSecretBcpgKey(dsK.X);
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) keyPair.PrivateKey.Key;
+ secKey = new ElGamalSecretBcpgKey(esK.X);
+ break;
+ default:
+ throw new PgpException("unknown key class");
+ }
+
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteObject(secKey);
+
+ byte[] keyData = bOut.ToArray();
+ byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length);
+
+ pOut.Write(checksumBytes);
+
+ byte[] bOutData = bOut.ToArray();
+
+ if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
+ {
+ this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData);
+ }
+ else
+ {
+ S2k s2k;
+ byte[] iv;
+ byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv);
+
+ int usage = useSHA1
+ ? SecretKeyPacket.UsageSha1
+ : SecretKeyPacket.UsageChecksum;
+
+ this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData);
+ }
+
+ this.trust = null;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception encrypting key", e);
+ }
+
+ this.keySigs = new ArrayList();
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSHA1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand)
+ {
+ try
+ {
+ this.trust = null;
+ this.ids = new ArrayList();
+ ids.Add(id);
+
+ this.idTrusts = new ArrayList();
+ idTrusts.Add(null);
+
+ this.idSigs = new ArrayList();
+
+ PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+ keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(certificationLevel, keyPair.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
+ this.pub = PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
+
+ ArrayList sigList = new ArrayList();
+ sigList.Add(certification);
+ idSigs.Add(sigList);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception encrypting key", e);
+ }
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel,
+ new PgpKeyPair(algorithm, pubKey, privKey, time),
+ id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSHA1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSHA1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ /// True, if this key is marked as suitable for signature generation.
+ public bool IsSigningKey
+ {
+ get
+ {
+ switch (pub.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ case PublicKeyAlgorithmTag.Dsa:
+ case PublicKeyAlgorithmTag.ECDsa:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /// True, if this is a master key.
+ public bool IsMasterKey
+ {
+ get { return subSigs == null; }
+ }
+
+ /// The algorithm the key is encrypted with.
+ public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
+ {
+ get { return secret.EncAlgorithm; }
+ }
+
+ /// The key ID of the public key associated with this key.
+ public long KeyId
+ {
+ get { return pub.KeyId; }
+ }
+
+ /// The public key associated with this key.
+ public PgpPublicKey PublicKey
+ {
+ get { return pub; }
+ }
+
+ /// Allows enumeration of any user IDs associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable UserIds
+ {
+ get { return pub.GetUserIds(); }
+ }
+
+ /// Allows enumeration of any user attribute vectors associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable UserAttributes
+ {
+ get { return pub.GetUserAttributes(); }
+ }
+
+ private byte[] ExtractKeyData(
+ char[] passPhrase)
+ {
+ SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm;
+ byte[] encData = secret.GetSecretKeyData();
+
+ if (alg == SymmetricKeyAlgorithmTag.Null)
+ return encData;
+
+ byte[] data;
+ IBufferedCipher c = null;
+ try
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(alg);
+ c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+
+ // TODO Factor this block out as 'encryptData'
+ try
+ {
+ KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
+ byte[] iv = secret.GetIV();
+
+ if (secret.PublicKeyPacket.Version == 4)
+ {
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ data = c.DoFinal(encData);
+
+ bool useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
+ byte[] check = Checksum(useSHA1, data, (useSHA1) ? data.Length - 20 : data.Length - 2);
+
+ for (int i = 0; i != check.Length; i++)
+ {
+ if (check[i] != data[data.Length - check.Length + i])
+ {
+ throw new PgpException("Checksum mismatch at " + i + " of " + check.Length);
+ }
+ }
+ }
+ else // version 2 or 3, RSA only.
+ {
+ data = new byte[encData.Length];
+
+ //
+ // read in the four numbers
+ //
+ int pos = 0;
+
+ for (int i = 0; i != 4; i++)
+ {
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
+
+ data[pos] = encData[pos];
+ data[pos + 1] = encData[pos + 1];
+ pos += 2;
+
+ c.DoFinal(encData, pos, encLen, data, pos);
+ pos += encLen;
+
+ if (i != 3)
+ {
+ Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length);
+ }
+ }
+
+ //
+ // verify Checksum
+ //
+ int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
+ int calcCs = 0;
+ for (int j=0; j < data.Length-2; j++)
+ {
+ calcCs += data[j] & 0xff;
+ }
+
+ calcCs &= 0xffff;
+ if (calcCs != cs)
+ {
+ throw new PgpException("Checksum mismatch: passphrase wrong, expected "
+ + cs.ToString("X")
+ + " found " + calcCs.ToString("X"));
+ }
+ }
+
+ return data;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception decrypting key", e);
+ }
+ }
+
+ /// Extract a PgpPrivateKey from this secret key's encrypted contents.
+ public PgpPrivateKey ExtractPrivateKey(
+ char[] passPhrase)
+ {
+ byte[] secKeyData = secret.GetSecretKeyData();
+ if (secKeyData == null || secKeyData.Length < 1)
+ return null;
+
+ PublicKeyPacket pubPk = secret.PublicKeyPacket;
+ try
+ {
+ byte[] data = ExtractKeyData(passPhrase);
+ BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false));
+ AsymmetricKeyParameter privateKey;
+ switch (pubPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key;
+ RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn);
+ RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters(
+ rsaPriv.Modulus,
+ rsaPub.PublicExponent,
+ rsaPriv.PrivateExponent,
+ rsaPriv.PrimeP,
+ rsaPriv.PrimeQ,
+ rsaPriv.PrimeExponentP,
+ rsaPriv.PrimeExponentQ,
+ rsaPriv.CrtCoefficient);
+ privateKey = rsaPrivSpec;
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key;
+ DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn);
+ DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
+ privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
+ ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn);
+ ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G);
+ privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams);
+ break;
+ default:
+ throw new PgpException("unknown public key algorithm encountered");
+ }
+
+ return new PgpPrivateKey(privateKey, KeyId);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception constructing key", e);
+ }
+ }
+
+ private static byte[] Checksum(
+ bool useSHA1,
+ byte[] bytes,
+ int length)
+ {
+ if (useSHA1)
+ {
+ try
+ {
+ IDigest dig = DigestUtilities.GetDigest("SHA1");
+ dig.BlockUpdate(bytes, 0, length);
+ return DigestUtilities.DoFinal(dig);
+ }
+ //catch (NoSuchAlgorithmException e)
+ catch (Exception e)
+ {
+ throw new PgpException("Can't find SHA-1", e);
+ }
+ }
+ else
+ {
+ int Checksum = 0;
+ for (int i = 0; i != length; i++)
+ {
+ Checksum += bytes[i];
+ }
+
+ return new byte[] { (byte)(Checksum >> 8), (byte)Checksum };
+ }
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ Encode(bOut);
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ bcpgOut.WritePacket(secret);
+ if (trust != null)
+ {
+ bcpgOut.WritePacket(trust);
+ }
+
+ if (subSigs == null) // is not a sub key
+ {
+ foreach (PgpSignature keySig in keySigs)
+ {
+ keySig.Encode(bcpgOut);
+ }
+
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (ids[i] is string)
+ {
+ string id = (string) ids[i];
+
+ bcpgOut.WritePacket(new UserIdPacket(id));
+ }
+ else
+ {
+ PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
+ bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+ }
+
+ if (idTrusts[i] != null)
+ {
+ bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
+ }
+
+ foreach (PgpSignature sig in (ArrayList) idSigs[i])
+ {
+ sig.Encode(bcpgOut);
+ }
+ }
+ }
+ else
+ {
+ foreach (PgpSignature subSig in subSigs)
+ {
+ subSig.Encode(bcpgOut);
+ }
+ }
+
+ // TODO Check that this is right/necessary
+ //bcpgOut.Finish();
+ }
+
+ ///
+ /// Return a copy of the passed in secret key, encrypted using a new password
+ /// and the passed in algorithm.
+ ///
+ /// The PgpSecretKey to be copied.
+ /// The current password for the key.
+ /// The new password for the key.
+ /// The algorithm to be used for the encryption.
+ /// Source of randomness.
+ public static PgpSecretKey CopyWithNewPassword(
+ PgpSecretKey key,
+ char[] oldPassPhrase,
+ char[] newPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase);
+ int s2kUsage = key.secret.S2kUsage;
+ byte[] iv = null;
+ S2k s2k = null;
+ byte[] keyData;
+
+ if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
+ {
+ s2kUsage = SecretKeyPacket.UsageNone;
+ if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum
+ {
+ keyData = new byte[rawKeyData.Length - 18];
+
+ Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);
+
+ byte[] check = Checksum(false, keyData, keyData.Length - 2);
+
+ keyData[keyData.Length - 2] = check[0];
+ keyData[keyData.Length - 1] = check[1];
+ }
+ else
+ {
+ keyData = rawKeyData;
+ }
+ }
+ else
+ {
+ try
+ {
+ keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception encrypting key", e);
+ }
+ }
+
+ SecretKeyPacket secret;
+ if (key.secret is SecretSubkeyPacket)
+ {
+ secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
+ newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+ }
+ else
+ {
+ secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
+ newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+ }
+
+ if (key.subSigs == null)
+ {
+ return new PgpSecretKey(secret, key.trust, key.keySigs, key.ids,
+ key.idTrusts, key.idSigs, key.pub);
+ }
+
+ return new PgpSecretKey(secret, key.trust, key.subSigs, key.pub);
+ }
+
+ private static byte[] EncryptKeyData(
+ byte[] rawKeyData,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ SecureRandom random,
+ out S2k s2k,
+ out byte[] iv)
+ {
+ IBufferedCipher c;
+ try
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+
+ byte[] s2kIV = new byte[8];
+ random.NextBytes(s2kIV);
+ s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60);
+
+ KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);
+
+ iv = new byte[c.GetBlockSize()];
+ random.NextBytes(iv);
+
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random));
+
+ return c.DoFinal(rawKeyData);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSecretKeyRing.cs b/src/core/srcbc/openpgp/PgpSecretKeyRing.cs
new file mode 100644
index 0000000..b6fa630
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSecretKeyRing.cs
@@ -0,0 +1,208 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Class to hold a single master secret key and its subkeys.
+ ///
+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+ /// or construct one of these you should use the PgpSecretKeyRingBundle class.
+ ///
+ ///
+ public class PgpSecretKeyRing
+ : PgpKeyRing
+ {
+ private readonly ArrayList keys;
+
+ internal PgpSecretKeyRing(
+ ArrayList keys)
+ {
+ this.keys = keys;
+ }
+
+ public PgpSecretKeyRing(
+ byte[] encoding)
+ : this(new MemoryStream(encoding))
+ {
+ }
+
+ public PgpSecretKeyRing(
+ Stream inputStream)
+ {
+ this.keys = new ArrayList();
+
+ BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+ PacketTag initialTag = bcpgInput.NextPacketTag();
+ if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey)
+ {
+ throw new IOException("secret key ring doesn't start with secret key tag: "
+ + "tag 0x" + ((int)initialTag).ToString("X"));
+ }
+
+ SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
+
+ //
+ // ignore GPG comment packets if found.
+ //
+ while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+ {
+ bcpgInput.ReadPacket();
+ }
+
+ TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
+
+ // revocation and direct signatures
+ ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+ ArrayList ids, idTrusts, idSigs;
+ ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+ keys.Add(new PgpSecretKey(secret, trust, keySigs, ids, idTrusts, idSigs));
+
+
+ // Read subkeys
+ while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey)
+ {
+ SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket();
+
+ //
+ // ignore GPG comment packets if found.
+ //
+ while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+ {
+ bcpgInput.ReadPacket();
+ }
+
+ TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
+ ArrayList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+ keys.Add(new PgpSecretKey(sub, subTrust, sigList));
+ }
+ }
+
+ /// Return the public key for the master key.
+ public PgpPublicKey GetPublicKey()
+ {
+ return ((PgpSecretKey) keys[0]).PublicKey;
+ }
+
+ /// Return the master private key.
+ public PgpSecretKey GetSecretKey()
+ {
+ return (PgpSecretKey) keys[0];
+ }
+
+ /// Allows enumeration of the secret keys.
+ /// An IEnumerable of PgpSecretKey objects.
+ public IEnumerable GetSecretKeys()
+ {
+ return new EnumerableProxy(keys);
+ }
+
+ public PgpSecretKey GetSecretKey(
+ long keyId)
+ {
+ foreach (PgpSecretKey k in keys)
+ {
+ if (keyId == k.KeyId)
+ {
+ return k;
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ foreach (PgpSecretKey k in keys)
+ {
+ k.Encode(outStr);
+ }
+ }
+
+ ///
+ /// Returns a new key ring with the secret key passed in either added or
+ /// replacing an existing one with the same key ID.
+ ///
+ /// The secret key ring to be modified.
+ /// The secret key to be inserted.
+ /// A new PgpSecretKeyRing
+ public static PgpSecretKeyRing InsertSecretKey(
+ PgpSecretKeyRing secRing,
+ PgpSecretKey secKey)
+ {
+ ArrayList keys = new ArrayList(secRing.keys);
+ bool found = false;
+ bool masterFound = false;
+
+ for (int i = 0; i != keys.Count; i++)
+ {
+ PgpSecretKey key = (PgpSecretKey) keys[i];
+
+ if (key.KeyId == secKey.KeyId)
+ {
+ found = true;
+ keys[i] = secKey;
+ }
+ if (key.IsMasterKey)
+ {
+ masterFound = true;
+ }
+ }
+
+ if (!found)
+ {
+ if (secKey.IsMasterKey && masterFound)
+ throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+ keys.Add(secKey);
+ }
+
+ return new PgpSecretKeyRing(keys);
+ }
+
+ /// Returns a new key ring with the secret key passed in removed from the key ring.
+ /// The secret key ring to be modified.
+ /// The secret key to be removed.
+ /// A new PgpSecretKeyRing, or null if secKey is not found.
+ public static PgpSecretKeyRing RemoveSecretKey(
+ PgpSecretKeyRing secRing,
+ PgpSecretKey secKey)
+ {
+ ArrayList keys = new ArrayList(secRing.keys);
+ bool found = false;
+
+ for (int i = 0; i < keys.Count; i++)
+ {
+ PgpSecretKey key = (PgpSecretKey)keys[i];
+
+ if (key.KeyId == secKey.KeyId)
+ {
+ found = true;
+ keys.RemoveAt(i);
+ }
+ }
+
+ return found ? new PgpSecretKeyRing(keys) : null;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSecretKeyRingBundle.cs b/src/core/srcbc/openpgp/PgpSecretKeyRingBundle.cs
new file mode 100644
index 0000000..bcf2e94
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSecretKeyRingBundle.cs
@@ -0,0 +1,270 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+ /// If you want to read an entire secret key file in one hit this is the class for you.
+ ///
+ public class PgpSecretKeyRingBundle
+ {
+ private readonly IDictionary secretRings;
+ private readonly ArrayList order;
+
+ private PgpSecretKeyRingBundle(
+ IDictionary secretRings,
+ ArrayList order)
+ {
+ this.secretRings = secretRings;
+ this.order = order;
+ }
+
+ public PgpSecretKeyRingBundle(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ /// Build a PgpSecretKeyRingBundle from the passed in input stream.
+ /// Input stream containing data.
+ /// If a problem parsing the stream occurs.
+ /// If an object is encountered which isn't a PgpSecretKeyRing.
+ public PgpSecretKeyRingBundle(
+ Stream inputStream)
+ : this(new PgpObjectFactory(inputStream).AllPgpObjects())
+ {
+ }
+
+ public PgpSecretKeyRingBundle(
+ IEnumerable e)
+ {
+ this.secretRings = new Hashtable();
+ this.order = new ArrayList();
+
+ foreach (object obj in e)
+ {
+ PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing;
+
+ if (pgpSecret == null)
+ {
+ throw new PgpException(obj.GetType().FullName + " found where PgpSecretKeyRing expected");
+ }
+
+ long key = pgpSecret.GetPublicKey().KeyId;
+ secretRings.Add(key, pgpSecret);
+ order.Add(key);
+ }
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return order.Count; }
+ }
+
+ /// Return the number of rings in this collection.
+ public int Count
+ {
+ get { return order.Count; }
+ }
+
+ /// Allow enumeration of the secret key rings making up this collection.
+ public IEnumerable GetKeyRings()
+ {
+ return new EnumerableProxy(secretRings.Values);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId)
+ {
+ return GetKeyRings(userId, false, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial)
+ {
+ return GetKeyRings(userId, matchPartial, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// If true, case is ignored in user ID comparisons.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial,
+ bool ignoreCase)
+ {
+ IList rings = new ArrayList();
+
+ if (ignoreCase)
+ {
+ userId = userId.ToLower(CultureInfo.InvariantCulture);
+ }
+
+ foreach (PgpSecretKeyRing secRing in GetKeyRings())
+ {
+ foreach (string nextUserID in secRing.GetSecretKey().UserIds)
+ {
+ string next = nextUserID;
+ if (ignoreCase)
+ {
+ next = next.ToLower(CultureInfo.InvariantCulture);
+ }
+
+ if (matchPartial)
+ {
+ if (next.IndexOf(userId) > -1)
+ {
+ rings.Add(secRing);
+ }
+ }
+ else
+ {
+ if (next.Equals(userId))
+ {
+ rings.Add(secRing);
+ }
+ }
+ }
+ }
+
+ return new EnumerableProxy(rings);
+ }
+
+ /// Return the PGP secret key associated with the given key id.
+ /// The ID of the secret key to return.
+ public PgpSecretKey GetSecretKey(
+ long keyId)
+ {
+ foreach (PgpSecretKeyRing secRing in GetKeyRings())
+ {
+ PgpSecretKey sec = secRing.GetSecretKey(keyId);
+
+ if (sec != null)
+ {
+ return sec;
+ }
+ }
+
+ return null;
+ }
+
+ /// Return the secret key ring which contains the key referred to by keyId
+ /// The ID of the secret key
+ public PgpSecretKeyRing GetSecretKeyRing(
+ long keyId)
+ {
+ long id = keyId;
+
+ if (secretRings.Contains(id))
+ {
+ return (PgpSecretKeyRing) secretRings[id];
+ }
+
+ foreach (PgpSecretKeyRing secretRing in GetKeyRings())
+ {
+ PgpSecretKey secret = secretRing.GetSecretKey(keyId);
+
+ if (secret != null)
+ {
+ return secretRing;
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ foreach (long key in order)
+ {
+ PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key];
+
+ pub.Encode(bcpgOut);
+ }
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle and
+ /// the passed in secret key ring.
+ ///
+ /// The PgpSecretKeyRingBundle the key ring is to be added to.
+ /// The key ring to be added.
+ /// A new PgpSecretKeyRingBundle merging the current one with the passed in key ring.
+ /// If the keyId for the passed in key ring is already present.
+ public static PgpSecretKeyRingBundle AddSecretKeyRing(
+ PgpSecretKeyRingBundle bundle,
+ PgpSecretKeyRing secretKeyRing)
+ {
+ long key = secretKeyRing.GetPublicKey().KeyId;
+
+ if (bundle.secretRings.Contains(key))
+ {
+ throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newSecretRings = new Hashtable(bundle.secretRings);
+ ArrayList newOrder = new ArrayList(bundle.order);
+
+ newSecretRings[key] = secretKeyRing;
+ newOrder.Add(key);
+
+ return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle with
+ /// the passed in secret key ring removed.
+ ///
+ /// The PgpSecretKeyRingBundle the key ring is to be removed from.
+ /// The key ring to be removed.
+ /// A new PgpSecretKeyRingBundle not containing the passed in key ring.
+ /// If the keyId for the passed in key ring is not present.
+ public static PgpSecretKeyRingBundle RemoveSecretKeyRing(
+ PgpSecretKeyRingBundle bundle,
+ PgpSecretKeyRing secretKeyRing)
+ {
+ long key = secretKeyRing.GetPublicKey().KeyId;
+
+ if (!bundle.secretRings.Contains(key))
+ {
+ throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newSecretRings = new Hashtable(bundle.secretRings);
+ ArrayList newOrder = new ArrayList(bundle.order);
+
+ newSecretRings.Remove(key);
+ newOrder.Remove(key);
+
+ return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSignature.cs b/src/core/srcbc/openpgp/PgpSignature.cs
new file mode 100644
index 0000000..2499200
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSignature.cs
@@ -0,0 +1,409 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A PGP signature object.
+ public class PgpSignature
+ {
+ public const int BinaryDocument = 0x00;
+ public const int CanonicalTextDocument = 0x01;
+ public const int StandAlone = 0x02;
+
+ public const int DefaultCertification = 0x10;
+ public const int NoCertification = 0x11;
+ public const int CasualCertification = 0x12;
+ public const int PositiveCertification = 0x13;
+
+ public const int SubkeyBinding = 0x18;
+ public const int DirectKey = 0x1f;
+ public const int KeyRevocation = 0x20;
+ public const int SubkeyRevocation = 0x28;
+ public const int CertificationRevocation = 0x30;
+ public const int Timestamp = 0x40;
+
+ private readonly SignaturePacket sigPck;
+ private readonly int signatureType;
+ private readonly TrustPacket trustPck;
+
+ private ISigner sig;
+ private byte lastb; // Initial value anything but '\r'
+
+ internal PgpSignature(
+ BcpgInputStream bcpgInput)
+ : this((SignaturePacket)bcpgInput.ReadPacket())
+ {
+ }
+
+ internal PgpSignature(
+ SignaturePacket sigPacket)
+ : this(sigPacket, null)
+ {
+ }
+
+ internal PgpSignature(
+ SignaturePacket sigPacket,
+ TrustPacket trustPacket)
+ {
+ if (sigPacket == null)
+ throw new ArgumentNullException("sigPacket");
+
+ this.sigPck = sigPacket;
+ this.signatureType = sigPck.SignatureType;
+ this.trustPck = trustPacket;
+ }
+
+ private void GetSig()
+ {
+ this.sig = SignerUtilities.GetSigner(
+ PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
+ }
+
+ /// The OpenPGP version number for this signature.
+ public int Version
+ {
+ get { return sigPck.Version; }
+ }
+
+ /// The key algorithm associated with this signature.
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return sigPck.KeyAlgorithm; }
+ }
+
+ /// The hash algorithm associated with this signature.
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return sigPck.HashAlgorithm; }
+ }
+
+ public void InitVerify(
+ PgpPublicKey pubKey)
+ {
+ lastb = 0;
+ if (sig == null)
+ {
+ GetSig();
+ }
+ try
+ {
+ sig.Init(false, pubKey.GetKey());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ sig.Update(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ sig.Update(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ sig.Update((byte)'\r');
+ sig.Update((byte)'\n');
+ }
+
+ public void Update(
+ params byte[] bytes)
+ {
+ Update(bytes, 0, bytes.Length);
+ }
+
+ public void Update(
+ byte[] bytes,
+ int off,
+ int length)
+ {
+ if (signatureType == CanonicalTextDocument)
+ {
+ int finish = off + length;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, off, length);
+ }
+ }
+
+ public bool Verify()
+ {
+ byte[] trailer = GetSignatureTrailer();
+ sig.BlockUpdate(trailer, 0, trailer.Length);
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ private void UpdateWithIdData(
+ int header,
+ byte[] idBytes)
+ {
+ this.Update(
+ (byte) header,
+ (byte)(idBytes.Length >> 24),
+ (byte)(idBytes.Length >> 16),
+ (byte)(idBytes.Length >> 8),
+ (byte)(idBytes.Length));
+ this.Update(idBytes);
+ }
+
+ private void UpdateWithPublicKey(
+ PgpPublicKey key)
+ {
+ byte[] keyBytes = GetEncodedPublicKey(key);
+
+ this.Update(
+ (byte) 0x99,
+ (byte)(keyBytes.Length >> 8),
+ (byte)(keyBytes.Length));
+ this.Update(keyBytes);
+ }
+
+ ///
+ /// Verify the signature as certifying the passed in public key as associated
+ /// with the passed in user attributes.
+ ///
+ /// User attributes the key was stored under.
+ /// The key to be verified.
+ /// True, if the signature matches, false otherwise.
+ public bool VerifyCertification(
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpPublicKey key)
+ {
+ UpdateWithPublicKey(key);
+
+ //
+ // hash in the userAttributes
+ //
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+ {
+ packet.Encode(bOut);
+ }
+ UpdateWithIdData(0xd1, bOut.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("cannot encode subpacket array", e);
+ }
+
+ this.Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(this.GetSignature());
+ }
+
+ ///
+ /// Verify the signature as certifying the passed in public key as associated
+ /// with the passed in ID.
+ ///
+ /// ID the key was stored under.
+ /// The key to be verified.
+ /// True, if the signature matches, false otherwise.
+ public bool VerifyCertification(
+ string id,
+ PgpPublicKey key)
+ {
+ UpdateWithPublicKey(key);
+
+ //
+ // hash in the id
+ //
+ UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ /// Verify a certification for the passed in key against the passed in master key.
+ /// The key we are verifying against.
+ /// The key we are verifying.
+ /// True, if the certification is valid, false otherwise.
+ public bool VerifyCertification(
+ PgpPublicKey masterKey,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(masterKey);
+ UpdateWithPublicKey(pubKey);
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ /// Verify a key certification, such as revocation, for the passed in key.
+ /// The key we are checking.
+ /// True, if the certification is valid, false otherwise.
+ public bool VerifyCertification(
+ PgpPublicKey pubKey)
+ {
+ if (SignatureType != KeyRevocation
+ && SignatureType != SubkeyRevocation)
+ {
+ throw new InvalidOperationException("signature is not a key signature");
+ }
+
+ UpdateWithPublicKey(pubKey);
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ public int SignatureType
+ {
+ get { return sigPck.SignatureType; }
+ }
+
+ /// The ID of the key that created the signature.
+ public long KeyId
+ {
+ get { return sigPck.KeyId; }
+ }
+
+ [Obsolete("Use 'CreationTime' property instead")]
+ public DateTime GetCreationTime()
+ {
+ return CreationTime;
+ }
+
+ /// The creation time of this signature.
+ public DateTime CreationTime
+ {
+ get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); }
+ }
+
+ public byte[] GetSignatureTrailer()
+ {
+ return sigPck.GetSignatureTrailer();
+ }
+
+ public PgpSignatureSubpacketVector GetHashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.GetHashedSubPackets());
+ }
+
+ public PgpSignatureSubpacketVector GetUnhashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.GetUnhashedSubPackets());
+ }
+
+ private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
+ {
+ return pcks == null ? null : new PgpSignatureSubpacketVector(pcks);
+ }
+
+ public byte[] GetSignature()
+ {
+ MPInteger[] sigValues = sigPck.GetSignature();
+ byte[] signature;
+
+ if (sigValues != null)
+ {
+ if (sigValues.Length == 1) // an RSA signature
+ {
+ signature = sigValues[0].Value.ToByteArrayUnsigned();
+ }
+ else
+ {
+ try
+ {
+ signature = new DerSequence(
+ new DerInteger(sigValues[0].Value),
+ new DerInteger(sigValues[1].Value)).GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding DSA sig.", e);
+ }
+ }
+ }
+ else
+ {
+ signature = sigPck.GetSignatureBytes();
+ }
+
+ return signature;
+ }
+
+ // TODO Handle the encoding stuff by subclassing BcpgObject?
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStream)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream);
+
+ bcpgOut.WritePacket(sigPck);
+
+ if (trustPck != null)
+ {
+ bcpgOut.WritePacket(trustPck);
+ }
+ }
+
+ private byte[] GetEncodedPublicKey(
+ PgpPublicKey pubKey)
+ {
+ try
+ {
+ return pubKey.publicPk.GetEncodedContents();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception preparing key.", e);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSignatureGenerator.cs b/src/core/srcbc/openpgp/PgpSignatureGenerator.cs
new file mode 100644
index 0000000..4ea0310
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSignatureGenerator.cs
@@ -0,0 +1,393 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for PGP signatures.
+ // TODO Should be able to implement ISigner?
+ public class PgpSignatureGenerator
+ {
+ private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
+
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private PgpPrivateKey privKey;
+ private ISigner sig;
+ private IDigest dig;
+ private int signatureType;
+ private byte lastb;
+
+ private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
+ private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
+
+ /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.
+ public PgpSignatureGenerator(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+
+ dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+ sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key)
+ {
+ InitSign(sigType, key, null);
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key,
+ SecureRandom random)
+ {
+ this.privKey = key;
+ this.signatureType = sigType;
+
+ try
+ {
+ ICipherParameters cp = key.Key;
+ if (random != null)
+ {
+ cp = new ParametersWithRandom(key.Key, random);
+ }
+
+ sig.Init(true, cp);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+
+ dig.Reset();
+ lastb = 0;
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ doUpdateByte((byte)'\r');
+ doUpdateByte((byte)'\n');
+ }
+
+ private void doUpdateByte(
+ byte b)
+ {
+ sig.Update(b);
+ dig.Update(b);
+ }
+
+ public void Update(
+ params byte[] b)
+ {
+ Update(b, 0, b.Length);
+ }
+
+ public void Update(
+ byte[] b,
+ int off,
+ int len)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + len;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, off, len);
+ dig.BlockUpdate(b, off, len);
+ }
+ }
+
+ public void SetHashedSubpackets(
+ PgpSignatureSubpacketVector hashedPackets)
+ {
+ hashed = hashedPackets == null
+ ? EmptySignatureSubpackets
+ : hashedPackets.ToSubpacketArray();
+ }
+
+ public void SetUnhashedSubpackets(
+ PgpSignatureSubpacketVector unhashedPackets)
+ {
+ unhashed = unhashedPackets == null
+ ? EmptySignatureSubpackets
+ : unhashedPackets.ToSubpacketArray();
+ }
+
+ /// Return the one pass header associated with the current signature.
+ public PgpOnePassSignature GenerateOnePassVersion(
+ bool isNested)
+ {
+ return new PgpOnePassSignature(
+ new OnePassSignaturePacket(
+ signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+ }
+
+ /// Return a signature object containing the current signature state.
+ public PgpSignature Generate()
+ {
+ SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
+
+ if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
+ {
+ hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
+ }
+
+ if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
+ && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
+ {
+ unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
+ }
+
+ int version = 4;
+ byte[] hData;
+
+ try
+ {
+ MemoryStream hOut = new MemoryStream();
+
+ for (int i = 0; i != hPkts.Length; i++)
+ {
+ hPkts[i].Encode(hOut);
+ }
+
+ byte[] data = hOut.ToArray();
+
+ MemoryStream sOut = new MemoryStream(data.Length + 6);
+ sOut.WriteByte((byte)version);
+ sOut.WriteByte((byte)signatureType);
+ sOut.WriteByte((byte)keyAlgorithm);
+ sOut.WriteByte((byte)hashAlgorithm);
+ sOut.WriteByte((byte)(data.Length >> 8));
+ sOut.WriteByte((byte)data.Length);
+ sOut.Write(data, 0, data.Length);
+
+ hData = sOut.ToArray();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding hashed data.", e);
+ }
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ hData = new byte[]
+ {
+ (byte) version,
+ 0xff,
+ (byte)(hData.Length >> 24),
+ (byte)(hData.Length >> 16),
+ (byte)(hData.Length >> 8),
+ (byte) hData.Length
+ };
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ byte[] sigBytes = sig.GenerateSignature();
+ byte[] digest = DigestUtilities.DoFinal(dig);
+ byte[] fingerPrint = new byte[] { digest[0], digest[1] };
+
+ // an RSA signature
+ bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+ || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+ MPInteger[] sigValues = isRsa
+ ? PgpUtilities.RsaSigToMpi(sigBytes)
+ : PgpUtilities.DsaSigToMpi(sigBytes);
+
+ return new PgpSignature(
+ new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm,
+ hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
+ }
+
+ /// Generate a certification for the passed in ID and key.
+ /// The ID we are certifying against the public key.
+ /// The key we are certifying against the ID.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ string id,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ //
+ // hash in the id
+ //
+ UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+
+ return Generate();
+ }
+
+ /// Generate a certification for the passed in userAttributes.
+ /// The ID we are certifying against the public key.
+ /// The key we are certifying against the ID.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ //
+ // hash in the attributes
+ //
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+ {
+ packet.Encode(bOut);
+ }
+ UpdateWithIdData(0xd1, bOut.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("cannot encode subpacket array", e);
+ }
+
+ return this.Generate();
+ }
+
+ /// Generate a certification for the passed in key against the passed in master key.
+ /// The key we are certifying against.
+ /// The key we are certifying.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpPublicKey masterKey,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(masterKey);
+ UpdateWithPublicKey(pubKey);
+
+ return Generate();
+ }
+
+ /// Generate a certification, such as a revocation, for the passed in key.
+ /// The key we are certifying.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ return Generate();
+ }
+
+ private byte[] GetEncodedPublicKey(
+ PgpPublicKey pubKey)
+ {
+ try
+ {
+ return pubKey.publicPk.GetEncodedContents();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception preparing key.", e);
+ }
+ }
+
+ private bool packetPresent(
+ SignatureSubpacket[] packets,
+ SignatureSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignatureSubpacket[] insertSubpacket(
+ SignatureSubpacket[] packets,
+ SignatureSubpacket subpacket)
+ {
+ SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1];
+ tmp[0] = subpacket;
+ packets.CopyTo(tmp, 1);
+ return tmp;
+ }
+
+ private void UpdateWithIdData(
+ int header,
+ byte[] idBytes)
+ {
+ this.Update(
+ (byte) header,
+ (byte)(idBytes.Length >> 24),
+ (byte)(idBytes.Length >> 16),
+ (byte)(idBytes.Length >> 8),
+ (byte)(idBytes.Length));
+ this.Update(idBytes);
+ }
+
+ private void UpdateWithPublicKey(
+ PgpPublicKey key)
+ {
+ byte[] keyBytes = GetEncodedPublicKey(key);
+
+ this.Update(
+ (byte) 0x99,
+ (byte)(keyBytes.Length >> 8),
+ (byte)(keyBytes.Length));
+ this.Update(keyBytes);
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSignatureList.cs b/src/core/srcbc/openpgp/PgpSignatureList.cs
new file mode 100644
index 0000000..49923ec
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A list of PGP signatures - normally in the signature block after literal data.
+ public class PgpSignatureList
+ : PgpObject
+ {
+ private PgpSignature[] sigs;
+
+ public PgpSignatureList(
+ PgpSignature[] sigs)
+ {
+ this.sigs = (PgpSignature[]) sigs.Clone();
+ }
+
+ public PgpSignatureList(
+ PgpSignature sig)
+ {
+ this.sigs = new PgpSignature[]{ sig };
+ }
+
+ public PgpSignature this[int index]
+ {
+ get { return sigs[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public PgpSignature Get(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return sigs.Length; }
+ }
+
+ public int Count
+ {
+ get { return sigs.Length; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return (sigs.Length == 0); }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs b/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs
new file mode 100644
index 0000000..740d6ce
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for signature subpackets.
+ public class PgpSignatureSubpacketGenerator
+ {
+ private ArrayList list = new ArrayList();
+
+ public void SetRevocable(
+ bool isCritical,
+ bool isRevocable)
+ {
+ list.Add(new Revocable(isCritical, isRevocable));
+ }
+
+ public void SetExportable(
+ bool isCritical,
+ bool isExportable)
+ {
+ list.Add(new Exportable(isCritical, isExportable));
+ }
+
+ ///
+ /// Add a TrustSignature packet to the signature. The values for depth and trust are largely
+ /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
+ ///
+ /// true if the packet is critical.
+ /// depth level.
+ /// trust amount.
+ public void SetTrust(
+ bool isCritical,
+ int depth,
+ int trustAmount)
+ {
+ list.Add(new TrustSignature(isCritical, depth, trustAmount));
+ }
+
+ ///
+ /// Set the number of seconds a key is valid for after the time of its creation.
+ /// A value of zero means the key never expires.
+ ///
+ /// True, if should be treated as critical, false otherwise.
+ /// The number of seconds the key is valid, or zero if no expiry.
+ public void SetKeyExpirationTime(
+ bool isCritical,
+ long seconds)
+ {
+ list.Add(new KeyExpirationTime(isCritical, seconds));
+ }
+
+ ///
+ /// Set the number of seconds a signature is valid for after the time of its creation.
+ /// A value of zero means the signature never expires.
+ ///
+ /// True, if should be treated as critical, false otherwise.
+ /// The number of seconds the signature is valid, or zero if no expiry.
+ public void SetSignatureExpirationTime(
+ bool isCritical,
+ long seconds)
+ {
+ list.Add(new SignatureExpirationTime(isCritical, seconds));
+ }
+
+ ///
+ /// Set the creation time for the signature.
+ ///
+ /// Note: this overrides the generation of a creation time when the signature
+ /// is generated.
+ ///
+ public void SetSignatureCreationTime(
+ bool isCritical,
+ DateTime date)
+ {
+ list.Add(new SignatureCreationTime(isCritical, date));
+ }
+
+ public void SetPreferredHashAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetPreferredSymmetricAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetPreferredCompressionAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetKeyFlags(
+ bool isCritical,
+ int flags)
+ {
+ list.Add(new KeyFlags(isCritical, flags));
+ }
+
+ public void SetSignerUserId(
+ bool isCritical,
+ string userId)
+ {
+ if (userId == null)
+ throw new ArgumentNullException("userId");
+
+ list.Add(new SignerUserId(isCritical, userId));
+ }
+
+ public void SetPrimaryUserId(
+ bool isCritical,
+ bool isPrimaryUserId)
+ {
+ list.Add(new PrimaryUserId(isCritical, isPrimaryUserId));
+ }
+
+ public void SetNotationData(
+ bool isCritical,
+ bool isHumanReadable,
+ string notationName,
+ string notationValue)
+ {
+ list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue));
+ }
+
+ public PgpSignatureSubpacketVector Generate()
+ {
+ return new PgpSignatureSubpacketVector(
+ (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket)));
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpSignatureSubpacketVector.cs b/src/core/srcbc/openpgp/PgpSignatureSubpacketVector.cs
new file mode 100644
index 0000000..03e493a
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpSignatureSubpacketVector.cs
@@ -0,0 +1,193 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Container for a list of signature subpackets.
+ public class PgpSignatureSubpacketVector
+ {
+ private readonly SignatureSubpacket[] packets;
+
+ internal PgpSignatureSubpacketVector(
+ SignatureSubpacket[] packets)
+ {
+ this.packets = packets;
+ }
+
+ public SignatureSubpacket GetSubpacket(
+ SignatureSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return packets[i];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return all signature subpackets of the passed in type.
+ * @param type subpacket type code
+ * @return an array of zero or more matching subpackets.
+ */
+ public SignatureSubpacket[] GetSubpackets(
+ SignatureSubpacketTag type)
+ {
+ ArrayList list = new ArrayList();
+
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ list.Add(packets[i]);
+ }
+ }
+
+ return (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket));
+ }
+
+ public NotationData[] GetNotationDataOccurences()
+ {
+ SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData);
+ NotationData[] vals = new NotationData[notations.Length];
+
+ for (int i = 0; i < notations.Length; i++)
+ {
+ vals[i] = (NotationData) notations[i];
+ }
+
+ return vals;
+ }
+
+ public long GetIssuerKeyId()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
+
+ return p == null ? 0 : ((IssuerKeyId) p).KeyId;
+ }
+
+ public bool HasSignatureCreationTime()
+ {
+ return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
+ }
+
+ public DateTime GetSignatureCreationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.CreationTime);
+
+ if (p == null)
+ {
+ throw new PgpException("SignatureCreationTime not available");
+ }
+
+ return ((SignatureCreationTime)p).GetTime();
+ }
+
+ ///
+ /// Return the number of seconds a signature is valid for after its creation date.
+ /// A value of zero means the signature never expires.
+ ///
+ /// Seconds a signature is valid for.
+ public long GetSignatureExpirationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.ExpireTime);
+
+ return p == null ? 0 : ((SignatureExpirationTime) p).Time;
+ }
+
+ ///
+ /// Return the number of seconds a key is valid for after its creation date.
+ /// A value of zero means the key never expires.
+ ///
+ /// Seconds a signature is valid for.
+ public long GetKeyExpirationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
+
+ return p == null ? 0 : ((KeyExpirationTime) p).Time;
+ }
+
+ public int[] GetPreferredHashAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int[] GetPreferredSymmetricAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int[] GetPreferredCompressionAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int GetKeyFlags()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyFlags);
+
+ return p == null ? 0 : ((KeyFlags) p).Flags;
+ }
+
+ public string GetSignerUserId()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.SignerUserId);
+
+ return p == null ? null : ((SignerUserId) p).GetId();
+ }
+
+ public SignatureSubpacketTag[] GetCriticalTags()
+ {
+ int count = 0;
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].IsCritical())
+ {
+ count++;
+ }
+ }
+
+ SignatureSubpacketTag[] list = new SignatureSubpacketTag[count];
+
+ count = 0;
+
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].IsCritical())
+ {
+ list[count++] = packets[i].SubpacketType;
+ }
+ }
+
+ return list;
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return packets.Length; }
+ }
+
+ /// Return the number of packets this vector contains.
+ public int Count
+ {
+ get { return packets.Length; }
+ }
+
+ internal SignatureSubpacket[] ToSubpacketArray()
+ {
+ return packets;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs b/src/core/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs
new file mode 100644
index 0000000..02b67d9
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs
@@ -0,0 +1,81 @@
+using Org.BouncyCastle.Bcpg.Attr;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Container for a list of user attribute subpackets.
+ public class PgpUserAttributeSubpacketVector
+ {
+ private readonly UserAttributeSubpacket[] packets;
+
+ internal PgpUserAttributeSubpacketVector(
+ UserAttributeSubpacket[] packets)
+ {
+ this.packets = packets;
+ }
+
+ public UserAttributeSubpacket GetSubpacket(
+ UserAttributeSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return packets[i];
+ }
+ }
+
+ return null;
+ }
+
+ public ImageAttrib GetImageAttribute()
+ {
+ UserAttributeSubpacket p = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
+
+ return p == null ? null : (ImageAttrib) p;
+ }
+
+ internal UserAttributeSubpacket[] ToSubpacketArray()
+ {
+ return packets;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ PgpUserAttributeSubpacketVector other = obj as PgpUserAttributeSubpacketVector;
+
+ if (other == null)
+ return false;
+
+ if (other.packets.Length != packets.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (!other.packets[i].Equals(packets[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int code = 0;
+
+ foreach (object o in packets)
+ {
+ code ^= o.GetHashCode();
+ }
+
+ return code;
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpUtilities.cs b/src/core/srcbc/openpgp/PgpUtilities.cs
new file mode 100644
index 0000000..557f340
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpUtilities.cs
@@ -0,0 +1,431 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Basic utility class.
+ public sealed class PgpUtilities
+ {
+ private PgpUtilities()
+ {
+ }
+
+ public static MPInteger[] DsaSigToMpi(
+ byte[] encoding)
+ {
+ DerInteger i1, i2;
+
+ try
+ {
+ Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+ i1 = (DerInteger) s[0];
+ i2 = (DerInteger) s[1];
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding signature", e);
+ }
+
+ return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) };
+ }
+
+ public static MPInteger[] RsaSigToMpi(
+ byte[] encoding)
+ {
+ return new MPInteger[]{ new MPInteger(new BigInteger(1, encoding)) };
+ }
+
+ public static string GetDigestName(
+ HashAlgorithmTag hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha1:
+ return "SHA1";
+ case HashAlgorithmTag.MD2:
+ return "MD2";
+ case HashAlgorithmTag.MD5:
+ return "MD5";
+ case HashAlgorithmTag.RipeMD160:
+ return "RIPEMD160";
+ case HashAlgorithmTag.Sha224:
+ return "SHA224";
+ case HashAlgorithmTag.Sha256:
+ return "SHA256";
+ case HashAlgorithmTag.Sha384:
+ return "SHA384";
+ case HashAlgorithmTag.Sha512:
+ return "SHA512";
+ default:
+ throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
+ }
+ }
+
+ public static string GetSignatureName(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ string encAlg;
+ switch (keyAlgorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ encAlg = "RSA";
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ encAlg = "DSA";
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ encAlg = "ElGamal";
+ break;
+ default:
+ throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
+ }
+
+ return GetDigestName(hashAlgorithm) + "with" + encAlg;
+ }
+
+ public static string GetSymmetricCipherName(
+ SymmetricKeyAlgorithmTag algorithm)
+ {
+ switch (algorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Null:
+ return null;
+ case SymmetricKeyAlgorithmTag.TripleDes:
+ return "DESEDE";
+ case SymmetricKeyAlgorithmTag.Idea:
+ return "IDEA";
+ case SymmetricKeyAlgorithmTag.Cast5:
+ return "CAST5";
+ case SymmetricKeyAlgorithmTag.Blowfish:
+ return "Blowfish";
+ case SymmetricKeyAlgorithmTag.Safer:
+ return "SAFER";
+ case SymmetricKeyAlgorithmTag.Des:
+ return "DES";
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Twofish:
+ return "Twofish";
+ default:
+ throw new PgpException("unknown symmetric algorithm: " + algorithm);
+ }
+ }
+
+ public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+ {
+ int keySize;
+ switch (algorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Des:
+ keySize = 64;
+ break;
+ case SymmetricKeyAlgorithmTag.Idea:
+ case SymmetricKeyAlgorithmTag.Cast5:
+ case SymmetricKeyAlgorithmTag.Blowfish:
+ case SymmetricKeyAlgorithmTag.Safer:
+ case SymmetricKeyAlgorithmTag.Aes128:
+ keySize = 128;
+ break;
+ case SymmetricKeyAlgorithmTag.TripleDes:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ keySize = 192;
+ break;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ case SymmetricKeyAlgorithmTag.Twofish:
+ keySize = 256;
+ break;
+ default:
+ throw new PgpException("unknown symmetric algorithm: " + algorithm);
+ }
+
+ return keySize;
+ }
+
+ public static KeyParameter MakeKey(
+ SymmetricKeyAlgorithmTag algorithm,
+ byte[] keyBytes)
+ {
+ string algName = GetSymmetricCipherName(algorithm);
+
+ return ParameterUtilities.CreateKeyParameter(algName, keyBytes);
+ }
+
+ public static KeyParameter MakeRandomKey(
+ SymmetricKeyAlgorithmTag algorithm,
+ SecureRandom random)
+ {
+ int keySize = GetKeySize(algorithm);
+ byte[] keyBytes = new byte[(keySize + 7) / 8];
+ random.NextBytes(keyBytes);
+ return MakeKey(algorithm, keyBytes);
+ }
+
+ public static KeyParameter MakeKeyFromPassPhrase(
+ SymmetricKeyAlgorithmTag algorithm,
+ S2k s2k,
+ char[] passPhrase)
+ {
+ int keySize = GetKeySize(algorithm);
+ byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
+ byte[] keyBytes = new byte[(keySize + 7) / 8];
+
+ int generatedBytes = 0;
+ int loopCount = 0;
+
+ while (generatedBytes < keyBytes.Length)
+ {
+ IDigest digest;
+ if (s2k != null)
+ {
+ try
+ {
+ switch (s2k.HashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha1:
+ digest = DigestUtilities.GetDigest("SHA1");
+ break;
+ default:
+ throw new PgpException("unknown hash algorithm: " + s2k.HashAlgorithm);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't find S2k digest", e);
+ }
+
+ for (int i = 0; i != loopCount; i++)
+ {
+ digest.Update(0);
+ }
+
+ byte[] iv = s2k.GetIV();
+
+ switch (s2k.Type)
+ {
+ case S2k.Simple:
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ break;
+ case S2k.Salted:
+ digest.BlockUpdate(iv, 0, iv.Length);
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ break;
+ case S2k.SaltedAndIterated:
+ long count = s2k.IterationCount;
+ digest.BlockUpdate(iv, 0, iv.Length);
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+
+ count -= iv.Length + pBytes.Length;
+
+ while (count > 0)
+ {
+ if (count < iv.Length)
+ {
+ digest.BlockUpdate(iv, 0, (int)count);
+ break;
+ }
+ else
+ {
+ digest.BlockUpdate(iv, 0, iv.Length);
+ count -= iv.Length;
+ }
+
+ if (count < pBytes.Length)
+ {
+ digest.BlockUpdate(pBytes, 0, (int)count);
+ count = 0;
+ }
+ else
+ {
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ count -= pBytes.Length;
+ }
+ }
+ break;
+ default:
+ throw new PgpException("unknown S2k type: " + s2k.Type);
+ }
+ }
+ else
+ {
+ try
+ {
+ digest = DigestUtilities.GetDigest("MD5");
+
+ for (int i = 0; i != loopCount; i++)
+ {
+ digest.Update(0);
+ }
+
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't find MD5 digest", e);
+ }
+ }
+
+ byte[] dig = DigestUtilities.DoFinal(digest);
+
+ if (dig.Length > (keyBytes.Length - generatedBytes))
+ {
+ Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
+ }
+ else
+ {
+ Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
+ }
+
+ generatedBytes += dig.Length;
+
+ loopCount++;
+ }
+
+ Array.Clear(pBytes, 0, pBytes.Length);
+
+ return MakeKey(algorithm, keyBytes);
+ }
+
+ /// Write out the passed in file as a literal data packet.
+ public static void WriteFileToLiteralData(
+ Stream outputStream,
+ char fileType,
+ FileInfo file)
+ {
+ Stream inStr = file.OpenRead();
+ Stream outStr = new PgpLiteralDataGenerator().Open(
+ outputStream, fileType, file.Name, file.Length, file.LastWriteTime);
+
+ Streams.PipeAll(inStr, outStr);
+
+ inStr.Close();
+ outStr.Close();
+ }
+
+ /// Write out the passed in file as a literal data packet in partial packet format.
+ public static void WriteFileToLiteralData(
+ Stream outputStream,
+ char fileType,
+ FileInfo file,
+ byte[] buffer)
+ {
+ PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+ Stream pOut = lData.Open(outputStream, fileType, file.Name, file.LastWriteTime, buffer);
+ FileStream inputStream = file.OpenRead();
+ byte[] buf = new byte[buffer.Length];
+
+ int len;
+ while ((len = inputStream.Read(buf, 0, buf.Length)) > 0)
+ {
+ pOut.Write(buf, 0, len);
+ }
+
+ lData.Close();
+ inputStream.Close();
+ }
+
+ private const int ReadAhead = 60;
+
+ private static bool IsPossiblyBase64(
+ int ch)
+ {
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/')
+ || (ch == '\r') || (ch == '\n');
+ }
+
+ ///
+ /// Return either an ArmoredInputStream or a BcpgInputStream based on whether
+ /// the initial characters of the stream are binary PGP encodings or not.
+ ///
+ public static Stream GetDecoderStream(
+ Stream inputStream)
+ {
+ // TODO Remove this restriction?
+ if (!inputStream.CanSeek)
+ throw new ArgumentException("inputStream must be seek-able", "inputStream");
+
+ long markedPos = inputStream.Position;
+
+ int ch = inputStream.ReadByte();
+ if ((ch & 0x80) != 0)
+ {
+ inputStream.Position = markedPos;
+
+ return inputStream;
+ }
+ else
+ {
+ if (!IsPossiblyBase64(ch))
+ {
+ inputStream.Position = markedPos;
+
+ return new ArmoredInputStream(inputStream);
+ }
+
+ byte[] buf = new byte[ReadAhead];
+ int count = 1;
+ int index = 1;
+
+ buf[0] = (byte)ch;
+ while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
+ {
+ if (!IsPossiblyBase64(ch))
+ {
+ inputStream.Position = markedPos;
+
+ return new ArmoredInputStream(inputStream);
+ }
+
+ if (ch != '\n' && ch != '\r')
+ {
+ buf[index++] = (byte)ch;
+ }
+
+ count++;
+ }
+
+ inputStream.Position = markedPos;
+
+ //
+ // nothing but new lines, little else, assume regular armoring
+ //
+ if (count < 4)
+ {
+ return new ArmoredInputStream(inputStream);
+ }
+
+ //
+ // test our non-blank data
+ //
+ byte[] firstBlock = new byte[8];
+ Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
+ byte[] decoded = Base64.Decode(firstBlock);
+
+ //
+ // it's a base64 PGP block.
+ //
+ bool hasHeaders = (decoded[0] & 0x80) == 0;
+
+ return new ArmoredInputStream(inputStream, hasHeaders);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/PgpV3SignatureGenerator.cs b/src/core/srcbc/openpgp/PgpV3SignatureGenerator.cs
new file mode 100644
index 0000000..638e406
--- /dev/null
+++ b/src/core/srcbc/openpgp/PgpV3SignatureGenerator.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for old style PGP V3 Signatures.
+ // TODO Should be able to implement ISigner?
+ public class PgpV3SignatureGenerator
+ {
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private PgpPrivateKey privKey;
+ private ISigner sig;
+ private IDigest dig;
+ private int signatureType;
+ private byte lastb;
+
+ /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.
+ public PgpV3SignatureGenerator(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+
+ dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+ sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key)
+ {
+ InitSign(sigType, key, null);
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key,
+ SecureRandom random)
+ {
+ this.privKey = key;
+ this.signatureType = sigType;
+
+ try
+ {
+ ICipherParameters cp = key.Key;
+ if (random != null)
+ {
+ cp = new ParametersWithRandom(key.Key, random);
+ }
+
+ sig.Init(true, cp);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+
+ dig.Reset();
+ lastb = 0;
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ doUpdateByte((byte)'\r');
+ doUpdateByte((byte)'\n');
+ }
+
+ private void doUpdateByte(
+ byte b)
+ {
+ sig.Update(b);
+ dig.Update(b);
+ }
+
+ public void Update(
+ byte[] b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ for (int i = 0; i != b.Length; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, 0, b.Length);
+ dig.BlockUpdate(b, 0, b.Length);
+ }
+ }
+
+ public void Update(
+ byte[] b,
+ int off,
+ int len)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + len;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, off, len);
+ dig.BlockUpdate(b, off, len);
+ }
+ }
+
+ /// Return the one pass header associated with the current signature.
+ public PgpOnePassSignature GenerateOnePassVersion(
+ bool isNested)
+ {
+ return new PgpOnePassSignature(
+ new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+ }
+
+ /// Return a V3 signature object containing the current signature state.
+ public PgpSignature Generate()
+ {
+ long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L;
+
+ byte[] hData = new byte[]
+ {
+ (byte) signatureType,
+ (byte)(creationTime >> 24),
+ (byte)(creationTime >> 16),
+ (byte)(creationTime >> 8),
+ (byte) creationTime
+ };
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ byte[] sigBytes = sig.GenerateSignature();
+ byte[] digest = DigestUtilities.DoFinal(dig);
+ byte[] fingerPrint = new byte[]{ digest[0], digest[1] };
+
+ // an RSA signature
+ bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+ || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+ MPInteger[] sigValues = isRsa
+ ? PgpUtilities.RsaSigToMpi(sigBytes)
+ : PgpUtilities.DsaSigToMpi(sigBytes);
+
+ return new PgpSignature(
+ new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm,
+ hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues));
+ }
+ }
+}
diff --git a/src/core/srcbc/openpgp/WrappedGeneratorStream.cs b/src/core/srcbc/openpgp/WrappedGeneratorStream.cs
new file mode 100644
index 0000000..e550ffd
--- /dev/null
+++ b/src/core/srcbc/openpgp/WrappedGeneratorStream.cs
@@ -0,0 +1,25 @@
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class WrappedGeneratorStream
+ : FilterStream
+ {
+ private readonly IStreamGenerator gen;
+
+ public WrappedGeneratorStream(
+ IStreamGenerator gen,
+ Stream str)
+ : base(str)
+ {
+ this.gen = gen;
+ }
+
+ public override void Close()
+ {
+ gen.Close();
+ }
+ }
+}
diff --git a/src/core/srcbc/openssl/IPasswordFinder.cs b/src/core/srcbc/openssl/IPasswordFinder.cs
new file mode 100644
index 0000000..d32d3fb
--- /dev/null
+++ b/src/core/srcbc/openssl/IPasswordFinder.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ public interface IPasswordFinder
+ {
+ char[] GetPassword();
+ }
+}
diff --git a/src/core/srcbc/openssl/PEMReader.cs b/src/core/srcbc/openssl/PEMReader.cs
new file mode 100644
index 0000000..982fc6f
--- /dev/null
+++ b/src/core/srcbc/openssl/PEMReader.cs
@@ -0,0 +1,453 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ /**
+ * Class for reading OpenSSL PEM encoded streams containing
+ * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
+ *
+ * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
+ * Certificates will be returned using the appropriate java.security type.
+ */
+ public class PemReader
+ {
+ private readonly TextReader reader;
+ private readonly IPasswordFinder pFinder;
+
+ public TextReader Reader
+ {
+ get { return reader; }
+ }
+
+ /**
+ * Create a new PemReader
+ *
+ * @param reader the Reader
+ */
+ public PemReader(
+ TextReader reader)
+ : this(reader, null)
+ {
+ }
+
+ /**
+ * Create a new PemReader with a password finder
+ *
+ * @param reader the Reader
+ * @param pFinder the password finder
+ */
+ public PemReader(
+ TextReader reader,
+ IPasswordFinder pFinder)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ this.reader = reader;
+ this.pFinder = pFinder;
+ }
+
+ private const string BeginString = "-----BEGIN ";
+
+ public object ReadObject()
+ {
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ int startPos = line.IndexOf(BeginString);
+ if (startPos == -1)
+ continue;
+
+ startPos += BeginString.Length;
+
+ int endPos = line.IndexOf('-', startPos);
+ if (endPos == -1)
+ endPos = line.Length;
+
+ string headerName = line.Substring(startPos, endPos - startPos).Trim();
+ //Console.WriteLine("[" + headerName + "]");
+
+ string endMarker = "-----END " + headerName;
+
+ switch (headerName)
+ {
+ case "PUBLIC KEY":
+ return ReadPublicKey(endMarker);
+ case "RSA PUBLIC KEY":
+ return ReadRsaPublicKey(endMarker);
+ case "CERTIFICATE REQUEST":
+ case "NEW CERTIFICATE REQUEST":
+ return ReadCertificateRequest(endMarker);
+ case "CERTIFICATE":
+ case "X509 CERTIFICATE":
+ return ReadCertificate(endMarker);
+ case "PKCS7":
+ return ReadPkcs7(endMarker);
+ case "X509 CRL":
+ return ReadCrl(endMarker);
+ case "ATTRIBUTE CERTIFICATE":
+ return ReadAttributeCertificate(endMarker);
+ case "RSA PRIVATE KEY":
+ return ReadKeyPair("RSA", endMarker);
+ case "DSA PRIVATE KEY":
+ return ReadKeyPair("DSA", endMarker);
+ // TODO Add back in when tests done, and return type issue resolved
+ //case "EC PARAMETERS":
+ // return ReadECParameters(endMarker);
+ case "EC PRIVATE KEY":
+ return ReadECPrivateKey(endMarker);
+ default:
+ // TODO Throw an exception for an unknown header?
+
+ // Ignore contents
+ ReadBytes(endMarker);
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] ReadBytes(
+ string endMarker)
+ {
+ return ReadBytesAndFields(endMarker, null);
+ }
+
+ private byte[] ReadBytesAndFields(
+ string endMarker,
+ IDictionary fields)
+ {
+ StringBuilder buf = new StringBuilder();
+
+ string line;
+ while ((line = reader.ReadLine()) != null
+ && line.IndexOf(endMarker) == -1)
+ {
+ int colonPos = line.IndexOf(':');
+
+ if (colonPos == -1)
+ {
+ buf.Append(line.Trim());
+ }
+ else if (fields != null)
+ {
+ // Process field
+ string fieldName = line.Substring(0, colonPos).Trim();
+
+ if (fieldName.StartsWith("X-"))
+ fieldName = fieldName.Substring(2);
+
+ string fieldValue = line.Substring(colonPos + 1).Trim();
+
+ // TODO Complain if field already specified?
+ fields[fieldName] = fieldValue;
+ }
+ }
+
+ if (line == null)
+ {
+ throw new IOException(endMarker + " not found");
+ }
+
+ if (buf.Length % 4 != 0)
+ {
+ throw new IOException("base64 data appears to be truncated");
+ }
+
+ return Base64.Decode(buf.ToString());
+ }
+
+ private AsymmetricKeyParameter ReadRsaPublicKey(
+ string endMarker)
+ {
+ RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance(
+ Asn1Object.FromByteArray(
+ ReadBytes(endMarker)));
+
+ return new RsaKeyParameters(
+ false, // not private
+ rsaPubStructure.Modulus,
+ rsaPubStructure.PublicExponent);
+ }
+
+ private AsymmetricKeyParameter ReadPublicKey(
+ string endMarker)
+ {
+ return PublicKeyFactory.CreateKey(
+ ReadBytes(endMarker));
+ }
+
+ /**
+ * Reads in a X509Certificate.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private X509Certificate ReadCertificate(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+
+ try
+ {
+ return new X509CertificateParser().ReadCertificate(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a X509CRL.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private X509Crl ReadCrl(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+
+ try
+ {
+ return new X509CrlParser().ReadCrl(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a PKCS10 certification request.
+ *
+ * @return the certificate request.
+ * @throws IOException if an I/O error occured
+ */
+ private Pkcs10CertificationRequest ReadCertificateRequest(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+
+ try
+ {
+ return new Pkcs10CertificationRequest(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a X509 Attribute Certificate.
+ *
+ * @return the X509 Attribute Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private IX509AttributeCertificate ReadAttributeCertificate(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+
+ return new X509V2AttributeCertificate(bytes);
+ }
+
+ /**
+ * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
+ * API.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ // TODO Consider returning Asn1.Pkcs.ContentInfo
+ private Asn1.Cms.ContentInfo ReadPkcs7(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+
+ try
+ {
+ return Asn1.Cms.ContentInfo.GetInstance(
+ Asn1Object.FromByteArray(bytes));
+ }
+ catch (Exception e)
+ {
+ throw new IOException("problem parsing PKCS7 object: " + e.ToString());
+ }
+ }
+
+ /**
+ * Read a Key Pair
+ */
+ private AsymmetricCipherKeyPair ReadKeyPair(
+ string type,
+ string endMarker)
+ {
+ //
+ // extract the key
+ //
+ IDictionary fields = new Hashtable();
+ byte[] keyBytes = ReadBytesAndFields(endMarker, fields);
+
+ string procType = (string) fields["Proc-Type"];
+
+ if (procType == "4,ENCRYPTED")
+ {
+ if (pFinder == null)
+ throw new InvalidOperationException("No password finder specified, but a password is required");
+
+ char[] password = pFinder.GetPassword();
+
+ if (password == null)
+ throw new IOException("Password is null, but a password is required");
+
+ string dekInfo = (string) fields["DEK-Info"];
+ string[] tknz = dekInfo.Split(',');
+
+ string dekAlgName = tknz[0].Trim();
+ byte[] iv = Hex.Decode(tknz[1].Trim());
+
+ keyBytes = PemUtilities.Crypt(false, keyBytes, password, dekAlgName, iv);
+ }
+
+ try
+ {
+ AsymmetricKeyParameter pubSpec, privSpec;
+ Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(keyBytes);
+
+ switch (type)
+ {
+ case "RSA":
+ {
+ RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq);
+
+ pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
+ privSpec = new RsaPrivateCrtKeyParameters(
+ rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent,
+ rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
+ rsa.Coefficient);
+
+ break;
+ }
+
+ case "DSA":
+ {
+ // TODO Create an ASN1 object somewhere for this?
+ //DerInteger v = (DerInteger)seq[0];
+ DerInteger p = (DerInteger)seq[1];
+ DerInteger q = (DerInteger)seq[2];
+ DerInteger g = (DerInteger)seq[3];
+ DerInteger y = (DerInteger)seq[4];
+ DerInteger x = (DerInteger)seq[5];
+
+ DsaParameters parameters = new DsaParameters(p.Value, q.Value, g.Value);
+
+ privSpec = new DsaPrivateKeyParameters(x.Value, parameters);
+ pubSpec = new DsaPublicKeyParameters(y.Value, parameters);
+
+ break;
+ }
+
+ default:
+ throw new ArgumentException("Unknown key type: " + type, "type");
+ }
+
+ return new AsymmetricCipherKeyPair(pubSpec, privSpec);
+ }
+ catch (Exception e)
+ {
+ throw new IOException(
+ "problem creating " + type + " private key: " + e.ToString());
+ }
+ }
+
+ // TODO Add an equivalent class for ECNamedCurveParameterSpec?
+ //private ECNamedCurveParameterSpec ReadECParameters(
+ private X9ECParameters ReadECParameters(
+ string endMarker)
+ {
+ byte[] bytes = ReadBytes(endMarker);
+ DerObjectIdentifier oid = (DerObjectIdentifier) Asn1Object.FromByteArray(bytes);
+
+ //return ECNamedCurveTable.getParameterSpec(oid.Id);
+ return GetCurveParameters(oid.Id);
+ }
+
+ //private static ECDomainParameters GetCurveParameters(
+ private static X9ECParameters GetCurveParameters(
+ string name)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+ X9ECParameters ecP = X962NamedCurves.GetByName(name);
+
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByName(name);
+ if (ecP == null)
+ {
+ ecP = NistNamedCurves.GetByName(name);
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByName(name);
+
+ if (ecP == null)
+ throw new Exception("unknown curve name: " + name);
+ }
+ }
+ }
+
+ //return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+ return ecP;
+ }
+
+ private AsymmetricCipherKeyPair ReadECPrivateKey(
+ string endMarker)
+ {
+ try
+ {
+ byte[] bytes = ReadBytes(endMarker);
+ ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(
+ (Asn1Sequence) Asn1Object.FromByteArray(bytes));
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters());
+
+ PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.ToAsn1Object());
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.GetPublicKey().GetBytes());
+
+ // TODO Are the keys returned here ECDSA, as Java version forces?
+ return new AsymmetricCipherKeyPair(
+ PublicKeyFactory.CreateKey(pubInfo),
+ PrivateKeyFactory.CreateKey(privInfo));
+ }
+ catch (InvalidCastException e)
+ {
+ throw new IOException("wrong ASN.1 object found in stream.", e);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("problem parsing EC private key.", e);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/openssl/PEMUtilities.cs b/src/core/srcbc/openssl/PEMUtilities.cs
new file mode 100644
index 0000000..e9671eb
--- /dev/null
+++ b/src/core/srcbc/openssl/PEMUtilities.cs
@@ -0,0 +1,138 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ internal sealed class PemUtilities
+ {
+ internal static bool ParseDekAlgName(
+ string dekAlgName,
+ out string baseAlg,
+ out string mode)
+ {
+ baseAlg = dekAlgName;
+ mode = "ECB";
+
+ if (dekAlgName == "DES-EDE" || dekAlgName == "DES-EDE3")
+ return true;
+
+ int pos = dekAlgName.LastIndexOf('-');
+ if (pos < 0)
+ return false;
+
+ baseAlg = dekAlgName.Substring(0, pos);
+ mode = dekAlgName.Substring(pos + 1);
+
+ return true;
+ }
+
+ internal static byte[] Crypt(
+ bool encrypt,
+ byte[] bytes,
+ char[] password,
+ string dekAlgName,
+ byte[] iv)
+ {
+ string baseAlg, mode;
+ if (!ParseDekAlgName(dekAlgName, out baseAlg, out mode))
+ throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName");
+
+ string padding;
+ switch (mode)
+ {
+ case "CBC":
+ case "ECB":
+ padding = "PKCS5Padding";
+ break;
+ case "CFB":
+ case "OFB":
+ padding = "NoPadding";
+ break;
+ default:
+ throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName");
+ }
+
+ string algorithm;
+
+ byte[] salt = iv;
+ switch (baseAlg)
+ {
+ case "AES-128":
+ case "AES-192":
+ case "AES-256":
+ algorithm = "AES";
+ if (salt.Length > 8)
+ {
+ salt = new byte[8];
+ Array.Copy(iv, 0, salt, 0, salt.Length);
+ }
+ break;
+ case "BF":
+ algorithm = "BLOWFISH";
+ break;
+ case "DES":
+ algorithm = "DES";
+ break;
+ case "DES-EDE":
+ case "DES-EDE3":
+ algorithm = "DESede";
+ break;
+ case "RC2":
+ case "RC2-40":
+ case "RC2-64":
+ algorithm = "RC2";
+ break;
+ default:
+ throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName");
+ }
+
+ string cipherName = algorithm + "/" + mode + "/" + padding;
+ IBufferedCipher cipher = CipherUtilities.GetCipher(cipherName);
+
+ ICipherParameters cParams = GetCipherParameters(password, baseAlg, salt);
+
+ if (mode != "ECB")
+ {
+ cParams = new ParametersWithIV(cParams, iv);
+ }
+
+ cipher.Init(encrypt, cParams);
+
+ return cipher.DoFinal(bytes);
+ }
+
+ private static ICipherParameters GetCipherParameters(
+ char[] password,
+ string baseAlg,
+ byte[] salt)
+ {
+ string algorithm;
+ int keyBits;
+ switch (baseAlg)
+ {
+ case "AES-128": keyBits = 128; algorithm = "AES128"; break;
+ case "AES-192": keyBits = 192; algorithm = "AES192"; break;
+ case "AES-256": keyBits = 256; algorithm = "AES256"; break;
+ case "BF": keyBits = 128; algorithm = "BLOWFISH"; break;
+ case "DES": keyBits = 64; algorithm = "DES"; break;
+ case "DES-EDE": keyBits = 128; algorithm = "DESEDE"; break;
+ case "DES-EDE3": keyBits = 192; algorithm = "DESEDE3"; break;
+ case "RC2": keyBits = 128; algorithm = "RC2"; break;
+ case "RC2-40": keyBits = 40; algorithm = "RC2"; break;
+ case "RC2-64": keyBits = 64; algorithm = "RC2"; break;
+ default:
+ return null;
+ }
+
+ OpenSslPbeParametersGenerator pGen = new OpenSslPbeParametersGenerator();
+
+ pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt);
+
+ return pGen.GenerateDerivedParameters(algorithm, keyBits);
+ }
+ }
+}
diff --git a/src/core/srcbc/openssl/PEMWriter.cs b/src/core/srcbc/openssl/PEMWriter.cs
new file mode 100644
index 0000000..e6fa7cb
--- /dev/null
+++ b/src/core/srcbc/openssl/PEMWriter.cs
@@ -0,0 +1,278 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ /// General purpose writer for OpenSSL PEM objects.
+ public class PemWriter
+ {
+ private readonly TextWriter writer;
+
+ public TextWriter Writer
+ {
+ get { return writer; }
+ }
+
+ /// The TextWriter object to write the output to.
+ public PemWriter(
+ TextWriter writer)
+ {
+ if (writer == null)
+ throw new ArgumentNullException("writer");
+
+ this.writer = writer;
+ }
+
+ public void WriteObject(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ string type;
+ byte[] encoding;
+
+ if (obj is X509Certificate)
+ {
+ // TODO Should we prefer "X509 CERTIFICATE" here?
+ type = "CERTIFICATE";
+ try
+ {
+ encoding = ((X509Certificate)obj).GetEncoded();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is X509Crl)
+ {
+ type = "X509 CRL";
+ try
+ {
+ encoding = ((X509Crl)obj).GetEncoded();
+ }
+ catch (CrlException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is AsymmetricCipherKeyPair)
+ {
+ WriteObject(((AsymmetricCipherKeyPair)obj).Private);
+ return;
+ }
+ else if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ encoding = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ else
+ {
+ type = "PUBLIC KEY";
+
+ encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
+ }
+ }
+ else if (obj is IX509AttributeCertificate)
+ {
+ type = "ATTRIBUTE CERTIFICATE";
+ encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
+ }
+ else if (obj is Pkcs10CertificationRequest)
+ {
+ type = "CERTIFICATE REQUEST";
+ encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
+ }
+ else if (obj is Asn1.Cms.ContentInfo)
+ {
+ type = "PKCS7";
+ encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
+ }
+ else
+ {
+ throw new ArgumentException("Object type not supported: " + obj.GetType().FullName, "obj");
+ }
+
+ WritePemBlock(type, encoding);
+ }
+
+ public void WriteObject(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ if (obj is AsymmetricCipherKeyPair)
+ {
+ WriteObject(((AsymmetricCipherKeyPair) obj).Private, algorithm, password, random);
+ return;
+ }
+
+ string type = null;
+ byte[] keyData = null;
+
+ if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ keyData = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ }
+
+ if (type == null || keyData == null)
+ {
+ // TODO Support other types?
+ throw new ArgumentException("Object type not supported: " + obj.GetType().FullName, "obj");
+ }
+
+
+ string dekAlgName = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ // Note: For backward compatibility
+ if (dekAlgName == "DESEDE")
+ {
+ dekAlgName = "DES-EDE3-CBC";
+ }
+
+ int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8;
+
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+
+ byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
+ byte[] hexIV = Hex.Encode(iv);
+
+ WritePemBlock(type, encData,
+ "Proc-Type: 4,ENCRYPTED",
+ "DEK-Info: " + dekAlgName + "," + Encoding.ASCII.GetString(hexIV, 0, hexIV.Length));
+ }
+
+ private byte[] EncodePrivateKey(
+ AsymmetricKeyParameter akp,
+ out string keyType)
+ {
+ PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
+
+ DerObjectIdentifier oid = info.AlgorithmID.ObjectID;
+
+ if (oid.Equals(X9ObjectIdentifiers.IdDsa))
+ {
+ keyType = "DSA";
+
+ DsaParameter p = DsaParameter.GetInstance(info.AlgorithmID.Parameters);
+
+ BigInteger x = ((DsaPrivateKeyParameters) akp).X;
+ BigInteger y = p.G.ModPow(x, p.P);
+
+ // TODO Create an ASN1 object somewhere for this?
+ return new DerSequence(
+ new DerInteger(0),
+ new DerInteger(p.P),
+ new DerInteger(p.Q),
+ new DerInteger(p.G),
+ new DerInteger(y),
+ new DerInteger(x)).GetEncoded();
+ }
+
+ if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
+ {
+ keyType = "RSA";
+ return info.PrivateKey.GetEncoded();
+ }
+
+ throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp");
+ }
+
+ private void WritePemBlock(
+ string type,
+ byte[] data,
+ params string[] fields)
+ {
+ WriteHeader(type);
+
+ if (fields.Length > 0)
+ {
+ foreach (string field in fields)
+ {
+ writer.WriteLine(field);
+ }
+
+ writer.WriteLine();
+ }
+
+ WriteBytes(Base64.Encode(data));
+
+ WriteFooter(type);
+ }
+
+ private void WriteHeader(
+ string type)
+ {
+ writer.WriteLine("-----BEGIN " + type + "-----");
+ }
+
+ private void WriteFooter(
+ string type)
+ {
+ writer.WriteLine("-----END " + type + "-----");
+ }
+
+ private const int LineLength = 64;
+
+ private void WriteBytes(
+ byte[] bytes)
+ {
+ int pos = 0;
+ int remaining = bytes.Length;
+ char[] buf = new char[LineLength];
+
+ while (remaining > LineLength)
+ {
+ Encoding.ASCII.GetChars(bytes, pos, LineLength, buf, 0);
+ writer.WriteLine(buf);
+
+ pos += LineLength;
+ remaining -= LineLength;
+ }
+
+ Encoding.ASCII.GetChars(bytes, pos, remaining, buf, 0);
+ writer.WriteLine(buf, 0, remaining);
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/AsymmetricKeyEntry.cs b/src/core/srcbc/pkcs/AsymmetricKeyEntry.cs
new file mode 100644
index 0000000..6dd2c0b
--- /dev/null
+++ b/src/core/srcbc/pkcs/AsymmetricKeyEntry.cs
@@ -0,0 +1,32 @@
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class AsymmetricKeyEntry
+ : Pkcs12Entry
+ {
+ private readonly AsymmetricKeyParameter key;
+
+ public AsymmetricKeyEntry(
+ AsymmetricKeyParameter key)
+ : base(new Hashtable())
+ {
+ this.key = key;
+ }
+
+ public AsymmetricKeyEntry(
+ AsymmetricKeyParameter key,
+ Hashtable attributes)
+ : base(attributes)
+ {
+ this.key = key;
+ }
+
+ public AsymmetricKeyParameter Key
+ {
+ get { return this.key; }
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs b/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs
new file mode 100644
index 0000000..67fcee3
--- /dev/null
+++ b/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public sealed class EncryptedPrivateKeyInfoFactory
+ {
+ private EncryptedPrivateKeyInfoFactory()
+ {
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ DerObjectIdentifier algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return CreateEncryptedPrivateKeyInfo(
+ algorithm.Id, passPhrase, salt, iterationCount,
+ PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ string algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return CreateEncryptedPrivateKeyInfo(
+ algorithm, passPhrase, salt, iterationCount,
+ PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ string algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ PrivateKeyInfo keyInfo)
+ {
+ if (!PbeUtilities.IsPbeAlgorithm(algorithm))
+ throw new ArgumentException("attempt to use non-Pbe algorithm with Pbe EncryptedPrivateKeyInfo generation");
+
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher;
+
+ if (cipher == null)
+ {
+ // TODO Throw exception?
+ }
+
+ Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters(
+ algorithm, salt, iterationCount);
+
+ ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters(
+ algorithm, passPhrase, parameters);
+
+ cipher.Init(true, keyParameters);
+
+ byte[] keyBytes = keyInfo.GetEncoded();
+ byte[] encoding = cipher.DoFinal(keyBytes);
+
+ DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm);
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters);
+
+ return new EncryptedPrivateKeyInfo(algID, encoding);
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/Pkcs10CertificationRequest.cs b/src/core/srcbc/pkcs/Pkcs10CertificationRequest.cs
new file mode 100644
index 0000000..9275d2e
--- /dev/null
+++ b/src/core/srcbc/pkcs/Pkcs10CertificationRequest.cs
@@ -0,0 +1,447 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ ///
+ /// A class for verifying and creating Pkcs10 Certification requests.
+ ///
+ ///
+ /// CertificationRequest ::= Sequence {
+ /// certificationRequestInfo CertificationRequestInfo,
+ /// signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ /// signature BIT STRING
+ /// }
+ ///
+ /// CertificationRequestInfo ::= Sequence {
+ /// version Integer { v1(0) } (v1,...),
+ /// subject Name,
+ /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ /// attributes [0] Attributes{{ CRIAttributes }}
+ /// }
+ ///
+ /// Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+ ///
+ /// Attr { ATTRIBUTE:IOSet } ::= Sequence {
+ /// type ATTRIBUTE.&id({IOSet}),
+ /// values Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ /// }
+ ///
+ /// see
+ public class Pkcs10CertificationRequest
+ : CertificationRequest
+ {
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable exParams = new Hashtable();
+ private static readonly Hashtable keyAlgorithms = new Hashtable();
+ private static readonly Hashtable oids = new Hashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static Pkcs10CertificationRequest()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.Add("MD2WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.Add("MD5WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("MD5WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("RSAWITHMD5", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("SHA1WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("SHA1WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RSAWITHSHA1", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", new DerObjectIdentifier("1.3.36.3.3.1.2"));
+ algorithms.Add("RIPEMD160WITHRSA", new DerObjectIdentifier("1.3.36.3.3.1.2"));
+ algorithms.Add("SHA1WITHDSA", new DerObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.Add("DSAWITHSHA1", new DerObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // reverse mappings
+ //
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411WITHECGOST3410");
+
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.Add(new DerObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+ oids.Add(OiwObjectIdentifiers.Sha1WithRsa, "SHA1WITHRSA");
+ oids.Add(OiwObjectIdentifiers.DsaWithSha1, "SHA1WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.Add(PkcsObjectIdentifiers.RsaEncryption, "RSA");
+ keyAlgorithms.Add(X9ObjectIdentifiers.IdDsa, "DSA");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ public Pkcs10CertificationRequest(
+ byte[] encoded)
+ : base((Asn1Sequence) Asn1Object.FromByteArray(encoded))
+ {
+ }
+
+ public Pkcs10CertificationRequest(
+ Asn1Sequence seq)
+ : base(seq)
+ {
+ }
+
+ public Pkcs10CertificationRequest(
+ Stream input)
+ : base((Asn1Sequence) Asn1Object.FromStream(input))
+ {
+ }
+
+ ///
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ ///
+ ///Name of Sig Alg.
+ /// X509Name of subject eg OU="My unit." O="My Organisatioin" C="au"
+ /// Public Key to be included in cert reqest.
+ /// ASN1Set of Attributes.
+ /// Matching Private key for nominated (above) public key to be used to sign the request.
+ public Pkcs10CertificationRequest(
+ string signatureAlgorithm,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ if (signatureAlgorithm == null)
+ throw new ArgumentNullException("signatureAlgorithm");
+ if (subject == null)
+ throw new ArgumentNullException("subject");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("expected public key", "publicKey");
+ if (!signingKey.IsPrivate)
+ throw new ArgumentException("key for signing must be private", "signingKey");
+
+// DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
+ string algorithmName = signatureAlgorithm.ToUpper(CultureInfo.InvariantCulture);
+ DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
+
+ if (sigOid == null)
+ throw new ArgumentException("Unknown signature type requested");
+
+ if (noParams.Contains(sigOid))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid);
+ }
+ else if (exParams.ContainsKey(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid, null);
+ }
+
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+ this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+
+ ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm);
+
+ sig.Init(true, signingKey);
+
+ try
+ {
+ // Encode.
+ byte[] b = reqInfo.GetDerEncoded();
+ sig.BlockUpdate(b, 0, b.Length);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("exception encoding TBS cert request", e);
+ }
+
+ // Generate Signature.
+ sigBits = new DerBitString(sig.GenerateSignature());
+ }
+
+// internal Pkcs10CertificationRequest(
+// Asn1InputStream seqStream)
+// {
+// Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
+// try
+// {
+// this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+// this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+// this.sigBits = (DerBitString) seq[2];
+// }
+// catch (Exception ex)
+// {
+// throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
+// }
+// }
+
+ ///
+ /// Get the public key.
+ ///
+ /// The public key.
+ public AsymmetricKeyParameter GetPublicKey()
+ {
+ return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo);
+ }
+
+ ///
+ /// Verify Pkcs10 Cert Request is valid.
+ ///
+ /// true = valid.
+ public bool Verify()
+ {
+ return Verify(this.GetPublicKey());
+ }
+
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ ISigner sig;
+
+ try
+ {
+ sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId));
+ }
+ catch (Exception e)
+ {
+ // try an alternate
+ string alt = (string) oids[sigAlgId.ObjectID];
+
+ if (alt != null)
+ {
+ sig = SignerUtilities.GetSigner(alt);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ SetSignatureParameters(sig, sigAlgId.Parameters);
+
+ sig.Init(false, publicKey);
+
+ try
+ {
+ byte[] b = reqInfo.GetDerEncoded();
+ sig.BlockUpdate(b, 0, b.Length);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request", e);
+ }
+
+ return sig.VerifySignature(sigBits.GetBytes());
+ }
+
+// ///
+// /// Get the Der Encoded Pkcs10 Certification Request.
+// ///
+// /// A byte array.
+// public byte[] GetEncoded()
+// {
+// return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
+// }
+
+ // TODO Figure out how to set parameters on an ISigner
+ private void SetSignatureParameters(
+ ISigner signature,
+ Asn1Encodable asn1Params)
+ {
+ if (asn1Params != null && !(asn1Params is Asn1Null))
+ {
+// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+// try
+// {
+// sigParams.init(asn1Params.ToAsn1Object().GetDerEncoded());
+// }
+// catch (IOException e)
+// {
+// throw new SignatureException("IOException decoding parameters: " + e.Message);
+// }
+
+ if (signature.AlgorithmName.EndsWith("MGF1"))
+ {
+ throw Platform.CreateNotImplementedException("signature algorithm with MGF1");
+
+// try
+// {
+// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+// }
+// catch (GeneralSecurityException e)
+// {
+// throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+// }
+ }
+ }
+ }
+
+ internal static string GetSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable asn1Params = sigAlgId.Parameters;
+
+ if (asn1Params != null && !(asn1Params is Asn1Null))
+ {
+ if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(asn1Params);
+ return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.ObjectID.Id;
+ }
+
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/Pkcs12Entry.cs b/src/core/srcbc/pkcs/Pkcs12Entry.cs
new file mode 100644
index 0000000..714e40d
--- /dev/null
+++ b/src/core/srcbc/pkcs/Pkcs12Entry.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public abstract class Pkcs12Entry
+ {
+ private readonly Hashtable attributes;
+
+ protected internal Pkcs12Entry(
+ Hashtable attributes)
+ {
+ this.attributes = attributes;
+
+ foreach (DictionaryEntry entry in attributes)
+ {
+ if (!(entry.Key is string))
+ throw new ArgumentException("Attribute keys must be of type: " + typeof(string).FullName, "attributes");
+ if (!(entry.Value is Asn1Encodable))
+ throw new ArgumentException("Attribute values must be of type: " + typeof(Asn1Encodable).FullName, "attributes");
+ }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetBagAttribute(
+ DerObjectIdentifier oid)
+ {
+ return (Asn1Encodable)this.attributes[oid.Id];
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetBagAttribute(
+ string oid)
+ {
+ return (Asn1Encodable)this.attributes[oid];
+ }
+
+ [Obsolete("Use 'BagAttributeKeys' property")]
+ public IEnumerator GetBagAttributeKeys()
+ {
+ return this.attributes.Keys.GetEnumerator();
+ }
+
+ public Asn1Encodable this[
+ DerObjectIdentifier oid]
+ {
+ get { return (Asn1Encodable) this.attributes[oid.Id]; }
+ }
+
+ public Asn1Encodable this[
+ string oid]
+ {
+ get { return (Asn1Encodable) this.attributes[oid]; }
+ }
+
+ public IEnumerable BagAttributeKeys
+ {
+ get { return new EnumerableProxy(this.attributes.Keys); }
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/Pkcs12Store.cs b/src/core/srcbc/pkcs/Pkcs12Store.cs
new file mode 100644
index 0000000..920683f
--- /dev/null
+++ b/src/core/srcbc/pkcs/Pkcs12Store.cs
@@ -0,0 +1,1129 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class Pkcs12Store
+ {
+ private readonly IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private readonly Hashtable localIds = new Hashtable();
+ private readonly IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private readonly Hashtable chainCerts = new Hashtable();
+ private readonly Hashtable keyCerts = new Hashtable();
+
+ private static readonly DerObjectIdentifier keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+ private static readonly DerObjectIdentifier CertAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+ private int MinIterations = 1024;
+ private int saltSize = 20;
+
+ private static SubjectKeyIdentifier CreateSubjectKeyID(
+ AsymmetricKeyParameter pubKey)
+ {
+ return new SubjectKeyIdentifier(
+ SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey));
+ }
+
+ internal class CertId
+ {
+ private readonly byte[] id;
+
+ internal CertId(
+ AsymmetricKeyParameter pubKey)
+ {
+ this.id = CreateSubjectKeyID(pubKey).GetKeyIdentifier();
+ }
+
+ internal CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ internal byte[] Id
+ {
+ get { return id; }
+ }
+
+ public override int GetHashCode()
+ {
+ return Arrays.GetHashCode(id);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ CertId other = obj as CertId;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(id, other.id);
+ }
+ }
+
+ public Pkcs12Store()
+ {
+ }
+
+ public Pkcs12Store(
+ Stream input,
+ char[] password)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (password == null)
+ throw new ArgumentNullException("password");
+
+ Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
+ Pfx bag = new Pfx(obj);
+ ContentInfo info = bag.AuthSafe;
+ bool unmarkedKey = false;
+ bool wrongPkcs12Zero = false;
+
+ if (bag.MacData != null) // check the mac code
+ {
+ MacData mData = bag.MacData;
+ DigestInfo dInfo = mData.Mac;
+ AlgorithmIdentifier algId = dInfo.AlgorithmID;
+ byte[] salt = mData.GetSalt();
+ int itCount = mData.IterationCount.IntValue;
+
+ byte[] data = ((Asn1OctetString) info.Content).GetOctets();
+
+ byte[] mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, false, data);
+ byte[] dig = dInfo.GetDigest();
+
+ if (!Arrays.AreEqual(mac, dig))
+ {
+ if (password.Length > 0)
+ throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+ // Try with incorrect zero length password
+ mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, true, data);
+
+ if (!Arrays.AreEqual(mac, dig))
+ throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+ wrongPkcs12Zero = true;
+ }
+ }
+
+ ArrayList chain = new ArrayList();
+
+ if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
+ {
+ byte[] octs = ((Asn1OctetString)info.Content).GetOctets();
+ AuthenticatedSafe authSafe = new AuthenticatedSafe(
+ (Asn1Sequence) Asn1OctetString.FromByteArray(octs));
+ ContentInfo[] cis = authSafe.GetContentInfo();
+
+ foreach (ContentInfo ci in cis)
+ {
+ DerObjectIdentifier oid = ci.ContentType;
+
+ if (oid.Equals(PkcsObjectIdentifiers.Data))
+ {
+ byte[] octets = ((Asn1OctetString)ci.Content).GetOctets();
+ Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+
+ foreach (Asn1Sequence subSeq in seq)
+ {
+ SafeBag b = new SafeBag(subSeq);
+
+ if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+ {
+ EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+ password, wrongPkcs12Zero, eIn);
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
+
+ //
+ // set the attributes on the key
+ //
+ Hashtable attributes = new Hashtable();
+ AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+ string alias = null;
+ Asn1OctetString localId = null;
+
+ if (b.BagAttributes != null)
+ {
+ foreach (Asn1Sequence sq in b.BagAttributes)
+ {
+ DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+ Asn1Set attrSet = (Asn1Set) sq[1];
+ Asn1Encodable attr = null;
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, it is an error
+ attributes.Add(aOid.Id, attr);
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ // TODO Do these in a separate loop, just collect aliases here
+ keys[alias] = pkcs12Key;
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ byte[] hex = Hex.Encode(localId.GetOctets());
+ string name = Encoding.ASCII.GetString(hex, 0, hex.Length);
+
+ if (alias == null)
+ {
+ keys[name] = pkcs12Key;
+ }
+ else
+ {
+ // TODO There may have been more than one alias
+ localIds[alias] = name;
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys["unmarked"] = pkcs12Key;
+ }
+ }
+ else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
+ {
+ chain.Add(b);
+ }
+ else
+ {
+ Console.WriteLine("extra " + b.BagID);
+ Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+ }
+ }
+ }
+ else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+ {
+ EncryptedData d = EncryptedData.GetInstance(ci.Content);
+ byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm,
+ password, wrongPkcs12Zero, d.Content.GetOctets());
+ Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+
+ foreach (Asn1Sequence subSeq in seq)
+ {
+ SafeBag b = new SafeBag(subSeq);
+
+ if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
+ {
+ chain.Add(b);
+ }
+ else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+ {
+ EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+ password, wrongPkcs12Zero, eIn);
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
+
+ //
+ // set the attributes on the key
+ //
+ Hashtable attributes = new Hashtable();
+ AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+ string alias = null;
+ Asn1OctetString localId = null;
+
+ foreach (Asn1Sequence sq in b.BagAttributes)
+ {
+ DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+ Asn1Set attrSet = (Asn1Set) sq[1];
+ Asn1Encodable attr = null;
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, it is an error
+ attributes.Add(aOid.Id, attr);
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ // TODO Do these in a separate loop, just collect aliases here
+ keys[alias] = pkcs12Key;
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+
+ // TODO Should we be checking localIds != null here
+ // as for PkcsObjectIdentifiers.Data version above?
+
+ byte[] hex = Hex.Encode(localId.GetOctets());
+ string name = Encoding.ASCII.GetString(hex, 0, hex.Length);
+
+ if (alias == null)
+ {
+ keys[name] = pkcs12Key;
+ }
+ else
+ {
+ // TODO There may have been more than one alias
+ localIds[alias] = name;
+ }
+ }
+ else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
+ {
+ PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue);
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
+
+ //
+ // set the attributes on the key
+ //
+ string alias = null;
+ Asn1OctetString localId = null;
+ Hashtable attributes = new Hashtable();
+ AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+
+ foreach (Asn1Sequence sq in b.BagAttributes)
+ {
+ DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+ Asn1Set attrSet = (Asn1Set) sq[1];
+ Asn1Encodable attr = null;
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, it is an error
+ attributes.Add(aOid.Id, attr);
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ // TODO Do these in a separate loop, just collect aliases here
+ keys[alias] = pkcs12Key;
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+
+ // TODO Should we be checking localIds != null here
+ // as for PkcsObjectIdentifiers.Data version above?
+
+ byte[] hex = Hex.Encode(localId.GetOctets());
+ string name = Encoding.ASCII.GetString(hex, 0, hex.Length);
+
+ if (alias == null)
+ {
+ keys[name] = pkcs12Key;
+ }
+ else
+ {
+ // TODO There may have been more than one alias
+ localIds[alias] = name;
+ }
+ }
+ else
+ {
+ Console.WriteLine("extra " + b.BagID);
+ Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("extra " + oid);
+ Console.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ foreach (SafeBag b in chain)
+ {
+ CertBag cb = new CertBag((Asn1Sequence)b.BagValue);
+ byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets();
+ X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
+
+ //
+ // set the attributes
+ //
+ Hashtable attributes = new Hashtable();
+ Asn1OctetString localId = null;
+ string alias = null;
+
+ if (b.BagAttributes != null)
+ {
+ foreach (Asn1Sequence sq in b.BagAttributes)
+ {
+ DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+ Asn1Set attrSet = (Asn1Set) sq[1];
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ Asn1Encodable attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, it is an error
+ attributes.Add(aOid.Id, attr);
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+ }
+
+ CertId certId = new CertId(cert.GetPublicKey());
+ X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes);
+
+ chainCerts[certId] = pkcs12Cert;
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.Count == 0)
+ {
+ byte[] hex = Hex.Encode(certId.Id);
+ string name = Encoding.ASCII.GetString(hex, 0, hex.Length);
+
+ keyCerts[name] = pkcs12Cert;
+
+ object temp = keys["unmarked"];
+ keys.Remove("unmarked");
+ keys[name] = temp;
+ }
+ }
+ else
+ {
+ if (localId != null)
+ {
+ byte[] hex = Hex.Encode(localId.GetOctets());
+ string name = Encoding.ASCII.GetString(hex, 0, hex.Length);
+
+ keyCerts[name] = pkcs12Cert;
+ }
+
+ if (alias != null)
+ {
+ // TODO There may have been more than one alias
+ certs[alias] = pkcs12Cert;
+ }
+ }
+ }
+ }
+
+ public AsymmetricKeyEntry GetKey(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (AsymmetricKeyEntry)keys[alias];
+ }
+
+ public bool IsCertificateEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (certs[alias] != null && keys[alias] == null);
+ }
+
+ public bool IsKeyEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (keys[alias] != null);
+ }
+
+ private Hashtable GetAliasesTable()
+ {
+ Hashtable tab = new Hashtable();
+
+ foreach (string key in certs.Keys)
+ {
+ tab[key] = "cert";
+ }
+
+ foreach (string a in keys.Keys)
+ {
+ if (tab[a] == null)
+ {
+ tab[a] = "key";
+ }
+ }
+
+ return tab;
+ }
+
+ public IEnumerable Aliases
+ {
+ get { return new EnumerableProxy(GetAliasesTable().Keys); }
+ }
+
+ public bool ContainsAlias(
+ string alias)
+ {
+ return certs[alias] != null || keys[alias] != null;
+ }
+
+ /**
+ * simply return the cert entry for the private key
+ */
+ public X509CertificateEntry GetCertificate(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ X509CertificateEntry c = (X509CertificateEntry) certs[alias];
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ string id = (string)localIds[alias];
+ if (id != null)
+ {
+ c = (X509CertificateEntry)keyCerts[id];
+ }
+ else
+ {
+ c = (X509CertificateEntry)keyCerts[alias];
+ }
+ }
+
+ return c;
+ }
+
+ public string GetCertificateAlias(
+ X509Certificate cert)
+ {
+ if (cert == null)
+ throw new ArgumentNullException("cert");
+
+ foreach (DictionaryEntry entry in certs)
+ {
+ X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+ if (entryValue.Certificate.Equals(cert))
+ {
+ return (string) entry.Key;
+ }
+ }
+
+ foreach (DictionaryEntry entry in keyCerts)
+ {
+ X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+ if (entryValue.Certificate.Equals(cert))
+ {
+ return (string) entry.Key;
+ }
+ }
+
+ return null;
+ }
+
+ public X509CertificateEntry[] GetCertificateChain(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ if (!IsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ X509CertificateEntry c = GetCertificate(alias);
+
+ if (c != null)
+ {
+ ArrayList cs = new ArrayList();
+
+ while (c != null)
+ {
+ X509Certificate x509c = c.Certificate;
+ X509CertificateEntry nextC = null;
+
+ Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+ if (ext != null)
+ {
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance(
+ Asn1Object.FromByteArray(ext.GetOctets()));
+
+ if (id.GetKeyIdentifier() != null)
+ {
+ nextC = (X509CertificateEntry) chainCerts[new CertId(id.GetKeyIdentifier())];
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ X509Name i = x509c.IssuerDN;
+ X509Name s = x509c.SubjectDN;
+
+ if (!i.Equivalent(s))
+ {
+ foreach (CertId certId in chainCerts.Keys)
+ {
+ X509CertificateEntry x509CertEntry = (X509CertificateEntry) chainCerts[certId];
+
+ X509Certificate crt = x509CertEntry.Certificate;
+
+ X509Name sub = crt.SubjectDN;
+ if (sub.Equivalent(i))
+ {
+ try
+ {
+ x509c.Verify(crt.GetPublicKey());
+
+ nextC = x509CertEntry;
+ break;
+ }
+ catch (InvalidKeyException)
+ {
+ // TODO What if it doesn't verify?
+ }
+ }
+ }
+ }
+ }
+
+ cs.Add(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ return (X509CertificateEntry[]) cs.ToArray(typeof(X509CertificateEntry));
+ }
+
+ return null;
+ }
+
+ public void SetCertificateEntry(
+ string alias,
+ X509CertificateEntry certEntry)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+ if (certEntry == null)
+ throw new ArgumentNullException("certEntry");
+ if (keys[alias] != null)
+ throw new ArgumentException("There is a key entry with the name " + alias + ".");
+
+ certs[alias] = certEntry;
+ chainCerts[new CertId(certEntry.Certificate.GetPublicKey())] = certEntry;
+ }
+
+ public void SetKeyEntry(
+ string alias,
+ AsymmetricKeyEntry keyEntry,
+ X509CertificateEntry[] chain)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+ if (keyEntry == null)
+ throw new ArgumentNullException("keyEntry");
+ if (keyEntry.Key.IsPrivate && (chain == null))
+ throw new ArgumentException("No certificate chain for private key");
+
+ if (keys[alias] != null)
+ {
+ DeleteEntry(alias);
+ }
+
+ keys[alias] = keyEntry;
+ certs[alias] = chain[0];
+
+ for (int i = 0; i != chain.Length; i++)
+ {
+ chainCerts[new CertId(chain[i].Certificate.GetPublicKey())] = chain[i];
+ }
+ }
+
+ public void DeleteEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ AsymmetricKeyEntry k = (AsymmetricKeyEntry)keys[alias];
+ if (k != null)
+ {
+ keys.Remove(alias);
+ }
+
+ X509CertificateEntry c = (X509CertificateEntry)certs[alias];
+
+ if (c != null)
+ {
+ certs.Remove(alias);
+ chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+ }
+
+ if (k != null)
+ {
+ string id = (string)localIds[alias];
+ if (id != null)
+ {
+ localIds.Remove(alias);
+ c = (X509CertificateEntry)keyCerts[id];
+ }
+ if (c != null)
+ {
+ keyCerts.Remove(id);
+ chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+ }
+ }
+
+ if (c == null && k == null)
+ {
+ throw new ArgumentException("no such entry as " + alias);
+ }
+ }
+
+ public bool IsEntryOfType(
+ string alias,
+ Type entryType)
+ {
+ if (entryType == typeof(X509CertificateEntry))
+ return IsCertificateEntry(alias);
+
+ if (entryType == typeof(AsymmetricKeyEntry))
+ return IsKeyEntry(alias) && GetCertificate(alias) != null;
+
+ return false;
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size()
+ {
+ return Count;
+ }
+
+ public int Count
+ {
+ // TODO Seems a little inefficient
+ get { return GetAliasesTable().Count; }
+ }
+
+ public void Save(
+ Stream stream,
+ char[] password,
+ SecureRandom random)
+ {
+ if (stream == null)
+ throw new ArgumentNullException("stream");
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ //
+ // handle the key
+ //
+ Asn1EncodableVector keyS = new Asn1EncodableVector();
+ foreach (string name in keys.Keys)
+ {
+ byte[] kSalt = new byte[saltSize];
+ random.NextBytes(kSalt);
+
+ AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name];
+ EncryptedPrivateKeyInfo kInfo =
+ EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+
+ Asn1EncodableVector kName = new Asn1EncodableVector();
+
+ foreach (string oid in privKey.BagAttributeKeys)
+ {
+ Asn1Encodable entry = privKey[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ kName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'name'
+ //if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ kName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(name))));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+ {
+ X509CertificateEntry ct = GetCertificate(name);
+ AsymmetricKeyParameter pubKey = ct.Certificate.GetPublicKey();
+ SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+ kName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+ new DerSet(subjectKeyID)));
+ }
+
+ SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
+ keyS.Add(kBag);
+ }
+
+ byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
+
+ BerOctetString keyString = new BerOctetString(derEncodedBytes);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[saltSize];
+
+ random.NextBytes(cSalt);
+
+ Asn1EncodableVector certSeq = new Asn1EncodableVector();
+ Pkcs12PbeParams cParams = new Pkcs12PbeParams(cSalt, MinIterations);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(CertAlgorithm, cParams.ToAsn1Object());
+ ISet doneCerts = new HashSet();
+
+ foreach (string name in keys.Keys)
+ {
+ X509CertificateEntry certEntry = GetCertificate(name);
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(certEntry.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in certEntry.BagAttributeKeys)
+ {
+ Asn1Encodable entry = certEntry[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'name'
+ //if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(name))));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+ {
+ AsymmetricKeyParameter pubKey = certEntry.Certificate.GetPublicKey();
+ SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+ new DerSet(subjectKeyID)));
+ }
+
+ SafeBag sBag = new SafeBag(
+ PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
+
+ certSeq.Add(sBag);
+
+ doneCerts.Add(certEntry.Certificate);
+ }
+
+ foreach (string certId in certs.Keys)
+ {
+ X509CertificateEntry cert = (X509CertificateEntry)certs[certId];
+
+ if (keys[certId] != null)
+ continue;
+
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(cert.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in cert.BagAttributeKeys)
+ {
+ Asn1Encodable entry = cert[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'certId'
+ //if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(certId))));
+ }
+
+ SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
+ cBag.ToAsn1Object(), new DerSet(fName));
+
+ certSeq.Add(sBag);
+
+ doneCerts.Add(cert.Certificate);
+ }
+
+ foreach (CertId certId in chainCerts.Keys)
+ {
+ X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];
+
+ if (doneCerts.Contains(cert.Certificate))
+ continue;
+
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(cert.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in cert.BagAttributeKeys)
+ {
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(cert[oid])));
+ }
+
+ SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
+
+ certSeq.Add(sBag);
+ }
+
+ derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
+
+ byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes);
+
+ EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(PkcsObjectIdentifiers.Data, keyString),
+ new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object())
+ };
+
+ byte[] data = new AuthenticatedSafe(info).GetEncoded();
+
+ ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ random.NextBytes(mSalt);
+
+ byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
+ mSalt, MinIterations, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ DigestInfo dInfo = new DigestInfo(algId, mac);
+
+ MacData mData = new MacData(dInfo, mSalt, MinIterations);
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ BerOutputStream berOut = new BerOutputStream(stream);
+ berOut.WriteObject(pfx);
+ }
+
+ private static byte[] CalculatePbeMac(
+ DerObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ bool wrongPkcs12Zero,
+ byte[] data)
+ {
+ Asn1Encodable asn1Params = PbeUtilities.GenerateAlgorithmParameters(
+ oid, salt, itCount);
+ ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+ oid, password, wrongPkcs12Zero, asn1Params);
+
+ IMac mac = (IMac) PbeUtilities.CreateEngine(oid);
+ mac.Init(cipherParams);
+ mac.BlockUpdate(data, 0, data.Length);
+ return MacUtilities.DoFinal(mac);
+ }
+
+ private static byte[] CryptPbeData(
+ bool forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ bool wrongPkcs12Zero,
+ byte[] data)
+ {
+ Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(algId.Parameters);
+ ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+ algId.ObjectID, password, wrongPkcs12Zero, pbeParams);
+
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algId.ObjectID) as IBufferedCipher;
+
+ if (cipher == null)
+ throw new Exception("Unknown encryption algorithm: " + algId.ObjectID);
+
+ cipher.Init(forEncryption, cipherParams);
+
+ return cipher.DoFinal(data);
+ }
+
+ private class IgnoresCaseHashtable
+ : IEnumerable
+ {
+ private readonly Hashtable orig = new Hashtable();
+ private readonly Hashtable keys = new Hashtable();
+
+ public IEnumerator GetEnumerator()
+ {
+ return orig.GetEnumerator();
+ }
+
+ public ICollection Keys
+ {
+ get { return orig.Keys; }
+ }
+
+ public object Remove(
+ string alias)
+ {
+ string lower = alias.ToLower(CultureInfo.InvariantCulture);
+ string k = (string) keys[lower];
+
+ if (k == null)
+ return null;
+
+ keys.Remove(lower);
+
+ object o = orig[k];
+ orig.Remove(k);
+ return o;
+ }
+
+ public object this[
+ string alias]
+ {
+ get
+ {
+ string lower = alias.ToLower(CultureInfo.InvariantCulture);
+ string k = (string) keys[lower];
+
+ if (k == null)
+ return null;
+
+ return orig[k];
+ }
+ set
+ {
+ string lower = alias.ToLower(CultureInfo.InvariantCulture);
+ string k = (string) keys[lower];
+ if (k != null)
+ {
+ orig.Remove(k);
+ }
+ keys[lower] = alias;
+ orig[alias] = value;
+ }
+ }
+
+ public ICollection Values
+ {
+ get { return orig.Values; }
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/PrivateKeyInfoFactory.cs b/src/core/srcbc/pkcs/PrivateKeyInfoFactory.cs
new file mode 100644
index 0000000..0964ef2
--- /dev/null
+++ b/src/core/srcbc/pkcs/PrivateKeyInfoFactory.cs
@@ -0,0 +1,211 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public sealed class PrivateKeyInfoFactory
+ {
+ private PrivateKeyInfoFactory()
+ {
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ AsymmetricKeyParameter key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (!key.IsPrivate)
+ throw new ArgumentException("Public key passed - private key expected", "key");
+
+ if (key is ElGamalPrivateKeyParameters)
+ {
+ ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(
+ _key.Parameters.P,
+ _key.Parameters.G).ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is DsaPrivateKeyParameters)
+ {
+ DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdDsa,
+ new DsaParameter(
+ _key.Parameters.P,
+ _key.Parameters.Q,
+ _key.Parameters.G).ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is DHPrivateKeyParameters)
+ {
+ /*
+ Process DH private key.
+ The value for L was set to zero implicitly.
+ This is the same action as found in JCEDHPrivateKey GetEncoded method.
+ */
+
+ DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
+
+ DHParameter withNewL = new DHParameter(
+ _key.Parameters.P, _key.Parameters.G, 0);
+
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.DhKeyAgreement,
+ withNewL.ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is RsaKeyParameters)
+ {
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
+
+ RsaPrivateKeyStructure keyStruct;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ _key.PublicExponent,
+ _key.Exponent,
+ _key.P,
+ _key.Q,
+ _key.DP,
+ _key.DQ,
+ _key.QInv);
+ }
+ else
+ {
+ RsaKeyParameters _key = (RsaKeyParameters) key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ BigInteger.Zero,
+ _key.Exponent,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero);
+ }
+
+ return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+ }
+
+ if (key is ECPrivateKeyParameters)
+ {
+ ECPrivateKeyParameters _key = (ECPrivateKeyParameters)key;
+ AlgorithmIdentifier algID;
+
+ if (_key.AlgorithmName == "ECGOST3410")
+ {
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x2001,
+ gostParams.ToAsn1Object());
+ }
+ else
+ {
+ X9ECParameters ecP = new X9ECParameters(
+ _key.Parameters.Curve,
+ _key.Parameters.G,
+ _key.Parameters.N,
+ _key.Parameters.H,
+ _key.Parameters.GetSeed());
+
+ X962Parameters x962 = new X962Parameters(ecP);
+
+ algID = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey,
+ x962.ToAsn1Object());
+ }
+
+ return new PrivateKeyInfo(algID, new ECPrivateKeyStructure(_key.D).ToAsn1Object());
+ }
+
+ if (key is Gost3410PrivateKeyParameters)
+ {
+ Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.X.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet, null);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided is not convertible: " + key.GetType().FullName);
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ char[] passPhrase,
+ EncryptedPrivateKeyInfo encInfo)
+ {
+ return CreatePrivateKeyInfo(passPhrase, false, encInfo);
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ char[] passPhrase,
+ bool wrongPkcs12Zero,
+ EncryptedPrivateKeyInfo encInfo)
+ {
+ AlgorithmIdentifier algID = encInfo.EncryptionAlgorithm;
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algID.ObjectID) as IBufferedCipher;
+
+ if (cipher == null)
+ {
+ // TODO Throw exception?
+ }
+
+ ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters(
+ algID.ObjectID, passPhrase, wrongPkcs12Zero, algID.Parameters);
+
+ cipher.Init(false, keyParameters);
+
+ byte[] keyBytes = encInfo.GetEncryptedData();
+ byte[] encoding = cipher.DoFinal(keyBytes);
+ Asn1Object asn1Data = Asn1Object.FromByteArray(encoding);
+
+ return PrivateKeyInfo.GetInstance(asn1Data);
+ }
+ }
+}
diff --git a/src/core/srcbc/pkcs/X509CertificateEntry.cs b/src/core/srcbc/pkcs/X509CertificateEntry.cs
new file mode 100644
index 0000000..8566425
--- /dev/null
+++ b/src/core/srcbc/pkcs/X509CertificateEntry.cs
@@ -0,0 +1,32 @@
+using System.Collections;
+
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class X509CertificateEntry
+ : Pkcs12Entry
+ {
+ private readonly X509Certificate cert;
+
+ public X509CertificateEntry(
+ X509Certificate cert)
+ : base(new Hashtable())
+ {
+ this.cert = cert;
+ }
+
+ public X509CertificateEntry(
+ X509Certificate cert,
+ Hashtable attributes)
+ : base(attributes)
+ {
+ this.cert = cert;
+ }
+
+ public X509Certificate Certificate
+ {
+ get { return this.cert; }
+ }
+ }
+}
diff --git a/src/core/srcbc/security/AgreementUtilities.cs b/src/core/srcbc/security/AgreementUtilities.cs
new file mode 100644
index 0000000..704dbcc
--- /dev/null
+++ b/src/core/srcbc/security/AgreementUtilities.cs
@@ -0,0 +1,99 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating IBasicAgreement objects from their names/Oids
+ ///
+ public sealed class AgreementUtilities
+ {
+ private AgreementUtilities()
+ {
+ }
+
+ private static readonly Hashtable algorithms = new Hashtable();
+ // private static readonly Hashtable oids = new Hashtable();
+
+ static AgreementUtilities()
+ {
+ //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?;
+ algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "DHWITHSHA1KDF";
+ //algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = ?;
+ }
+
+ public static IBasicAgreement GetBasicAgreement(
+ DerObjectIdentifier oid)
+ {
+ return GetBasicAgreement(oid.Id);
+ }
+
+ public static IBasicAgreement GetBasicAgreement(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ switch (mechanism)
+ {
+ case "DH":
+ return new DHBasicAgreement();
+ case "ECDH":
+ return new ECDHBasicAgreement();
+ case "ECDHC":
+ return new ECDHCBasicAgreement();
+ }
+
+ throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised.");
+ }
+
+ public static IBasicAgreement GetBasicAgreementWithKdf(
+ DerObjectIdentifier oid,
+ string wrapAlgorithm)
+ {
+ return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm);
+ }
+
+ public static IBasicAgreement GetBasicAgreementWithKdf(
+ string agreeAlgorithm,
+ string wrapAlgorithm)
+ {
+ string upper = agreeAlgorithm.ToUpper(CultureInfo.InvariantCulture);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ switch (mechanism)
+ {
+ case "DHWITHSHA1KDF":
+ return new ECDHWithKdfBasicAgreement(
+ wrapAlgorithm,
+ new ECDHKekGenerator(
+ new Sha1Digest()));
+ }
+
+ throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+ }
+}
diff --git a/src/core/srcbc/security/CipherUtilities.cs b/src/core/srcbc/security/CipherUtilities.cs
new file mode 100644
index 0000000..4c3372e
--- /dev/null
+++ b/src/core/srcbc/security/CipherUtilities.cs
@@ -0,0 +1,566 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Cipher Utility class contains methods that can not be specifically grouped into other classes.
+ ///
+ public sealed class CipherUtilities
+ {
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable oids = new Hashtable();
+
+ static CipherUtilities()
+ {
+ // TODO Flesh out the list of aliases
+
+ algorithms[NistObjectIdentifiers.IdAes128Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES/ECB/PKCS7"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS7"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS7PADDING"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES/ECB/PKCS5"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES/ECB/PKCS5PADDING"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS5"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS5PADDING"] = "AES/ECB/PKCS7PADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "AES/CBC/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "AES/CBC/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "AES/CBC/PKCS7PADDING";
+ algorithms["AES/CBC/PKCS7"] = "AES/CBC/PKCS7PADDING";
+ algorithms["AES/CBC/PKCS5"] = "AES/CBC/PKCS7PADDING";
+ algorithms["AES/CBC/PKCS5PADDING"] = "AES/CBC/PKCS7PADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Ofb.Id] = "AES/OFB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Ofb.Id] = "AES/OFB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Ofb.Id] = "AES/OFB/PKCS7PADDING";
+ algorithms["AES/OFB/PKCS7"] = "AES/OFB/PKCS7PADDING";
+ algorithms["AES/OFB/PKCS5"] = "AES/OFB/PKCS7PADDING";
+ algorithms["AES/OFB/PKCS5PADDING"] = "AES/OFB/PKCS7PADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Cfb.Id] = "AES/CFB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Cfb.Id] = "AES/CFB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Cfb.Id] = "AES/CFB/PKCS7PADDING";
+ algorithms["AES/CFB/PKCS7"] = "AES/CFB/PKCS7PADDING";
+ algorithms["AES/CFB/PKCS5"] = "AES/CFB/PKCS7PADDING";
+ algorithms["AES/CFB/PKCS5PADDING"] = "AES/CFB/PKCS7PADDING";
+
+ algorithms["RSA//PKCS1"] = "RSA//PKCS1PADDING";
+ algorithms["RSA/ECB/PKCS1"] = "RSA//PKCS1PADDING";
+ algorithms["RSA/ECB/PKCS1PADDING"] = "RSA//PKCS1PADDING";
+ algorithms[PkcsObjectIdentifiers.RsaEncryption.Id] = "RSA//PKCS1PADDING";
+
+ algorithms[OiwObjectIdentifiers.DesCbc.Id] = "DES/CBC";
+ algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDE/CBC";
+ algorithms[PkcsObjectIdentifiers.RC2Cbc.Id] = "RC2/CBC";
+ algorithms["1.3.6.1.4.1.188.7.1.1.2"] = "IDEA/CBC";
+ algorithms["1.2.840.113533.7.66.10"] = "CAST5/CBC";
+
+ algorithms["RC4"] = "ARC4";
+ algorithms["ARCFOUR"] = "ARC4";
+ algorithms["1.2.840.113549.3.4"] = "ARC4";
+
+
+
+ algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEWITHSHAAND128BITRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEWITHSHAAND128BITRC4";
+ algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEWITHSHAAND40BITRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEWITHSHAAND40BITRC4";
+
+ algorithms["PBEWITHSHA1ANDDES"] = "PBEWITHSHA1ANDDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEWITHSHA1ANDDES-CBC";
+ algorithms["PBEWITHSHA1ANDRC2"] = "PBEWITHSHA1ANDRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEWITHSHA1ANDRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms["PBEWITHSHAAND3KEYTRIPLEDES"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms["PBEWITHSHA1ANDDESEDE"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+
+ algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+
+ algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEWITHSHAAND128BITRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEWITHSHAAND128BITRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEWITHSHAAND40BITRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEWITHSHAAND40BITRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEWITHSHA256AND128BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEWITHSHA256AND192BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEWITHSHA256AND256BITAES-CBC-BC";
+
+
+ algorithms["GOST"] = "GOST28147";
+ algorithms["GOST-28147"] = "GOST28147";
+ algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING";
+
+ algorithms["RC5-32"] = "RC5";
+
+ algorithms[NttObjectIdentifiers.IdCamellia128Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+ algorithms[NttObjectIdentifiers.IdCamellia192Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+ algorithms[NttObjectIdentifiers.IdCamellia256Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+
+ algorithms[KisaObjectIdentifiers.IdSeedCbc.Id] = "SEED/CBC/PKCS7PADDING";
+ }
+
+ private CipherUtilities()
+ {
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a give encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+ // TODO Don't really want to support this
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ if (mechanism == null)
+ throw new ArgumentNullException("mechanism");
+
+ mechanism = mechanism.ToUpper(CultureInfo.InvariantCulture);
+ string aliased = (string) algorithms[mechanism];
+
+ if (aliased != null)
+ mechanism = aliased;
+
+ return (DerObjectIdentifier) oids[mechanism];
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static IBufferedCipher GetCipher(
+ DerObjectIdentifier oid)
+ {
+ return GetCipher(oid.Id);
+ }
+
+ public static IBufferedCipher GetCipher(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ string aliased = (string) algorithms[algorithm];
+
+ if (aliased != null)
+ algorithm = aliased;
+
+
+
+ IBasicAgreement iesAgreement = null;
+ if (algorithm == "IES")
+ {
+ iesAgreement = new DHBasicAgreement();
+ }
+ else if (algorithm == "ECIES")
+ {
+ iesAgreement = new ECDHBasicAgreement();
+ }
+
+ if (iesAgreement != null)
+ {
+ return new BufferedIesCipher(
+ new IesEngine(
+ iesAgreement,
+ new Kdf2BytesGenerator(
+ new Sha1Digest()),
+ new HMac(
+ new Sha1Digest())));
+ }
+
+
+
+ if (algorithm.StartsWith("PBE"))
+ {
+ switch (algorithm)
+ {
+ case "PBEWITHSHAAND2-KEYTRIPLEDES-CBC":
+ case "PBEWITHSHAAND3-KEYTRIPLEDES-CBC":
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new DesEdeEngine()));
+
+ case "PBEWITHSHAAND128BITRC2-CBC":
+ case "PBEWITHSHAAND40BITRC2-CBC":
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new RC2Engine()));
+
+ case "PBEWITHSHAAND128BITAES-CBC-BC":
+ case "PBEWITHSHAAND192BITAES-CBC-BC":
+ case "PBEWITHSHAAND256BITAES-CBC-BC":
+ case "PBEWITHSHA256AND128BITAES-CBC-BC":
+ case "PBEWITHSHA256AND192BITAES-CBC-BC":
+ case "PBEWITHSHA256AND256BITAES-CBC-BC":
+ case "PBEWITHMD5AND128BITAES-CBC-OPENSSL":
+ case "PBEWITHMD5AND192BITAES-CBC-OPENSSL":
+ case "PBEWITHMD5AND256BITAES-CBC-OPENSSL":
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new AesFastEngine()));
+
+ case "PBEWITHSHA1ANDDES-CBC":
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new DesEngine()));
+
+ case "PBEWITHSHA1ANDRC2-CBC":
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new RC2Engine()));
+ }
+ }
+
+
+
+ string[] parts = algorithm.Split('/');
+
+ IBlockCipher blockCipher = null;
+ IAsymmetricBlockCipher asymBlockCipher = null;
+ IStreamCipher streamCipher = null;
+
+ switch (parts[0])
+ {
+ case "AES":
+ blockCipher = new AesFastEngine();
+ break;
+ case "ARC4":
+ streamCipher = new RC4Engine();
+ break;
+ case "BLOWFISH":
+ blockCipher = new BlowfishEngine();
+ break;
+ case "CAMELLIA":
+ blockCipher = new CamelliaEngine();
+ break;
+ case "CAST5":
+ blockCipher = new Cast5Engine();
+ break;
+ case "CAST6":
+ blockCipher = new Cast6Engine();
+ break;
+ case "DES":
+ blockCipher = new DesEngine();
+ break;
+ case "DESEDE":
+ blockCipher = new DesEdeEngine();
+ break;
+ case "ELGAMAL":
+ asymBlockCipher = new ElGamalEngine();
+ break;
+ case "GOST28147":
+ blockCipher = new Gost28147Engine();
+ break;
+ case "HC128":
+ streamCipher = new HC128Engine();
+ break;
+ case "HC256":
+ streamCipher = new HC256Engine();
+ break;
+ case "IDEA":
+ blockCipher = new IdeaEngine();
+ break;
+ case "NOEKEON":
+ blockCipher = new NoekeonEngine();
+ break;
+ case "PBEWITHSHAAND128BITRC4":
+ case "PBEWITHSHAAND40BITRC4":
+ streamCipher = new RC4Engine();
+ break;
+ case "RC2":
+ blockCipher = new RC2Engine();
+ break;
+ case "RC5":
+ blockCipher = new RC532Engine();
+ break;
+ case "RC5-64":
+ blockCipher = new RC564Engine();
+ break;
+ case "RC6":
+ blockCipher = new RC6Engine();
+ break;
+ case "RIJNDAEL":
+ blockCipher = new RijndaelEngine();
+ break;
+ case "RSA":
+ asymBlockCipher = new RsaBlindedEngine();
+ break;
+ case "SALSA20":
+ streamCipher = new Salsa20Engine();
+ break;
+ case "SEED":
+ blockCipher = new SeedEngine();
+ break;
+ case "SERPENT":
+ blockCipher = new SerpentEngine();
+ break;
+ case "SKIPJACK":
+ blockCipher = new SkipjackEngine();
+ break;
+ case "TEA":
+ blockCipher = new TeaEngine();
+ break;
+ case "TWOFISH":
+ blockCipher = new TwofishEngine();
+ break;
+ case "VMPC":
+ streamCipher = new VmpcEngine();
+ break;
+ case "VMPC-KSA3":
+ streamCipher = new VmpcKsa3Engine();
+ break;
+ case "XTEA":
+ blockCipher = new XteaEngine();
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+
+ if (streamCipher != null)
+ {
+ if (parts.Length > 1)
+ throw new ArgumentException("Modes and paddings not used for stream ciphers");
+
+ return new BufferedStreamCipher(streamCipher);
+ }
+
+
+ bool cts = false;
+ bool padded = true;
+ IBlockCipherPadding padding = null;
+ IAeadBlockCipher aeadBlockCipher = null;
+
+ if (parts.Length > 2)
+ {
+ if (streamCipher != null)
+ throw new ArgumentException("Paddings not used for stream ciphers");
+
+ switch (parts[2])
+ {
+ case "NOPADDING":
+ padded = false;
+ break;
+ case "":
+ case "RAW":
+ break;
+ case "ISO10126PADDING":
+ case "ISO10126D2PADDING":
+ case "ISO10126-2PADDING":
+ padding = new ISO10126d2Padding();
+ break;
+ case "ISO7816-4PADDING":
+ case "ISO9797-1PADDING":
+ padding = new ISO7816d4Padding();
+ break;
+ case "ISO9796-1":
+ case "ISO9796-1PADDING":
+ asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher);
+ break;
+ case "OAEP":
+ case "OAEPPADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher);
+ break;
+ case "OAEPWITHMD5ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest());
+ break;
+ case "OAEPWITHSHA1ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest());
+ break;
+ case "OAEPWITHSHA224ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest());
+ break;
+ case "OAEPWITHSHA256ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest());
+ break;
+ case "OAEPWITHSHA384ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest());
+ break;
+ case "OAEPWITHSHA512ANDMGF1PADDING":
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest());
+ break;
+ case "PKCS1":
+ case "PKCS1PADDING":
+ asymBlockCipher = new Pkcs1Encoding(asymBlockCipher);
+ break;
+ case "PKCS5":
+ case "PKCS5PADDING":
+ case "PKCS7":
+ case "PKCS7PADDING":
+ // NB: Padding defaults to Pkcs7Padding already
+ break;
+ case "TBCPADDING":
+ padding = new TbcPadding();
+ break;
+ case "WITHCTS":
+ cts = true;
+ break;
+ case "X9.23PADDING":
+ case "X923PADDING":
+ padding = new X923Padding();
+ break;
+ case "ZEROBYTEPADDING":
+ padding = new ZeroBytePadding();
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+
+ string mode = "";
+ if (parts.Length > 1)
+ {
+ mode = parts[1];
+
+ int di = GetDigitIndex(mode);
+ string modeName = di >= 0 ? mode.Substring(0, di) : mode;
+
+ switch (modeName)
+ {
+ case "":
+ case "ECB":
+ case "NONE":
+ break;
+ case "CBC":
+ blockCipher = new CbcBlockCipher(blockCipher);
+ break;
+ case "CCM":
+ aeadBlockCipher = new CcmBlockCipher(blockCipher);
+ break;
+ case "CFB":
+ {
+ int bits = (di < 0)
+ ? 8 * blockCipher.GetBlockSize()
+ : int.Parse(mode.Substring(di));
+
+ blockCipher = new CfbBlockCipher(blockCipher, bits);
+ break;
+ }
+ case "CTR":
+ blockCipher = new SicBlockCipher(blockCipher);
+ break;
+ case "CTS":
+ cts = true;
+ blockCipher = new CbcBlockCipher(blockCipher);
+ break;
+ case "EAX":
+ aeadBlockCipher = new EaxBlockCipher(blockCipher);
+ break;
+ case "GCM":
+ aeadBlockCipher = new GcmBlockCipher(blockCipher);
+ break;
+ case "GOFB":
+ blockCipher = new GOfbBlockCipher(blockCipher);
+ break;
+ case "OFB":
+ {
+ int bits = (di < 0)
+ ? 8 * blockCipher.GetBlockSize()
+ : int.Parse(mode.Substring(di));
+
+ blockCipher = new OfbBlockCipher(blockCipher, bits);
+ break;
+ }
+ case "OPENPGPCFB":
+ blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
+ break;
+ case "SIC":
+ if (blockCipher.GetBlockSize() < 16)
+ {
+ throw new ArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+ }
+ blockCipher = new SicBlockCipher(blockCipher);
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+
+ if (aeadBlockCipher != null)
+ {
+ if (cts)
+ throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers.");
+ if (padded && parts.Length > 1 && parts[2] != "")
+ throw new SecurityUtilityException("Bad padding specified for AEAD cipher.");
+
+ return new BufferedAeadBlockCipher(aeadBlockCipher);
+ }
+
+ if (blockCipher != null)
+ {
+ if (cts)
+ {
+ return new CtsBlockCipher(blockCipher);
+ }
+
+ if (!padded || blockCipher.IsPartialBlockOkay)
+ {
+ return new BufferedBlockCipher(blockCipher);
+ }
+
+ if (padding != null)
+ {
+ return new PaddedBufferedBlockCipher(blockCipher, padding);
+ }
+
+ return new PaddedBufferedBlockCipher(blockCipher);
+ }
+
+ if (asymBlockCipher != null)
+ {
+ return new BufferedAsymmetricBlockCipher(asymBlockCipher);
+ }
+
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private static int GetDigitIndex(
+ string s)
+ {
+ for (int i = 0; i < s.Length; ++i)
+ {
+ if (char.IsDigit(s[i]))
+ return i;
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/src/core/srcbc/security/DigestUtilities.cs b/src/core/srcbc/security/DigestUtilities.cs
new file mode 100644
index 0000000..1a0aea7
--- /dev/null
+++ b/src/core/srcbc/security/DigestUtilities.cs
@@ -0,0 +1,150 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Security
+{
+
+ ///
+ /// Utility class for creating IDigest objects from their names/Oids
+ ///
+ public sealed class DigestUtilities
+ {
+ private DigestUtilities()
+ {
+ }
+
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable oids = new Hashtable();
+
+ static DigestUtilities()
+ {
+ algorithms[PkcsObjectIdentifiers.MD2.Id] = "MD2";
+ algorithms[PkcsObjectIdentifiers.MD4.Id] = "MD4";
+ algorithms[PkcsObjectIdentifiers.MD5.Id] = "MD5";
+
+ algorithms["SHA1"] = "SHA-1";
+ algorithms[OiwObjectIdentifiers.IdSha1.Id] = "SHA-1";
+ algorithms["SHA224"] = "SHA-224";
+ algorithms[NistObjectIdentifiers.IdSha224.Id] = "SHA-224";
+ algorithms["SHA256"] = "SHA-256";
+ algorithms[NistObjectIdentifiers.IdSha256.Id] = "SHA-256";
+ algorithms["SHA384"] = "SHA-384";
+ algorithms[NistObjectIdentifiers.IdSha384.Id] = "SHA-384";
+ algorithms["SHA512"] = "SHA-512";
+ algorithms[NistObjectIdentifiers.IdSha512.Id] = "SHA-512";
+
+ algorithms["RIPEMD-128"] = "RIPEMD128";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "RIPEMD128";
+ algorithms["RIPEMD-160"] = "RIPEMD160";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "RIPEMD160";
+ algorithms["RIPEMD-256"] = "RIPEMD256";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "RIPEMD256";
+ algorithms["RIPEMD-320"] = "RIPEMD320";
+// algorithms[TeleTrusTObjectIdentifiers.RipeMD320.Id] = "RIPEMD320";
+
+ algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
+
+
+
+ oids["MD2"] = PkcsObjectIdentifiers.MD2;
+ oids["MD4"] = PkcsObjectIdentifiers.MD4;
+ oids["MD5"] = PkcsObjectIdentifiers.MD5;
+ oids["SHA-1"] = OiwObjectIdentifiers.IdSha1;
+ oids["SHA-224"] = NistObjectIdentifiers.IdSha224;
+ oids["SHA-256"] = NistObjectIdentifiers.IdSha256;
+ oids["SHA-384"] = NistObjectIdentifiers.IdSha384;
+ oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
+ oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+ oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a given digest mechanism.
+ ///
+ /// A string representation of the digest meanism.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)];
+
+ if (mechanism != null)
+ {
+ return (DerObjectIdentifier)oids[mechanism];
+ }
+
+ return null;
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static IDigest GetDigest(
+ DerObjectIdentifier id)
+ {
+ return GetDigest(id.Id);
+ }
+
+ public static IDigest GetDigest(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ switch (mechanism)
+ {
+ case "GOST3411": return new Gost3411Digest();
+ case "MD2": return new MD2Digest();
+ case "MD4": return new MD4Digest();
+ case "MD5": return new MD5Digest();
+ case "RIPEMD128": return new RipeMD128Digest();
+ case "RIPEMD160": return new RipeMD160Digest();
+ case "RIPEMD256": return new RipeMD256Digest();
+ case "RIPEMD320": return new RipeMD320Digest();
+ case "SHA-1": return new Sha1Digest();
+ case "SHA-224": return new Sha224Digest();
+ case "SHA-256": return new Sha256Digest();
+ case "SHA-384": return new Sha384Digest();
+ case "SHA-512": return new Sha512Digest();
+ case "TIGER": return new TigerDigest();
+ case "WHIRLPOOL": return new WhirlpoolDigest();
+ default:
+ throw new SecurityUtilityException("Digest " + mechanism + " not recognised.");
+ }
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ public static byte[] DoFinal(
+ IDigest digest)
+ {
+ byte[] b = new byte[digest.GetDigestSize()];
+ digest.DoFinal(b, 0);
+ return b;
+ }
+ }
+}
diff --git a/src/core/srcbc/security/DotNetUtilities.cs b/src/core/srcbc/security/DotNetUtilities.cs
new file mode 100644
index 0000000..32fb601
--- /dev/null
+++ b/src/core/srcbc/security/DotNetUtilities.cs
@@ -0,0 +1,163 @@
+#if !NETCF_1_0
+
+using System;
+using System.Security.Cryptography;
+using SystemX509 = System.Security.Cryptography.X509Certificates;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world.
+ ///
+ public sealed class DotNetUtilities
+ {
+ private DotNetUtilities()
+ {
+ }
+
+ ///
+ /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure.
+ ///
+ ///
+ /// A System.Security.Cryptography.X509Certificate.
+ public static SystemX509.X509Certificate ToX509Certificate(
+ X509CertificateStructure x509Struct)
+ {
+ return new SystemX509.X509Certificate(x509Struct.GetDerEncoded());
+ }
+
+ public static SystemX509.X509Certificate ToX509Certificate(
+ X509Certificate x509Cert)
+ {
+ return new SystemX509.X509Certificate(x509Cert.GetEncoded());
+ }
+
+ public static X509Certificate FromX509Certificate(
+ SystemX509.X509Certificate x509Cert)
+ {
+ return new X509CertificateParser().ReadCertificate(x509Cert.GetRawCertData());
+ }
+
+ public static AsymmetricCipherKeyPair GetDsaKeyPair(
+ DSACryptoServiceProvider dsaCsp)
+ {
+ return GetDsaKeyPair(dsaCsp.ExportParameters(true));
+ }
+
+ public static AsymmetricCipherKeyPair GetDsaKeyPair(
+ DSAParameters dp)
+ {
+ DsaValidationParameters validationParameters = (dp.Seed != null)
+ ? new DsaValidationParameters(dp.Seed, dp.Counter)
+ : null;
+
+ DsaParameters parameters = new DsaParameters(
+ new BigInteger(1, dp.P),
+ new BigInteger(1, dp.Q),
+ new BigInteger(1, dp.G),
+ validationParameters);
+
+ DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters(
+ new BigInteger(1, dp.Y),
+ parameters);
+
+ DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters(
+ new BigInteger(1, dp.X),
+ parameters);
+
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ public static DsaPublicKeyParameters GetDsaPublicKey(
+ DSACryptoServiceProvider dsaCsp)
+ {
+ return GetDsaPublicKey(dsaCsp.ExportParameters(false));
+ }
+
+ public static DsaPublicKeyParameters GetDsaPublicKey(
+ DSAParameters dp)
+ {
+ DsaValidationParameters validationParameters = (dp.Seed != null)
+ ? new DsaValidationParameters(dp.Seed, dp.Counter)
+ : null;
+
+ DsaParameters parameters = new DsaParameters(
+ new BigInteger(1, dp.P),
+ new BigInteger(1, dp.Q),
+ new BigInteger(1, dp.G),
+ validationParameters);
+
+ return new DsaPublicKeyParameters(
+ new BigInteger(1, dp.Y),
+ parameters);
+ }
+
+ public static AsymmetricCipherKeyPair GetRsaKeyPair(
+ RSACryptoServiceProvider rsaCsp)
+ {
+ return GetRsaKeyPair(rsaCsp.ExportParameters(true));
+ }
+
+ public static AsymmetricCipherKeyPair GetRsaKeyPair(
+ RSAParameters rp)
+ {
+ BigInteger modulus = new BigInteger(1, rp.Modulus);
+ BigInteger pubExp = new BigInteger(1, rp.Exponent);
+
+ RsaKeyParameters pubKey = new RsaKeyParameters(
+ false,
+ modulus,
+ pubExp);
+
+ RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+ modulus,
+ pubExp,
+ new BigInteger(1, rp.D),
+ new BigInteger(1, rp.P),
+ new BigInteger(1, rp.Q),
+ new BigInteger(1, rp.DP),
+ new BigInteger(1, rp.DQ),
+ new BigInteger(1, rp.InverseQ));
+
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ public static RsaKeyParameters GetRsaPublicKey(
+ RSACryptoServiceProvider rsaCsp)
+ {
+ return GetRsaPublicKey(rsaCsp.ExportParameters(false));
+ }
+
+ public static RsaKeyParameters GetRsaPublicKey(
+ RSAParameters rp)
+ {
+ return new RsaKeyParameters(
+ false,
+ new BigInteger(1, rp.Modulus),
+ new BigInteger(1, rp.Exponent));
+ }
+
+ public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)
+ {
+ if (privateKey is DSACryptoServiceProvider)
+ {
+ return GetDsaKeyPair((DSACryptoServiceProvider) privateKey);
+ }
+
+ if (privateKey is RSACryptoServiceProvider)
+ {
+ return GetRsaKeyPair((RSACryptoServiceProvider) privateKey);
+ }
+
+ throw new ArgumentException("Unsupported algorithm specified", "privateKey");
+ }
+ }
+}
+
+#endif
diff --git a/src/core/srcbc/security/GeneralSecurityException.cs b/src/core/srcbc/security/GeneralSecurityException.cs
new file mode 100644
index 0000000..e22bb20
--- /dev/null
+++ b/src/core/srcbc/security/GeneralSecurityException.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class GeneralSecurityException
+ : Exception
+ {
+ public GeneralSecurityException()
+ : base()
+ {
+ }
+
+ public GeneralSecurityException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public GeneralSecurityException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/security/GeneratorUtilities.cs b/src/core/srcbc/security/GeneratorUtilities.cs
new file mode 100644
index 0000000..9e9df9a
--- /dev/null
+++ b/src/core/srcbc/security/GeneratorUtilities.cs
@@ -0,0 +1,352 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class GeneratorUtilities
+ {
+ private GeneratorUtilities()
+ {
+ }
+
+ private static readonly Hashtable kgAlgorithms = new Hashtable();
+ private static readonly Hashtable kpgAlgorithms = new Hashtable();
+
+ static GeneratorUtilities()
+ {
+ //
+ // key generators.
+ //
+ AddKgAlgorithm("AES",
+ "AESWRAP");
+ AddKgAlgorithm("AES128",
+ "2.16.840.1.101.3.4.2",
+ NistObjectIdentifiers.IdAes128Cbc,
+ NistObjectIdentifiers.IdAes128Cfb,
+ NistObjectIdentifiers.IdAes128Ecb,
+ NistObjectIdentifiers.IdAes128Ofb,
+ NistObjectIdentifiers.IdAes128Wrap);
+ AddKgAlgorithm("AES192",
+ "2.16.840.1.101.3.4.22",
+ NistObjectIdentifiers.IdAes192Cbc,
+ NistObjectIdentifiers.IdAes192Cfb,
+ NistObjectIdentifiers.IdAes192Ecb,
+ NistObjectIdentifiers.IdAes192Ofb,
+ NistObjectIdentifiers.IdAes192Wrap);
+ AddKgAlgorithm("AES256",
+ "2.16.840.1.101.3.4.42",
+ NistObjectIdentifiers.IdAes256Cbc,
+ NistObjectIdentifiers.IdAes256Cfb,
+ NistObjectIdentifiers.IdAes256Ecb,
+ NistObjectIdentifiers.IdAes256Ofb,
+ NistObjectIdentifiers.IdAes256Wrap);
+ AddKgAlgorithm("BLOWFISH");
+ AddKgAlgorithm("CAMELLIA",
+ "CAMELLIAWRAP");
+ AddKgAlgorithm("CAMELLIA128",
+ NttObjectIdentifiers.IdCamellia128Cbc,
+ NttObjectIdentifiers.IdCamellia128Wrap);
+ AddKgAlgorithm("CAMELLIA192",
+ NttObjectIdentifiers.IdCamellia192Cbc,
+ NttObjectIdentifiers.IdCamellia192Wrap);
+ AddKgAlgorithm("CAMELLIA256",
+ NttObjectIdentifiers.IdCamellia256Cbc,
+ NttObjectIdentifiers.IdCamellia256Wrap);
+ AddKgAlgorithm("CAST5",
+ "1.2.840.113533.7.66.10");
+ AddKgAlgorithm("CAST6");
+ AddKgAlgorithm("DES",
+ OiwObjectIdentifiers.DesCbc);
+ AddKgAlgorithm("DESEDE",
+ "DESEDEWRAP",
+ PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+ AddKgAlgorithm("DESEDE3",
+ PkcsObjectIdentifiers.DesEde3Cbc);
+ AddKgAlgorithm("GOST28147",
+ "GOST",
+ "GOST-28147",
+ CryptoProObjectIdentifiers.GostR28147Cbc);
+ AddKgAlgorithm("HC128");
+ AddKgAlgorithm("HC256");
+ AddKgAlgorithm("IDEA",
+ "1.3.6.1.4.1.188.7.1.1.2");
+ AddKgAlgorithm("NOEKEON");
+ AddKgAlgorithm("RC2",
+ PkcsObjectIdentifiers.RC2Cbc,
+ PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+ AddKgAlgorithm("RC4",
+ "ARC4",
+ "1.2.840.113549.3.4");
+ AddKgAlgorithm("RC5",
+ "RC5-32");
+ AddKgAlgorithm("RC5-64");
+ AddKgAlgorithm("RC6");
+ AddKgAlgorithm("RIJNDAEL");
+ AddKgAlgorithm("SALSA20");
+ AddKgAlgorithm("SEED",
+ KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+ KisaObjectIdentifiers.IdSeedCbc);
+ AddKgAlgorithm("SERPENT");
+ AddKgAlgorithm("SKIPJACK");
+ AddKgAlgorithm("TEA");
+ AddKgAlgorithm("TWOFISH");
+ AddKgAlgorithm("VMPC");
+ AddKgAlgorithm("VMPC-KSA3");
+ AddKgAlgorithm("XTEA");
+
+ //
+ // HMac key generators
+ //
+ AddHMacKeyGenerator("MD2");
+ AddHMacKeyGenerator("MD4");
+ AddHMacKeyGenerator("MD5",
+ IanaObjectIdentifiers.HmacMD5);
+ AddHMacKeyGenerator("SHA1",
+ PkcsObjectIdentifiers.IdHmacWithSha1,
+ IanaObjectIdentifiers.HmacSha1);
+ AddHMacKeyGenerator("SHA224",
+ PkcsObjectIdentifiers.IdHmacWithSha224);
+ AddHMacKeyGenerator("SHA256",
+ PkcsObjectIdentifiers.IdHmacWithSha256);
+ AddHMacKeyGenerator("SHA384",
+ PkcsObjectIdentifiers.IdHmacWithSha384);
+ AddHMacKeyGenerator("SHA512",
+ PkcsObjectIdentifiers.IdHmacWithSha512);
+ AddHMacKeyGenerator("RIPEMD128");
+ AddHMacKeyGenerator("RIPEMD160",
+ IanaObjectIdentifiers.HmacRipeMD160);
+ AddHMacKeyGenerator("TIGER",
+ IanaObjectIdentifiers.HmacTiger);
+
+
+
+ //
+ // key pair generators.
+ //
+ AddKpgAlgorithm("DH");
+ AddKpgAlgorithm("DSA");
+ AddKpgAlgorithm("EC");
+ AddKpgAlgorithm("ECDH",
+ "ECIES");
+ AddKpgAlgorithm("ECDHC");
+ AddKpgAlgorithm("ECDSA");
+ AddKpgAlgorithm("ECGOST3410",
+ "ECGOST-3410",
+ "GOST-3410-2001");
+ AddKpgAlgorithm("ELGAMAL");
+ AddKpgAlgorithm("GOST3410",
+ "GOST-3410",
+ "GOST-3410-94");
+ AddKpgAlgorithm("RSA",
+ "1.2.840.113549.1.1.1");
+ }
+
+ private static void AddKgAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ kgAlgorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ kgAlgorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ private static void AddKpgAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ kpgAlgorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ kpgAlgorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ private static void AddHMacKeyGenerator(
+ string algorithm,
+ params object[] aliases)
+ {
+ string mainName = "HMAC" + algorithm;
+
+ kgAlgorithms[mainName] = mainName;
+ kgAlgorithms["HMAC-" + algorithm] = mainName;
+ kgAlgorithms["HMAC/" + algorithm] = mainName;
+
+ foreach (object alias in aliases)
+ {
+ kgAlgorithms[alias.ToString()] = mainName;
+ }
+ }
+
+ // TODO Consider making this public
+ internal static string GetCanonicalKeyGeneratorAlgorithm(
+ string algorithm)
+ {
+ return (string) kgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+ }
+
+ // TODO Consider making this public
+ internal static string GetCanonicalKeyPairGeneratorAlgorithm(
+ string algorithm)
+ {
+ return (string) kpgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+ }
+
+ public static CipherKeyGenerator GetKeyGenerator(
+ DerObjectIdentifier oid)
+ {
+ return GetKeyGenerator(oid.Id);
+ }
+
+ public static CipherKeyGenerator GetKeyGenerator(
+ string algorithm)
+ {
+ string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
+
+ if (canonicalName == null)
+ throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+
+ switch (canonicalName)
+ {
+ case "DES":
+ return new DesKeyGenerator(64);
+ case "DESEDE":
+ return new DesEdeKeyGenerator(128);
+ case "DESEDE3":
+ return new DesEdeKeyGenerator(192);
+ case "AES":
+ return new CipherKeyGenerator(192);
+ case "AES128":
+ return new CipherKeyGenerator(128);
+ case "AES192":
+ return new CipherKeyGenerator(192);
+ case "AES256":
+ return new CipherKeyGenerator(256);
+ case "BLOWFISH":
+ return new CipherKeyGenerator(448);
+ case "CAMELLIA":
+ return new CipherKeyGenerator(256);
+ case "CAMELLIA128":
+ return new CipherKeyGenerator(128);
+ case "CAMELLIA192":
+ return new CipherKeyGenerator(192);
+ case "CAMELLIA256":
+ return new CipherKeyGenerator(256);
+ case "CAST5":
+ return new CipherKeyGenerator(128);
+ case "CAST6":
+ return new CipherKeyGenerator(256);
+ case "GOST28147":
+ return new CipherKeyGenerator(256);
+ case "HC128":
+ return new CipherKeyGenerator(128);
+ case "HC256":
+ return new CipherKeyGenerator(256);
+ case "HMACMD2":
+ case "HMACMD4":
+ case "HMACMD5":
+ return new CipherKeyGenerator(128);
+ case "HMACSHA1":
+ return new CipherKeyGenerator(160);
+ case "HMACSHA224":
+ return new CipherKeyGenerator(224);
+ case "HMACSHA256":
+ return new CipherKeyGenerator(256);
+ case "HMACSHA384":
+ return new CipherKeyGenerator(384);
+ case "HMACSHA512":
+ return new CipherKeyGenerator(512);
+ case "HMACRIPEMD128":
+ return new CipherKeyGenerator(128);
+ case "HMACRIPEMD160":
+ return new CipherKeyGenerator(160);
+ case "HMACTIGER":
+ return new CipherKeyGenerator(192);
+ case "IDEA":
+ return new CipherKeyGenerator(128);
+ case "NOEKEON":
+ return new CipherKeyGenerator(128);
+ case "RC2":
+ case "RC4":
+ case "RC5":
+ return new CipherKeyGenerator(128);
+ case "RC5-64":
+ case "RC6":
+ return new CipherKeyGenerator(256);
+ case "RIJNDAEL":
+ return new CipherKeyGenerator(192);
+ case "SALSA20":
+ return new CipherKeyGenerator(128);
+ case "SEED":
+ return new CipherKeyGenerator(128);
+ case "SERPENT":
+ return new CipherKeyGenerator(192);
+ case "SKIPJACK":
+ return new CipherKeyGenerator(80);
+ case "TEA":
+ case "XTEA":
+ return new CipherKeyGenerator(128);
+ case "TWOFISH":
+ return new CipherKeyGenerator(256);
+ case "VMPC":
+ case "VMPC-KSA3":
+ return new CipherKeyGenerator(128);
+ }
+
+ throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+ }
+
+ public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+ DerObjectIdentifier oid)
+ {
+ return GetKeyPairGenerator(oid.Id);
+ }
+
+ public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+ string algorithm)
+ {
+ string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm);
+
+ if (canonicalName == null)
+ throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised.");
+
+ switch (canonicalName)
+ {
+ case "DH":
+ return new DHKeyPairGenerator();
+ case "DSA":
+ return new DsaKeyPairGenerator();
+ case "EC":
+ case "ECDH":
+ case "ECDHC":
+ case "ECDSA":
+ case "ECGOST3410":
+ return new ECKeyPairGenerator(canonicalName);
+ case "ELGAMAL":
+ return new ElGamalKeyPairGenerator();
+ case "GOST3410":
+ return new Gost3410KeyPairGenerator();
+ case "RSA":
+ return new RsaKeyPairGenerator();
+ default:
+ break;
+ }
+
+ throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised.");
+ }
+ }
+}
diff --git a/src/core/srcbc/security/InvalidKeyException.cs b/src/core/srcbc/security/InvalidKeyException.cs
new file mode 100644
index 0000000..570188f
--- /dev/null
+++ b/src/core/srcbc/security/InvalidKeyException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class InvalidKeyException : KeyException
+ {
+ public InvalidKeyException() : base() { }
+ public InvalidKeyException(string message) : base(message) { }
+ public InvalidKeyException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/InvalidParameterException.cs b/src/core/srcbc/security/InvalidParameterException.cs
new file mode 100644
index 0000000..ea7b82f
--- /dev/null
+++ b/src/core/srcbc/security/InvalidParameterException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class InvalidParameterException : KeyException
+ {
+ public InvalidParameterException() : base() { }
+ public InvalidParameterException(string message) : base(message) { }
+ public InvalidParameterException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/KeyException.cs b/src/core/srcbc/security/KeyException.cs
new file mode 100644
index 0000000..d7a4099
--- /dev/null
+++ b/src/core/srcbc/security/KeyException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class KeyException : GeneralSecurityException
+ {
+ public KeyException() : base() { }
+ public KeyException(string message) : base(message) { }
+ public KeyException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/MacUtilities.cs b/src/core/srcbc/security/MacUtilities.cs
new file mode 100644
index 0000000..d227c03
--- /dev/null
+++ b/src/core/srcbc/security/MacUtilities.cs
@@ -0,0 +1,220 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating HMac object from their names/Oids
+ ///
+ public sealed class MacUtilities
+ {
+ private MacUtilities()
+ {
+ }
+
+ private static readonly Hashtable algorithms = new Hashtable();
+// private static readonly Hashtable oids = new Hashtable();
+
+ static MacUtilities()
+ {
+ algorithms[IanaObjectIdentifiers.HmacMD5.Id] = "HMAC-MD5";
+ algorithms[IanaObjectIdentifiers.HmacRipeMD160.Id] = "HMAC-RIPEMD160";
+ algorithms[IanaObjectIdentifiers.HmacSha1.Id] = "HMAC-SHA1";
+ algorithms[IanaObjectIdentifiers.HmacTiger.Id] = "HMAC-TIGER";
+
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha1.Id] = "HMAC-SHA1";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha224.Id] = "HMAC-SHA224";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha256.Id] = "HMAC-SHA256";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512";
+
+ algorithms["DES"] = "DESMAC";
+ algorithms["DES/CFB8"] = "DESMAC/CFB8";
+ algorithms["DESEDE"] = "DESEDEMAC";
+ algorithms["DESEDE/CFB8"] = "DESEDEMAC/CFB8";
+ algorithms["DESISO9797MAC"] = "DESWITHISO9797";
+ algorithms["DESEDE64"] = "DESEDEMAC64";
+
+ algorithms["DESEDE64WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+ algorithms["DESEDEISO9797ALG1MACWITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+ algorithms["DESEDEISO9797ALG1WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+
+ algorithms["ISO9797ALG3"] = "ISO9797ALG3MAC";
+ algorithms["ISO9797ALG3MACWITHISO7816-4PADDING"] = "ISO9797ALG3WITHISO7816-4PADDING";
+
+ algorithms["SKIPJACK"] = "SKIPJACKMAC";
+ algorithms["SKIPJACK/CFB8"] = "SKIPJACKMAC/CFB8";
+ algorithms["IDEA"] = "IDEAMAC";
+ algorithms["IDEA/CFB8"] = "IDEAMAC/CFB8";
+ algorithms["RC2"] = "RC2MAC";
+ algorithms["RC2/CFB8"] = "RC2MAC/CFB8";
+ algorithms["RC5"] = "RC5MAC";
+ algorithms["RC5/CFB8"] = "RC5MAC/CFB8";
+ algorithms["GOST28147"] = "GOST28147MAC";
+ algorithms["VMPC"] = "VMPCMAC";
+ algorithms["VMPC-MAC"] = "VMPCMAC";
+
+ algorithms["PBEWITHHMACSHA"] = "PBEWITHHMACSHA1";
+ algorithms["1.3.14.3.2.26"] = "PBEWITHHMACSHA1";
+ }
+
+// ///
+// /// Returns a ObjectIdentifier for a given digest mechanism.
+// ///
+// /// A string representation of the digest meanism.
+// /// A DerObjectIdentifier, null if the Oid is not available.
+// public static DerObjectIdentifier GetObjectIdentifier(
+// string mechanism)
+// {
+// mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)];
+//
+// if (mechanism != null)
+// {
+// return (DerObjectIdentifier)oids[mechanism];
+// }
+//
+// return null;
+// }
+
+// public static ICollection Algorithms
+// {
+// get { return oids.Keys; }
+// }
+
+ public static IMac GetMac(
+ DerObjectIdentifier id)
+ {
+ return GetMac(id.Id);
+ }
+
+ public static IMac GetMac(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ if (mechanism.StartsWith("PBEWITH"))
+ {
+ mechanism = mechanism.Substring("PBEWITH".Length);
+ }
+
+ if (mechanism.StartsWith("HMAC"))
+ {
+ string digestName;
+ if (mechanism.StartsWith("HMAC-") || mechanism.StartsWith("HMAC/"))
+ {
+ digestName = mechanism.Substring(5);
+ }
+ else
+ {
+ digestName = mechanism.Substring(4);
+ }
+
+ return new HMac(DigestUtilities.GetDigest(digestName));
+ }
+
+ if (mechanism == "DESMAC")
+ {
+ return new CbcBlockCipherMac(new DesEngine());
+ }
+ if (mechanism == "DESMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new DesEngine());
+ }
+ if (mechanism == "DESEDEMAC")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine());
+ }
+ if (mechanism == "DESEDEMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new DesEdeEngine());
+ }
+ if (mechanism == "DESEDEMAC64")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine(), 64);
+ }
+ if (mechanism == "DESEDEMAC64WITHISO7816-4PADDING")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine(), 64, new ISO7816d4Padding());
+ }
+ if (mechanism == "DESWITHISO9797"
+ || mechanism == "ISO9797ALG3MAC")
+ {
+ return new ISO9797Alg3Mac(new DesEngine());
+ }
+ if (mechanism == "ISO9797ALG3WITHISO7816-4PADDING")
+ {
+ return new ISO9797Alg3Mac(new DesEngine(), new ISO7816d4Padding());
+ }
+ if (mechanism == "SKIPJACKMAC")
+ {
+ return new CbcBlockCipherMac(new SkipjackEngine());
+ }
+ if (mechanism == "SKIPJACKMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new SkipjackEngine());
+ }
+ if (mechanism == "IDEAMAC")
+ {
+ return new CbcBlockCipherMac(new IdeaEngine());
+ }
+ if (mechanism == "IDEAMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new IdeaEngine());
+ }
+ if (mechanism == "RC2MAC")
+ {
+ return new CbcBlockCipherMac(new RC2Engine());
+ }
+ if (mechanism == "RC2MAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new RC2Engine());
+ }
+ if (mechanism == "RC5MAC")
+ {
+ return new CbcBlockCipherMac(new RC532Engine());
+ }
+ if (mechanism == "RC5MAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new RC532Engine());
+ }
+ if (mechanism == "GOST28147MAC")
+ {
+ return new Gost28147Mac();
+ }
+ if (mechanism == "VMPCMAC")
+ {
+ return new VmpcMac();
+ }
+ throw new SecurityUtilityException("Mac " + mechanism + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ public static byte[] DoFinal(
+ IMac mac)
+ {
+ byte[] b = new byte[mac.GetMacSize()];
+ mac.DoFinal(b, 0);
+ return b;
+ }
+ }
+}
diff --git a/src/core/srcbc/security/NoSuchAlgorithmException.cs b/src/core/srcbc/security/NoSuchAlgorithmException.cs
new file mode 100644
index 0000000..1487556
--- /dev/null
+++ b/src/core/srcbc/security/NoSuchAlgorithmException.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ [Obsolete("Never thrown")]
+ public class NoSuchAlgorithmException : GeneralSecurityException
+ {
+ public NoSuchAlgorithmException() : base() {}
+ public NoSuchAlgorithmException(string message) : base(message) {}
+ public NoSuchAlgorithmException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/src/core/srcbc/security/ParameterUtilities.cs b/src/core/srcbc/security/ParameterUtilities.cs
new file mode 100644
index 0000000..5abbc13
--- /dev/null
+++ b/src/core/srcbc/security/ParameterUtilities.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class ParameterUtilities
+ {
+ private ParameterUtilities()
+ {
+ }
+
+ private static readonly Hashtable algorithms = new Hashtable();
+
+ static ParameterUtilities()
+ {
+ AddAlgorithm("AES",
+ "AESWRAP");
+ AddAlgorithm("AES128",
+ "2.16.840.1.101.3.4.2",
+ NistObjectIdentifiers.IdAes128Cbc,
+ NistObjectIdentifiers.IdAes128Cfb,
+ NistObjectIdentifiers.IdAes128Ecb,
+ NistObjectIdentifiers.IdAes128Ofb,
+ NistObjectIdentifiers.IdAes128Wrap);
+ AddAlgorithm("AES192",
+ "2.16.840.1.101.3.4.22",
+ NistObjectIdentifiers.IdAes192Cbc,
+ NistObjectIdentifiers.IdAes192Cfb,
+ NistObjectIdentifiers.IdAes192Ecb,
+ NistObjectIdentifiers.IdAes192Ofb,
+ NistObjectIdentifiers.IdAes192Wrap);
+ AddAlgorithm("AES256",
+ "2.16.840.1.101.3.4.42",
+ NistObjectIdentifiers.IdAes256Cbc,
+ NistObjectIdentifiers.IdAes256Cfb,
+ NistObjectIdentifiers.IdAes256Ecb,
+ NistObjectIdentifiers.IdAes256Ofb,
+ NistObjectIdentifiers.IdAes256Wrap);
+ AddAlgorithm("BLOWFISH");
+ AddAlgorithm("CAMELLIA",
+ "CAMELLIAWRAP");
+ AddAlgorithm("CAMELLIA128",
+ NttObjectIdentifiers.IdCamellia128Cbc,
+ NttObjectIdentifiers.IdCamellia128Wrap);
+ AddAlgorithm("CAMELLIA192",
+ NttObjectIdentifiers.IdCamellia192Cbc,
+ NttObjectIdentifiers.IdCamellia192Wrap);
+ AddAlgorithm("CAMELLIA256",
+ NttObjectIdentifiers.IdCamellia256Cbc,
+ NttObjectIdentifiers.IdCamellia256Wrap);
+ AddAlgorithm("CAST5",
+ "1.2.840.113533.7.66.10");
+ AddAlgorithm("CAST6");
+ AddAlgorithm("DES",
+ OiwObjectIdentifiers.DesCbc);
+ AddAlgorithm("DESEDE",
+ "DESEDEWRAP",
+ PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+ AddAlgorithm("DESEDE3",
+ PkcsObjectIdentifiers.DesEde3Cbc);
+ AddAlgorithm("GOST28147",
+ "GOST",
+ "GOST-28147",
+ CryptoProObjectIdentifiers.GostR28147Cbc);
+ AddAlgorithm("HC128");
+ AddAlgorithm("HC256");
+ AddAlgorithm("IDEA",
+ "1.3.6.1.4.1.188.7.1.1.2");
+ AddAlgorithm("NOEKEON");
+ AddAlgorithm("RC2",
+ PkcsObjectIdentifiers.RC2Cbc,
+ PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+ AddAlgorithm("RC4",
+ "ARC4",
+ "1.2.840.113549.3.4");
+ AddAlgorithm("RC5",
+ "RC5-32");
+ AddAlgorithm("RC5-64");
+ AddAlgorithm("RC6");
+ AddAlgorithm("RIJNDAEL");
+ AddAlgorithm("SALSA20");
+ AddAlgorithm("SEED",
+ KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+ KisaObjectIdentifiers.IdSeedCbc);
+ AddAlgorithm("SERPENT");
+ AddAlgorithm("SKIPJACK");
+ AddAlgorithm("TEA");
+ AddAlgorithm("TWOFISH");
+ AddAlgorithm("VMPC");
+ AddAlgorithm("VMPC-KSA3");
+ AddAlgorithm("XTEA");
+ }
+
+ private static void AddAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ algorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ algorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ public static string GetCanonicalAlgorithmName(
+ string algorithm)
+ {
+ return (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ DerObjectIdentifier algOid,
+ byte[] keyBytes)
+ {
+ return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ string algorithm,
+ byte[] keyBytes)
+ {
+ return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ DerObjectIdentifier algOid,
+ byte[] keyBytes,
+ int offset,
+ int length)
+ {
+ return CreateKeyParameter(algOid.Id, keyBytes, offset, length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ string algorithm,
+ byte[] keyBytes,
+ int offset,
+ int length)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ switch (canonical)
+ {
+ case "DES":
+ return new DesParameters(keyBytes, offset, length);
+ case "DESEDE":
+ case "DESEDE3":
+ return new DesEdeParameters(keyBytes, offset, length);
+ case "RC2":
+ return new RC2Parameters(keyBytes, offset, length);
+ default:
+ return new KeyParameter(keyBytes, offset, length);
+ }
+ }
+
+ public static ICipherParameters GetCipherParameters(
+ DerObjectIdentifier algOid,
+ ICipherParameters key,
+ Asn1Object asn1Params)
+ {
+ return GetCipherParameters(algOid.Id, key, asn1Params);
+ }
+
+ public static ICipherParameters GetCipherParameters(
+ string algorithm,
+ ICipherParameters key,
+ Asn1Object asn1Params)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ byte[] iv = null;
+
+ try
+ {
+ switch (canonical)
+ {
+ case "AES":
+ case "AES128":
+ case "AES192":
+ case "AES256":
+ case "BLOWFISH":
+ case "CAMELLIA":
+ case "CAMELLIA128":
+ case "CAMELLIA192":
+ case "CAMELLIA256":
+ case "DES":
+ case "DESEDE":
+ case "DESEDE3":
+ case "NOEKEON":
+ case "RIJNDAEL":
+ case "SEED":
+ case "SKIPJACK":
+ case "TWOFISH":
+ iv = ((Asn1OctetString) asn1Params).GetOctets();
+ break;
+ case "RC2":
+ iv = RC2CbcParameter.GetInstance(asn1Params).GetIV();
+ break;
+ case "IDEA":
+ iv = IdeaCbcPar.GetInstance(asn1Params).GetIV();
+ break;
+ case "CAST5":
+ iv = Cast5CbcParameters.GetInstance(asn1Params).GetIV();
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Could not process ASN.1 parameters", e);
+ }
+
+ if (iv != null)
+ {
+ return new ParametersWithIV(key, iv);
+ }
+
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+ }
+
+ public static Asn1Encodable GenerateParameters(
+ DerObjectIdentifier algID,
+ SecureRandom random)
+ {
+ return GenerateParameters(algID.Id, random);
+ }
+
+ public static Asn1Encodable GenerateParameters(
+ string algorithm,
+ SecureRandom random)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ switch (canonical)
+ {
+ // TODO These algorithms support an IV (see GetCipherParameters)
+ // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+// case "BLOWFISH":
+// case "RIJNDAEL":
+// case "SKIPJACK":
+// case "TWOFISH":
+
+ case "AES":
+ case "AES128":
+ case "AES192":
+ case "AES256":
+ return CreateIVOctetString(random, 16);
+ case "CAMELLIA":
+ case "CAMELLIA128":
+ case "CAMELLIA192":
+ case "CAMELLIA256":
+ return CreateIVOctetString(random, 16);
+ case "CAST5":
+ return new Cast5CbcParameters(CreateIV(random, 8), 128);
+ case "DES":
+ case "DESEDE":
+ case "DESEDE3":
+ return CreateIVOctetString(random, 8);
+ case "IDEA":
+ return new IdeaCbcPar(CreateIV(random, 8));
+ case "NOEKEON":
+ return CreateIVOctetString(random, 16);
+ case "RC2":
+ return new RC2CbcParameter(CreateIV(random, 8));
+ case "SEED":
+ return CreateIVOctetString(random, 16);
+ }
+
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+ }
+
+ private static Asn1OctetString CreateIVOctetString(
+ SecureRandom random,
+ int ivLength)
+ {
+ return new DerOctetString(CreateIV(random, ivLength));
+ }
+
+ private static byte[] CreateIV(
+ SecureRandom random,
+ int ivLength)
+ {
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+ return iv;
+ }
+ }
+}
diff --git a/src/core/srcbc/security/PbeUtilities.cs b/src/core/srcbc/security/PbeUtilities.cs
new file mode 100644
index 0000000..3717137
--- /dev/null
+++ b/src/core/srcbc/security/PbeUtilities.cs
@@ -0,0 +1,554 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ ///
+ ///
+ public sealed class PbeUtilities
+ {
+ private PbeUtilities()
+ {
+ }
+
+ const string Pkcs5S1 = "Pkcs5S1";
+ const string Pkcs5S2 = "Pkcs5S2";
+ const string Pkcs12 = "Pkcs12";
+ const string OpenSsl = "OpenSsl";
+
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable algorithmType = new Hashtable();
+ private static readonly Hashtable oids = new Hashtable();
+
+ static PbeUtilities()
+ {
+ algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
+ algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
+ algorithms["PBEWITHMD2ANDDES-CBC"] = "PBEwithMD2andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD2AndDesCbc.Id] = "PBEwithMD2andDES-CBC";
+ algorithms["PBEWITHMD2ANDRC2-CBC"] = "PBEwithMD2andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc.Id] = "PBEwithMD2andRC2-CBC";
+ algorithms["PBEWITHMD5ANDDES-CBC"] = "PBEwithMD5andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD5AndDesCbc.Id] = "PBEwithMD5andDES-CBC";
+ algorithms["PBEWITHMD5ANDRC2-CBC"] = "PBEwithMD5andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc.Id] = "PBEwithMD5andRC2-CBC";
+ algorithms["PBEWITHSHA1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA-1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA-1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA-1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA-1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PKCS12"] = "Pkcs12";
+ algorithms["PBEWITHSHAAND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHA-1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHAAND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHA-1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHAAND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHA-1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHAAND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHA-1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHAAND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHAAND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHAAND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHAANDIDEA"] = "PBEwithSHA-1andIDEA-CBC";
+ algorithms["PBEWITHSHAANDIDEA-CBC"] = "PBEwithSHA-1andIDEA-CBC";
+ algorithms["PBEWITHSHAANDTWOFISH"] = "PBEwithSHA-1andTWOFISH-CBC";
+ algorithms["PBEWITHSHAANDTWOFISH-CBC"] = "PBEwithSHA-1andTWOFISH-CBC";
+ algorithms["PBEWITHHMACSHA1"] = "PBEwithHmacSHA-1";
+ algorithms["PBEWITHHMACSHA-1"] = "PBEwithHmacSHA-1";
+ algorithms[OiwObjectIdentifiers.IdSha1.Id] = "PBEwithHmacSHA-1";
+ algorithms["PBEWITHHMACSHA224"] = "PBEwithHmacSHA-224";
+ algorithms["PBEWITHHMACSHA-224"] = "PBEwithHmacSHA-224";
+ algorithms[NistObjectIdentifiers.IdSha224.Id] = "PBEwithHmacSHA-224";
+ algorithms["PBEWITHHMACSHA256"] = "PBEwithHmacSHA-256";
+ algorithms["PBEWITHHMACSHA-256"] = "PBEwithHmacSHA-256";
+ algorithms[NistObjectIdentifiers.IdSha256.Id] = "PBEwithHmacSHA-256";
+ algorithms["PBEWITHHMACRIPEMD128"] = "PBEwithHmacRipeMD128";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "PBEwithHmacRipeMD128";
+ algorithms["PBEWITHHMACRIPEMD160"] = "PBEwithHmacRipeMD160";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "PBEwithHmacRipeMD160";
+ algorithms["PBEWITHHMACRIPEMD256"] = "PBEwithHmacRipeMD256";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "PBEwithHmacRipeMD256";
+ algorithms["PBEWITHHMACTIGER"] = "PBEwithHmacTiger";
+
+ algorithms["PBEWITHMD5AND128BITAES-CBC-OPENSSL"] = "PBEwithMD5and128bitAES-CBC-OpenSSL";
+ algorithms["PBEWITHMD5AND192BITAES-CBC-OPENSSL"] = "PBEwithMD5and192bitAES-CBC-OpenSSL";
+ algorithms["PBEWITHMD5AND256BITAES-CBC-OPENSSL"] = "PBEwithMD5and256bitAES-CBC-OpenSSL";
+
+ algorithmType["Pkcs5scheme1"] = Pkcs5S1;
+ algorithmType["Pkcs5scheme2"] = Pkcs5S2;
+ algorithmType["PBEwithMD2andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD2andRC2-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD5andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD5andRC2-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithSHA-1andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithSHA-1andRC2-CBC"] = Pkcs5S1;
+ algorithmType["Pkcs12"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitRC4"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and40bitRC4"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and3-keyDESEDE-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and2-keyDESEDE-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitRC2-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and40bitRC2-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and192bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and256bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and128bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and192bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and256bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1andIDEA-CBC"] = "Pkcs12";
+ algorithmType["PBEwithSHA-1andTWOFISH-CBC"] = "Pkcs12";
+ algorithmType["PBEwithHmacSHA-1"] = Pkcs12;
+ algorithmType["PBEwithHmacSHA-224"] = Pkcs12;
+ algorithmType["PBEwithHmacSHA-256"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD128"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD160"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD256"] = Pkcs12;
+ algorithmType["PBEwithHmacTiger"] = Pkcs12;
+
+ algorithmType["PBEwithMD5and128bitAES-CBC-OpenSSL"] = OpenSsl;
+ algorithmType["PBEwithMD5and192bitAES-CBC-OpenSSL"] = OpenSsl;
+ algorithmType["PBEwithMD5and256bitAES-CBC-OpenSSL"] = OpenSsl;
+
+ oids["PBEwithMD2andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndDesCbc;
+ oids["PBEwithMD2andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc;
+ oids["PBEwithMD5andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndDesCbc;
+ oids["PBEwithMD5andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc;
+ oids["PBEwithSHA-1andDES-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndDesCbc;
+ oids["PBEwithSHA-1andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc;
+ oids["PBEwithSHA-1and128bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4;
+ oids["PBEwithSHA-1and40bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4;
+ oids["PBEwithSHA-1and3-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+ oids["PBEwithSHA-1and2-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc;
+ oids["PBEwithSHA-1and128bitRC2-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc;
+ oids["PBEwithSHA-1and40bitRC2-CBC"] = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+ oids["PBEwithHmacSHA-1"] = OiwObjectIdentifiers.IdSha1;
+ oids["PBEwithHmacSHA-224"] = NistObjectIdentifiers.IdSha224;
+ oids["PBEwithHmacSHA-256"] = NistObjectIdentifiers.IdSha256;
+ oids["PBEwithHmacRipeMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oids["PBEwithHmacRipeMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oids["PBEwithHmacRipeMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+ }
+
+ static PbeParametersGenerator MakePbeGenerator(
+ string type,
+ IDigest digest,
+ byte[] key,
+ byte[] salt,
+ int iterationCount)
+ {
+ PbeParametersGenerator generator;
+
+ if (type.Equals(Pkcs5S1))
+ {
+ generator = new Pkcs5S1ParametersGenerator(digest);
+ }
+ else if (type.Equals(Pkcs5S2))
+ {
+ generator = new Pkcs5S2ParametersGenerator();
+ }
+ else if (type.Equals(Pkcs12))
+ {
+ generator = new Pkcs12ParametersGenerator(digest);
+ }
+ else if (type.Equals(OpenSsl))
+ {
+ generator = new OpenSslPbeParametersGenerator();
+ }
+ else
+ {
+ throw new ArgumentException("Unknown PBE type: " + type, "type");
+ }
+
+ generator.Init(key, salt, iterationCount);
+ return generator;
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a give encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)];
+ if (mechanism != null)
+ {
+ return (DerObjectIdentifier)oids[mechanism];
+ }
+ return null;
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static bool IsPkcs12(
+ string algorithm)
+ {
+ string mechanism = (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ return mechanism != null && Pkcs12.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPkcs5Scheme1(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ return mechanism != null && Pkcs5S1.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPkcs5Scheme2(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ return mechanism != null && Pkcs5S2.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsOpenSsl(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ return mechanism != null && OpenSsl.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPbeAlgorithm(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ return mechanism != null && algorithmType[mechanism] != null;
+ }
+
+ public static Asn1Encodable GenerateAlgorithmParameters(
+ DerObjectIdentifier algorithmOid,
+ byte[] salt,
+ int iterationCount)
+ {
+ return GenerateAlgorithmParameters(algorithmOid.Id, salt, iterationCount);
+ }
+
+ public static Asn1Encodable GenerateAlgorithmParameters(
+ string algorithm,
+ byte[] salt,
+ int iterationCount)
+ {
+ if (IsPkcs12(algorithm))
+ {
+ return new Pkcs12PbeParams(salt, iterationCount);
+ }
+ else if (IsPkcs5Scheme2(algorithm))
+ {
+ return new Pbkdf2Params(salt, iterationCount);
+ }
+ else
+ {
+ return new PbeParameter(salt, iterationCount);
+ }
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ DerObjectIdentifier algorithmOid,
+ char[] password,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithmOid.Id, password, false, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ DerObjectIdentifier algorithmOid,
+ char[] password,
+ bool wrongPkcs12Zero,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithmOid.Id, password, wrongPkcs12Zero, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ string algorithm,
+ char[] password,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithm, password, false, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ string algorithm,
+ char[] password,
+ bool wrongPkcs12Zero,
+ Asn1Encodable pbeParameters)
+ {
+ string mechanism = (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+ byte[] keyBytes;
+ //string type = (string)algorithmType[mechanism];
+ byte[] salt;
+ int iterationCount;
+
+ if (IsPkcs12(mechanism))
+ {
+ Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(pbeParameters);
+ salt = pbeParams.GetIV();
+ iterationCount = pbeParams.Iterations.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs12PasswordToBytes(password, wrongPkcs12Zero);
+ }
+ else if (IsPkcs5Scheme2(mechanism))
+ {
+ Pbkdf2Params pbeParams = Pbkdf2Params.GetInstance(pbeParameters);
+ salt = pbeParams.GetSalt();
+ iterationCount = pbeParams.IterationCount.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+ }
+ else
+ {
+ PbeParameter pbeParams = PbeParameter.GetInstance(pbeParameters);
+ salt = pbeParams.GetSalt();
+ iterationCount = pbeParams.IterationCount.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+ }
+
+ ICipherParameters parameters = null;
+
+ if (mechanism.StartsWith("PBEwithSHA-1"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], new Sha1Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithSHA-1and128bitRC4"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC4", 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and40bitRC4"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC4", 40);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and3-keyDESEDE-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DESEDE", 192, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and2-keyDESEDE-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DESEDE", 128, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and128bitRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 128, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and40bitRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 40, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and128bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and192bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and256bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ }
+ else if (mechanism.StartsWith("PBEwithSHA-256"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], new Sha256Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithSHA-256and128bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-256and192bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-256and256bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ }
+ else if (mechanism.StartsWith("PBEwithMD5"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string)algorithmType[mechanism], new MD5Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithMD5andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD5andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD5and128bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithMD5and192bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithMD5and256bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ }
+ else if (mechanism.StartsWith("PBEwithMD2"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string)algorithmType[mechanism], new MD2Digest(), keyBytes, salt, iterationCount);
+ if (mechanism.Equals("PBEwithMD2andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD2andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ }
+ else if (mechanism.StartsWith("PBEwithHmac"))
+ {
+ string digestName = mechanism.Substring("PBEwithHmac".Length);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], digest, keyBytes, salt, iterationCount);
+
+ int bitLen = digest.GetDigestSize() * 8;
+ parameters = generator.GenerateDerivedMacParameters(bitLen);
+ }
+
+ Array.Clear(keyBytes, 0, keyBytes.Length);
+
+ return parameters;
+ }
+
+ public static object CreateEngine(
+ DerObjectIdentifier algorithmOid)
+ {
+ return CreateEngine(algorithmOid.Id);
+ }
+
+ private static bool EndsWith(
+ string s,
+ string ending)
+ {
+ int pos = s.Length - ending.Length;
+
+ return pos >= 0 && s.Substring(pos) == ending;
+ }
+
+ public static object CreateEngine(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)];
+
+ if (mechanism.StartsWith("PBEwithHmac"))
+ {
+ string digestName = mechanism.Substring("PBEwithHmac".Length);
+
+ return MacUtilities.GetMac("HMAC/" + digestName);
+ }
+
+ if (mechanism.StartsWith("PBEwithMD2")
+ || mechanism.StartsWith("PBEwithMD5")
+ || mechanism.StartsWith("PBEwithSHA-1"))
+ {
+ if (EndsWith(mechanism, "RC2-CBC"))
+ {
+ return CipherUtilities.GetCipher("RC2/CBC");
+ }
+
+ if (EndsWith(mechanism, "RC4"))
+ {
+ return CipherUtilities.GetCipher("RC4");
+ }
+
+ if (EndsWith(mechanism, "DES-CBC"))
+ {
+ return CipherUtilities.GetCipher("DES/CBC");
+ }
+
+ if (EndsWith(mechanism, "DESEDE-CBC"))
+ {
+ return CipherUtilities.GetCipher("DESEDE/CBC");
+ }
+ }
+
+ return null;
+ }
+
+ public static string GetEncodingName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+ }
+}
diff --git a/src/core/srcbc/security/PrivateKeyFactory.cs b/src/core/srcbc/security/PrivateKeyFactory.cs
new file mode 100644
index 0000000..79fa72d
--- /dev/null
+++ b/src/core/srcbc/security/PrivateKeyFactory.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class PrivateKeyFactory
+ {
+ private PrivateKeyFactory()
+ {
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ byte[] privateKeyInfoData)
+ {
+ return CreateKey(
+ PrivateKeyInfo.GetInstance(
+ Asn1Object.FromByteArray(privateKeyInfoData)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ Stream inStr)
+ {
+ return CreateKey(
+ PrivateKeyInfo.GetInstance(
+ Asn1Object.FromStream(inStr)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ PrivateKeyInfo keyInfo)
+ {
+ AlgorithmIdentifier algID = keyInfo.AlgorithmID;
+ DerObjectIdentifier algOid = algID.ObjectID;
+
+ if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption))
+ {
+ RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure(
+ Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+
+ return new RsaPrivateCrtKeyParameters(
+ keyStructure.Modulus,
+ keyStructure.PublicExponent,
+ keyStructure.PrivateExponent,
+ keyStructure.Prime1,
+ keyStructure.Prime2,
+ keyStructure.Exponent1,
+ keyStructure.Exponent2,
+ keyStructure.Coefficient);
+ }
+ else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
+ {
+ DHParameter para = new DHParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derX = (DerInteger)keyInfo.PrivateKey;
+
+ return new DHPrivateKeyParameters(
+ derX.Value,
+ new DHParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+ {
+ ElGamalParameter para = new ElGamalParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derX = (DerInteger)keyInfo.PrivateKey;
+
+ return new ElGamalPrivateKeyParameters(
+ derX.Value,
+ new ElGamalParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdDsa))
+ {
+ DerInteger derX = (DerInteger) keyInfo.PrivateKey;
+ Asn1Encodable ae = algID.Parameters;
+
+ DsaParameters parameters = null;
+ if (ae != null)
+ {
+ DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+ parameters = new DsaParameters(para.P, para.Q, para.G);
+ }
+
+ return new DsaPrivateKeyParameters(derX.Value, parameters);
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
+ X9ECParameters ecP;
+
+ if (para.IsNamedCurve)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+ DerObjectIdentifier oid = (DerObjectIdentifier) para.Parameters;
+ ecP = X962NamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = NistNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByOid(oid);
+ }
+ }
+ }
+ }
+ else
+ {
+ ecP = new X9ECParameters((Asn1Sequence) para.Parameters);
+ }
+
+ ECDomainParameters dParams = new ECDomainParameters(
+ ecP.Curve,
+ ecP.G,
+ ecP.N,
+ ecP.H,
+ ecP.GetSeed());
+
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
+ Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+
+ return new ECPrivateKeyParameters(ec.GetKey(), dParams);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
+ Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+
+ ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+ if (ecP == null)
+ return null;
+
+ return new ECPrivateKeyParameters(ec.GetKey(), gostParams.PublicKeyParamSet);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+ DerOctetString derX = (DerOctetString) keyInfo.PrivateKey;
+ byte[] keyEnc = derX.GetOctets();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyEnc.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
+ }
+
+ BigInteger x = new BigInteger(1, keyBytes);
+
+ return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
+ }
+ else
+ {
+ throw new SecurityUtilityException("algorithm identifier in key not recognised");
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/security/PublicKeyFactory.cs b/src/core/srcbc/security/PublicKeyFactory.cs
new file mode 100644
index 0000000..775b84e
--- /dev/null
+++ b/src/core/srcbc/security/PublicKeyFactory.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class PublicKeyFactory
+ {
+ private PublicKeyFactory()
+ {
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ byte[] keyInfoData)
+ {
+ return CreateKey(
+ SubjectPublicKeyInfo.GetInstance(
+ Asn1Object.FromByteArray(keyInfoData)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ Stream inStr)
+ {
+ return CreateKey(
+ SubjectPublicKeyInfo.GetInstance(
+ Asn1Object.FromStream(inStr)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ SubjectPublicKeyInfo keyInfo)
+ {
+ AlgorithmIdentifier algID = keyInfo.AlgorithmID;
+ DerObjectIdentifier algOid = algID.ObjectID;
+
+ if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
+ || algOid.Equals(X509ObjectIdentifiers.IdEARsa))
+ {
+ RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance(
+ keyInfo.GetPublicKey());
+
+ return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent);
+ }
+ else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement)
+ || algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
+ {
+ DHParameter para = new DHParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+ return new DHPublicKeyParameters(derY.Value, new DHParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+ {
+ ElGamalParameter para = new ElGamalParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+ return new ElGamalPublicKeyParameters(
+ derY.Value,
+ new ElGamalParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)
+ || algOid.Equals(OiwObjectIdentifiers.DsaWithSha1))
+ {
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+ Asn1Encodable ae = algID.Parameters;
+
+ DsaParameters parameters = null;
+ if (ae != null)
+ {
+ DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+ parameters = new DsaParameters(para.P, para.Q, para.G);
+ }
+
+ return new DsaPublicKeyParameters(derY.Value, parameters);
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ X962Parameters para = new X962Parameters(
+ algID.Parameters.ToAsn1Object());
+ X9ECParameters ecP;
+
+ if (para.IsNamedCurve)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+ DerObjectIdentifier oid = (DerObjectIdentifier)para.Parameters;
+ ecP = X962NamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = NistNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByOid(oid);
+ }
+ }
+ }
+ }
+ else
+ {
+ ecP = new X9ECParameters((Asn1Sequence)para.Parameters.ToAsn1Object());
+ }
+
+ ECDomainParameters dParams = new ECDomainParameters(
+ ecP.Curve,
+ ecP.G,
+ ecP.N,
+ ecP.H,
+ ecP.GetSeed());
+
+ DerBitString bits = keyInfo.PublicKeyData;
+ byte[] data = bits.GetBytes();
+ Asn1OctetString key = new DerOctetString(data);
+
+ X9ECPoint derQ = new X9ECPoint(dParams.Curve, key);
+
+ return new ECPublicKeyParameters(derQ.Point, dParams);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ (Asn1Sequence) algID.Parameters);
+
+ Asn1OctetString key;
+ try
+ {
+ key = (Asn1OctetString) keyInfo.GetPublicKey();
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid info structure in GOST3410 public key");
+ }
+
+ byte[] keyEnc = key.GetOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != y.Length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != x.Length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+ if (ecP == null)
+ return null;
+
+ ECPoint q = ecP.Curve.CreatePoint(new BigInteger(1, x), new BigInteger(1, y), false);
+
+ return new ECPublicKeyParameters(q, gostParams.PublicKeyParamSet);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+ {
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ (Asn1Sequence) algID.Parameters);
+
+ DerOctetString derY;
+ try
+ {
+ derY = (DerOctetString) keyInfo.GetPublicKey();
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid info structure in GOST3410 public key");
+ }
+
+ byte[] keyEnc = derY.GetOctets();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyEnc.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
+ }
+
+ BigInteger y = new BigInteger(1, keyBytes);
+
+ return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
+ }
+ else
+ {
+ throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/security/SecureRandom.cs b/src/core/srcbc/security/SecureRandom.cs
new file mode 100644
index 0000000..bffb5a9
--- /dev/null
+++ b/src/core/srcbc/security/SecureRandom.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng;
+
+namespace Org.BouncyCastle.Security
+{
+ public class SecureRandom
+ : Random
+ {
+ private static readonly SecureRandom[] master = { null };
+ private static SecureRandom Master
+ {
+ get
+ {
+ if (master[0] == null)
+ {
+ IRandomGenerator gen = new DigestRandomGenerator(new Sha256Digest());
+ gen = new ReversedWindowGenerator(gen, 32);
+ SecureRandom sr = master[0] = new SecureRandom(gen);
+
+ sr.SetSeed(DateTime.Now.Ticks);
+ sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true));
+ sr.GenerateSeed(1 + sr.Next(32));
+ }
+
+ return master[0];
+ }
+ }
+
+ public static SecureRandom GetInstance(
+ string algorithm)
+ {
+ // TODO Compared to JDK, we don't auto-seed if the client forgets - problem?
+
+ // TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities?
+ IDigest digest = null;
+ switch (algorithm.ToUpper(CultureInfo.InvariantCulture))
+ {
+ case "SHA1PRNG":
+ digest = new Sha1Digest();
+ break;
+ case "SHA256PRNG":
+ digest = new Sha256Digest();
+ break;
+ }
+
+ if (digest != null)
+ {
+ return new SecureRandom(new DigestRandomGenerator(digest));
+ }
+
+ throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
+ }
+
+ public static byte[] GetSeed(
+ int length)
+ {
+ return Master.GenerateSeed(length);
+ }
+
+ protected IRandomGenerator generator;
+
+ public SecureRandom()
+ : base(0)
+ {
+ this.generator = new DigestRandomGenerator(new Sha1Digest());
+ SetSeed(GetSeed(8));
+ }
+
+ public SecureRandom(
+ byte[] inSeed)
+ : base(0)
+ {
+ this.generator = new DigestRandomGenerator(new Sha1Digest());
+ SetSeed(inSeed);
+ }
+
+ /// Use the specified instance of IRandomGenerator as random source.
+ ///
+ /// This constructor performs no seeding of either the IRandomGenerator or the
+ /// constructed SecureRandom. It is the responsibility of the client to provide
+ /// proper seed material as necessary/appropriate for the given IRandomGenerator
+ /// implementation.
+ ///
+ /// The source to generate all random bytes from.
+ public SecureRandom(
+ IRandomGenerator generator)
+ : base(0)
+ {
+ this.generator = generator;
+ }
+
+ public virtual byte[] GenerateSeed(
+ int length)
+ {
+ SetSeed(DateTime.Now.Ticks);
+
+ byte[] rv = new byte[length];
+ NextBytes(rv);
+ return rv;
+ }
+
+ public virtual void SetSeed(
+ byte[] inSeed)
+ {
+ generator.AddSeedMaterial(inSeed);
+ }
+
+ public virtual void SetSeed(
+ long seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public override int Next()
+ {
+ for (;;)
+ {
+ int i = NextInt() & int.MaxValue;
+
+ if (i != int.MaxValue)
+ return i;
+ }
+ }
+
+ public override int Next(
+ int maxValue)
+ {
+ if (maxValue < 2)
+ {
+ if (maxValue < 0)
+ throw new ArgumentOutOfRangeException("maxValue < 0");
+
+ return 0;
+ }
+
+ // Test whether maxValue is a power of 2
+ if ((maxValue & -maxValue) == maxValue)
+ {
+ int val = NextInt() & int.MaxValue;
+ long lr = ((long) maxValue * (long) val) >> 31;
+ return (int) lr;
+ }
+
+ int bits, result;
+ do
+ {
+ bits = NextInt() & int.MaxValue;
+ result = bits % maxValue;
+ }
+ while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
+
+ return result;
+ }
+
+ public override int Next(
+ int minValue,
+ int maxValue)
+ {
+ if (maxValue <= minValue)
+ {
+ if (maxValue == minValue)
+ return minValue;
+
+ throw new ArgumentException("maxValue cannot be less than minValue");
+ }
+
+ int diff = maxValue - minValue;
+ if (diff > 0)
+ return minValue + Next(diff);
+
+ for (;;)
+ {
+ int i = NextInt();
+
+ if (i >= minValue && i < maxValue)
+ return i;
+ }
+ }
+
+ public override void NextBytes(
+ byte[] buffer)
+ {
+ generator.NextBytes(buffer);
+ }
+
+ public virtual void NextBytes(
+ byte[] buffer,
+ int start,
+ int length)
+ {
+ generator.NextBytes(buffer, start, length);
+ }
+
+ private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
+
+ public override double NextDouble()
+ {
+ return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
+ }
+
+ public virtual int NextInt()
+ {
+ byte[] intBytes = new byte[4];
+ NextBytes(intBytes);
+
+ int result = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ result = (result << 8) + (intBytes[i] & 0xff);
+ }
+
+ return result;
+ }
+
+ public virtual long NextLong()
+ {
+ return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
+ }
+ }
+}
diff --git a/src/core/srcbc/security/SecurityUtilityException.cs b/src/core/srcbc/security/SecurityUtilityException.cs
new file mode 100644
index 0000000..e57a00a
--- /dev/null
+++ b/src/core/srcbc/security/SecurityUtilityException.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class SecurityUtilityException
+ : Exception
+ {
+ /**
+ * base constructor.
+ */
+ public SecurityUtilityException()
+ {
+ }
+
+ /**
+ * create a SecurityUtilityException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public SecurityUtilityException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public SecurityUtilityException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/security/SignatureException.cs b/src/core/srcbc/security/SignatureException.cs
new file mode 100644
index 0000000..a1a631b
--- /dev/null
+++ b/src/core/srcbc/security/SignatureException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ public class SignatureException : GeneralSecurityException
+ {
+ public SignatureException() : base() { }
+ public SignatureException(string message) : base(message) { }
+ public SignatureException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/SignerUtilities.cs b/src/core/srcbc/security/SignerUtilities.cs
new file mode 100644
index 0000000..e684aef
--- /dev/null
+++ b/src/core/srcbc/security/SignerUtilities.cs
@@ -0,0 +1,517 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Signer Utility class contains methods that can not be specifically grouped into other classes.
+ ///
+ public sealed class SignerUtilities
+ {
+ private SignerUtilities()
+ {
+ }
+
+ internal static readonly Hashtable algorithms = new Hashtable();
+ internal static readonly Hashtable oids = new Hashtable();
+
+ static SignerUtilities()
+ {
+ algorithms["MD2WITHRSA"] = "MD2withRSA";
+ algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA";
+ algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA";
+
+ algorithms["MD4WITHRSA"] = "MD4withRSA";
+ algorithms["MD4WITHRSAENCRYPTION"] = "MD4withRSA";
+ algorithms[PkcsObjectIdentifiers.MD4WithRsaEncryption.Id] = "MD4withRSA";
+
+ algorithms["MD5WITHRSA"] = "MD5withRSA";
+ algorithms["MD5WITHRSAENCRYPTION"] = "MD5withRSA";
+ algorithms[PkcsObjectIdentifiers.MD5WithRsaEncryption.Id] = "MD5withRSA";
+
+ algorithms["SHA1WITHRSA"] = "SHA-1withRSA";
+ algorithms["SHA1WITHRSAENCRYPTION"] = "SHA-1withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id] = "SHA-1withRSA";
+ algorithms["SHA-1WITHRSA"] = "SHA-1withRSA";
+
+ algorithms["SHA224WITHRSA"] = "SHA-224withRSA";
+ algorithms["SHA224WITHRSAENCRYPTION"] = "SHA-224withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id] = "SHA-224withRSA";
+ algorithms["SHA-224WITHRSA"] = "SHA-224withRSA";
+
+ algorithms["SHA256WITHRSA"] = "SHA-256withRSA";
+ algorithms["SHA256WITHRSAENCRYPTION"] = "SHA-256withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id] = "SHA-256withRSA";
+ algorithms["SHA-256WITHRSA"] = "SHA-256withRSA";
+
+ algorithms["SHA384WITHRSA"] = "SHA-384withRSA";
+ algorithms["SHA384WITHRSAENCRYPTION"] = "SHA-384withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id] = "SHA-384withRSA";
+ algorithms["SHA-384WITHRSA"] = "SHA-384withRSA";
+
+ algorithms["SHA512WITHRSA"] = "SHA-512withRSA";
+ algorithms["SHA512WITHRSAENCRYPTION"] = "SHA-512withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id] = "SHA-512withRSA";
+ algorithms["SHA-512WITHRSA"] = "SHA-512withRSA";
+
+ algorithms["PSSWITHRSA"] = "PSSwithRSA";
+ algorithms["RSASSA-PSS"] = "PSSwithRSA";
+ algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
+
+ algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+
+ algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+
+ algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA-256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+
+ algorithms["SHA384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA-384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+
+ algorithms["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+
+ algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
+ algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA";
+
+ algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
+ algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA";
+
+ algorithms["RIPEMD256WITHRSA"] = "RIPEMD256withRSA";
+ algorithms["RIPEMD256WITHRSAENCRYPTION"] = "RIPEMD256withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256.Id] = "RIPEMD256withRSA";
+
+ algorithms["NONEWITHDSA"] = "NONEwithDSA";
+ algorithms["DSAWITHNONE"] = "NONEwithDSA";
+
+ algorithms["DSA"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
+ algorithms["SHA/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA-1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
+ algorithms["SHA-1WITHDSA"] = "SHA-1withDSA";
+ algorithms[X9ObjectIdentifiers.IdDsaWithSha1.Id] = "SHA-1withDSA";
+
+ algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
+ algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
+ algorithms["SHA224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA-224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
+ algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
+
+ algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
+ algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
+ algorithms["SHA256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA-256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
+ algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
+
+ algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
+ algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
+ algorithms["SHA384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA-384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
+ algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
+
+ algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
+ algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
+ algorithms["SHA512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA-512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
+ algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
+
+
+ algorithms["ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
+ algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA-1WITHECDSA"] = "SHA-1withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
+
+ algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
+ algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
+
+ algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
+ algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
+
+ algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
+ algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
+
+ algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
+ algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
+
+ algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
+ algorithms["SHA-512/ECDSA"] = "RIPEMD160withECDSA";
+ algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
+ algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
+ algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
+ algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
+
+ algorithms["GOST-3410"] = "GOST3410";
+ algorithms["GOST-3410-94"] = "GOST3410";
+ algorithms["GOST3411WITHGOST3410"] = "GOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
+
+ algorithms["ECGOST-3410"] = "ECGOST3410";
+ algorithms["ECGOST-3410-2001"] = "ECGOST3410";
+ algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
+
+
+
+ oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
+ oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
+ oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
+
+ oids["SHA-1withRSA"] = PkcsObjectIdentifiers.Sha1WithRsaEncryption;
+ oids["SHA-224withRSA"] = PkcsObjectIdentifiers.Sha224WithRsaEncryption;
+ oids["SHA-256withRSA"] = PkcsObjectIdentifiers.Sha256WithRsaEncryption;
+ oids["SHA-384withRSA"] = PkcsObjectIdentifiers.Sha384WithRsaEncryption;
+ oids["SHA-512withRSA"] = PkcsObjectIdentifiers.Sha512WithRsaEncryption;
+
+ oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+
+ oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
+ oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
+ oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
+
+ oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
+
+ oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
+ oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
+ oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
+ oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
+ oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
+
+ oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
+ oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a give encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+ // TODO Don't really want to support this
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ if (mechanism == null)
+ throw new ArgumentNullException("mechanism");
+
+ mechanism = mechanism.ToUpper(CultureInfo.InvariantCulture);
+ string aliased = (string) algorithms[mechanism];
+
+ if (aliased != null)
+ mechanism = aliased;
+
+ return (DerObjectIdentifier) oids[mechanism];
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static ISigner GetSigner(
+ DerObjectIdentifier id)
+ {
+ return GetSigner(id.Id);
+ }
+
+ public static ISigner GetSigner(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = algorithm.ToUpper(CultureInfo.InvariantCulture);
+
+ string mechanism = (string) algorithms[algorithm];
+
+ if (mechanism == null)
+ mechanism = algorithm;
+
+ if (mechanism.Equals("MD2withRSA"))
+ {
+ return (new RsaDigestSigner(new MD2Digest()));
+ }
+ if (mechanism.Equals("MD4withRSA"))
+ {
+ return (new RsaDigestSigner(new MD4Digest()));
+ }
+ if (mechanism.Equals("MD5withRSA"))
+ {
+ return (new RsaDigestSigner(new MD5Digest()));
+ }
+ if (mechanism.Equals("SHA-1withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha512Digest()));
+ }
+ if (mechanism.Equals("RIPEMD128withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD128Digest()));
+ }
+ if (mechanism.Equals("RIPEMD160withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD160Digest()));
+ }
+ if (mechanism.Equals("RIPEMD256withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD256Digest()));
+ }
+
+ if (mechanism.Equals("PSSwithRSA"))
+ {
+ // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+ // to be used can be overridden by subsequent parameter settings.
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-1withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("NONEwithDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
+ }
+ if (mechanism.Equals("SHA-1withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("SHA-1withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("RIPEMD160withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
+ }
+
+ if (mechanism.Equals("SHA1WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA224WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA256WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA384WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA512WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("GOST3410"))
+ {
+ return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
+ }
+ if (mechanism.Equals("ECGOST3410"))
+ {
+ return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+ }
+
+ if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+ }
+ if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+ }
+ if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+ }
+
+ throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+ }
+
+ public static string GetEncodingName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private class NullDigest : IDigest
+ {
+ private readonly MemoryStream bOut = new MemoryStream();
+
+ public string AlgorithmName
+ {
+ get { return "NULL"; }
+ }
+
+ public int GetByteLength()
+ {
+ // TODO Is this okay?
+ return 0;
+ }
+
+ public int GetDigestSize()
+ {
+ return (int) bOut.Length;
+ }
+
+ public void Update(byte b)
+ {
+ bOut.WriteByte(b);
+ }
+
+ public void BlockUpdate(byte[] inBytes, int inOff, int len)
+ {
+ bOut.Write(inBytes, inOff, len);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ byte[] res = bOut.ToArray();
+ res.CopyTo(outBytes, outOff);
+ return res.Length;
+ }
+
+ public void Reset()
+ {
+ bOut.SetLength(0);
+ }
+ }
+
+ }
+}
diff --git a/src/core/srcbc/security/WrapperUtilities.cs b/src/core/srcbc/security/WrapperUtilities.cs
new file mode 100644
index 0000000..47a2cbc
--- /dev/null
+++ b/src/core/srcbc/security/WrapperUtilities.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating IWrapper objects from their names/Oids
+ ///
+ public sealed class WrapperUtilities
+ {
+ private WrapperUtilities()
+ {
+ }
+
+ private static readonly Hashtable algorithms = new Hashtable();
+// private static readonly Hashtable oids = new Hashtable();
+
+ static WrapperUtilities()
+ {
+ algorithms[NistObjectIdentifiers.IdAes128Wrap.Id] = "AESWRAP";
+ algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP";
+ algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP";
+
+ algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP";
+ algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP";
+ algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP";
+
+ algorithms[PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id] = "DESEDEWRAP";
+
+ algorithms[PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id] = "RC2WRAP";
+
+ algorithms[KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id] = "SEEDWRAP";
+ }
+
+ public static IWrapper GetWrapper(
+ DerObjectIdentifier oid)
+ {
+ return GetWrapper(oid.Id);
+ }
+
+ public static IWrapper GetWrapper(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ switch (mechanism)
+ {
+ case "AESWRAP":
+ return new AesWrapEngine();
+ case "CAMELLIAWRAP":
+ return new CamelliaWrapEngine();
+ case "DESEDEWRAP":
+ return new DesEdeWrapEngine();
+ case "RC2WRAP":
+ return new RC2WrapEngine();
+ case "SEEDWRAP":
+ return new SeedWrapEngine();
+ case "DESEDERFC3211WRAP":
+ return new Rfc3211WrapEngine(new DesEdeEngine());
+ case "AESRFC3211WRAP":
+ return new Rfc3211WrapEngine(new AesFastEngine());
+ case "CAMELLIARFC3211WRAP":
+ return new Rfc3211WrapEngine(new CamelliaEngine());
+ }
+
+ // Create an IBufferedCipher and use it as IWrapper (via BufferedCipherWrapper)
+ IBufferedCipher blockCipher = CipherUtilities.GetCipher(algorithm);
+
+ if (blockCipher != null)
+ return new BufferedCipherWrapper(blockCipher);
+
+ throw new SecurityUtilityException("Wrapper " + algorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private class BufferedCipherWrapper
+ : IWrapper
+ {
+ private readonly IBufferedCipher cipher;
+ private bool forWrapping;
+
+ public BufferedCipherWrapper(
+ IBufferedCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+
+ cipher.Init(forWrapping, parameters);
+ }
+
+ public byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ throw new InvalidOperationException("Not initialised for wrapping");
+
+ return cipher.DoFinal(input, inOff, length);
+ }
+
+ public byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ throw new InvalidOperationException("Not initialised for Unwrapping");
+
+ return cipher.DoFinal(input, inOff, length);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CertificateEncodingException.cs b/src/core/srcbc/security/cert/CertificateEncodingException.cs
new file mode 100644
index 0000000..0b7f4f9
--- /dev/null
+++ b/src/core/srcbc/security/cert/CertificateEncodingException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CertificateEncodingException : CertificateException
+ {
+ public CertificateEncodingException() : base() { }
+ public CertificateEncodingException(string msg) : base(msg) { }
+ public CertificateEncodingException(string msg, Exception e) : base(msg, e) { }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CertificateException.cs b/src/core/srcbc/security/cert/CertificateException.cs
new file mode 100644
index 0000000..9a3d9b2
--- /dev/null
+++ b/src/core/srcbc/security/cert/CertificateException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CertificateException : GeneralSecurityException
+ {
+ public CertificateException() : base() { }
+ public CertificateException(string message) : base(message) { }
+ public CertificateException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CertificateExpiredException.cs b/src/core/srcbc/security/cert/CertificateExpiredException.cs
new file mode 100644
index 0000000..8c2458c
--- /dev/null
+++ b/src/core/srcbc/security/cert/CertificateExpiredException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CertificateExpiredException : CertificateException
+ {
+ public CertificateExpiredException() : base() { }
+ public CertificateExpiredException(string message) : base(message) { }
+ public CertificateExpiredException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CertificateNotYetValidException.cs b/src/core/srcbc/security/cert/CertificateNotYetValidException.cs
new file mode 100644
index 0000000..4906f64
--- /dev/null
+++ b/src/core/srcbc/security/cert/CertificateNotYetValidException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CertificateNotYetValidException : CertificateException
+ {
+ public CertificateNotYetValidException() : base() { }
+ public CertificateNotYetValidException(string message) : base(message) { }
+ public CertificateNotYetValidException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CertificateParsingException.cs b/src/core/srcbc/security/cert/CertificateParsingException.cs
new file mode 100644
index 0000000..a0c7d8f
--- /dev/null
+++ b/src/core/srcbc/security/cert/CertificateParsingException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CertificateParsingException : CertificateException
+ {
+ public CertificateParsingException() : base() { }
+ public CertificateParsingException(string message) : base(message) { }
+ public CertificateParsingException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/src/core/srcbc/security/cert/CrlException.cs b/src/core/srcbc/security/cert/CrlException.cs
new file mode 100644
index 0000000..2b9b194
--- /dev/null
+++ b/src/core/srcbc/security/cert/CrlException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+ public class CrlException : GeneralSecurityException
+ {
+ public CrlException() : base() { }
+ public CrlException(string msg) : base(msg) {}
+ public CrlException(string msg, Exception e) : base(msg, e) {}
+ }
+}
diff --git a/src/core/srcbc/tsp/GenTimeAccuracy.cs b/src/core/srcbc/tsp/GenTimeAccuracy.cs
new file mode 100644
index 0000000..1bfe53d
--- /dev/null
+++ b/src/core/srcbc/tsp/GenTimeAccuracy.cs
@@ -0,0 +1,33 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class GenTimeAccuracy
+ {
+ private Accuracy accuracy;
+
+ public GenTimeAccuracy(
+ Accuracy accuracy)
+ {
+ this.accuracy = accuracy;
+ }
+
+ public int Seconds { get { return GetTimeComponent(accuracy.Seconds); } }
+
+ public int Millis { get { return GetTimeComponent(accuracy.Millis); } }
+
+ public int Micros { get { return GetTimeComponent(accuracy.Micros); } }
+
+ private int GetTimeComponent(
+ DerInteger time)
+ {
+ return time == null ? 0 : time.Value.IntValue;
+ }
+
+ public override string ToString()
+ {
+ return Seconds + "." + Millis.ToString("000") + Micros.ToString("000");
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TSPAlgorithms.cs b/src/core/srcbc/tsp/TSPAlgorithms.cs
new file mode 100644
index 0000000..ee5c4b5
--- /dev/null
+++ b/src/core/srcbc/tsp/TSPAlgorithms.cs
@@ -0,0 +1,47 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Recognised hash algorithms for the time stamp protocol.
+ */
+ public abstract class TspAlgorithms
+ {
+ public static readonly string MD5 = PkcsObjectIdentifiers.MD5.Id;
+
+ public static readonly string Sha1 = OiwObjectIdentifiers.IdSha1.Id;
+
+ public static readonly string Sha224 = NistObjectIdentifiers.IdSha224.Id;
+ public static readonly string Sha256 = NistObjectIdentifiers.IdSha256.Id;
+ public static readonly string Sha384 = NistObjectIdentifiers.IdSha384.Id;
+ public static readonly string Sha512 = NistObjectIdentifiers.IdSha512.Id;
+
+ public static readonly string RipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+ public static readonly string RipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+ public static readonly string RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+
+ public static readonly string Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
+
+ public static readonly ArrayList Allowed;
+
+ static TspAlgorithms()
+ {
+ string[] algs = new string[]
+ {
+ Gost3411, MD5, Sha1, Sha224, Sha256, Sha384, Sha512, RipeMD128, RipeMD160, RipeMD256
+ };
+
+ Allowed = new ArrayList();
+ foreach (string alg in algs)
+ {
+ Allowed.Add(alg);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TSPException.cs b/src/core/srcbc/tsp/TSPException.cs
new file mode 100644
index 0000000..22f1041
--- /dev/null
+++ b/src/core/srcbc/tsp/TSPException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TspException
+ : Exception
+ {
+ public TspException()
+ {
+ }
+
+ public TspException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public TspException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TSPUtil.cs b/src/core/srcbc/tsp/TSPUtil.cs
new file mode 100644
index 0000000..6bc5403
--- /dev/null
+++ b/src/core/srcbc/tsp/TSPUtil.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TspUtil
+ {
+ private static readonly IDictionary digestLengths = new Hashtable();
+ private static readonly IDictionary digestNames = new Hashtable();
+
+ static TspUtil()
+ {
+ digestLengths.Add(PkcsObjectIdentifiers.MD5.Id, 16);
+ digestLengths.Add(OiwObjectIdentifiers.IdSha1.Id, 20);
+ digestLengths.Add(NistObjectIdentifiers.IdSha224.Id, 28);
+ digestLengths.Add(NistObjectIdentifiers.IdSha256.Id, 32);
+ digestLengths.Add(NistObjectIdentifiers.IdSha384.Id, 48);
+ digestLengths.Add(NistObjectIdentifiers.IdSha512.Id, 64);
+
+ digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
+ digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
+ digestNames.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
+ digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
+ digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
+ digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
+ digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1");
+ digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224");
+ digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256");
+ digestNames.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id, "SHA384");
+ digestNames.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id, "SHA512");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
+ digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411");
+ }
+
+ /**
+ * Validate the passed in certificate as being of the correct type to be used
+ * for time stamping. To be valid it must have an ExtendedKeyUsage extension
+ * which has a key purpose identifier of id-kp-timeStamping.
+ *
+ * @param cert the certificate of interest.
+ * @throws TspValidationException if the certicate fails on one of the check points.
+ */
+ public static void ValidateCertificate(
+ X509Certificate cert)
+ {
+ if (cert.Version != 3)
+ throw new ArgumentException("Certificate must have an ExtendedKeyUsage extension.");
+
+ Asn1OctetString ext = cert.GetExtensionValue(X509Extensions.ExtendedKeyUsage);
+ if (ext == null)
+ throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension.");
+
+ if (!cert.GetCriticalExtensionOids().Contains(X509Extensions.ExtendedKeyUsage.Id))
+ throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical.");
+
+ try
+ {
+ ExtendedKeyUsage extKey = ExtendedKeyUsage.GetInstance(
+ Asn1Object.FromByteArray(ext.GetOctets()));
+
+ if (!extKey.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || extKey.Count != 1)
+ throw new TspValidationException("ExtendedKeyUsage not solely time stamping.");
+ }
+ catch (IOException)
+ {
+ throw new TspValidationException("cannot process ExtendedKeyUsage extension");
+ }
+ }
+
+ ///
+ /// Return the digest algorithm using one of the standard JCA string
+ /// representations rather than the algorithm identifier (if possible).
+ ///
+ internal static string GetDigestAlgName(
+ string digestAlgOID)
+ {
+ string digestName = (string) digestNames[digestAlgOID];
+
+ return digestName != null ? digestName : digestAlgOID;
+ }
+
+ internal static int GetDigestLength(
+ string digestAlgOID)
+ {
+ string digestName = GetDigestAlgName(digestAlgOID);
+
+ try
+ {
+ if (digestLengths.Contains(digestAlgOID))
+ {
+ return (int) digestLengths[digestAlgOID];
+ }
+
+ return DigestUtilities.GetDigest(digestName).GetDigestSize();
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new TspException("digest algorithm cannot be found.", e);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TSPValidationException.cs b/src/core/srcbc/tsp/TSPValidationException.cs
new file mode 100644
index 0000000..c59868a
--- /dev/null
+++ b/src/core/srcbc/tsp/TSPValidationException.cs
@@ -0,0 +1,39 @@
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Exception thrown if a TSP request or response fails to validate.
+ *
+ * If a failure code is assciated with the exception it can be retrieved using
+ * the getFailureCode() method.
+ */
+ public class TspValidationException
+ : TspException
+ {
+ private int failureCode;
+
+ public TspValidationException(
+ string message)
+ : base(message)
+ {
+ this.failureCode = -1;
+ }
+
+ public TspValidationException(
+ string message,
+ int failureCode)
+ : base(message)
+ {
+ this.failureCode = failureCode;
+ }
+
+ /**
+ * Return the failure code associated with this exception - if one is set.
+ *
+ * @return the failure code if set, -1 otherwise.
+ */
+ public int FailureCode
+ {
+ get { return failureCode; }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampRequest.cs b/src/core/srcbc/tsp/TimeStampRequest.cs
new file mode 100644
index 0000000..84cf311
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampRequest.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Base class for an RFC 3161 Time Stamp Request.
+ */
+ public class TimeStampRequest
+ : X509ExtensionBase
+ {
+ private TimeStampReq req;
+
+ public TimeStampRequest(
+ TimeStampReq req)
+ {
+ this.req = req;
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in byte array.
+ *
+ * @param req byte array containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(
+ byte[] req)
+ : this(new Asn1InputStream(req))
+ {
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in input stream.
+ *
+ * @param in input stream containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(
+ Stream input)
+ : this(new Asn1InputStream(input))
+ {
+ }
+
+ private TimeStampRequest(
+ Asn1InputStream str)
+ {
+ try
+ {
+ this.req = TimeStampReq.GetInstance(str.ReadObject());
+ }
+ catch (InvalidCastException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ catch (ArgumentException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ }
+
+ public int Version
+ {
+ get { return req.Version.Value.IntValue; }
+ }
+
+ public string MessageImprintAlgOid
+ {
+ get { return req.MessageImprint.HashAlgorithm.ObjectID.Id; }
+ }
+
+ public byte[] GetMessageImprintDigest()
+ {
+ return req.MessageImprint.GetHashedMessage();
+ }
+
+ public string ReqPolicy
+ {
+ get
+ {
+ return req.ReqPolicy == null
+ ? null
+ : req.ReqPolicy.Id;
+ }
+ }
+
+ public BigInteger Nonce
+ {
+ get
+ {
+ return req.Nonce == null
+ ? null
+ : req.Nonce.Value;
+ }
+ }
+
+ public bool CertReq
+ {
+ get
+ {
+ return req.CertReq == null
+ ? false
+ : req.CertReq.IsTrue;
+ }
+ }
+
+ /**
+ * Validate the timestamp request, checking the digest to see if it is of an
+ * accepted type and whether it is of the correct length for the algorithm specified.
+ *
+ * @param algorithms a set of string OIDS giving accepted algorithms.
+ * @param policies if non-null a set of policies we are willing to sign under.
+ * @param extensions if non-null a set of extensions we are willing to accept.
+ * @throws TspException if the request is invalid, or processing fails.
+ */
+ public void Validate(
+ IList algorithms,
+ IList policies,
+ IList extensions)
+ {
+ if (!algorithms.Contains(this.MessageImprintAlgOid))
+ {
+ throw new TspValidationException("request contains unknown algorithm.", PkiFailureInfo.BadAlg);
+ }
+
+ if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy))
+ {
+ throw new TspValidationException("request contains unknown policy.", PkiFailureInfo.UnacceptedPolicy);
+ }
+
+ if (this.Extensions != null && extensions != null)
+ {
+ foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids)
+ {
+ if (!extensions.Contains(oid.Id))
+ {
+ throw new TspValidationException("request contains unknown extension.",
+ PkiFailureInfo.UnacceptedExtension);
+ }
+ }
+ }
+
+ int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid);
+
+ if (digestLength != this.GetMessageImprintDigest().Length)
+ {
+ throw new TspValidationException("imprint digest the wrong length.",
+ PkiFailureInfo.BadDataFormat);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return req.GetEncoded();
+ }
+
+ internal X509Extensions Extensions
+ {
+ get { return req.Extensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return Extensions;
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampRequestGenerator.cs b/src/core/srcbc/tsp/TimeStampRequestGenerator.cs
new file mode 100644
index 0000000..eadceb5
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampRequestGenerator.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Generator for RFC 3161 Time Stamp Request objects.
+ */
+ public class TimeStampRequestGenerator
+ {
+ private DerObjectIdentifier reqPolicy;
+
+ private DerBoolean certReq;
+
+ private Hashtable extensions = new Hashtable();
+ private ArrayList extOrdering = new ArrayList();
+
+ public void SetReqPolicy(
+ string reqPolicy)
+ {
+ this.reqPolicy = new DerObjectIdentifier(reqPolicy);
+ }
+
+ public void SetCertReq(
+ bool certReq)
+ {
+ this.certReq = DerBoolean.GetInstance(certReq);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws IOException
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable value)
+ {
+ this.AddExtension(oid, critical, value.GetEncoded());
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] value)
+ {
+ DerObjectIdentifier derOid = new DerObjectIdentifier(oid);
+ extensions[derOid] = new X509Extension(critical, new DerOctetString(value));
+ extOrdering.Add(derOid);
+ }
+
+ public TimeStampRequest Generate(
+ string digestAlgorithm,
+ byte[] digest)
+ {
+ return this.Generate(digestAlgorithm, digest, null);
+ }
+
+ public TimeStampRequest Generate(
+ string digestAlgorithmOid,
+ byte[] digest,
+ BigInteger nonce)
+ {
+ if (digestAlgorithmOid == null)
+ {
+ throw new ArgumentException("No digest algorithm specified");
+ }
+
+ DerObjectIdentifier digestAlgOid = new DerObjectIdentifier(digestAlgorithmOid);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOid, DerNull.Instance);
+ MessageImprint messageImprint = new MessageImprint(algID, digest);
+
+ X509Extensions ext = null;
+
+ if (extOrdering.Count != 0)
+ {
+ ext = new X509Extensions(extOrdering, extensions);
+ }
+
+ DerInteger derNonce = nonce == null
+ ? null
+ : new DerInteger(nonce);
+
+ return new TimeStampRequest(
+ new TimeStampReq(messageImprint, reqPolicy, derNonce, certReq, ext));
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampResponse.cs b/src/core/srcbc/tsp/TimeStampResponse.cs
new file mode 100644
index 0000000..37971ac
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampResponse.cs
@@ -0,0 +1,173 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Base class for an RFC 3161 Time Stamp Response object.
+ */
+ public class TimeStampResponse
+ {
+ private TimeStampResp resp;
+ private TimeStampToken timeStampToken;
+
+ public TimeStampResponse(
+ TimeStampResp resp)
+ {
+ this.resp = resp;
+
+ if (resp.TimeStampToken != null)
+ {
+ timeStampToken = new TimeStampToken(resp.TimeStampToken);
+ }
+ }
+
+ /**
+ * Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
+ *
+ * @param resp the byte array containing the encoded response.
+ * @throws TspException if the response is malformed.
+ * @throws IOException if the byte array doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(
+ byte[] resp)
+ : this(readTimeStampResp(new Asn1InputStream(resp)))
+ {
+ }
+
+ /**
+ * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
+ *
+ * @param input the input stream containing the encoded response.
+ * @throws TspException if the response is malformed.
+ * @throws IOException if the stream doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(
+ Stream input)
+ : this(readTimeStampResp(new Asn1InputStream(input)))
+ {
+ }
+
+ private static TimeStampResp readTimeStampResp(
+ Asn1InputStream input)
+ {
+ try
+ {
+ return TimeStampResp.GetInstance(input.ReadObject());
+ }
+ catch (ArgumentException e)
+ {
+ throw new TspException("malformed timestamp response: " + e, e);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TspException("malformed timestamp response: " + e, e);
+ }
+ }
+
+ public int Status
+ {
+ get { return resp.Status.Status.IntValue; }
+ }
+
+ public string GetStatusString()
+ {
+ if (resp.Status.StatusString == null)
+ {
+ return null;
+ }
+
+ StringBuilder statusStringBuf = new StringBuilder();
+ PkiFreeText text = resp.Status.StatusString;
+ for (int i = 0; i != text.Count; i++)
+ {
+ statusStringBuf.Append(text[i].GetString());
+ }
+
+ return statusStringBuf.ToString();
+ }
+
+ public PkiFailureInfo GetFailInfo()
+ {
+ if (resp.Status.FailInfo == null)
+ {
+ return null;
+ }
+
+ return new PkiFailureInfo(resp.Status.FailInfo);
+ }
+
+ public TimeStampToken TimeStampToken
+ {
+ get { return timeStampToken; }
+ }
+
+ /**
+ * Check this response against to see if it a well formed response for
+ * the passed in request. Validation will include checking the time stamp
+ * token if the response status is GRANTED or GRANTED_WITH_MODS.
+ *
+ * @param request the request to be checked against
+ * @throws TspException if the request can not match this response.
+ */
+ public void Validate(
+ TimeStampRequest request)
+ {
+ TimeStampToken tok = this.TimeStampToken;
+
+ if (tok != null)
+ {
+ TimeStampTokenInfo tstInfo = tok.TimeStampInfo;
+
+ if (request.Nonce != null && !request.Nonce.Equals(tstInfo.Nonce))
+ {
+ throw new TspValidationException("response contains wrong nonce value.");
+ }
+
+ if (this.Status != (int) PkiStatus.Granted && this.Status != (int) PkiStatus.GrantedWithMods)
+ {
+ throw new TspValidationException("time stamp token found in failed request.");
+ }
+
+ if (!Arrays.AreEqual(request.GetMessageImprintDigest(), tstInfo.GetMessageImprintDigest()))
+ {
+ throw new TspValidationException("response for different message imprint digest.");
+ }
+
+ if (!tstInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid))
+ {
+ throw new TspValidationException("response for different message imprint algorithm.");
+ }
+
+ if (tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate] == null)
+ {
+ throw new TspValidationException("no signing certificate attribute present.");
+ }
+
+ if (request.ReqPolicy != null && !request.ReqPolicy.Equals(tstInfo.Policy))
+ {
+ throw new TspValidationException("TSA policy wrong for request.");
+ }
+ }
+ else if (this.Status == (int) PkiStatus.Granted || this.Status == (int) PkiStatus.GrantedWithMods)
+ {
+ throw new TspValidationException("no time stamp token found and one expected.");
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampResponseGenerator.cs b/src/core/srcbc/tsp/TimeStampResponseGenerator.cs
new file mode 100644
index 0000000..acd13fd
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampResponseGenerator.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Generator for RFC 3161 Time Stamp Responses.
+ */
+ public class TimeStampResponseGenerator
+ {
+ private PkiStatus status;
+
+ private Asn1EncodableVector statusStrings;
+
+ private int failInfo;
+ private TimeStampTokenGenerator tokenGenerator;
+ private IList acceptedAlgorithms;
+ private IList acceptedPolicies;
+ private IList acceptedExtensions;
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms)
+ : this(tokenGenerator, acceptedAlgorithms, null, null)
+ {
+ }
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms,
+ IList acceptedPolicy)
+ : this(tokenGenerator, acceptedAlgorithms, acceptedPolicy, null)
+ {
+ }
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms,
+ IList acceptedPolicies,
+ IList acceptedExtensions)
+ {
+ this.tokenGenerator = tokenGenerator;
+ this.acceptedAlgorithms = acceptedAlgorithms;
+ this.acceptedPolicies = acceptedPolicies;
+ this.acceptedExtensions = acceptedExtensions;
+
+ statusStrings = new Asn1EncodableVector();
+ }
+
+ private void addStatusString(
+ string statusString)
+ {
+ statusStrings.Add(new DerUtf8String(statusString));
+ }
+
+ private void setFailInfoField(int field)
+ {
+ failInfo = failInfo | field;
+ }
+
+ private PkiStatusInfo getPkiStatusInfo()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger((int) status));
+
+ if (statusStrings.Count > 0)
+ {
+ v.Add(new PkiFreeText(new DerSequence(statusStrings)));
+ }
+
+ if (failInfo != 0)
+ {
+ v.Add(new FailInfo(failInfo));
+ }
+
+ return new PkiStatusInfo(new DerSequence(v));
+ }
+
+ public TimeStampResponse Generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ DateTime genTime)
+ {
+ TimeStampResp resp;
+
+ try
+ {
+ request.Validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);
+
+ status = PkiStatus.Granted;
+ this.addStatusString("Operation Okay");
+
+ PkiStatusInfo pkiStatusInfo = getPkiStatusInfo();
+
+ ContentInfo tstTokenContentInfo;
+ try
+ {
+ TimeStampToken token = tokenGenerator.Generate(request, serialNumber, genTime);
+ byte[] encoded = token.ToCmsSignedData().GetEncoded();
+
+ tstTokenContentInfo = ContentInfo.GetInstance(Asn1Object.FromByteArray(encoded));
+ }
+ catch (IOException ioEx)
+ {
+ throw new TspException(
+ "Timestamp token received cannot be converted to ContentInfo", ioEx);
+ }
+
+ resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo);
+ }
+ catch (TspValidationException e)
+ {
+ status = PkiStatus.Rejection;
+
+ this.setFailInfoField(e.FailureCode);
+ this.addStatusString(e.Message);
+
+ PkiStatusInfo pkiStatusInfo = getPkiStatusInfo();
+
+ resp = new TimeStampResp(pkiStatusInfo, null);
+ }
+
+ try
+ {
+ return new TimeStampResponse(resp);
+ }
+ catch (IOException)
+ {
+ throw new TspException("created badly formatted response!");
+ }
+ }
+
+ class FailInfo
+ : DerBitString
+ {
+ internal FailInfo(
+ int failInfoValue)
+ : base(GetBytes(failInfoValue), GetPadBits(failInfoValue))
+ {
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampToken.cs b/src/core/srcbc/tsp/TimeStampToken.cs
new file mode 100644
index 0000000..af613e0
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampToken.cs
@@ -0,0 +1,304 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampToken
+ {
+ private readonly CmsSignedData tsToken;
+ private readonly SignerInformation tsaSignerInfo;
+// private readonly DateTime genTime;
+ private readonly TimeStampTokenInfo tstInfo;
+ private readonly CertID certID;
+
+ public TimeStampToken(
+ Asn1.Cms.ContentInfo contentInfo)
+ : this(new CmsSignedData(contentInfo))
+ {
+ }
+
+ public TimeStampToken(
+ CmsSignedData signedData)
+ {
+ this.tsToken = signedData;
+
+ if (!this.tsToken.SignedContentTypeOid.Equals(PkcsObjectIdentifiers.IdCTTstInfo.Id))
+ {
+ throw new TspValidationException("ContentInfo object not for a time stamp.");
+ }
+
+ ICollection signers = tsToken.GetSignerInfos().GetSigners();
+
+ if (signers.Count != 1)
+ {
+ throw new ArgumentException("Time-stamp token signed by "
+ + signers.Count
+ + " signers, but it must contain just the TSA signature.");
+ }
+
+
+ IEnumerator signerEnum = signers.GetEnumerator();
+
+ signerEnum.MoveNext();
+ tsaSignerInfo = (SignerInformation) signerEnum.Current;
+
+ try
+ {
+ CmsProcessable content = tsToken.SignedContent;
+ MemoryStream bOut = new MemoryStream();
+
+ content.Write(bOut);
+
+ this.tstInfo = new TimeStampTokenInfo(
+ TstInfo.GetInstance(
+ Asn1Object.FromByteArray(bOut.ToArray())));
+
+ Asn1.Cms.Attribute attr = tsaSignerInfo.SignedAttributes[
+ PkcsObjectIdentifiers.IdAASigningCertificate];
+
+// if (attr == null)
+// {
+// throw new TspValidationException(
+// "no signing certificate attribute found, time stamp invalid.");
+// }
+//
+// SigningCertificate signCert = SigningCertificate.GetInstance(
+// attr.AttrValues[0]);
+//
+// this.certID = EssCertID.GetInstance(signCert.GetCerts()[0]);
+
+ if (attr != null)
+ {
+ SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]);
+
+ this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0]));
+ }
+ else
+ {
+ attr = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+ if (attr == null)
+ throw new TspValidationException("no signing certificate attribute found, time stamp invalid.");
+
+ SigningCertificateV2 signCertV2 = SigningCertificateV2.GetInstance(attr.AttrValues[0]);
+
+ this.certID = new CertID(EssCertIDv2.GetInstance(signCertV2.GetCerts()[0]));
+ }
+ }
+ catch (CmsException e)
+ {
+ throw new TspException(e.Message, e.InnerException);
+ }
+ }
+
+ public TimeStampTokenInfo TimeStampInfo
+ {
+ get { return tstInfo; }
+ }
+
+ public SignerID SignerID
+ {
+ get { return tsaSignerInfo.SignerID; }
+ }
+
+ public Asn1.Cms.AttributeTable SignedAttributes
+ {
+ get { return tsaSignerInfo.SignedAttributes; }
+ }
+
+ public Asn1.Cms.AttributeTable UnsignedAttributes
+ {
+ get { return tsaSignerInfo.UnsignedAttributes; }
+ }
+
+// public IX509Store GetCertificatesAndCrls(
+// string type)
+// {
+// return tsToken.GetCertificatesAndCrls(type);
+// }
+
+ public IX509Store GetCertificates(
+ string type)
+ {
+ return tsToken.GetCertificates(type);
+ }
+
+ public IX509Store GetCrls(
+ string type)
+ {
+ return tsToken.GetCrls(type);
+ }
+
+ /**
+ * Validate the time stamp token.
+ *
+ * To be valid the token must be signed by the passed in certificate and
+ * the certificate must be the one referred to by the SigningCertificate
+ * attribute included in the hashed attributes of the token. The
+ * certificate must also have the ExtendedKeyUsageExtension with only
+ * KeyPurposeID.IdKPTimeStamping and have been valid at the time the
+ * timestamp was created.
+ *
+ *
+ * A successful call to validate means all the above are true.
+ *
+ */
+ public void Validate(
+ X509Certificate cert)
+ {
+ IDigest digest;
+ try
+ {
+ digest = DigestUtilities.GetDigest(certID.GetHashAlgorithm());
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new TspException("cannot find algorithm: " + e.Message, e);
+ }
+
+ try
+ {
+ byte[] certEncoded = cert.GetEncoded();
+ digest.BlockUpdate(certEncoded, 0, certEncoded.Length);
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ if (!Arrays.AreEqual(certID.GetCertHash(), hash))
+ {
+ throw new TspValidationException("certificate hash does not match certID hash.");
+ }
+
+ if (certID.IssuerSerial != null)
+ {
+ if (!certID.IssuerSerial.Serial.Value.Equals(cert.SerialNumber))
+ {
+ throw new TspValidationException("certificate serial number does not match certID for signature.");
+ }
+
+ GeneralName[] names = certID.IssuerSerial.Issuer.GetNames();
+ X509Name principal = PrincipalUtilities.GetIssuerX509Principal(cert);
+ bool found = false;
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == 4
+ && X509Name.GetInstance(names[i].Name).Equivalent(principal))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new TspValidationException("certificate name does not match certID for signature. ");
+ }
+ }
+
+ TspUtil.ValidateCertificate(cert);
+
+ cert.CheckValidity(tstInfo.GenTime);
+
+ if (!tsaSignerInfo.Verify(cert))
+ {
+ throw new TspValidationException("signature not created by certificate.");
+ }
+ }
+ catch (CmsException e)
+ {
+ if (e.InnerException != null)
+ {
+ throw new TspException(e.Message, e.InnerException);
+ }
+
+ throw new TspException("CMS exception: " + e, e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new TspException("problem processing certificate: " + e, e);
+ }
+ }
+
+ /**
+ * Return the underlying CmsSignedData object.
+ *
+ * @return the underlying CMS structure.
+ */
+ public CmsSignedData ToCmsSignedData()
+ {
+ return tsToken;
+ }
+
+ /**
+ * Return a ASN.1 encoded byte stream representing the encoded object.
+ *
+ * @throws IOException if encoding fails.
+ */
+ public byte[] GetEncoded()
+ {
+ return tsToken.GetEncoded();
+ }
+
+
+ // perhaps this should be done using an interface on the ASN.1 classes...
+ private class CertID
+ {
+ private EssCertID certID;
+ private EssCertIDv2 certIDv2;
+
+ internal CertID(EssCertID certID)
+ {
+ this.certID = certID;
+ this.certIDv2 = null;
+ }
+
+ internal CertID(EssCertIDv2 certID)
+ {
+ this.certIDv2 = certID;
+ this.certID = null;
+ }
+
+ public string GetHashAlgorithm()
+ {
+ if (certID != null)
+ return "SHA-1";
+
+ if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.ObjectID))
+ return "SHA-256";
+
+ return certIDv2.HashAlgorithm.ObjectID.Id;
+ }
+
+ public byte[] GetCertHash()
+ {
+ return certID != null
+ ? certID.GetCertHash()
+ : certIDv2.GetCertHash();
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get
+ {
+ return certID != null
+ ? certID.IssuerSerial
+ : certIDv2.IssuerSerial;
+ }
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampTokenGenerator.cs b/src/core/srcbc/tsp/TimeStampTokenGenerator.cs
new file mode 100644
index 0000000..a2a8ef9
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampTokenGenerator.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampTokenGenerator
+ {
+ private int accuracySeconds = -1;
+ private int accuracyMillis = -1;
+ private int accuracyMicros = -1;
+ private bool ordering = false;
+ private GeneralName tsa = null;
+ private string tsaPolicyOID;
+
+ private AsymmetricKeyParameter key;
+ private X509Certificate cert;
+ private string digestOID;
+ private Asn1.Cms.AttributeTable signedAttr;
+ private Asn1.Cms.AttributeTable unsignedAttr;
+ private IX509Store x509Certs;
+ private IX509Store x509Crls;
+
+ /**
+ * basic creation - only the default attributes will be included here.
+ */
+ public TimeStampTokenGenerator(
+ AsymmetricKeyParameter key,
+ X509Certificate cert,
+ string digestOID,
+ string tsaPolicyOID)
+ : this(key, cert, digestOID, tsaPolicyOID, null, null)
+ {
+ }
+
+ /**
+ * create with a signer with extra signed/unsigned attributes.
+ */
+ public TimeStampTokenGenerator(
+ AsymmetricKeyParameter key,
+ X509Certificate cert,
+ string digestOID,
+ string tsaPolicyOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ this.key = key;
+ this.cert = cert;
+ this.digestOID = digestOID;
+ this.tsaPolicyOID = tsaPolicyOID;
+ this.unsignedAttr = unsignedAttr;
+
+ TspUtil.ValidateCertificate(cert);
+
+ //
+ // add the essCertid
+ //
+ Hashtable signedAttrs;
+ if (signedAttr != null)
+ {
+ signedAttrs = signedAttr.ToHashtable();
+ }
+ else
+ {
+ signedAttrs = new Hashtable();
+ }
+
+ IDigest digest;
+ try
+ {
+ digest = DigestUtilities.GetDigest("SHA-1");
+ }
+ catch (Exception e)
+ {
+ throw new TspException("Can't find a SHA-1 implementation.", e);
+ }
+
+ try
+ {
+ byte[] certEncoded = cert.GetEncoded();
+ digest.BlockUpdate(certEncoded, 0, certEncoded.Length);
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ EssCertID essCertid = new EssCertID(hash);
+
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+ PkcsObjectIdentifiers.IdAASigningCertificate,
+ new DerSet(new SigningCertificate(essCertid)));
+
+ signedAttrs[attr.AttrType] = attr;
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new TspException("Exception processing certificate.", e);
+ }
+
+ this.signedAttr = new Asn1.Cms.AttributeTable(signedAttrs);
+ }
+
+ public void SetCertificates(
+ IX509Store certificates)
+ {
+ this.x509Certs = certificates;
+ }
+
+ public void SetCrls(
+ IX509Store crls)
+ {
+ this.x509Crls = crls;
+ }
+
+ public void SetAccuracySeconds(
+ int accuracySeconds)
+ {
+ this.accuracySeconds = accuracySeconds;
+ }
+
+ public void SetAccuracyMillis(
+ int accuracyMillis)
+ {
+ this.accuracyMillis = accuracyMillis;
+ }
+
+ public void SetAccuracyMicros(
+ int accuracyMicros)
+ {
+ this.accuracyMicros = accuracyMicros;
+ }
+
+ public void SetOrdering(
+ bool ordering)
+ {
+ this.ordering = ordering;
+ }
+
+ public void SetTsa(
+ GeneralName tsa)
+ {
+ this.tsa = tsa;
+ }
+
+ //------------------------------------------------------------------------------
+
+ public TimeStampToken Generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ DateTime genTime)
+ {
+ DerObjectIdentifier digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance);
+ MessageImprint messageImprint = new MessageImprint(algID, request.GetMessageImprintDigest());
+
+ Accuracy accuracy = null;
+ if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
+ {
+ DerInteger seconds = null;
+ if (accuracySeconds > 0)
+ {
+ seconds = new DerInteger(accuracySeconds);
+ }
+
+ DerInteger millis = null;
+ if (accuracyMillis > 0)
+ {
+ millis = new DerInteger(accuracyMillis);
+ }
+
+ DerInteger micros = null;
+ if (accuracyMicros > 0)
+ {
+ micros = new DerInteger(accuracyMicros);
+ }
+
+ accuracy = new Accuracy(seconds, millis, micros);
+ }
+
+ DerBoolean derOrdering = null;
+ if (ordering)
+ {
+ derOrdering = DerBoolean.GetInstance(ordering);
+ }
+
+ DerInteger nonce = null;
+ if (request.Nonce != null)
+ {
+ nonce = new DerInteger(request.Nonce);
+ }
+
+ DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID);
+ if (request.ReqPolicy != null)
+ {
+ tsaPolicy = new DerObjectIdentifier(request.ReqPolicy);
+ }
+
+ TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
+ new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy,
+ derOrdering, nonce, tsa, request.Extensions);
+
+ try
+ {
+ CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator();
+
+ byte[] derEncodedTstInfo = tstInfo.GetDerEncoded();
+
+ if (request.CertReq)
+ {
+ signedDataGenerator.AddCertificates(x509Certs);
+ }
+
+ signedDataGenerator.AddCrls(x509Crls);
+ signedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr);
+
+ CmsSignedData signedData = signedDataGenerator.Generate(
+ PkcsObjectIdentifiers.IdCTTstInfo.Id,
+ new CmsProcessableByteArray(derEncodedTstInfo),
+ true);
+
+ return new TimeStampToken(signedData);
+ }
+ catch (CmsException cmsEx)
+ {
+ throw new TspException("Error generating time-stamp token", cmsEx);
+ }
+ catch (IOException e)
+ {
+ throw new TspException("Exception encoding info", e);
+ }
+ catch (X509StoreException e)
+ {
+ throw new TspException("Exception handling CertStore", e);
+ }
+// catch (InvalidAlgorithmParameterException e)
+// {
+// throw new TspException("Exception handling CertStore CRLs", e);
+// }
+ }
+ }
+}
diff --git a/src/core/srcbc/tsp/TimeStampTokenInfo.cs b/src/core/srcbc/tsp/TimeStampTokenInfo.cs
new file mode 100644
index 0000000..a2391ca
--- /dev/null
+++ b/src/core/srcbc/tsp/TimeStampTokenInfo.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampTokenInfo
+ {
+ private TstInfo tstInfo;
+ private DateTime genTime;
+
+ public TimeStampTokenInfo(
+ TstInfo tstInfo)
+ {
+ this.tstInfo = tstInfo;
+
+ try
+ {
+ this.genTime = tstInfo.GenTime.ToDateTime();
+ }
+ catch (Exception e)
+ {
+ throw new TspException("unable to parse genTime field: " + e.Message);
+ }
+ }
+
+ public bool IsOrdered
+ {
+ get { return tstInfo.Ordering.IsTrue; }
+ }
+
+ public Accuracy Accuracy
+ {
+ get { return tstInfo.Accuracy; }
+ }
+
+ public DateTime GenTime
+ {
+ get { return genTime; }
+ }
+
+ public GenTimeAccuracy GenTimeAccuracy
+ {
+ get
+ {
+ return this.Accuracy == null
+ ? null
+ : new GenTimeAccuracy(this.Accuracy);
+ }
+ }
+
+ public string Policy
+ {
+ get { return tstInfo.Policy.Id; }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return tstInfo.SerialNumber.Value; }
+ }
+
+ public GeneralName Tsa
+ {
+ get { return tstInfo.Tsa; }
+ }
+
+ /**
+ * @return the nonce value, null if there isn't one.
+ */
+ public BigInteger Nonce
+ {
+ get
+ {
+ return tstInfo.Nonce == null
+ ? null
+ : tstInfo.Nonce.Value;
+ }
+ }
+
+ public string MessageImprintAlgOid
+ {
+ get { return tstInfo.MessageImprint.HashAlgorithm.ObjectID.Id; }
+ }
+
+ public byte[] GetMessageImprintDigest()
+ {
+ return tstInfo.MessageImprint.GetHashedMessage();
+ }
+
+ public byte[] GetEncoded()
+ {
+ return tstInfo.GetEncoded();
+ }
+
+ public TstInfo TstInfo
+ {
+ get { return tstInfo; }
+ }
+ }
+}
diff --git a/src/core/srcbc/util/Arrays.cs b/src/core/srcbc/util/Arrays.cs
new file mode 100644
index 0000000..af16246
--- /dev/null
+++ b/src/core/srcbc/util/Arrays.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities
+{
+
+ /// General array utilities.
+ public sealed class Arrays
+ {
+ private Arrays()
+ {
+ }
+
+ ///
+ /// Are two arrays equal.
+ ///
+ /// Left side.
+ /// Right side.
+ /// True if equal.
+ public static bool AreEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ [Obsolete("Use 'AreEqual' method instead")]
+ public static bool AreSame(
+ byte[] a,
+ byte[] b)
+ {
+ return AreEqual(a, b);
+ }
+
+ public static bool AreEqual(
+ int[] a,
+ int[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ private static bool HaveSameContents(
+ byte[] a,
+ byte[] b)
+ {
+ if (a.Length != b.Length)
+ return false;
+
+ for (int i = 0; i < a.Length; i++)
+ {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool HaveSameContents(
+ int[] a,
+ int[] b)
+ {
+ if (a.Length != b.Length)
+ return false;
+
+ for (int i = 0; i < a.Length; i++)
+ {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public static string ToString(
+ object[] a)
+ {
+ StringBuilder sb = new StringBuilder('[');
+ if (a.Length > 0)
+ {
+ sb.Append(a[0]);
+ for (int index = 1; index < a.Length; ++index)
+ {
+ sb.Append(", ").Append(a[index]);
+ }
+ }
+ sb.Append(']');
+ return sb.ToString();
+ }
+
+ public static int GetHashCode(
+ byte[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static byte[] Clone(
+ byte[] data)
+ {
+ return data == null ? null : (byte[]) data.Clone();
+ }
+
+ public static int[] Clone(
+ int[] data)
+ {
+ return data == null ? null : (int[]) data.Clone();
+ }
+ }
+}
diff --git a/src/core/srcbc/util/BigIntegers.cs b/src/core/srcbc/util/BigIntegers.cs
new file mode 100644
index 0000000..b3c57a0
--- /dev/null
+++ b/src/core/srcbc/util/BigIntegers.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /**
+ * BigInteger utilities.
+ */
+ public sealed class BigIntegers
+ {
+ private BigIntegers()
+ {
+ }
+
+ /**
+ * Return the passed in value as an unsigned byte array.
+ *
+ * @param value value to be converted.
+ * @return a byte array without a leading zero byte if present in the signed encoding.
+ */
+ public static byte[] AsUnsignedByteArray(
+ BigInteger n)
+ {
+ return n.ToByteArrayUnsigned();
+ }
+ }
+}
diff --git a/src/core/srcbc/util/Platform.cs b/src/core/srcbc/util/Platform.cs
new file mode 100644
index 0000000..e52fc96
--- /dev/null
+++ b/src/core/srcbc/util/Platform.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities
+{
+ internal sealed class Platform
+ {
+ private Platform()
+ {
+ }
+
+#if NETCF_1_0
+ internal static Exception CreateNotImplementedException(
+ string message)
+ {
+ return new Exception("Not implemented: " + message);
+ }
+
+ internal static bool Equals(
+ object a,
+ object b)
+ {
+ return a == b || (a != null && b != null && a.Equals(b));
+ }
+
+ internal static string GetEnvironmentVariable(
+ string variable)
+ {
+ return null;
+ }
+
+ private static string GetNewLine()
+ {
+ MemoryStream buf = new MemoryStream();
+ StreamWriter w = new StreamWriter(buf, Encoding.ASCII);
+ w.WriteLine();
+ w.Close();
+ byte[] bs = buf.ToArray();
+ return Encoding.ASCII.GetString(bs, 0, bs.Length);
+ }
+#else
+ internal static Exception CreateNotImplementedException(
+ string message)
+ {
+ return new NotImplementedException(message);
+ }
+
+ internal static string GetEnvironmentVariable(
+ string variable)
+ {
+ try
+ {
+ return Environment.GetEnvironmentVariable(variable);
+ }
+ catch (System.Security.SecurityException)
+ {
+ // We don't have the required permission to read this environment variable,
+ // which is fine, just act as if it's not set
+ return null;
+ }
+ }
+
+ private static string GetNewLine()
+ {
+ return Environment.NewLine;
+ }
+#endif
+
+ internal static readonly string NewLine = GetNewLine();
+ }
+}
diff --git a/src/core/srcbc/util/Strings.cs b/src/core/srcbc/util/Strings.cs
new file mode 100644
index 0000000..491ddad
--- /dev/null
+++ b/src/core/srcbc/util/Strings.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /// General string utilities.
+ public sealed class Strings
+ {
+ private Strings()
+ {
+ }
+
+ public static string FromByteArray(
+ byte[] bs)
+ {
+ char[] cs = new char[bs.Length];
+ for (int i = 0; i < cs.Length; ++i)
+ {
+ cs[i] = Convert.ToChar(bs[i]);
+ }
+ return new string(cs);
+ }
+
+ public static byte[] ToByteArray(
+ string s)
+ {
+ byte[] bs = new byte[s.Length];
+ for (int i = 0; i < bs.Length; ++i)
+ {
+ bs[i] = Convert.ToByte(s[i]);
+ }
+ return bs;
+ }
+ }
+}
diff --git a/src/core/srcbc/util/bzip2/BZip2Constants.cs b/src/core/srcbc/util/bzip2/BZip2Constants.cs
new file mode 100644
index 0000000..0cbadb9
--- /dev/null
+++ b/src/core/srcbc/util/bzip2/BZip2Constants.cs
@@ -0,0 +1,139 @@
+using System;
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Ant" and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * Base class for both the compress and decompress classes.
+ * Holds common arrays, and static data.
+ *
+ * @author Keiron Liddle
+ */
+ public class BZip2Constants {
+
+ public const int baseBlockSize = 100000;
+ public const int MAX_ALPHA_SIZE = 258;
+ public const int MAX_CODE_LEN = 23;
+ public const int RUNA = 0;
+ public const int RUNB = 1;
+ public const int N_GROUPS = 6;
+ public const int G_SIZE = 50;
+ public const int N_ITERS = 4;
+ public const int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+ public const int NUM_OVERSHOOT_BYTES = 20;
+
+ public static int[] rNums = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/bzip2/CBZip2InputStream.cs b/src/core/srcbc/util/bzip2/CBZip2InputStream.cs
new file mode 100644
index 0000000..b3773c1
--- /dev/null
+++ b/src/core/srcbc/util/bzip2/CBZip2InputStream.cs
@@ -0,0 +1,954 @@
+using System;
+using System.IO;
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Ant" and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * An input stream that decompresses from the BZip2 format (with the file
+ * header chars) to be read as any other stream.
+ *
+ * @author Keiron Liddle
+ *
+ * NB: note this class has been modified to read the leading BZ from the
+ * start of the BZIP2 stream to make it compatible with other PGP programs.
+ */
+ public class CBZip2InputStream : Stream
+ {
+ private static void Cadvise() {
+ //System.out.Println("CRC Error");
+ //throw new CCoruptionError();
+ }
+
+ private static void BadBGLengths() {
+ Cadvise();
+ }
+
+ private static void BitStreamEOF() {
+ Cadvise();
+ }
+
+ private static void CompressedStreamEOF() {
+ Cadvise();
+ }
+
+ private void MakeMaps() {
+ int i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char) i;
+ unseqToSeq[i] = (char) nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ /*
+ index of the last char in the block, so
+ the block size == last + 1.
+ */
+ private int last;
+
+ /*
+ index in zptr[] of original string after sorting.
+ */
+ private int origPtr;
+
+ /*
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ */
+ private int blockSize100k;
+
+ private bool blockRandomised;
+
+ private int bsBuff;
+ private int bsLive;
+ private CRC mCrc = new CRC();
+
+ private bool[] inUse = new bool[256];
+ private int nInUse;
+
+ private char[] seqToUnseq = new char[256];
+ private char[] unseqToSeq = new char[256];
+
+ private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ private int[] tt;
+ private char[] ll8;
+
+ /*
+ freq table collected to save a pass over the data
+ during decompression.
+ */
+ private int[] unzftab = new int[256];
+
+ private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[] minLens = new int[BZip2Constants.N_GROUPS];
+
+ private Stream bsStream;
+
+ private bool streamEnd = false;
+
+ private int currentChar = -1;
+
+ private const int START_BLOCK_STATE = 1;
+ private const int RAND_PART_A_STATE = 2;
+ private const int RAND_PART_B_STATE = 3;
+ private const int RAND_PART_C_STATE = 4;
+ private const int NO_RAND_PART_A_STATE = 5;
+ private const int NO_RAND_PART_B_STATE = 6;
+ private const int NO_RAND_PART_C_STATE = 7;
+
+ private int currentState = START_BLOCK_STATE;
+
+ private int storedBlockCRC, storedCombinedCRC;
+ private int computedBlockCRC, computedCombinedCRC;
+
+ int i2, count, chPrev, ch2;
+ int i, tPos;
+ int rNToGo = 0;
+ int rTPos = 0;
+ int j2;
+ char z;
+
+ public CBZip2InputStream(Stream zStream) {
+ ll8 = null;
+ tt = null;
+ BsSetStream(zStream);
+ Initialize();
+ InitBlock();
+ SetupBlock();
+ }
+
+ internal static int[][] InitIntArray(int n1, int n2) {
+ int[][] a = new int[n1][];
+ for (int k = 0; k < n1; ++k) {
+ a[k] = new int[n2];
+ }
+ return a;
+ }
+
+ internal static char[][] InitCharArray(int n1, int n2) {
+ char[][] a = new char[n1][];
+ for (int k = 0; k < n1; ++k) {
+ a[k] = new char[n2];
+ }
+ return a;
+ }
+
+ public override int ReadByte() {
+ if (streamEnd) {
+ return -1;
+ } else {
+ int retChar = currentChar;
+ switch (currentState) {
+ case START_BLOCK_STATE:
+ break;
+ case RAND_PART_A_STATE:
+ break;
+ case RAND_PART_B_STATE:
+ SetupRandPartB();
+ break;
+ case RAND_PART_C_STATE:
+ SetupRandPartC();
+ break;
+ case NO_RAND_PART_A_STATE:
+ break;
+ case NO_RAND_PART_B_STATE:
+ SetupNoRandPartB();
+ break;
+ case NO_RAND_PART_C_STATE:
+ SetupNoRandPartC();
+ break;
+ default:
+ break;
+ }
+ return retChar;
+ }
+ }
+
+ private void Initialize() {
+ char magic3, magic4;
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ if (magic3 != 'B' && magic4 != 'Z')
+ {
+ throw new IOException("Not a BZIP2 marked stream");
+ }
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {
+ BsFinishedWithStream();
+ streamEnd = true;
+ return;
+ }
+
+ SetDecompressStructureSizes(magic4 - '0');
+ computedCombinedCRC = 0;
+ }
+
+ private void InitBlock() {
+ char magic1, magic2, magic3, magic4;
+ char magic5, magic6;
+ magic1 = BsGetUChar();
+ magic2 = BsGetUChar();
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ magic5 = BsGetUChar();
+ magic6 = BsGetUChar();
+ if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45
+ && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
+ Complete();
+ return;
+ }
+
+ if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59
+ || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
+ BadBlockHeader();
+ streamEnd = true;
+ return;
+ }
+
+ storedBlockCRC = BsGetInt32();
+
+ if (BsR(1) == 1) {
+ blockRandomised = true;
+ } else {
+ blockRandomised = false;
+ }
+
+ // currBlockNo++;
+ GetAndMoveToFrontDecode();
+
+ mCrc.InitialiseCRC();
+ currentState = START_BLOCK_STATE;
+ }
+
+ private void EndBlock() {
+ computedBlockCRC = mCrc.GetFinalCRC();
+ /* A bad CRC is considered a fatal error. */
+ if (storedBlockCRC != computedBlockCRC) {
+ CrcError();
+ }
+
+ computedCombinedCRC = (computedCombinedCRC << 1)
+ | (int)(((uint)computedCombinedCRC) >> 31);
+ computedCombinedCRC ^= computedBlockCRC;
+ }
+
+ private void Complete() {
+ storedCombinedCRC = BsGetInt32();
+ if (storedCombinedCRC != computedCombinedCRC) {
+ CrcError();
+ }
+
+ BsFinishedWithStream();
+ streamEnd = true;
+ }
+
+ private static void BlockOverrun() {
+ Cadvise();
+ }
+
+ private static void BadBlockHeader() {
+ Cadvise();
+ }
+
+ private static void CrcError() {
+ Cadvise();
+ }
+
+ private void BsFinishedWithStream() {
+ try {
+ if (this.bsStream != null) {
+ this.bsStream.Close();
+ this.bsStream = null;
+ }
+ } catch {
+ //ignore
+ }
+ }
+
+ private void BsSetStream(Stream f) {
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ }
+
+ private int BsR(int n) {
+ int v;
+ while (bsLive < n) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+
+ v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
+ bsLive -= n;
+ return v;
+ }
+
+ private char BsGetUChar() {
+ return (char) BsR(8);
+ }
+
+ private int BsGetint() {
+ int u = 0;
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ return u;
+ }
+
+ private int BsGetIntVS(int numBits) {
+ return (int) BsR(numBits);
+ }
+
+ private int BsGetInt32() {
+ return (int) BsGetint();
+ }
+
+ private void HbCreateDecodeTables(int[] limit, int[] basev,
+ int[] perm, char[] length,
+ int minLen, int maxLen, int alphaSize) {
+ int pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++) {
+ for (j = 0; j < alphaSize; j++) {
+ if (length[j] == i) {
+ perm[pp] = j;
+ pp++;
+ }
+ }
+ }
+
+ for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ basev[i] = 0;
+ }
+ for (i = 0; i < alphaSize; i++) {
+ basev[length[i] + 1]++;
+ }
+
+ for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ basev[i] += basev[i - 1];
+ }
+
+ for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ limit[i] = 0;
+ }
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (basev[i + 1] - basev[i]);
+ limit[i] = vec - 1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++) {
+ basev[i] = ((limit[i - 1] + 1) << 1) - basev[i];
+ }
+ }
+
+ private void RecvDecodingTables() {
+ char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ int i, j, t, nGroups, nSelectors, alphaSize;
+ int minLen, maxLen;
+ bool[] inUse16 = new bool[16];
+
+ /* Receive the mapping table */
+ for (i = 0; i < 16; i++) {
+ if (BsR(1) == 1) {
+ inUse16[i] = true;
+ } else {
+ inUse16[i] = false;
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ for (j = 0; j < 16; j++) {
+ if (BsR(1) == 1) {
+ inUse[i * 16 + j] = true;
+ }
+ }
+ }
+ }
+
+ MakeMaps();
+ alphaSize = nInUse + 2;
+
+ /* Now the selectors */
+ nGroups = BsR(3);
+ nSelectors = BsR(15);
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (BsR(1) == 1) {
+ j++;
+ }
+ selectorMtf[i] = (char) j;
+ }
+
+ /* Undo the MTF values for the selectors. */
+ {
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char tmp, v;
+ for (v = '\0'; v < nGroups; v++) {
+ pos[v] = v;
+ }
+
+ for (i = 0; i < nSelectors; i++) {
+ v = selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) {
+ pos[v] = pos[v - 1];
+ v--;
+ }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+ }
+
+ /* Now the coding tables */
+ for (t = 0; t < nGroups; t++) {
+ int curr = BsR(5);
+ for (i = 0; i < alphaSize; i++) {
+ while (BsR(1) == 1) {
+ if (BsR(1) == 0) {
+ curr++;
+ } else {
+ curr--;
+ }
+ }
+ len[t][i] = (char) curr;
+ }
+ }
+
+ /* Create the Huffman decoding tables */
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen,
+ maxLen, alphaSize);
+ minLens[t] = minLen;
+ }
+ }
+
+ private void GetAndMoveToFrontDecode() {
+ char[] yy = new char[256];
+ int i, j, nextSym, limitLast;
+ int EOB, groupNo, groupPos;
+
+ limitLast = BZip2Constants.baseBlockSize * blockSize100k;
+ origPtr = BsGetIntVS(24);
+
+ RecvDecodingTables();
+ EOB = nInUse + 1;
+ groupNo = -1;
+ groupPos = 0;
+
+ /*
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ */
+ for (i = 0; i <= 255; i++) {
+ unzftab[i] = 0;
+ }
+
+ for (i = 0; i <= 255; i++) {
+ yy[i] = (char) i;
+ }
+
+ last = -1;
+
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+
+ while (true) {
+
+ if (nextSym == EOB) {
+ break;
+ }
+
+ if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) {
+ char ch;
+ int s = -1;
+ int N = 1;
+ do {
+ if (nextSym == BZip2Constants.RUNA) {
+ s = s + (0 + 1) * N;
+ } else if (nextSym == BZip2Constants.RUNB) {
+ s = s + (1 + 1) * N;
+ }
+ N = N * 2;
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+ } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
+
+ s++;
+ ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ while (s > 0) {
+ last++;
+ ll8[last] = ch;
+ s--;
+ }
+
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+ continue;
+ } else {
+ char tmp;
+ last++;
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+
+ tmp = yy[nextSym - 1];
+ unzftab[seqToUnseq[tmp]]++;
+ ll8[last] = seqToUnseq[tmp];
+
+ /*
+ This loop is hammered during decompression,
+ hence the unrolling.
+
+ for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+ */
+
+ j = nextSym - 1;
+ for (; j > 3; j -= 4) {
+ yy[j] = yy[j - 1];
+ yy[j - 1] = yy[j - 2];
+ yy[j - 2] = yy[j - 3];
+ yy[j - 3] = yy[j - 4];
+ }
+ for (; j > 0; j--) {
+ yy[j] = yy[j - 1];
+ }
+
+ yy[0] = tmp;
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+ continue;
+ }
+ }
+ }
+
+ private void SetupBlock() {
+ int[] cftab = new int[257];
+ char ch;
+
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) {
+ cftab[i] = unzftab[i - 1];
+ }
+ for (i = 1; i <= 256; i++) {
+ cftab[i] += cftab[i - 1];
+ }
+
+ for (i = 0; i <= last; i++) {
+ ch = (char) ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+ cftab = null;
+
+ tPos = tt[origPtr];
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /* not a char and not EOF */
+
+ if (blockRandomised) {
+ rNToGo = 0;
+ rTPos = 0;
+ SetupRandPartA();
+ } else {
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetupRandPartA() {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ ch2 ^= (int) ((rNToGo == 1) ? 1 : 0);
+ i2++;
+
+ currentChar = ch2;
+ currentState = RAND_PART_B_STATE;
+ mCrc.UpdateCRC(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupNoRandPartA() {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ i2++;
+
+ currentChar = ch2;
+ currentState = NO_RAND_PART_B_STATE;
+ mCrc.UpdateCRC(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupRandPartB() {
+ if (ch2 != chPrev) {
+ currentState = RAND_PART_A_STATE;
+ count = 1;
+ SetupRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ z ^= (char)((rNToGo == 1) ? 1 : 0);
+ j2 = 0;
+ currentState = RAND_PART_C_STATE;
+ SetupRandPartC();
+ } else {
+ currentState = RAND_PART_A_STATE;
+ SetupRandPartA();
+ }
+ }
+ }
+
+ private void SetupRandPartC() {
+ if (j2 < (int) z) {
+ currentChar = ch2;
+ mCrc.UpdateCRC(ch2);
+ j2++;
+ } else {
+ currentState = RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupRandPartA();
+ }
+ }
+
+ private void SetupNoRandPartB() {
+ if (ch2 != chPrev) {
+ currentState = NO_RAND_PART_A_STATE;
+ count = 1;
+ SetupNoRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ currentState = NO_RAND_PART_C_STATE;
+ j2 = 0;
+ SetupNoRandPartC();
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ SetupNoRandPartA();
+ }
+ }
+ }
+
+ private void SetupNoRandPartC() {
+ if (j2 < (int) z) {
+ currentChar = ch2;
+ mCrc.UpdateCRC(ch2);
+ j2++;
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetDecompressStructureSizes(int newSize100k) {
+ if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k
+ && blockSize100k <= 9)) {
+ // throw new IOException("Invalid block size");
+ }
+
+ blockSize100k = newSize100k;
+
+ if (newSize100k == 0) {
+ return;
+ }
+
+ int n = BZip2Constants.baseBlockSize * newSize100k;
+ ll8 = new char[n];
+ tt = new int[n];
+ }
+
+ public override void Flush() {
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ int c = -1;
+ int k;
+ for (k = 0; k < count; ++k) {
+ c = ReadByte();
+ if (c == -1)
+ break;
+ buffer[k + offset] = (byte)c;
+ }
+ return k;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ }
+
+ public override bool CanRead {
+ get {
+ return true;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ return false;
+ }
+ }
+
+ public override long Length {
+ get {
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ return 0;
+ }
+ set {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/bzip2/CBZip2OutputStream.cs b/src/core/srcbc/util/bzip2/CBZip2OutputStream.cs
new file mode 100644
index 0000000..71bbbbc
--- /dev/null
+++ b/src/core/srcbc/util/bzip2/CBZip2OutputStream.cs
@@ -0,0 +1,1731 @@
+using System;
+using System.IO;
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Ant" and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * An output stream that compresses into the BZip2 format (with the file
+ * header chars) into another stream.
+ *
+ * @author Keiron Liddle
+ *
+ * TODO: Update to BZip2 1.0.1
+ * NB: note this class has been modified to add a leading BZ to the
+ * start of the BZIP2 stream to make it compatible with other PGP programs.
+ */
+ public class CBZip2OutputStream : Stream
+ {
+ protected const int SETMASK = (1 << 21);
+ protected const int CLEARMASK = (~SETMASK);
+ protected const int GREATER_ICOST = 15;
+ protected const int LESSER_ICOST = 0;
+ protected const int SMALL_THRESH = 20;
+ protected const int DEPTH_THRESH = 10;
+
+ /*
+ If you are ever unlucky/improbable enough
+ to get a stack overflow whilst sorting,
+ increase the following constant and try
+ again. In practice I have never seen the
+ stack go above 27 elems, so the following
+ limit seems very generous.
+ */
+ protected const int QSORT_STACK_SIZE = 1000;
+ private bool finished;
+
+ private static void Panic() {
+ //System.out.Println("panic");
+ //throw new CError();
+ }
+
+ private void MakeMaps() {
+ int i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char) i;
+ unseqToSeq[i] = (char) nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ protected static void HbMakeCodeLengths(char[] len, int[] freq,
+ int alphaSize, int maxLen) {
+ /*
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ */
+ int nNodes, nHeap, n1, n2, i, j, k;
+ bool tooLong;
+
+ int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];
+ int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+ int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+
+ for (i = 0; i < alphaSize; i++) {
+ weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+ }
+
+ while (true) {
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ {
+ int zz, tmp;
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ }
+ if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) {
+ Panic();
+ }
+
+ while (nHeap > 1) {
+ n1 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ {
+ int zz = 0, yy = 0, tmp = 0;
+ zz = 1;
+ tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap
+ && weight[heap[yy + 1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ }
+ n2 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ {
+ int zz = 0, yy = 0, tmp = 0;
+ zz = 1;
+ tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap
+ && weight[heap[yy + 1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ }
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+
+ weight[nNodes] = (int)((uint)((weight[n1] & 0xffffff00)
+ + (weight[n2] & 0xffffff00))
+ | (uint)(1 + (((weight[n1] & 0x000000ff) >
+ (weight[n2] & 0x000000ff)) ?
+ (weight[n1] & 0x000000ff) :
+ (weight[n2] & 0x000000ff))));
+
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ {
+ int zz = 0, tmp = 0;
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ }
+ if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {
+ Panic();
+ }
+
+ tooLong = false;
+ for (i = 1; i <= alphaSize; i++) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) {
+ k = parent[k];
+ j++;
+ }
+ len[i - 1] = (char) j;
+ if (j > maxLen) {
+ tooLong = true;
+ }
+ }
+
+ if (!tooLong) {
+ break;
+ }
+
+ for (i = 1; i < alphaSize; i++) {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+ }
+
+ /*
+ index of the last char in the block, so
+ the block size == last + 1.
+ */
+ int last;
+
+ /*
+ index in zptr[] of original string after sorting.
+ */
+ int origPtr;
+
+ /*
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ */
+ int blockSize100k;
+
+ bool blockRandomised;
+
+ int bytesOut;
+ int bsBuff;
+ int bsLive;
+ CRC mCrc = new CRC();
+
+ private bool[] inUse = new bool[256];
+ private int nInUse;
+
+ private char[] seqToUnseq = new char[256];
+ private char[] unseqToSeq = new char[256];
+
+ private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ private char[] block;
+ private int[] quadrant;
+ private int[] zptr;
+ private short[] szptr;
+ private int[] ftab;
+
+ private int nMTF;
+
+ private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];
+
+ /*
+ * Used when sorting. If too many long comparisons
+ * happen, we stop sorting, randomise the block
+ * slightly, and try again.
+ */
+ private int workFactor;
+ private int workDone;
+ private int workLimit;
+ private bool firstAttempt;
+ private int nBlocksRandomised;
+
+ private int currentChar = -1;
+ private int runLength = 0;
+
+ public CBZip2OutputStream(Stream inStream) : this(inStream, 9) {
+ }
+
+ public CBZip2OutputStream(Stream inStream, int inBlockSize)
+ {
+ block = null;
+ quadrant = null;
+ zptr = null;
+ ftab = null;
+
+ inStream.WriteByte((byte)'B');
+ inStream.WriteByte((byte)'Z');
+
+ BsSetStream(inStream);
+
+ workFactor = 50;
+ if (inBlockSize > 9) {
+ inBlockSize = 9;
+ }
+ if (inBlockSize < 1) {
+ inBlockSize = 1;
+ }
+ blockSize100k = inBlockSize;
+ AllocateCompressStructures();
+ Initialize();
+ InitBlock();
+ }
+
+ /**
+ *
+ * modified by Oliver Merkel, 010128
+ *
+ */
+ public override void WriteByte(byte bv) {
+ int b = (256 + bv) % 256;
+ if (currentChar != -1) {
+ if (currentChar == b) {
+ runLength++;
+ if (runLength > 254) {
+ WriteRun();
+ currentChar = -1;
+ runLength = 0;
+ }
+ } else {
+ WriteRun();
+ runLength = 1;
+ currentChar = b;
+ }
+ } else {
+ currentChar = b;
+ runLength++;
+ }
+ }
+
+ private void WriteRun() {
+ if (last < allowableBlockSize) {
+ inUse[currentChar] = true;
+ for (int i = 0; i < runLength; i++) {
+ mCrc.UpdateCRC((char) currentChar);
+ }
+ switch (runLength) {
+ case 1:
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ case 2:
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ case 3:
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ default:
+ inUse[runLength - 4] = true;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) (runLength - 4);
+ break;
+ }
+ } else {
+ EndBlock();
+ InitBlock();
+ WriteRun();
+ }
+ }
+
+ bool closed = false;
+
+ protected void Finalize() {
+ Close();
+ }
+
+ public override void Close() {
+ if (closed) {
+ return;
+ }
+
+ Finish();
+
+ closed = true;
+ base.Close();
+ bsStream.Close();
+ }
+
+ public void Finish() {
+ if (finished) {
+ return;
+ }
+
+ if (runLength > 0) {
+ WriteRun();
+ }
+ currentChar = -1;
+ EndBlock();
+ EndCompression();
+ finished = true;
+ Flush();
+ }
+
+ public override void Flush() {
+ bsStream.Flush();
+ }
+
+ private int blockCRC, combinedCRC;
+
+ private void Initialize() {
+ bytesOut = 0;
+ nBlocksRandomised = 0;
+
+ /* Write `magic' bytes h indicating file-format == huffmanised,
+ followed by a digit indicating blockSize100k.
+ */
+ BsPutUChar('h');
+ BsPutUChar('0' + blockSize100k);
+
+ combinedCRC = 0;
+ }
+
+ private int allowableBlockSize;
+
+ private void InitBlock() {
+ // blockNo++;
+ mCrc.InitialiseCRC();
+ last = -1;
+ // ch = 0;
+
+ for (int i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ /* 20 is just a paranoia constant */
+ allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;
+ }
+
+ private void EndBlock() {
+ blockCRC = mCrc.GetFinalCRC();
+ combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31);
+ combinedCRC ^= blockCRC;
+
+ /* sort the block and establish posn of original string */
+ DoReversibleTransformation();
+
+ /*
+ A 6-byte block header, the value chosen arbitrarily
+ as 0x314159265359 :-). A 32 bit value does not really
+ give a strong enough guarantee that the value will not
+ appear by chance in the compressed datastream. Worst-case
+ probability of this event, for a 900k block, is about
+ 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+ For a compressed file of size 100Gb -- about 100000 blocks --
+ only a 48-bit marker will do. NB: normal compression/
+ decompression do *not* rely on these statistical properties.
+ They are only important when trying to recover blocks from
+ damaged files.
+ */
+ BsPutUChar(0x31);
+ BsPutUChar(0x41);
+ BsPutUChar(0x59);
+ BsPutUChar(0x26);
+ BsPutUChar(0x53);
+ BsPutUChar(0x59);
+
+ /* Now the block's CRC, so it is in a known place. */
+ BsPutint(blockCRC);
+
+ /* Now a single bit indicating randomisation. */
+ if (blockRandomised) {
+ BsW(1, 1);
+ nBlocksRandomised++;
+ } else {
+ BsW(1, 0);
+ }
+
+ /* Finally, block's contents proper. */
+ MoveToFrontCodeAndSend();
+ }
+
+ private void EndCompression() {
+ /*
+ Now another magic 48-bit number, 0x177245385090, to
+ indicate the end of the last block. (Sqrt(pi), if
+ you want to know. I did want to use e, but it contains
+ too much repetition -- 27 18 28 18 28 46 -- for me
+ to feel statistically comfortable. Call me paranoid.)
+ */
+ BsPutUChar(0x17);
+ BsPutUChar(0x72);
+ BsPutUChar(0x45);
+ BsPutUChar(0x38);
+ BsPutUChar(0x50);
+ BsPutUChar(0x90);
+
+ BsPutint(combinedCRC);
+
+ BsFinishedWithStream();
+ }
+
+ private void HbAssignCodes(int[] code, char[] length, int minLen,
+ int maxLen, int alphaSize) {
+ int n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++) {
+ for (i = 0; i < alphaSize; i++) {
+ if (length[i] == n) {
+ code[i] = vec;
+ vec++;
+ }
+ };
+ vec <<= 1;
+ }
+ }
+
+ private void BsSetStream(Stream f) {
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ }
+
+ private void BsFinishedWithStream() {
+ while (bsLive > 0) {
+ int ch = (bsBuff >> 24);
+ try {
+ bsStream.WriteByte((byte)ch); // write 8-bit
+ } catch (IOException e) {
+ throw e;
+ }
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ }
+
+ private void BsW(int n, int v) {
+ while (bsLive >= 8) {
+ int ch = (bsBuff >> 24);
+ try {
+ bsStream.WriteByte((byte)ch); // write 8-bit
+ } catch (IOException e) {
+ throw e;
+ }
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ bsBuff |= (v << (32 - bsLive - n));
+ bsLive += n;
+ }
+
+ private void BsPutUChar(int c) {
+ BsW(8, c);
+ }
+
+ private void BsPutint(int u) {
+ BsW(8, (u >> 24) & 0xff);
+ BsW(8, (u >> 16) & 0xff);
+ BsW(8, (u >> 8) & 0xff);
+ BsW(8, u & 0xff);
+ }
+
+ private void BsPutIntVS(int numBits, int c) {
+ BsW(numBits, c);
+ }
+
+ private void SendMTFValues() {
+ char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+ int v, t, i, j, gs, ge, totc, bt, bc, iter;
+ int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+ int nGroups, nBytes;
+
+ alphaSize = nInUse + 2;
+ for (t = 0; t < BZip2Constants.N_GROUPS; t++) {
+ for (v = 0; v < alphaSize; v++) {
+ len[t][v] = (char) GREATER_ICOST;
+ }
+ }
+
+ /* Decide how many coding tables to use */
+ if (nMTF <= 0) {
+ Panic();
+ }
+
+ if (nMTF < 200) {
+ nGroups = 2;
+ } else if (nMTF < 600) {
+ nGroups = 3;
+ } else if (nMTF < 1200) {
+ nGroups = 4;
+ } else if (nMTF < 2400) {
+ nGroups = 5;
+ } else {
+ nGroups = 6;
+ }
+
+ /* Generate an initial set of coding tables */ {
+ int nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs - 1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize - 1) {
+ ge++;
+ aFreq += mtfFreq[ge];
+ }
+
+ if (ge > gs && nPart != nGroups && nPart != 1
+ && ((nGroups - nPart) % 2 == 1)) {
+ aFreq -= mtfFreq[ge];
+ ge--;
+ }
+
+ for (v = 0; v < alphaSize; v++) {
+ if (v >= gs && v <= ge) {
+ len[nPart - 1][v] = (char) LESSER_ICOST;
+ } else {
+ len[nPart - 1][v] = (char) GREATER_ICOST;
+ }
+ }
+
+ nPart--;
+ gs = ge + 1;
+ remF -= aFreq;
+ }
+ }
+
+ int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ int[] fave = new int[BZip2Constants.N_GROUPS];
+ short[] cost = new short[BZip2Constants.N_GROUPS];
+ /*
+ Iterate up to N_ITERS times to improve the tables.
+ */
+ for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) {
+ for (t = 0; t < nGroups; t++) {
+ fave[t] = 0;
+ }
+
+ for (t = 0; t < nGroups; t++) {
+ for (v = 0; v < alphaSize; v++) {
+ rfreq[t][v] = 0;
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (true) {
+
+ /* Set group start & end marks. */
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ /*
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ */
+ for (t = 0; t < nGroups; t++) {
+ cost[t] = 0;
+ }
+
+ if (nGroups == 6) {
+ short cost0, cost1, cost2, cost3, cost4, cost5;
+ cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+ for (i = gs; i <= ge; i++) {
+ short icv = szptr[i];
+ cost0 += (short)len[0][icv];
+ cost1 += (short)len[1][icv];
+ cost2 += (short)len[2][icv];
+ cost3 += (short)len[3][icv];
+ cost4 += (short)len[4][icv];
+ cost5 += (short)len[5][icv];
+ }
+ cost[0] = cost0;
+ cost[1] = cost1;
+ cost[2] = cost2;
+ cost[3] = cost3;
+ cost[4] = cost4;
+ cost[5] = cost5;
+ } else {
+ for (i = gs; i <= ge; i++) {
+ short icv = szptr[i];
+ for (t = 0; t < nGroups; t++) {
+ cost[t] += (short)len[t][icv];
+ }
+ }
+ }
+
+ /*
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ */
+ bc = 999999999;
+ bt = -1;
+ for (t = 0; t < nGroups; t++) {
+ if (cost[t] < bc) {
+ bc = cost[t];
+ bt = t;
+ }
+ };
+ totc += bc;
+ fave[bt]++;
+ selector[nSelectors] = (char) bt;
+ nSelectors++;
+
+ /*
+ Increment the symbol frequencies for the selected table.
+ */
+ for (i = gs; i <= ge; i++) {
+ rfreq[bt][szptr[i]]++;
+ }
+
+ gs = ge + 1;
+ }
+
+ /*
+ Recompute the tables based on the accumulated frequencies.
+ */
+ for (t = 0; t < nGroups; t++) {
+ HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+ }
+ }
+
+ rfreq = null;
+ fave = null;
+ cost = null;
+
+ if (!(nGroups < 8)) {
+ Panic();
+ }
+ if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {
+ Panic();
+ }
+
+
+ /* Compute MTF values for the selectors. */
+ {
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char ll_i, tmp2, tmp;
+ for (i = 0; i < nGroups; i++) {
+ pos[i] = (char) i;
+ }
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = selector[i];
+ j = 0;
+ tmp = pos[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ }
+ pos[0] = tmp;
+ selectorMtf[i] = (char) j;
+ }
+ }
+
+ int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+ /* Assign actual codes for the tables. */
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ if (maxLen > 20) {
+ Panic();
+ }
+ if (minLen < 1) {
+ Panic();
+ }
+ HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+ }
+
+ /* Transmit the mapping table. */
+ {
+ bool[] inUse16 = new bool[16];
+ for (i = 0; i < 16; i++) {
+ inUse16[i] = false;
+ for (j = 0; j < 16; j++) {
+ if (inUse[i * 16 + j]) {
+ inUse16[i] = true;
+ }
+ }
+ }
+
+ nBytes = bytesOut;
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ BsW(1, 1);
+ } else {
+ BsW(1, 0);
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ for (j = 0; j < 16; j++) {
+ if (inUse[i * 16 + j]) {
+ BsW(1, 1);
+ } else {
+ BsW(1, 0);
+ }
+ }
+ }
+ }
+
+ }
+
+ /* Now the selectors. */
+ nBytes = bytesOut;
+ BsW(3, nGroups);
+ BsW(15, nSelectors);
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < selectorMtf[i]; j++) {
+ BsW(1, 1);
+ }
+ BsW(1, 0);
+ }
+
+ /* Now the coding tables. */
+ nBytes = bytesOut;
+
+ for (t = 0; t < nGroups; t++) {
+ int curr = len[t][0];
+ BsW(5, curr);
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < len[t][i]) {
+ BsW(2, 2);
+ curr++; /* 10 */
+ }
+ while (curr > len[t][i]) {
+ BsW(2, 3);
+ curr--; /* 11 */
+ }
+ BsW(1, 0);
+ }
+ }
+
+ /* And finally, the block data proper */
+ nBytes = bytesOut;
+ selCtr = 0;
+ gs = 0;
+ while (true) {
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+ for (i = gs; i <= ge; i++) {
+ BsW(len[selector[selCtr]][szptr[i]],
+ code[selector[selCtr]][szptr[i]]);
+ }
+
+ gs = ge + 1;
+ selCtr++;
+ }
+ if (!(selCtr == nSelectors)) {
+ Panic();
+ }
+ }
+
+ private void MoveToFrontCodeAndSend() {
+ BsPutIntVS(24, origPtr);
+ GenerateMTFValues();
+ SendMTFValues();
+ }
+
+ private Stream bsStream;
+
+ private void SimpleSort(int lo, int hi, int d) {
+ int i, j, h, bigN, hp;
+ int v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) {
+ return;
+ }
+
+ hp = 0;
+ while (incs[hp] < bigN) {
+ hp++;
+ }
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (true) {
+ /* copy 1 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /* copy 2 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /* copy 3 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ }
+ }
+
+ private void Vswap(int p1, int p2, int n) {
+ int temp = 0;
+ while (n > 0) {
+ temp = zptr[p1];
+ zptr[p1] = zptr[p2];
+ zptr[p2] = temp;
+ p1++;
+ p2++;
+ n--;
+ }
+ }
+
+ private char Med3(char a, char b, char c) {
+ char t;
+ if (a > b) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ if (b > c) {
+ t = b;
+ b = c;
+ c = t;
+ }
+ if (a > b) {
+ b = a;
+ }
+ return b;
+ }
+
+ internal class StackElem {
+ internal int ll;
+ internal int hh;
+ internal int dd;
+ }
+
+ private void QSort3(int loSt, int hiSt, int dSt) {
+ int unLo, unHi, ltLo, gtHi, med, n, m;
+ int sp, lo, hi, d;
+ StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+ for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+ stack[count] = new StackElem();
+ }
+
+ sp = 0;
+
+ stack[sp].ll = loSt;
+ stack[sp].hh = hiSt;
+ stack[sp].dd = dSt;
+ sp++;
+
+ while (sp > 0) {
+ if (sp >= QSORT_STACK_SIZE) {
+ Panic();
+ }
+
+ sp--;
+ lo = stack[sp].ll;
+ hi = stack[sp].hh;
+ d = stack[sp].dd;
+
+ if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+ SimpleSort(lo, hi, d);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ continue;
+ }
+
+ med = Med3(block[zptr[lo] + d + 1],
+ block[zptr[hi ] + d + 1],
+ block[zptr[(lo + hi) >> 1] + d + 1]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true) {
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int) block[zptr[unLo] + d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unLo];
+ zptr[unLo] = zptr[ltLo];
+ zptr[ltLo] = temp;
+ ltLo++;
+ unLo++;
+ continue;
+ };
+ if (n > 0) {
+ break;
+ }
+ unLo++;
+ }
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int) block[zptr[unHi] + d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unHi];
+ zptr[unHi] = zptr[gtHi];
+ zptr[gtHi] = temp;
+ gtHi--;
+ unHi--;
+ continue;
+ };
+ if (n < 0) {
+ break;
+ }
+ unHi--;
+ }
+ if (unLo > unHi) {
+ break;
+ }
+ int tempx = zptr[unLo];
+ zptr[unLo] = zptr[unHi];
+ zptr[unHi] = tempx;
+ unLo++;
+ unHi--;
+ }
+
+ if (gtHi < ltLo) {
+ stack[sp].ll = lo;
+ stack[sp].hh = hi;
+ stack[sp].dd = d + 1;
+ sp++;
+ continue;
+ }
+
+ n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);
+ Vswap(lo, unLo - n, n);
+ m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);
+ Vswap(unLo, hi - m + 1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ stack[sp].ll = lo;
+ stack[sp].hh = n;
+ stack[sp].dd = d;
+ sp++;
+
+ stack[sp].ll = n + 1;
+ stack[sp].hh = m - 1;
+ stack[sp].dd = d + 1;
+ sp++;
+
+ stack[sp].ll = m;
+ stack[sp].hh = hi;
+ stack[sp].dd = d;
+ sp++;
+ }
+ }
+
+ private void MainSort() {
+ int i, j, ss, sb;
+ int[] runningOrder = new int[256];
+ int[] copy = new int[256];
+ bool[] bigDone = new bool[256];
+ int c1, c2;
+ int numQSorted;
+
+ /*
+ In the various block-sized structures, live data runs
+ from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First,
+ set up the overshoot area for block.
+ */
+
+ // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" );
+ for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ block[last + i + 2] = block[(i % (last + 1)) + 1];
+ }
+ for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ quadrant[i] = 0;
+ }
+
+ block[0] = (char) (block[last + 1]);
+
+ if (last < 4000) {
+ /*
+ Use SimpleSort(), since the full sorting mechanism
+ has quite a large constant overhead.
+ */
+ for (i = 0; i <= last; i++) {
+ zptr[i] = i;
+ }
+ firstAttempt = false;
+ workDone = workLimit = 0;
+ SimpleSort(0, last, 0);
+ } else {
+ numQSorted = 0;
+ for (i = 0; i <= 255; i++) {
+ bigDone[i] = false;
+ }
+
+ for (i = 0; i <= 65536; i++) {
+ ftab[i] = 0;
+ }
+
+ c1 = block[0];
+ for (i = 0; i <= last; i++) {
+ c2 = block[i + 1];
+ ftab[(c1 << 8) + c2]++;
+ c1 = c2;
+ }
+
+ for (i = 1; i <= 65536; i++) {
+ ftab[i] += ftab[i - 1];
+ }
+
+ c1 = block[1];
+ for (i = 0; i < last; i++) {
+ c2 = block[i + 2];
+ j = (c1 << 8) + c2;
+ c1 = c2;
+ ftab[j]--;
+ zptr[ftab[j]] = i;
+ }
+
+ j = ((block[last + 1]) << 8) + (block[1]);
+ ftab[j]--;
+ zptr[ftab[j]] = last;
+
+ /*
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ */
+
+ for (i = 0; i <= 255; i++) {
+ runningOrder[i] = i;
+ }
+
+ {
+ int vv;
+ int h = 1;
+ do {
+ h = 3 * h + 1;
+ }
+ while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ((ftab[((runningOrder[j - h]) + 1) << 8]
+ - ftab[(runningOrder[j - h]) << 8]) >
+ (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
+ runningOrder[j] = runningOrder[j - h];
+ j = j - h;
+ if (j <= (h - 1)) {
+ break;
+ }
+ }
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*
+ The main sorting loop.
+ */
+ for (i = 0; i <= 255; i++) {
+
+ /*
+ Process big buckets, starting with the least full.
+ */
+ ss = runningOrder[i];
+
+ /*
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j]. Hopefully
+ previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ */
+ for (j = 0; j <= 255; j++) {
+ sb = (ss << 8) + j;
+ if (!((ftab[sb] & SETMASK) == SETMASK)) {
+ int lo = ftab[sb] & CLEARMASK;
+ int hi = (ftab[sb + 1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ QSort3(lo, hi, 2);
+ numQSorted += (hi - lo + 1);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ /*
+ The ss big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+ */
+ bigDone[ss] = true;
+
+ if (i < 255) {
+ int bbStart = ftab[ss << 8] & CLEARMASK;
+ int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
+ int shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) {
+ shifts++;
+ }
+
+ for (j = 0; j < bbSize; j++) {
+ int a2update = zptr[bbStart + j];
+ int qVal = (j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {
+ quadrant[a2update + last + 1] = qVal;
+ }
+ }
+
+ if (!(((bbSize - 1) >> shifts) <= 65535)) {
+ Panic();
+ }
+ }
+
+ /*
+ Now scan this big bucket so as to synthesise the
+ sorted order for small buckets [t, ss] for all t != ss.
+ */
+ for (j = 0; j <= 255; j++) {
+ copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ }
+
+ for (j = ftab[ss << 8] & CLEARMASK;
+ j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) {
+ c1 = block[zptr[j]];
+ if (!bigDone[c1]) {
+ zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+ copy[c1]++;
+ }
+ }
+
+ for (j = 0; j <= 255; j++) {
+ ftab[(j << 8) + ss] |= SETMASK;
+ }
+ }
+ }
+ }
+
+ private void RandomiseBlock() {
+ int i;
+ int rNToGo = 0;
+ int rTPos = 0;
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i <= last; i++) {
+ if (rNToGo == 0) {
+ rNToGo = (char) BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0);
+ // handle 16 bit signed numbers
+ block[i + 1] &= (char)0xFF;
+
+ inUse[block[i + 1]] = true;
+ }
+ }
+
+ private void DoReversibleTransformation() {
+ int i;
+
+ workLimit = workFactor * last;
+ workDone = 0;
+ blockRandomised = false;
+ firstAttempt = true;
+
+ MainSort();
+
+ if (workDone > workLimit && firstAttempt) {
+ RandomiseBlock();
+ workLimit = workDone = 0;
+ blockRandomised = true;
+ firstAttempt = false;
+ MainSort();
+ }
+
+ origPtr = -1;
+ for (i = 0; i <= last; i++) {
+ if (zptr[i] == 0) {
+ origPtr = i;
+ break;
+ }
+ };
+
+ if (origPtr == -1) {
+ Panic();
+ }
+ }
+
+ private bool FullGtU(int i1, int i2) {
+ int k;
+ char c1, c2;
+ int s1, s2;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ k = last + 1;
+
+ do {
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ if (i1 > last) {
+ i1 -= last;
+ i1--;
+ };
+ if (i2 > last) {
+ i2 -= last;
+ i2--;
+ };
+
+ k -= 4;
+ workDone++;
+ } while (k >= 0);
+
+ return false;
+ }
+
+ /*
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+ */
+ private int[] incs = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484 };
+
+ private void AllocateCompressStructures() {
+ int n = BZip2Constants.baseBlockSize * blockSize100k;
+ block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ zptr = new int[n];
+ ftab = new int[65537];
+
+ if (block == null || quadrant == null || zptr == null
+ || ftab == null) {
+ //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+ //compressOutOfMemory ( totalDraw, n );
+ }
+
+ /*
+ The back end needs a place to store the MTF values
+ whilst it calculates the coding tables. We could
+ put them in the zptr array. However, these values
+ will fit in a short, so we overlay szptr at the
+ start of zptr, in the hope of reducing the number
+ of cache misses induced by the multiple traversals
+ of the MTF values when calculating coding tables.
+ Seems to improve compression speed by about 1%.
+ */
+ // szptr = zptr;
+
+
+ szptr = new short[2 * n];
+ }
+
+ private void GenerateMTFValues() {
+ char[] yy = new char[256];
+ int i, j;
+ char tmp;
+ char tmp2;
+ int zPend;
+ int wr;
+ int EOB;
+
+ MakeMaps();
+ EOB = nInUse + 1;
+
+ for (i = 0; i <= EOB; i++) {
+ mtfFreq[i] = 0;
+ }
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < nInUse; i++) {
+ yy[i] = (char) i;
+ }
+
+
+ for (i = 0; i <= last; i++) {
+ char ll_i;
+
+ ll_i = unseqToSeq[block[zptr[i]]];
+
+ j = 0;
+ tmp = yy[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = yy[j];
+ yy[j] = tmp2;
+ };
+ yy[0] = tmp;
+
+ if (j == 0) {
+ zPend++;
+ } else {
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short) BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short) BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ };
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+ szptr[wr] = (short) (j + 1);
+ wr++;
+ mtfFreq[j + 1]++;
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short) BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short) BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ }
+
+ szptr[wr] = (short) EOB;
+ wr++;
+ mtfFreq[EOB]++;
+
+ nMTF = wr;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ return 0;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ for (int k = 0; k < count; ++k) {
+ WriteByte(buffer[k + offset]);
+ }
+ }
+
+ public override bool CanRead {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ return true;
+ }
+ }
+
+ public override long Length {
+ get {
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ return 0;
+ }
+ set {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/bzip2/CRC.cs b/src/core/srcbc/util/bzip2/CRC.cs
new file mode 100644
index 0000000..c1eb57c
--- /dev/null
+++ b/src/core/srcbc/util/bzip2/CRC.cs
@@ -0,0 +1,170 @@
+using System;
+
+/*
+ * The Apache Software License), Version 1.1
+ *
+ * Copyright (c) 2001-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms), with or without
+ * modification), are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice), this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution), if
+ * any), must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately), this acknowlegement may appear in the software itself),
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Ant" and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission), please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES), INCLUDING), BUT NOT LIMITED TO), THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT), INDIRECT), INCIDENTAL),
+ * SPECIAL), EXEMPLARY), OR CONSEQUENTIAL DAMAGES (INCLUDING), BUT NOT
+ * LIMITED TO), PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE), DATA), OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY), WHETHER IN CONTRACT), STRICT LIABILITY),
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE), EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation), please see
+ * .
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle), Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * A simple class the hold and calculate the CRC for sanity checking
+ * of the data.
+ *
+ * @author Keiron Liddle
+ */
+ internal class CRC
+ {
+ public static int[] crc32Table = {
+ unchecked((int)0x00000000), unchecked((int)0x04c11db7), unchecked((int)0x09823b6e), unchecked((int)0x0d4326d9),
+ unchecked((int)0x130476dc), unchecked((int)0x17c56b6b), unchecked((int)0x1a864db2), unchecked((int)0x1e475005),
+ unchecked((int)0x2608edb8), unchecked((int)0x22c9f00f), unchecked((int)0x2f8ad6d6), unchecked((int)0x2b4bcb61),
+ unchecked((int)0x350c9b64), unchecked((int)0x31cd86d3), unchecked((int)0x3c8ea00a), unchecked((int)0x384fbdbd),
+ unchecked((int)0x4c11db70), unchecked((int)0x48d0c6c7), unchecked((int)0x4593e01e), unchecked((int)0x4152fda9),
+ unchecked((int)0x5f15adac), unchecked((int)0x5bd4b01b), unchecked((int)0x569796c2), unchecked((int)0x52568b75),
+ unchecked((int)0x6a1936c8), unchecked((int)0x6ed82b7f), unchecked((int)0x639b0da6), unchecked((int)0x675a1011),
+ unchecked((int)0x791d4014), unchecked((int)0x7ddc5da3), unchecked((int)0x709f7b7a), unchecked((int)0x745e66cd),
+ unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), unchecked((int)0x95609039),
+ unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5),
+ unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), unchecked((int)0xb3687d81),
+ unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d),
+ unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), unchecked((int)0xd9714b49),
+ unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), unchecked((int)0xca753d95),
+ unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1),
+ unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d),
+ unchecked((int)0x34867077), unchecked((int)0x30476dc0), unchecked((int)0x3d044b19), unchecked((int)0x39c556ae),
+ unchecked((int)0x278206ab), unchecked((int)0x23431b1c), unchecked((int)0x2e003dc5), unchecked((int)0x2ac12072),
+ unchecked((int)0x128e9dcf), unchecked((int)0x164f8078), unchecked((int)0x1b0ca6a1), unchecked((int)0x1fcdbb16),
+ unchecked((int)0x018aeb13), unchecked((int)0x054bf6a4), unchecked((int)0x0808d07d), unchecked((int)0x0cc9cdca),
+ unchecked((int)0x7897ab07), unchecked((int)0x7c56b6b0), unchecked((int)0x71159069), unchecked((int)0x75d48dde),
+ unchecked((int)0x6b93dddb), unchecked((int)0x6f52c06c), unchecked((int)0x6211e6b5), unchecked((int)0x66d0fb02),
+ unchecked((int)0x5e9f46bf), unchecked((int)0x5a5e5b08), unchecked((int)0x571d7dd1), unchecked((int)0x53dc6066),
+ unchecked((int)0x4d9b3063), unchecked((int)0x495a2dd4), unchecked((int)0x44190b0d), unchecked((int)0x40d816ba),
+ unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e),
+ unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), unchecked((int)0xb2e29692),
+ unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), unchecked((int)0x87ee0df6),
+ unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a),
+ unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), unchecked((int)0xedf73b3e),
+ unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), unchecked((int)0xfef34de2),
+ unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686),
+ unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a),
+ unchecked((int)0x690ce0ee), unchecked((int)0x6dcdfd59), unchecked((int)0x608edb80), unchecked((int)0x644fc637),
+ unchecked((int)0x7a089632), unchecked((int)0x7ec98b85), unchecked((int)0x738aad5c), unchecked((int)0x774bb0eb),
+ unchecked((int)0x4f040d56), unchecked((int)0x4bc510e1), unchecked((int)0x46863638), unchecked((int)0x42472b8f),
+ unchecked((int)0x5c007b8a), unchecked((int)0x58c1663d), unchecked((int)0x558240e4), unchecked((int)0x51435d53),
+ unchecked((int)0x251d3b9e), unchecked((int)0x21dc2629), unchecked((int)0x2c9f00f0), unchecked((int)0x285e1d47),
+ unchecked((int)0x36194d42), unchecked((int)0x32d850f5), unchecked((int)0x3f9b762c), unchecked((int)0x3b5a6b9b),
+ unchecked((int)0x0315d626), unchecked((int)0x07d4cb91), unchecked((int)0x0a97ed48), unchecked((int)0x0e56f0ff),
+ unchecked((int)0x1011a0fa), unchecked((int)0x14d0bd4d), unchecked((int)0x19939b94), unchecked((int)0x1d528623),
+ unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7),
+ unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), unchecked((int)0xef68060b),
+ unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), unchecked((int)0xda649d6f),
+ unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3),
+ unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7),
+ unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b),
+ unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), unchecked((int)0x9675461f),
+ unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), unchecked((int)0x857130c3),
+ unchecked((int)0x5d8a9099), unchecked((int)0x594b8d2e), unchecked((int)0x5408abf7), unchecked((int)0x50c9b640),
+ unchecked((int)0x4e8ee645), unchecked((int)0x4a4ffbf2), unchecked((int)0x470cdd2b), unchecked((int)0x43cdc09c),
+ unchecked((int)0x7b827d21), unchecked((int)0x7f436096), unchecked((int)0x7200464f), unchecked((int)0x76c15bf8),
+ unchecked((int)0x68860bfd), unchecked((int)0x6c47164a), unchecked((int)0x61043093), unchecked((int)0x65c52d24),
+ unchecked((int)0x119b4be9), unchecked((int)0x155a565e), unchecked((int)0x18197087), unchecked((int)0x1cd86d30),
+ unchecked((int)0x029f3d35), unchecked((int)0x065e2082), unchecked((int)0x0b1d065b), unchecked((int)0x0fdc1bec),
+ unchecked((int)0x3793a651), unchecked((int)0x3352bbe6), unchecked((int)0x3e119d3f), unchecked((int)0x3ad08088),
+ unchecked((int)0x2497d08d), unchecked((int)0x2056cd3a), unchecked((int)0x2d15ebe3), unchecked((int)0x29d4f654),
+ unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0),
+ unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c),
+ unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18),
+ unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), unchecked((int)0xfde69bc4),
+ unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0),
+ unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c),
+ unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668),
+ unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4)
+ };
+
+ public CRC() {
+ InitialiseCRC();
+ }
+
+ internal void InitialiseCRC() {
+ globalCrc = unchecked((int)0xffffffff);
+ }
+
+ internal int GetFinalCRC() {
+ return ~globalCrc;
+ }
+
+ internal int GetGlobalCRC() {
+ return globalCrc;
+ }
+
+ internal void SetGlobalCRC(int newCrc) {
+ globalCrc = newCrc;
+ }
+
+ internal void UpdateCRC(int inCh) {
+ int temp = (globalCrc >> 24) ^ inCh;
+ if (temp < 0) {
+ temp = 256 + temp;
+ }
+ globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
+ }
+
+ internal int globalCrc;
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/collections/CollectionUtilities.cs b/src/core/srcbc/util/collections/CollectionUtilities.cs
new file mode 100644
index 0000000..c845c83
--- /dev/null
+++ b/src/core/srcbc/util/collections/CollectionUtilities.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public sealed class CollectionUtilities
+ {
+ private CollectionUtilities()
+ {
+ }
+
+ public static bool CheckElementsAreOfType(
+ IEnumerable e,
+ Type t)
+ {
+ foreach (object o in e)
+ {
+ if (!t.IsInstanceOfType(o))
+ return false;
+ }
+ return true;
+ }
+
+ public static string ToString(
+ IEnumerable c)
+ {
+ StringBuilder sb = new StringBuilder("[");
+
+ IEnumerator e = c.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ sb.Append(e.Current.ToString());
+
+ while (e.MoveNext())
+ {
+ sb.Append(", ");
+ sb.Append(e.Current.ToString());
+ }
+ }
+
+ sb.Append(']');
+
+ return sb.ToString();
+ }
+ }
+}
diff --git a/src/core/srcbc/util/collections/EmptyEnumerable.cs b/src/core/srcbc/util/collections/EmptyEnumerable.cs
new file mode 100644
index 0000000..a34b0af
--- /dev/null
+++ b/src/core/srcbc/util/collections/EmptyEnumerable.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public sealed class EmptyEnumerable
+ : IEnumerable
+ {
+ public static readonly IEnumerable Instance = new EmptyEnumerable();
+
+ private EmptyEnumerable()
+ {
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return EmptyEnumerator.Instance;
+ }
+ }
+
+ public sealed class EmptyEnumerator
+ : IEnumerator
+ {
+ public static readonly IEnumerator Instance = new EmptyEnumerator();
+
+ private EmptyEnumerator()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ return false;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public object Current
+ {
+ get { throw new InvalidOperationException("No elements"); }
+ }
+ }
+}
diff --git a/src/core/srcbc/util/collections/EnumerableProxy.cs b/src/core/srcbc/util/collections/EnumerableProxy.cs
new file mode 100644
index 0000000..6ac9893
--- /dev/null
+++ b/src/core/srcbc/util/collections/EnumerableProxy.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public sealed class EnumerableProxy
+ : IEnumerable
+ {
+ private readonly IEnumerable inner;
+
+ public EnumerableProxy(
+ IEnumerable inner)
+ {
+ if (inner == null)
+ throw new ArgumentNullException("inner");
+
+ this.inner = inner;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return inner.GetEnumerator();
+ }
+ }
+}
diff --git a/src/core/srcbc/util/collections/HashSet.cs b/src/core/srcbc/util/collections/HashSet.cs
new file mode 100644
index 0000000..fef6e83
--- /dev/null
+++ b/src/core/srcbc/util/collections/HashSet.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class HashSet
+ : ISet
+ {
+ private readonly Hashtable impl = new Hashtable();
+
+ public HashSet()
+ {
+ }
+
+ public HashSet(ISet s)
+ {
+ foreach (object o in s)
+ {
+ Add(o);
+ }
+ }
+
+ public void Add(object o)
+ {
+ impl[o] = null;
+ }
+
+ public bool Contains(object o)
+ {
+ return impl.ContainsKey(o);
+ }
+
+ public void CopyTo(Array array, int index)
+ {
+ impl.Keys.CopyTo(array, index);
+ }
+
+ public int Count
+ {
+ get { return impl.Count; }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return impl.Keys.GetEnumerator();
+ }
+
+ public bool IsSynchronized
+ {
+ get { return impl.IsSynchronized; }
+ }
+
+ public void Remove(object o)
+ {
+ impl.Remove(o);
+ }
+
+ public object SyncRoot
+ {
+ get { return impl.SyncRoot; }
+ }
+ }
+}
diff --git a/src/core/srcbc/util/collections/ISet.cs b/src/core/srcbc/util/collections/ISet.cs
new file mode 100644
index 0000000..3e0a1b2
--- /dev/null
+++ b/src/core/srcbc/util/collections/ISet.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public interface ISet
+ : ICollection
+ {
+ void Add(object o);
+ bool Contains(object o);
+ void Remove(object o);
+ }
+}
diff --git a/src/core/srcbc/util/date/DateTimeObject.cs b/src/core/srcbc/util/date/DateTimeObject.cs
new file mode 100644
index 0000000..f5be6ce
--- /dev/null
+++ b/src/core/srcbc/util/date/DateTimeObject.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+ public sealed class DateTimeObject
+ {
+ private readonly DateTime dt;
+
+ public DateTimeObject(
+ DateTime dt)
+ {
+ this.dt = dt;
+ }
+
+ public DateTime Value
+ {
+ get { return dt; }
+ }
+
+ public override string ToString()
+ {
+ return dt.ToString();
+ }
+ }
+}
diff --git a/src/core/srcbc/util/date/DateTimeUtilities.cs b/src/core/srcbc/util/date/DateTimeUtilities.cs
new file mode 100644
index 0000000..449934d
--- /dev/null
+++ b/src/core/srcbc/util/date/DateTimeUtilities.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+ public class DateTimeUtilities
+ {
+ public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1);
+
+ private DateTimeUtilities()
+ {
+ }
+
+ ///
+ /// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value.
+ ///
+ /// A UTC DateTime value not before epoch.
+ /// Number of whole milliseconds after epoch.
+ /// 'dateTime' is before epoch.
+ public static long DateTimeToUnixMs(
+ DateTime dateTime)
+ {
+ if (dateTime.CompareTo(UnixEpoch) < 0)
+ throw new ArgumentException("DateTime value may not be before the epoch", "dateTime");
+
+ return (dateTime.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
+ }
+
+ ///
+ /// Create a DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+ ///
+ /// Number of milliseconds since the epoch.
+ /// A UTC DateTime value
+ public static DateTime UnixMsToDateTime(
+ long unixMs)
+ {
+ return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks);
+ }
+
+ ///
+ /// Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+ ///
+ public static long CurrentUnixMs()
+ {
+ return DateTimeToUnixMs(DateTime.UtcNow);
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/Base64.cs b/src/core/srcbc/util/encoders/Base64.cs
new file mode 100644
index 0000000..66c1e07
--- /dev/null
+++ b/src/core/srcbc/util/encoders/Base64.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public sealed class Base64
+ {
+// private static readonly IEncoder encoder = new Base64Encoder();
+
+ private Base64()
+ {
+ }
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ string s = Convert.ToBase64String(data, 0, data.Length);
+ return Encoding.ASCII.GetBytes(s);
+
+// MemoryStream bOut = new MemoryStream();
+// encoder.Encode(data, 0, data.Length, bOut);
+// return bOut.ToArray();
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStream)
+ {
+ string s = Convert.ToBase64String(data, 0, data.Length);
+ byte[] encoded = Encoding.ASCII.GetBytes(s);
+ outStream.Write(encoded, 0, encoded.Length);
+ return encoded.Length;
+
+// return encoder.Encode(data, 0, data.Length, outStream);
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ string s = Convert.ToBase64String(data, off, length);
+ byte[] encoded = Encoding.ASCII.GetBytes(s);
+ outStream.Write(encoded, 0, encoded.Length);
+ return encoded.Length;
+
+// return encoder.Encode(data, off, length, outStream);
+ }
+
+ /**
+ * decode the base 64 encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ string s = Encoding.ASCII.GetString(data, 0, data.Length);
+ return Convert.FromBase64String(s);
+
+// MemoryStream bOut = new MemoryStream();
+// encoder.Decode(data, 0, data.Length, bOut);
+// return bOut.ToArray();
+ }
+
+ /**
+ * decode the base 64 encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ return Convert.FromBase64String(data);
+
+// MemoryStream bOut = new MemoryStream();
+// encoder.DecodeString(data, bOut);
+// return bOut.ToArray();
+ }
+
+ /**
+ * decode the base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStream)
+ {
+ byte[] decoded = Decode(data);
+ outStream.Write(decoded, 0, decoded.Length);
+ return decoded.Length;
+
+// return encoder.DecodeString(data, outStream);
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/Base64Encoder.cs b/src/core/srcbc/util/encoders/Base64Encoder.cs
new file mode 100644
index 0000000..45fc1bb
--- /dev/null
+++ b/src/core/srcbc/util/encoders/Base64Encoder.cs
@@ -0,0 +1,307 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public class Base64Encoder
+ : IEncoder
+ {
+ protected readonly byte[] encodingTable =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
+
+ protected byte padding = (byte)'=';
+
+ /*
+ * set up the decoding table.
+ */
+ protected readonly byte[] decodingTable = new byte[128];
+
+ protected void InitialiseDecodingTable()
+ {
+ for (int i = 0; i < encodingTable.Length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+ }
+
+ public Base64Encoder()
+ {
+ InitialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a base 64 output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ int modulus = length % 3;
+ int dataLength = (length - modulus);
+ int a1, a2, a3;
+
+ for (int i = off; i < off + dataLength; i += 3)
+ {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+
+ outStream.WriteByte(encodingTable[(int) ((uint) a1 >> 2) & 0x3f]);
+ outStream.WriteByte(encodingTable[((a1 << 4) | (int) ((uint) a2 >> 4)) & 0x3f]);
+ outStream.WriteByte(encodingTable[((a2 << 2) | (int) ((uint) a3 >> 6)) & 0x3f]);
+ outStream.WriteByte(encodingTable[a3 & 0x3f]);
+ }
+
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+
+ switch (modulus)
+ {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[off + dataLength] & 0xff;
+ b1 = (d1 >> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ outStream.WriteByte(encodingTable[b1]);
+ outStream.WriteByte(encodingTable[b2]);
+ outStream.WriteByte(padding);
+ outStream.WriteByte(padding);
+ break;
+ case 2:
+ d1 = data[off + dataLength] & 0xff;
+ d2 = data[off + dataLength + 1] & 0xff;
+
+ b1 = (d1 >> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ outStream.WriteByte(encodingTable[b1]);
+ outStream.WriteByte(encodingTable[b2]);
+ outStream.WriteByte(encodingTable[b3]);
+ outStream.WriteByte(padding);
+ break;
+ }
+
+ return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+ }
+
+ private bool ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Decode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ byte b1, b2, b3, b4;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ outLen += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ outLen += decodeLastBlock(outStream, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
+
+ return outLen;
+ }
+
+ private int nextI(
+ byte[] data,
+ int i,
+ int finish)
+ {
+ while ((i < finish) && ignore((char)data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+
+ /**
+ * decode the base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int DecodeString(
+ string data,
+ Stream outStream)
+ {
+ // Platform Implementation
+// byte[] bytes = Convert.FromBase64String(data);
+// outStream.Write(bytes, 0, bytes.Length);
+// return bytes.Length;
+
+ byte b1, b2, b3, b4;
+ int length = 0;
+
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!ignore(data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ length += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
+
+ return length;
+ }
+
+ private int decodeLastBlock(
+ Stream outStream,
+ char c1,
+ char c2,
+ char c3,
+ char c4)
+ {
+ if (c3 == padding)
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+
+ return 1;
+ }
+
+ if (c4 == padding)
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+ byte b3 = decodingTable[c3];
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+
+ return 2;
+ }
+
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+ byte b3 = decodingTable[c3];
+ byte b4 = decodingTable[c4];
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ return 3;
+ }
+ }
+
+ private int nextI(string data, int i, int finish)
+ {
+ while ((i < finish) && ignore(data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/BufferedDecoder.cs b/src/core/srcbc/util/encoders/BufferedDecoder.cs
new file mode 100644
index 0000000..e43d96d
--- /dev/null
+++ b/src/core/srcbc/util/encoders/BufferedDecoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A buffering class to allow translation from one format to another to
+ /// be done in discrete chunks.
+ ///
+ public class BufferedDecoder
+ {
+ internal byte[] buffer;
+ internal int bufOff;
+
+ internal ITranslator translator;
+
+ ///
+ /// Create a buffered Decoder.
+ ///
+ /// The translater to use.
+ /// The size of the buffer.
+ public BufferedDecoder(
+ ITranslator translator,
+ int bufferSize)
+ {
+ this.translator = translator;
+
+ if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+ {
+ throw new ArgumentException("buffer size not multiple of input block size");
+ }
+
+ buffer = new byte[bufferSize];
+// bufOff = 0;
+ }
+
+ ///
+ /// Process one byte of data.
+ ///
+ /// Data in.
+ /// Byte array for the output.
+ /// The offset in the output byte array to start writing from.
+ /// The amount of output bytes.
+ public int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ buffer[bufOff++] = input;
+
+ if (bufOff == buffer.Length)
+ {
+ resultLen = translator.Decode(buffer, 0, buffer.Length, output, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+
+ ///
+ /// Process data from a byte array.
+ ///
+ /// The input data.
+ /// Start position within input data array.
+ /// Amount of data to process from input data array.
+ /// Array to store output.
+ /// Position in output array to start writing from.
+ /// The amount of output bytes.
+ public int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = buffer.Length - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buffer, bufOff, gapLen);
+
+ resultLen += translator.Decode(buffer, 0, buffer.Length, outBytes, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % buffer.Length);
+
+ resultLen += translator.Decode(input, inOff, chunkSize, outBytes, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ Array.Copy(input, inOff, buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/util/encoders/BufferedEncoder.cs b/src/core/srcbc/util/encoders/BufferedEncoder.cs
new file mode 100644
index 0000000..20c236f
--- /dev/null
+++ b/src/core/srcbc/util/encoders/BufferedEncoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A class that allows encoding of data using a specific encoder to be processed in chunks.
+ ///
+ public class BufferedEncoder
+ {
+ internal byte[] Buffer;
+ internal int bufOff;
+
+ internal ITranslator translator;
+
+
+ ///
+ /// Create.
+ ///
+ /// The translator to use.
+ /// Size of the chunks.
+ public BufferedEncoder(
+ ITranslator translator,
+ int bufferSize)
+ {
+ this.translator = translator;
+
+ if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+ {
+ throw new ArgumentException("buffer size not multiple of input block size");
+ }
+
+ Buffer = new byte[bufferSize];
+// bufOff = 0;
+ }
+
+
+ ///
+ /// Process one byte of data.
+ ///
+ /// The byte.
+ /// An array to store output in.
+ /// Offset within output array to start writing from.
+ ///
+ public int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ Buffer[bufOff++] = input;
+
+ if (bufOff == Buffer.Length)
+ {
+ resultLen = translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ ///
+ /// Process data from a byte array.
+ ///
+ /// Input data Byte array containing data to be processed.
+ /// Start position within input data array.
+ /// Amount of input data to be processed.
+ /// Output data array.
+ /// Offset within output data array to start writing to.
+ /// The amount of data written.
+ public int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = Buffer.Length - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+ resultLen += translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % Buffer.Length);
+
+ resultLen += translator.Encode(input, inOff, chunkSize, outBytes, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/util/encoders/Hex.cs b/src/core/srcbc/util/encoders/Hex.cs
new file mode 100644
index 0000000..fe63b18
--- /dev/null
+++ b/src/core/srcbc/util/encoders/Hex.cs
@@ -0,0 +1,114 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// Class to decode and encode Hex.
+ ///
+ public sealed class Hex
+ {
+ private static readonly IEncoder encoder = new HexEncoder();
+
+ private Hex()
+ {
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ return Encode(data, 0, data.Length);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ MemoryStream bOut = new MemoryStream(length * 2);
+
+ encoder.Encode(data, off, length, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStream)
+ {
+ return encoder.Encode(data, 0, data.Length, outStream);
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ return encoder.Encode(data, off, length, outStream);
+ }
+
+ /**
+ * decode the Hex encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+ encoder.Decode(data, 0, data.Length, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the Hex encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+ encoder.DecodeString(data, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the Hex encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStream)
+ {
+ return encoder.DecodeString(data, outStream);
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/HexEncoder.cs b/src/core/srcbc/util/encoders/HexEncoder.cs
new file mode 100644
index 0000000..b850570
--- /dev/null
+++ b/src/core/srcbc/util/encoders/HexEncoder.cs
@@ -0,0 +1,164 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public class HexEncoder
+ : IEncoder
+ {
+ private static readonly byte[] encodingTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ /*
+ * set up the decoding table.
+ */
+ internal static readonly byte[] decodingTable = new byte[128];
+
+ static HexEncoder()
+ {
+ for (int i = 0; i < encodingTable.Length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+
+ decodingTable['A'] = decodingTable['a'];
+ decodingTable['B'] = decodingTable['b'];
+ decodingTable['C'] = decodingTable['c'];
+ decodingTable['D'] = decodingTable['d'];
+ decodingTable['E'] = decodingTable['e'];
+ decodingTable['F'] = decodingTable['f'];
+ }
+
+ /**
+ * encode the input data producing a Hex output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ for (int i = off; i < (off + length); i++)
+ {
+ int v = data[i];
+
+ outStream.WriteByte(encodingTable[v >> 4]);
+ outStream.WriteByte(encodingTable[v & 0xf]);
+ }
+
+ return length * 2;
+ }
+
+ private bool ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the Hex encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Decode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ byte b1, b2;
+ int outLen = 0;
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ while (i < end)
+ {
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ outStream.WriteByte((byte)((b1 << 4) | b2));
+
+ outLen++;
+ }
+
+ return outLen;
+ }
+
+ /**
+ * decode the Hex encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int DecodeString(
+ string data,
+ Stream outStream)
+ {
+ byte b1, b2;
+ int length = 0;
+
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!ignore(data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ while (i < end)
+ {
+ while (i < end && ignore(data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && ignore(data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ outStream.WriteByte((byte)((b1 << 4) | b2));
+
+ length++;
+ }
+
+ return length;
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/HexTranslator.cs b/src/core/srcbc/util/encoders/HexTranslator.cs
new file mode 100644
index 0000000..3db3b55
--- /dev/null
+++ b/src/core/srcbc/util/encoders/HexTranslator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A hex translator.
+ ///
+ public class HexTranslator : ITranslator
+ {
+ private static readonly byte[] hexTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ ///
+ /// Return encoded block size.
+ ///
+ /// 2
+ public int GetEncodedBlockSize()
+ {
+ return 2;
+ }
+
+ ///
+ /// Encode some data.
+ ///
+ /// Input data array.
+ /// Start position within input data array.
+ /// The amount of data to process.
+ /// The output data array.
+ /// The offset within the output data array to start writing from.
+ /// Amount of data encoded.
+ public int Encode(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] outBytes,
+ int outOff)
+ {
+ for (int i = 0, j = 0; i < length; i++, j += 2)
+ {
+ outBytes[outOff + j] = hexTable[(input[inOff] >> 4) & 0x0f];
+ outBytes[outOff + j + 1] = hexTable[input[inOff] & 0x0f];
+
+ inOff++;
+ }
+
+ return length * 2;
+ }
+
+ ///
+ /// Returns the decoded block size.
+ ///
+ /// 1
+ public int GetDecodedBlockSize()
+ {
+ return 1;
+ }
+
+ ///
+ /// Decode data from a byte array.
+ ///
+ /// The input data array.
+ /// Start position within input data array.
+ /// The amounty of data to process.
+ /// The output data array.
+ /// The position within the output data array to start writing from.
+ /// The amount of data written.
+ public int Decode(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] outBytes,
+ int outOff)
+ {
+ int halfLength = length / 2;
+ byte left, right;
+ for (int i = 0; i < halfLength; i++)
+ {
+ left = input[inOff + i * 2];
+ right = input[inOff + i * 2 + 1];
+
+ if (left < (byte)'a')
+ {
+ outBytes[outOff] = (byte)((left - '0') << 4);
+ }
+ else
+ {
+ outBytes[outOff] = (byte)((left - 'a' + 10) << 4);
+ }
+ if (right < (byte)'a')
+ {
+ outBytes[outOff] += (byte)(right - '0');
+ }
+ else
+ {
+ outBytes[outOff] += (byte)(right - 'a' + 10);
+ }
+
+ outOff++;
+ }
+
+ return halfLength;
+ }
+ }
+
+}
diff --git a/src/core/srcbc/util/encoders/IEncoder.cs b/src/core/srcbc/util/encoders/IEncoder.cs
new file mode 100644
index 0000000..4a1aca3
--- /dev/null
+++ b/src/core/srcbc/util/encoders/IEncoder.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII
+ * encodings).
+ */
+ public interface IEncoder
+ {
+ int Encode(byte[] data, int off, int length, Stream outStream);
+
+ int Decode(byte[] data, int off, int length, Stream outStream);
+
+ int DecodeString(string data, Stream outStream);
+ }
+}
diff --git a/src/core/srcbc/util/encoders/Translator.cs b/src/core/srcbc/util/encoders/Translator.cs
new file mode 100644
index 0000000..3231432
--- /dev/null
+++ b/src/core/srcbc/util/encoders/Translator.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// Translator interface.
+ ///
+ public interface ITranslator
+ {
+ int GetEncodedBlockSize();
+
+ int Encode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+
+ int GetDecodedBlockSize();
+
+ int Decode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+ }
+
+}
diff --git a/src/core/srcbc/util/encoders/UrlBase64.cs b/src/core/srcbc/util/encoders/UrlBase64.cs
new file mode 100644
index 0000000..f88d82d
--- /dev/null
+++ b/src/core/srcbc/util/encoders/UrlBase64.cs
@@ -0,0 +1,127 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ *
+ */
+ public class UrlBase64
+ {
+ private static readonly IEncoder encoder = new UrlBase64Encoder();
+
+ /**
+ * Encode the input data producing a URL safe base 64 encoded byte array.
+ *
+ * @return a byte array containing the URL safe base 64 encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.Encode(data, 0, data.Length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception encoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStr)
+ {
+ return encoder.Encode(data, 0, data.Length, outStr);
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded input data - white space will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.Decode(data, 0, data.Length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the URL safe base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ byte[] data,
+ Stream outStr)
+ {
+ return encoder.Decode(data, 0, data.Length, outStr);
+ }
+
+ /**
+ * decode the URL safe base 64 encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.DecodeString(data, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStr)
+ {
+ return encoder.DecodeString(data, outStr);
+ }
+ }
+}
diff --git a/src/core/srcbc/util/encoders/UrlBase64Encoder.cs b/src/core/srcbc/util/encoders/UrlBase64Encoder.cs
new file mode 100644
index 0000000..99c9c9c
--- /dev/null
+++ b/src/core/srcbc/util/encoders/UrlBase64Encoder.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ *
+ */
+ public class UrlBase64Encoder
+ : Base64Encoder
+ {
+ public UrlBase64Encoder()
+ {
+ encodingTable[encodingTable.Length - 2] = (byte) '-';
+ encodingTable[encodingTable.Length - 1] = (byte) '_';
+ padding = (byte) '.';
+ // we must re-create the decoding table with the new encoded values.
+ InitialiseDecodingTable();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/io/BaseInputStream.cs b/src/core/srcbc/util/io/BaseInputStream.cs
new file mode 100644
index 0000000..4c28e13
--- /dev/null
+++ b/src/core/srcbc/util/io/BaseInputStream.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public abstract class BaseInputStream : Stream
+ {
+ private bool closed;
+
+ public sealed override bool CanRead { get { return !closed; } }
+ public sealed override bool CanSeek { get { return false; } }
+ public sealed override bool CanWrite { get { return false; } }
+ public override void Close() { closed = true; }
+ public sealed override void Flush() {}
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int pos = offset;
+ try
+ {
+ int end = offset + count;
+ while (pos < end)
+ {
+ int b = ReadByte();
+ if (b == -1) break;
+ buffer[pos++] = (byte) b;
+ }
+ }
+ catch (IOException)
+ {
+ if (pos == offset) throw;
+ }
+ return pos - offset;
+ }
+
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+ public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+ }
+}
diff --git a/src/core/srcbc/util/io/BaseOutputStream.cs b/src/core/srcbc/util/io/BaseOutputStream.cs
new file mode 100644
index 0000000..339eef4
--- /dev/null
+++ b/src/core/srcbc/util/io/BaseOutputStream.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public abstract class BaseOutputStream : Stream
+ {
+ private bool closed;
+
+ public sealed override bool CanRead { get { return false; } }
+ public sealed override bool CanSeek { get { return false; } }
+ public sealed override bool CanWrite { get { return !closed; } }
+ public override void Close() { closed = true; }
+ public override void Flush() {}
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+ public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(0 <= offset && offset <= buffer.Length);
+ Debug.Assert(count >= 0);
+
+ int end = offset + count;
+
+ Debug.Assert(0 <= end && end <= buffer.Length);
+
+ for (int i = offset; i < end; ++i)
+ {
+ this.WriteByte(buffer[i]);
+ }
+ }
+
+ public virtual void Write(params byte[] buffer)
+ {
+ Write(buffer, 0, buffer.Length);
+ }
+ }
+}
diff --git a/src/core/srcbc/util/io/PushbackStream.cs b/src/core/srcbc/util/io/PushbackStream.cs
new file mode 100644
index 0000000..ce34e79
--- /dev/null
+++ b/src/core/srcbc/util/io/PushbackStream.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class PushbackStream
+ : FilterStream
+ {
+ private int buf = -1;
+
+ public PushbackStream(
+ Stream s)
+ : base(s)
+ {
+ }
+
+ public override int ReadByte()
+ {
+ if (buf != -1)
+ {
+ int tmp = buf;
+ buf = -1;
+ return tmp;
+ }
+
+ return base.ReadByte();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (buf != -1 && count > 0)
+ {
+ // TODO Can this case be made more efficient?
+ buffer[offset] = (byte) buf;
+ buf = -1;
+ return 1;
+ }
+
+ return base.Read(buffer, offset, count);
+ }
+
+ public virtual void Unread(int b)
+ {
+ if (buf != -1)
+ throw new InvalidOperationException("Can only push back one byte");
+
+ buf = b & 0xFF;
+ }
+ }
+}
diff --git a/src/core/srcbc/util/io/Streams.cs b/src/core/srcbc/util/io/Streams.cs
new file mode 100644
index 0000000..38f2633
--- /dev/null
+++ b/src/core/srcbc/util/io/Streams.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public sealed class Streams
+ {
+ private const int BufferSize = 512;
+
+ private Streams()
+ {
+ }
+
+ public static void Drain(Stream inStr)
+ {
+ byte[] bs = new byte[BufferSize];
+ while (inStr.Read(bs, 0, bs.Length) > 0)
+ {
+ }
+ }
+
+ public static byte[] ReadAll(Stream inStr)
+ {
+ MemoryStream buf = new MemoryStream();
+ PipeAll(inStr, buf);
+ return buf.ToArray();
+ }
+
+ public static int ReadFully(Stream inStr, byte[] buf)
+ {
+ return ReadFully(inStr, buf, 0, buf.Length);
+ }
+
+ public static int ReadFully(Stream inStr, byte[] buf, int off, int len)
+ {
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int numRead = inStr.Read(buf, off + totalRead, len - totalRead);
+ if (numRead < 1)
+ break;
+ totalRead += numRead;
+ }
+ return totalRead;
+ }
+
+ public static void PipeAll(Stream inStr, Stream outStr)
+ {
+ byte[] bs = new byte[BufferSize];
+ int numRead;
+ while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
+ {
+ outStr.Write(bs, 0, numRead);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/util/net/IPAddress.cs b/src/core/srcbc/util/net/IPAddress.cs
new file mode 100644
index 0000000..08976f6
--- /dev/null
+++ b/src/core/srcbc/util/net/IPAddress.cs
@@ -0,0 +1,112 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Utilities.Net
+{
+ public class IPAddress
+ {
+ /**
+ * Validate the given IPv4 or IPv6 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid address, false otherwise
+ */
+ public static bool IsValid(
+ string address)
+ {
+ return IsValidIPv4(address) || IsValidIPv6(address);
+ }
+
+ /**
+ * Validate the given IPv4 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ private static bool IsValidIPv4(
+ string address)
+ {
+ if (address.Length == 0)
+ return false;
+
+ BigInteger octet;
+ int octets = 0;
+
+ string temp = address + ".";
+
+ int pos;
+ int start = 0;
+ while (start < temp.Length
+ && (pos = temp.IndexOf('.', start)) > start)
+ {
+ if (octets == 4)
+ return false;
+
+ try
+ {
+ octet = new BigInteger(temp.Substring(start, pos - start));
+ }
+ catch (FormatException)
+ {
+ return false;
+ }
+
+ if (octet.SignValue < 0 || octet.BitLength > 8)
+ return false;
+
+ start = pos + 1;
+ ++octets;
+ }
+
+ return octets == 4;
+ }
+
+ /**
+ * Validate the given IPv6 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ private static bool IsValidIPv6(
+ string address)
+ {
+ if (address.Length == 0)
+ return false;
+
+ BigInteger octet;
+ int octets = 0;
+
+ string temp = address + ":";
+
+ int pos;
+ int start = 0;
+ while (start < temp.Length
+ && (pos = temp.IndexOf(':', start)) > start)
+ {
+ if (octets == 8)
+ return false;
+
+ try
+ {
+ octet = new BigInteger(temp.Substring(start, pos - start), 16);
+ }
+ catch (FormatException)
+ {
+ return false;
+ }
+
+ if (octet.SignValue < 0 || octet.BitLength > 16)
+ return false;
+
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 8;
+ }
+ }
+}
diff --git a/src/core/srcbc/util/zlib/Adler32.cs b/src/core/srcbc/util/zlib/Adler32.cs
new file mode 100644
index 0000000..4926360
--- /dev/null
+++ b/src/core/srcbc/util/zlib/Adler32.cs
@@ -0,0 +1,88 @@
+using System;
+/*
+ * $Id: Adler32.cs,v 1.1.1.1 2007/01/24 16:41:26 psoares33 Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class Adler32{
+
+ // largest prime smaller than 65536
+ private const int BASE=65521;
+ // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+ private const int NMAX=5552;
+
+ internal long adler32(long adler, byte[] buf, int index, int len){
+ if(buf == null){ return 1L; }
+
+ long s1=adler&0xffff;
+ long s2=(adler>>16)&0xffff;
+ int k;
+
+ while(len > 0) {
+ k=len=16){
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ k-=16;
+ }
+ if(k!=0){
+ do{
+ s1+=buf[index++]&0xff; s2+=s1;
+ }
+ while(--k!=0);
+ }
+ s1%=BASE;
+ s2%=BASE;
+ }
+ return (s2<<16)|s1;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/zlib/Deflate.cs b/src/core/srcbc/util/zlib/Deflate.cs
new file mode 100644
index 0000000..d3c3143
--- /dev/null
+++ b/src/core/srcbc/util/zlib/Deflate.cs
@@ -0,0 +1,1640 @@
+using System;
+/*
+ * $Id: Deflate.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ public sealed class Deflate{
+
+ private const int MAX_MEM_LEVEL=9;
+
+ private const int Z_DEFAULT_COMPRESSION=-1;
+
+ private const int MAX_WBITS=15; // 32K LZ77 window
+ private const int DEF_MEM_LEVEL=8;
+
+ internal class Config{
+ internal int good_length; // reduce lazy search above this match length
+ internal int max_lazy; // do not perform lazy search above this match length
+ internal int nice_length; // quit search above this match length
+ internal int max_chain;
+ internal int func;
+ internal Config(int good_length, int max_lazy,
+ int nice_length, int max_chain, int func){
+ this.good_length=good_length;
+ this.max_lazy=max_lazy;
+ this.nice_length=nice_length;
+ this.max_chain=max_chain;
+ this.func=func;
+ }
+ }
+
+ private const int STORED=0;
+ private const int FAST=1;
+ private const int SLOW=2;
+ private static readonly Config[] config_table;
+
+ static Deflate(){
+ config_table=new Config[10];
+ // good lazy nice chain
+ config_table[0]=new Config(0, 0, 0, 0, STORED);
+ config_table[1]=new Config(4, 4, 8, 4, FAST);
+ config_table[2]=new Config(4, 5, 16, 8, FAST);
+ config_table[3]=new Config(4, 6, 32, 32, FAST);
+
+ config_table[4]=new Config(4, 4, 16, 16, SLOW);
+ config_table[5]=new Config(8, 16, 32, 32, SLOW);
+ config_table[6]=new Config(8, 16, 128, 128, SLOW);
+ config_table[7]=new Config(8, 32, 128, 256, SLOW);
+ config_table[8]=new Config(32, 128, 258, 1024, SLOW);
+ config_table[9]=new Config(32, 258, 258, 4096, SLOW);
+ }
+
+ private static readonly String[] z_errmsg = {
+ "need dictionary", // Z_NEED_DICT 2
+ "stream end", // Z_STREAM_END 1
+ "", // Z_OK 0
+ "file error", // Z_ERRNO (-1)
+ "stream error", // Z_STREAM_ERROR (-2)
+ "data error", // Z_DATA_ERROR (-3)
+ "insufficient memory", // Z_MEM_ERROR (-4)
+ "buffer error", // Z_BUF_ERROR (-5)
+ "incompatible version",// Z_VERSION_ERROR (-6)
+ ""
+ };
+
+ // block not completed, need more input or more output
+ private const int NeedMore=0;
+
+ // block flush performed
+ private const int BlockDone=1;
+
+ // finish started, need only more output at next deflate
+ private const int FinishStarted=2;
+
+ // finish done, accept no more input or output
+ private const int FinishDone=3;
+
+ // preset dictionary flag in zlib header
+ private const int PRESET_DICT=0x20;
+
+ private const int Z_FILTERED=1;
+ private const int Z_HUFFMAN_ONLY=2;
+ private const int Z_DEFAULT_STRATEGY=0;
+
+ private const int Z_NO_FLUSH=0;
+ private const int Z_PARTIAL_FLUSH=1;
+ private const int Z_SYNC_FLUSH=2;
+ private const int Z_FULL_FLUSH=3;
+ private const int Z_FINISH=4;
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int INIT_STATE=42;
+ private const int BUSY_STATE=113;
+ private const int FINISH_STATE=666;
+
+ // The deflate compression method
+ private const int Z_DEFLATED=8;
+
+ private const int STORED_BLOCK=0;
+ private const int STATIC_TREES=1;
+ private const int DYN_TREES=2;
+
+ // The three kinds of block type
+ private const int Z_BINARY=0;
+ private const int Z_ASCII=1;
+ private const int Z_UNKNOWN=2;
+
+ private const int Buf_size=8*2;
+
+ // repeat previous bit length 3-6 times (2 bits of repeat count)
+ private const int REP_3_6=16;
+
+ // repeat a zero length 3-10 times (3 bits of repeat count)
+ private const int REPZ_3_10=17;
+
+ // repeat a zero length 11-138 times (7 bits of repeat count)
+ private const int REPZ_11_138=18;
+
+ private const int MIN_MATCH=3;
+ private const int MAX_MATCH=258;
+ private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1);
+
+ private const int MAX_BITS=15;
+ private const int D_CODES=30;
+ private const int BL_CODES=19;
+ private const int LENGTH_CODES=29;
+ private const int LITERALS=256;
+ private const int L_CODES=(LITERALS+1+LENGTH_CODES);
+ private const int HEAP_SIZE=(2*L_CODES+1);
+
+ private const int END_BLOCK=256;
+
+ internal ZStream strm; // pointer back to this zlib stream
+ internal int status; // as the name implies
+ internal byte[] pending_buf; // output still pending
+ internal int pending_buf_size; // size of pending_buf
+ internal int pending_out; // next pending byte to output to the stream
+ internal int pending; // nb of bytes in the pending buffer
+ internal int noheader; // suppress zlib header and adler32
+ internal byte data_type; // UNKNOWN, BINARY or ASCII
+ internal byte method; // STORED (for zip only) or DEFLATED
+ internal int last_flush; // value of flush param for previous deflate call
+
+ internal int w_size; // LZ77 window size (32K by default)
+ internal int w_bits; // log2(w_size) (8..16)
+ internal int w_mask; // w_size - 1
+
+ internal byte[] window;
+ // Sliding window. Input bytes are read into the second half of the window,
+ // and move to the first half later to keep a dictionary of at least wSize
+ // bytes. With this organization, matches are limited to a distance of
+ // wSize-MAX_MATCH bytes, but this ensures that IO is always
+ // performed with a length multiple of the block size. Also, it limits
+ // the window size to 64K, which is quite useful on MSDOS.
+ // To do: use the user input buffer as sliding window.
+
+ internal int window_size;
+ // Actual size of window: 2*wSize, except when the user input buffer
+ // is directly used as sliding window.
+
+ internal short[] prev;
+ // Link to older string with same hash index. To limit the size of this
+ // array to 64K, this link is maintained only for the last 32K strings.
+ // An index in this array is thus a window index modulo 32K.
+
+ internal short[] head; // Heads of the hash chains or NIL.
+
+ internal int ins_h; // hash index of string to be inserted
+ internal int hash_size; // number of elements in hash table
+ internal int hash_bits; // log2(hash_size)
+ internal int hash_mask; // hash_size-1
+
+ // Number of bits by which ins_h must be shifted at each input
+ // step. It must be such that after MIN_MATCH steps, the oldest
+ // byte no longer takes part in the hash key, that is:
+ // hash_shift * MIN_MATCH >= hash_bits
+ internal int hash_shift;
+
+ // Window position at the beginning of the current output block. Gets
+ // negative when the window is moved backwards.
+
+ internal int block_start;
+
+ internal int match_length; // length of best match
+ internal int prev_match; // previous match
+ internal int match_available; // set if previous match exists
+ internal int strstart; // start of string to insert
+ internal int match_start; // start of matching string
+ internal int lookahead; // number of valid bytes ahead in window
+
+ // Length of the best match at previous step. Matches not greater than this
+ // are discarded. This is used in the lazy match evaluation.
+ internal int prev_length;
+
+ // To speed up deflation, hash chains are never searched beyond this
+ // length. A higher limit improves compression ratio but degrades the speed.
+ internal int max_chain_length;
+
+ // Attempt to find a better match only when the current match is strictly
+ // smaller than this value. This mechanism is used only for compression
+ // levels >= 4.
+ internal int max_lazy_match;
+
+ // Insert new strings in the hash table only if the match length is not
+ // greater than this length. This saves time but degrades compression.
+ // max_insert_length is used only for compression levels <= 3.
+
+ internal int level; // compression level (1..9)
+ internal int strategy; // favor or force Huffman coding
+
+ // Use a faster search when the previous match is longer than this
+ internal int good_match;
+
+ // Stop searching when current match exceeds this
+ internal int nice_match;
+
+ internal short[] dyn_ltree; // literal and length tree
+ internal short[] dyn_dtree; // distance tree
+ internal short[] bl_tree; // Huffman tree for bit lengths
+
+ internal Tree l_desc=new Tree(); // desc for literal tree
+ internal Tree d_desc=new Tree(); // desc for distance tree
+ internal Tree bl_desc=new Tree(); // desc for bit length tree
+
+ // number of codes at each bit length for an optimal tree
+ internal short[] bl_count=new short[MAX_BITS+1];
+
+ // heap used to build the Huffman trees
+ internal int[] heap=new int[2*L_CODES+1];
+
+ internal int heap_len; // number of elements in the heap
+ internal int heap_max; // element of largest frequency
+ // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ // The same heap array is used to build all trees.
+
+ // Depth of each subtree used as tie breaker for trees of equal frequency
+ internal byte[] depth=new byte[2*L_CODES+1];
+
+ internal int l_buf; // index for literals or lengths */
+
+ // Size of match buffer for literals/lengths. There are 4 reasons for
+ // limiting lit_bufsize to 64K:
+ // - frequencies can be kept in 16 bit counters
+ // - if compression is not successful for the first block, all input
+ // data is still in the window so we can still emit a stored block even
+ // when input comes from standard input. (This can also be done for
+ // all blocks if lit_bufsize is not greater than 32K.)
+ // - if compression is not successful for a file smaller than 64K, we can
+ // even emit a stored file instead of a stored block (saving 5 bytes).
+ // This is applicable only for zip (not gzip or zlib).
+ // - creating new Huffman trees less frequently may not provide fast
+ // adaptation to changes in the input data statistics. (Take for
+ // example a binary file with poorly compressible code followed by
+ // a highly compressible string table.) Smaller buffer sizes give
+ // fast adaptation but have of course the overhead of transmitting
+ // trees more frequently.
+ // - I can't count above 4
+ internal int lit_bufsize;
+
+ internal int last_lit; // running index in l_buf
+
+ // Buffer for distances. To simplify the code, d_buf and l_buf have
+ // the same number of elements. To use different lengths, an extra flag
+ // array would be necessary.
+
+ internal int d_buf; // index of pendig_buf
+
+ internal int opt_len; // bit length of current block with optimal trees
+ internal int static_len; // bit length of current block with static trees
+ internal int matches; // number of string matches in current block
+ internal int last_eob_len; // bit length of EOB code for last block
+
+ // Output buffer. bits are inserted starting at the bottom (least
+ // significant bits).
+ internal uint bi_buf;
+
+ // Number of valid bits in bi_buf. All bits above the last valid bit
+ // are always zero.
+ internal int bi_valid;
+
+ internal Deflate(){
+ dyn_ltree=new short[HEAP_SIZE*2];
+ dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
+ bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths
+ }
+
+ internal void lm_init() {
+ window_size=2*w_size;
+
+ head[hash_size-1]=0;
+ for(int i=0; i= 3; max_blindex--) {
+ if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break;
+ }
+ // Update opt_len to include the bit length tree and counts
+ opt_len += 3*(max_blindex+1) + 5+5+4;
+
+ return max_blindex;
+ }
+
+
+ // Send the header for a block using dynamic Huffman trees: the counts, the
+ // lengths of the bit length codes, the literal tree and the distance tree.
+ // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ internal void send_all_trees(int lcodes, int dcodes, int blcodes){
+ int rank; // index in bl_order
+
+ send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
+ send_bits(dcodes-1, 5);
+ send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt
+ for (rank = 0; rank < blcodes; rank++) {
+ send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3);
+ }
+ send_tree(dyn_ltree, lcodes-1); // literal tree
+ send_tree(dyn_dtree, dcodes-1); // distance tree
+ }
+
+ // Send a literal or distance tree in compressed form, using the codes in
+ // bl_tree.
+ internal void send_tree (short[] tree,// the tree to be sent
+ int max_code // and its largest code of non zero frequency
+ ){
+ int n; // iterates over all tree elements
+ int prevlen = -1; // last emitted length
+ int curlen; // length of current code
+ int nextlen = tree[0*2+1]; // length of next code
+ int count = 0; // repeat count of the current code
+ int max_count = 7; // max repeat count
+ int min_count = 4; // min repeat count
+
+ if (nextlen == 0){ max_count = 138; min_count = 3; }
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[(n+1)*2+1];
+ if(++count < max_count && curlen == nextlen) {
+ continue;
+ }
+ else if(count < min_count) {
+ do { send_code(curlen, bl_tree); } while (--count != 0);
+ }
+ else if(curlen != 0){
+ if(curlen != prevlen){
+ send_code(curlen, bl_tree); count--;
+ }
+ send_code(REP_3_6, bl_tree);
+ send_bits(count-3, 2);
+ }
+ else if(count <= 10){
+ send_code(REPZ_3_10, bl_tree);
+ send_bits(count-3, 3);
+ }
+ else{
+ send_code(REPZ_11_138, bl_tree);
+ send_bits(count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if(nextlen == 0){
+ max_count = 138; min_count = 3;
+ }
+ else if(curlen == nextlen){
+ max_count = 6; min_count = 3;
+ }
+ else{
+ max_count = 7; min_count = 4;
+ }
+ }
+ }
+
+ // Output a byte on the stream.
+ // IN assertion: there is enough room in pending_buf.
+ internal void put_byte(byte[] p, int start, int len){
+ System.Array.Copy(p, start, pending_buf, pending, len);
+ pending+=len;
+ }
+
+ internal void put_byte(byte c){
+ pending_buf[pending++]=c;
+ }
+ internal void put_short(int w) {
+ pending_buf[pending++]=(byte)(w/*&0xff*/);
+ pending_buf[pending++]=(byte)(w>>8);
+ }
+ internal void putShortMSB(int b){
+ pending_buf[pending++]=(byte)(b>>8);
+ pending_buf[pending++]=(byte)(b/*&0xff*/);
+ }
+
+ internal void send_code(int c, short[] tree){
+ int c2=c*2;
+ send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff));
+ }
+
+ internal void send_bits(int val, int length){
+ if (bi_valid > Buf_size - length) {
+ bi_buf |= (uint)(val << bi_valid);
+ pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ bi_buf = ((uint)val) >> (Buf_size - bi_valid);
+ bi_valid += length - Buf_size;
+ } else {
+ bi_buf |= (uint)(val << bi_valid);
+ bi_valid += length;
+ }
+// int len = length;
+// if (bi_valid > (int)Buf_size - len) {
+// int val = value;
+// // bi_buf |= (val << bi_valid);
+// bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff));
+// put_short(bi_buf);
+// bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid));
+// bi_valid += len - Buf_size;
+// } else {
+// // bi_buf |= (value) << bi_valid;
+// bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff));
+// bi_valid += len;
+// }
+ }
+
+ // Send one empty static block to give enough lookahead for inflate.
+ // This takes 10 bits, of which 7 may remain in the bit buffer.
+ // The current inflate code requires 9 bits of lookahead. If the
+ // last two codes for the previous block (real code plus EOB) were coded
+ // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ // the last real code. In this case we send two empty static blocks instead
+ // of one. (There are no problems if the previous block is stored or fixed.)
+ // To simplify the code, we assume the worst case of last real code encoded
+ // on one bit only.
+ internal void _tr_align(){
+ send_bits(STATIC_TREES<<1, 3);
+ send_code(END_BLOCK, StaticTree.static_ltree);
+
+ bi_flush();
+
+ // Of the 10 bits for the empty block, we have already sent
+ // (10 - bi_valid) bits. The lookahead for the last real code (before
+ // the EOB of the previous block) was thus at least one plus the length
+ // of the EOB plus what we have just sent of the empty static block.
+ if (1 + last_eob_len + 10 - bi_valid < 9) {
+ send_bits(STATIC_TREES<<1, 3);
+ send_code(END_BLOCK, StaticTree.static_ltree);
+ bi_flush();
+ }
+ last_eob_len = 7;
+ }
+
+
+ // Save the match info and tally the frequency counts. Return true if
+ // the current block must be flushed.
+ internal bool _tr_tally (int dist, // distance of matched string
+ int lc // match length-MIN_MATCH or unmatched char (if dist==0)
+ ){
+
+ pending_buf[d_buf+last_lit*2] = (byte)(dist>>8);
+ pending_buf[d_buf+last_lit*2+1] = (byte)dist;
+
+ pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
+
+ if (dist == 0) {
+ // lc is the unmatched char
+ dyn_ltree[lc*2]++;
+ }
+ else {
+ matches++;
+ // Here, lc is the match length - MIN_MATCH
+ dist--; // dist = match distance - 1
+ dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++;
+ dyn_dtree[Tree.d_code(dist)*2]++;
+ }
+
+ if ((last_lit & 0x1fff) == 0 && level > 2) {
+ // Compute an upper bound for the compressed length
+ int out_length = last_lit*8;
+ int in_length = strstart - block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (int)((int)dyn_dtree[dcode*2] *
+ (5L+Tree.extra_dbits[dcode]));
+ }
+ out_length >>= 3;
+ if ((matches < (last_lit/2)) && out_length < in_length/2) return true;
+ }
+
+ return (last_lit == lit_bufsize-1);
+ // We avoid equality with lit_bufsize because of wraparound at 64K
+ // on 16 bit machines and because stored blocks are restricted to
+ // 64K-1 bytes.
+ }
+
+ // Send the block data compressed using the given Huffman trees
+ internal void compress_block(short[] ltree, short[] dtree){
+ int dist; // distance of matched string
+ int lc; // match length or unmatched char (if dist == 0)
+ int lx = 0; // running index in l_buf
+ int code; // the code to send
+ int extra; // number of extra bits to send
+
+ if (last_lit != 0){
+ do{
+ dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
+ (pending_buf[d_buf+lx*2+1]&0xff);
+ lc=(pending_buf[l_buf+lx])&0xff; lx++;
+
+ if(dist == 0){
+ send_code(lc, ltree); // send a literal byte
+ }
+ else{
+ // Here, lc is the match length - MIN_MATCH
+ code = Tree._length_code[lc];
+
+ send_code(code+LITERALS+1, ltree); // send the length code
+ extra = Tree.extra_lbits[code];
+ if(extra != 0){
+ lc -= Tree.base_length[code];
+ send_bits(lc, extra); // send the extra length bits
+ }
+ dist--; // dist is now the match distance - 1
+ code = Tree.d_code(dist);
+
+ send_code(code, dtree); // send the distance code
+ extra = Tree.extra_dbits[code];
+ if (extra != 0) {
+ dist -= Tree.base_dist[code];
+ send_bits(dist, extra); // send the extra distance bits
+ }
+ } // literal or match pair ?
+
+ // Check that the overlay between pending_buf and d_buf+l_buf is ok:
+ }
+ while (lx < last_lit);
+ }
+
+ send_code(END_BLOCK, ltree);
+ last_eob_len = ltree[END_BLOCK*2+1];
+ }
+
+ // Set the data type to ASCII or BINARY, using a crude approximation:
+ // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ // IN assertion: the fields freq of dyn_ltree are set and the total of all
+ // frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ internal void set_data_type(){
+ int n = 0;
+ int ascii_freq = 0;
+ int bin_freq = 0;
+ while(n<7){ bin_freq += dyn_ltree[n*2]; n++;}
+ while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;}
+ while(n (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+ }
+
+ // Flush the bit buffer, keeping at most 7 bits in it.
+ internal void bi_flush(){
+ if (bi_valid == 16) {
+ pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ bi_buf=0;
+ bi_valid=0;
+ }
+ else if (bi_valid >= 8) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ bi_buf>>=8;
+ bi_buf &= 0x00ff;
+ bi_valid-=8;
+ }
+ }
+
+ // Flush the bit buffer and align the output on a byte boundary
+ internal void bi_windup(){
+ if (bi_valid > 8) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ } else if (bi_valid > 0) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ }
+ bi_buf = 0;
+ bi_valid = 0;
+ }
+
+ // Copy a stored block, storing first the length and its
+ // one's complement if requested.
+ internal void copy_block(int buf, // the input data
+ int len, // its length
+ bool header // true if block header must be written
+ ){
+ //int index=0;
+ bi_windup(); // align on byte boundary
+ last_eob_len = 8; // enough lookahead for inflate
+
+ if (header) {
+ put_short((short)len);
+ put_short((short)~len);
+ }
+
+ // while(len--!=0) {
+ // put_byte(window[buf+index]);
+ // index++;
+ // }
+ put_byte(window, buf, len);
+ }
+
+ internal void flush_block_only(bool eof){
+ _tr_flush_block(block_start>=0 ? block_start : -1,
+ strstart-block_start,
+ eof);
+ block_start=strstart;
+ strm.flush_pending();
+ }
+
+ // Copy without compression as much as possible from the input stream, return
+ // the current block state.
+ // This function does not insert new strings in the dictionary since
+ // uncompressible data is probably not useful. This function is used
+ // only for the level=0 compression option.
+ // NOTE: this function should be optimized to avoid extra copying from
+ // window to pending_buf.
+ internal int deflate_stored(int flush){
+ // Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ // to pending_buf_size, and each stored block has a 5 byte header:
+
+ int max_block_size = 0xffff;
+ int max_start;
+
+ if(max_block_size > pending_buf_size - 5) {
+ max_block_size = pending_buf_size - 5;
+ }
+
+ // Copy as much as possible from input to output:
+ while(true){
+ // Fill the window as much as possible:
+ if(lookahead<=1){
+ fill_window();
+ if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore;
+ if(lookahead==0) break; // flush the current block
+ }
+
+ strstart+=lookahead;
+ lookahead=0;
+
+ // Emit a stored block if pending_buf will be full:
+ max_start=block_start+max_block_size;
+ if(strstart==0|| strstart>=max_start) {
+ // strstart == 0 is possible when wraparound on 16-bit machine
+ lookahead = (int)(strstart-max_start);
+ strstart = (int)max_start;
+
+ flush_block_only(false);
+ if(strm.avail_out==0) return NeedMore;
+
+ }
+
+ // Flush if we may have to slide, otherwise block_start may become
+ // negative and the data will be gone:
+ if(strstart-block_start >= w_size-MIN_LOOKAHEAD) {
+ flush_block_only(false);
+ if(strm.avail_out==0) return NeedMore;
+ }
+ }
+
+ flush_block_only(flush == Z_FINISH);
+ if(strm.avail_out==0)
+ return (flush == Z_FINISH) ? FinishStarted : NeedMore;
+
+ return flush == Z_FINISH ? FinishDone : BlockDone;
+ }
+
+ // Send a stored block
+ internal void _tr_stored_block(int buf, // input block
+ int stored_len, // length of input block
+ bool eof // true if this is the last block for a file
+ ){
+ send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type
+ copy_block(buf, stored_len, true); // with header
+ }
+
+ // Determine the best encoding for the current block: dynamic trees, static
+ // trees or store, and output the encoded block to the zip file.
+ internal void _tr_flush_block(int buf, // input block, or NULL if too old
+ int stored_len, // length of input block
+ bool eof // true if this is the last block for a file
+ ) {
+ int opt_lenb, static_lenb;// opt_len and static_len in bytes
+ int max_blindex = 0; // index of last bit length code of non zero freq
+
+ // Build the Huffman trees unless a stored block is forced
+ if(level > 0) {
+ // Check if the file is ascii or binary
+ if(data_type == Z_UNKNOWN) set_data_type();
+
+ // Construct the literal and distance trees
+ l_desc.build_tree(this);
+
+ d_desc.build_tree(this);
+
+ // At this point, opt_len and static_len are the total bit lengths of
+ // the compressed block data, excluding the tree representations.
+
+ // Build the bit length tree for the above two trees, and get the index
+ // in bl_order of the last bit length code to send.
+ max_blindex=build_bl_tree();
+
+ // Determine the best encoding. Compute first the block length in bytes
+ opt_lenb=(opt_len+3+7)>>3;
+ static_lenb=(static_len+3+7)>>3;
+
+ if(static_lenb<=opt_lenb) opt_lenb=static_lenb;
+ }
+ else {
+ opt_lenb=static_lenb=stored_len+5; // force a stored block
+ }
+
+ if(stored_len+4<=opt_lenb && buf != -1){
+ // 4: two words for the lengths
+ // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ // Otherwise we can't have processed more than WSIZE input bytes since
+ // the last block flush, because compression would have been
+ // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ // transform a block into a stored block.
+ _tr_stored_block(buf, stored_len, eof);
+ }
+ else if(static_lenb == opt_lenb){
+ send_bits((STATIC_TREES<<1)+(eof?1:0), 3);
+ compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
+ }
+ else{
+ send_bits((DYN_TREES<<1)+(eof?1:0), 3);
+ send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+ compress_block(dyn_ltree, dyn_dtree);
+ }
+
+ // The above check is made mod 2^32, for files larger than 512 MB
+ // and uLong implemented on 32 bits.
+
+ init_block();
+
+ if(eof){
+ bi_windup();
+ }
+ }
+
+ // Fill the window when the lookahead becomes insufficient.
+ // Updates strstart and lookahead.
+ //
+ // IN assertion: lookahead < MIN_LOOKAHEAD
+ // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ // At least one byte has been read, or avail_in == 0; reads are
+ // performed for at least two bytes (required for the zip translate_eol
+ // option -- not supported here).
+ internal void fill_window(){
+ int n, m;
+ int p;
+ int more; // Amount of free space at the end of the window.
+
+ do{
+ more = (window_size-lookahead-strstart);
+
+ // Deal with !@#$% 64K limit:
+ if(more==0 && strstart==0 && lookahead==0){
+ more = w_size;
+ }
+ else if(more==-1) {
+ // Very unlikely, but possible on 16 bit machine if strstart == 0
+ // and lookahead == 1 (input done one byte at time)
+ more--;
+
+ // If the window is almost full and there is insufficient lookahead,
+ // move the upper half to the lower one to make room in the upper half.
+ }
+ else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) {
+ System.Array.Copy(window, w_size, window, 0, w_size);
+ match_start-=w_size;
+ strstart-=w_size; // we now have strstart >= MAX_DIST
+ block_start-=w_size;
+
+ // Slide the hash table (could be avoided with 32 bit values
+ // at the expense of memory usage). We slide even when level == 0
+ // to keep the hash table consistent if we switch back to level > 0
+ // later. (Using level 0 permanently is not an optimal usage of
+ // zlib, so we don't care about this pathological case.)
+
+ n = hash_size;
+ p=n;
+ do {
+ m = (head[--p]&0xffff);
+ head[p]=(short)(m>=w_size ? (m-w_size) : 0);
+ }
+ while (--n != 0);
+
+ n = w_size;
+ p = n;
+ do {
+ m = (prev[--p]&0xffff);
+ prev[p] = (short)(m >= w_size ? (m-w_size) : 0);
+ // If n is not on any hash chain, prev[n] is garbage but
+ // its value will never be used.
+ }
+ while (--n!=0);
+ more += w_size;
+ }
+
+ if (strm.avail_in == 0) return;
+
+ // If there was no sliding:
+ // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ // more == window_size - lookahead - strstart
+ // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ // => more >= window_size - 2*WSIZE + 2
+ // In the BIG_MEM or MMAP case (not yet supported),
+ // window_size == input_size + MIN_LOOKAHEAD &&
+ // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ // Otherwise, window_size == 2*WSIZE so more >= 2.
+ // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+
+ n = strm.read_buf(window, strstart + lookahead, more);
+ lookahead += n;
+
+ // Initialize the hash value now that we have some input:
+ if(lookahead >= MIN_MATCH) {
+ ins_h = window[strstart]&0xff;
+ ins_h=(((ins_h)<= MIN_MATCH){
+ ins_h=(((ins_h)<=MIN_MATCH){
+ // check_match(strstart, match_start, match_length);
+
+ bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH);
+
+ lookahead -= match_length;
+
+ // Insert new strings in the hash table only if the match length
+ // is not too large. This saves time but degrades compression.
+ if(match_length <= max_lazy_match &&
+ lookahead >= MIN_MATCH) {
+ match_length--; // string at strstart already in hash table
+ do{
+ strstart++;
+
+ ins_h=((ins_h<= MIN_MATCH) {
+ ins_h=(((ins_h)< 4096))) {
+
+ // If prev_match is also MIN_MATCH, match_start is garbage
+ // but we will ignore the current match anyway.
+ match_length = MIN_MATCH-1;
+ }
+ }
+
+ // If there was a match at the previous step and the current
+ // match is not better, output the previous match:
+ if(prev_length >= MIN_MATCH && match_length <= prev_length) {
+ int max_insert = strstart + lookahead - MIN_MATCH;
+ // Do not insert strings in hash table beyond this.
+
+ // check_match(strstart-1, prev_match, prev_length);
+
+ bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+ // Insert in hash table all strings up to the end of the match.
+ // strstart-1 and strstart are already inserted. If there is not
+ // enough lookahead, the last two strings are not inserted in
+ // the hash table.
+ lookahead -= prev_length-1;
+ prev_length -= 2;
+ do{
+ if(++strstart <= max_insert) {
+ ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ?
+ strstart-(w_size-MIN_LOOKAHEAD) : 0;
+ int nice_match=this.nice_match;
+
+ // Stop when cur_match becomes <= limit. To simplify the code,
+ // we prevent matches with the string of window index 0.
+
+ int wmask = w_mask;
+
+ int strend = strstart + MAX_MATCH;
+ byte scan_end1 = window[scan+best_len-1];
+ byte scan_end = window[scan+best_len];
+
+ // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ // It is easy to get rid of this optimization if necessary.
+
+ // Do not waste too much time if we already have a good match:
+ if (prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+
+ // Do not look for matches beyond the end of the input. This is necessary
+ // to make deflate deterministic.
+ if (nice_match > lookahead) nice_match = lookahead;
+
+ do {
+ match = cur_match;
+
+ // Skip to next match if the match length cannot increase
+ // or if the match length is less than 2:
+ if (window[match+best_len] != scan_end ||
+ window[match+best_len-1] != scan_end1 ||
+ window[match] != window[scan] ||
+ window[++match] != window[scan+1]) continue;
+
+ // The check at best_len-1 can be removed because it will be made
+ // again later. (This heuristic is not always a win.)
+ // It is not necessary to compare scan[2] and match[2] since they
+ // are always equal when the other bytes match, given that
+ // the hash keys are equal and that HASH_BITS >= 8.
+ scan += 2; match++;
+
+ // We check for insufficient lookahead only every 8th comparison;
+ // the 256th check will be made at strstart+258.
+ do {
+ } while (window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ scan < strend);
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+ if(len>best_len) {
+ match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+ scan_end1 = window[scan+best_len-1];
+ scan_end = window[scan+best_len];
+ }
+
+ } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit
+ && --chain_length != 0);
+
+ if (best_len <= lookahead) return best_len;
+ return lookahead;
+ }
+
+ internal int deflateInit(ZStream strm, int level, int bits){
+ return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY);
+ }
+ internal int deflateInit(ZStream strm, int level){
+ return deflateInit(strm, level, MAX_WBITS);
+ }
+ internal int deflateInit2(ZStream strm, int level, int method, int windowBits,
+ int memLevel, int strategy){
+ int noheader = 0;
+ // byte[] my_version=ZLIB_VERSION;
+
+ //
+ // if (version == null || version[0] != my_version[0]
+ // || stream_size != sizeof(z_stream)) {
+ // return Z_VERSION_ERROR;
+ // }
+
+ strm.msg = null;
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+ if (windowBits < 0) { // undocumented feature: suppress zlib header
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL ||
+ method != Z_DEFLATED ||
+ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm.dstate = (Deflate)this;
+
+ this.noheader = noheader;
+ w_bits = windowBits;
+ w_size = 1 << w_bits;
+ w_mask = w_size - 1;
+
+ hash_bits = memLevel + 7;
+ hash_size = 1 << hash_bits;
+ hash_mask = hash_size - 1;
+ hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ window = new byte[w_size*2];
+ prev = new short[w_size];
+ head = new short[hash_size];
+
+ lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
+
+ // We overlay pending_buf and d_buf+l_buf. This works since the average
+ // output size for (length,distance) codes is <= 24 bits.
+ pending_buf = new byte[lit_bufsize*4];
+ pending_buf_size = lit_bufsize*4;
+
+ d_buf = lit_bufsize/2;
+ l_buf = (1+2)*lit_bufsize;
+
+ this.level = level;
+
+ //System.out.println("level="+level);
+
+ this.strategy = strategy;
+ this.method = (byte)method;
+
+ return deflateReset(strm);
+ }
+
+ internal int deflateReset(ZStream strm){
+ strm.total_in = strm.total_out = 0;
+ strm.msg = null; //
+ strm.data_type = Z_UNKNOWN;
+
+ pending = 0;
+ pending_out = 0;
+
+ if(noheader < 0) {
+ noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
+ }
+ status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
+ strm.adler=strm._adler.adler32(0, null, 0, 0);
+
+ last_flush = Z_NO_FLUSH;
+
+ tr_init();
+ lm_init();
+ return Z_OK;
+ }
+
+ internal int deflateEnd(){
+ if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){
+ return Z_STREAM_ERROR;
+ }
+ // Deallocate in reverse order of allocations:
+ pending_buf=null;
+ head=null;
+ prev=null;
+ window=null;
+ // free
+ // dstate=null;
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+ }
+
+ internal int deflateParams(ZStream strm, int _level, int _strategy){
+ int err=Z_OK;
+
+ if(_level == Z_DEFAULT_COMPRESSION){
+ _level = 6;
+ }
+ if(_level < 0 || _level > 9 ||
+ _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+
+ if(config_table[level].func!=config_table[_level].func &&
+ strm.total_in != 0) {
+ // Flush the last buffer:
+ err = strm.deflate(Z_PARTIAL_FLUSH);
+ }
+
+ if(level != _level) {
+ level = _level;
+ max_lazy_match = config_table[level].max_lazy;
+ good_match = config_table[level].good_length;
+ nice_match = config_table[level].nice_length;
+ max_chain_length = config_table[level].max_chain;
+ }
+ strategy = _strategy;
+ return err;
+ }
+
+ internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
+ int length = dictLength;
+ int index=0;
+
+ if(dictionary == null || status != INIT_STATE)
+ return Z_STREAM_ERROR;
+
+ strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
+
+ if(length < MIN_MATCH) return Z_OK;
+ if(length > w_size-MIN_LOOKAHEAD){
+ length = w_size-MIN_LOOKAHEAD;
+ index=dictLength-length; // use the tail of the dictionary
+ }
+ System.Array.Copy(dictionary, index, window, 0, length);
+ strstart = length;
+ block_start = length;
+
+ // Insert all strings in the hash table (except for the last two bytes).
+ // s->lookahead stays null, so s->ins_h will be recomputed at the next
+ // call of fill_window.
+
+ ins_h = window[0]&0xff;
+ ins_h=(((ins_h)<Z_FINISH || flush<0){
+ return Z_STREAM_ERROR;
+ }
+
+ if(strm.next_out == null ||
+ (strm.next_in == null && strm.avail_in != 0) ||
+ (status == FINISH_STATE && flush != Z_FINISH)) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)];
+ return Z_STREAM_ERROR;
+ }
+ if(strm.avail_out == 0){
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ this.strm = strm; // just in case
+ old_flush = last_flush;
+ last_flush = flush;
+
+ // Write the zlib header
+ if(status == INIT_STATE) {
+ int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
+ int level_flags=((level-1)&0xff)>>1;
+
+ if(level_flags>3) level_flags=3;
+ header |= (level_flags<<6);
+ if(strstart!=0) header |= PRESET_DICT;
+ header+=31-(header % 31);
+
+ status=BUSY_STATE;
+ putShortMSB(header);
+
+
+ // Save the adler32 of the preset dictionary:
+ if(strstart!=0){
+ putShortMSB((int)(strm.adler>>16));
+ putShortMSB((int)(strm.adler&0xffff));
+ }
+ strm.adler=strm._adler.adler32(0, null, 0, 0);
+ }
+
+ // Flush as much pending output as possible
+ if(pending != 0) {
+ strm.flush_pending();
+ if(strm.avail_out == 0) {
+ //System.out.println(" avail_out==0");
+ // Since avail_out is 0, deflate will be called again with
+ // more output space, but possibly with both pending and
+ // avail_in equal to zero. There won't be anything to do,
+ // but this is not an error situation so make sure we
+ // return OK instead of BUF_ERROR at next call of deflate:
+ last_flush = -1;
+ return Z_OK;
+ }
+
+ // Make sure there is something to do and avoid duplicate consecutive
+ // flushes. For repeated and useless calls with Z_FINISH, we keep
+ // returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ }
+ else if(strm.avail_in==0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ // User must not provide more input after the first FINISH:
+ if(status == FINISH_STATE && strm.avail_in != 0) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ // Start a new block or continue the current one.
+ if(strm.avail_in!=0 || lookahead!=0 ||
+ (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
+ int bstate=-1;
+ switch(config_table[level].func){
+ case STORED:
+ bstate = deflate_stored(flush);
+ break;
+ case FAST:
+ bstate = deflate_fast(flush);
+ break;
+ case SLOW:
+ bstate = deflate_slow(flush);
+ break;
+ default:
+ break;
+ }
+
+ if (bstate==FinishStarted || bstate==FinishDone) {
+ status = FINISH_STATE;
+ }
+ if (bstate==NeedMore || bstate==FinishStarted) {
+ if(strm.avail_out == 0) {
+ last_flush = -1; // avoid BUF_ERROR next call, see above
+ }
+ return Z_OK;
+ // If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ // of deflate should use the same flush parameter to make sure
+ // that the flush is complete. So we don't have to output an
+ // empty block here, this will be done at next call. This also
+ // ensures that for a very small output buffer, we emit at most
+ // one empty block.
+ }
+
+ if (bstate==BlockDone) {
+ if(flush == Z_PARTIAL_FLUSH) {
+ _tr_align();
+ }
+ else { // FULL_FLUSH or SYNC_FLUSH
+ _tr_stored_block(0, 0, false);
+ // For a full flush, this empty block will be recognized
+ // as a special marker by inflate_sync().
+ if(flush == Z_FULL_FLUSH) {
+ //state.head[s.hash_size-1]=0;
+ for(int i=0; i>16));
+ putShortMSB((int)(strm.adler&0xffff));
+ strm.flush_pending();
+
+ // If avail_out is zero, the application will call deflate again
+ // to flush the rest.
+ noheader = -1; // write the trailer only once!
+ return pending != 0 ? Z_OK : Z_STREAM_END;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/zlib/InfBlocks.cs b/src/core/srcbc/util/zlib/InfBlocks.cs
new file mode 100644
index 0000000..333c701
--- /dev/null
+++ b/src/core/srcbc/util/zlib/InfBlocks.cs
@@ -0,0 +1,618 @@
+using System;
+/*
+ * $Id: InfBlocks.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfBlocks{
+ private const int MANY=1440;
+
+ // And'ing with mask[n] masks the lower n bits
+ private static readonly int[] inflate_mask = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+ 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+ 0x00007fff, 0x0000ffff
+ };
+
+ // Table for deflate from PKZIP's appnote.txt.
+ static readonly int[] border = { // Order of the bit length code lengths
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+ };
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int TYPE=0; // get type bits (3, including end bit)
+ private const int LENS=1; // get lengths for stored
+ private const int STORED=2;// processing stored block
+ private const int TABLE=3; // get table lengths
+ private const int BTREE=4; // get bit lengths tree for a dynamic block
+ private const int DTREE=5; // get length, distance trees for a dynamic block
+ private const int CODES=6; // processing fixed or dynamic block
+ private const int DRY=7; // output remaining window bytes
+ private const int DONE=8; // finished last block, done
+ private const int BAD=9; // ot a data error--stuck here
+
+ internal int mode; // current inflate_block mode
+
+ internal int left; // if STORED, bytes left to copy
+
+ internal int table; // table lengths (14 bits)
+ internal int index; // index into blens (or border)
+ internal int[] blens; // bit lengths of codes
+ internal int[] bb=new int[1]; // bit length tree depth
+ internal int[] tb=new int[1]; // bit length decoding tree
+
+ internal InfCodes codes=new InfCodes(); // if CODES, current state
+
+ int last; // true if this block is the last block
+
+ // mode independent information
+ internal int bitk; // bits in bit buffer
+ internal int bitb; // bit buffer
+ internal int[] hufts; // single malloc for tree space
+ internal byte[] window; // sliding window
+ internal int end; // one byte after sliding window
+ internal int read; // window read pointer
+ internal int write; // window write pointer
+ internal Object checkfn; // check function
+ internal long check; // check on output
+
+ internal InfTree inftree=new InfTree();
+
+ internal InfBlocks(ZStream z, Object checkfn, int w){
+ hufts=new int[MANY*3];
+ window=new byte[w];
+ end=w;
+ this.checkfn = checkfn;
+ mode = TYPE;
+ reset(z, null);
+ }
+
+ internal void reset(ZStream z, long[] c){
+ if(c!=null) c[0]=check;
+ if(mode==BTREE || mode==DTREE){
+ }
+ if(mode==CODES){
+ codes.free(z);
+ }
+ mode=TYPE;
+ bitk=0;
+ bitb=0;
+ read=write=0;
+
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(0L, null, 0, 0);
+ }
+
+ internal int proc(ZStream z, int r){
+ int t; // temporary storage
+ int b; // bit buffer
+ int k; // bits in bit buffer
+ int p; // input data pointer
+ int n; // bytes available there
+ int q; // output window write pointer
+ int m; { // bytes to end of window or read pointer
+
+ // copy input/output information to locals (UPDATE macro restores)
+ p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} {
+ q=write;m=(int)(q> 1){
+ case 0: { // stored
+ b>>=(3);k-=(3);}
+ t = k & 7; { // go to byte boundary
+
+ b>>=(t);k-=(t);}
+ mode = LENS; // get length of stored block
+ break;
+ case 1: { // fixed
+ int[] bl=new int[1];
+ int[] bd=new int[1];
+ int[][] tl=new int[1][];
+ int[][] td=new int[1][];
+
+ InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
+ codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
+ } {
+
+ b>>=(3);k-=(3);}
+
+ mode = CODES;
+ break;
+ case 2: { // dynamic
+
+ b>>=(3);k-=(3);}
+
+ mode = TABLE;
+ break;
+ case 3: { // illegal
+
+ b>>=(3);k-=(3);}
+ mode = BAD;
+ z.msg = "invalid block type";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ break;
+ case LENS:
+
+ while(k<(32)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<> 16) & 0xffff) != (b & 0xffff)){
+ mode = BAD;
+ z.msg = "invalid stored block lengths";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ left = (b & 0xffff);
+ b = k = 0; // dump bits
+ mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0){
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ if(m==0){
+ if(q==end&&read!=0){
+ q=0; m=(int)(qn) t = n;
+ if(t>m) t = m;
+ System.Array.Copy(z.next_in, p, window, q, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((left -= t) != 0)
+ break;
+ mode = last!=0 ? DRY : TYPE;
+ break;
+ case TABLE:
+
+ while(k<(14)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) {
+ mode = BAD;
+ z.msg = "too many length or distance symbols";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if(blens==null || blens.Length>=(14);k-=(14);}
+
+ index = 0;
+ mode = BTREE;
+ goto case BTREE;
+ case BTREE:
+ while (index < 4 + (table >> 10)){
+ while(k<(3)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(3);k-=(3);}
+ }
+
+ while(index < 19){
+ blens[border[index++]] = 0;
+ }
+
+ bb[0] = 7;
+ t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
+ if (t != Z_OK){
+ r = t;
+ if (r == Z_DATA_ERROR){
+ blens=null;
+ mode = BAD;
+ }
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ index = 0;
+ mode = DTREE;
+ goto case DTREE;
+ case DTREE:
+ while (true){
+ t = table;
+ if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){
+ break;
+ }
+
+ int i, j, c;
+
+ t = bb[0];
+
+ while(k<(t)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(t);k-=(t);
+ blens[index++] = c;
+ }
+ else { // c == 16..18
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+
+ while(k<(t+i)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(t);k-=(t);
+
+ j += (b & inflate_mask[i]);
+
+ b>>=(i);k-=(i);
+
+ i = index;
+ t = table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1)){
+ blens=null;
+ mode = BAD;
+ z.msg = "invalid bit length repeat";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ c = c == 16 ? blens[i-1] : 0;
+ do{
+ blens[i++] = c;
+ }
+ while (--j!=0);
+ index = i;
+ }
+ }
+
+ tb[0]=-1; {
+ int[] bl=new int[1];
+ int[] bd=new int[1];
+ int[] tl=new int[1];
+ int[] td=new int[1];
+ bl[0] = 9; // must be <= 9 for lookahead assumptions
+ bd[0] = 6; // must be <= 9 for lookahead assumptions
+
+ t = table;
+ t = inftree.inflate_trees_dynamic(257 + (t & 0x1f),
+ 1 + ((t >> 5) & 0x1f),
+ blens, bl, bd, tl, td, hufts, z);
+
+ if (t != Z_OK){
+ if (t == Z_DATA_ERROR){
+ blens=null;
+ mode = BAD;
+ }
+ r = t;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
+ }
+ mode = CODES;
+ goto case CODES;
+ case CODES:
+ bitb=b; bitk=k;
+ z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+
+ if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
+ return inflate_flush(z, r);
+ }
+ r = Z_OK;
+ codes.free(z);
+
+ p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk;
+ q=write;m=(int)(q z.avail_out) n = z.avail_out;
+ if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z.avail_out -= n;
+ z.total_out += n;
+
+ // update check information
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(check, window, q, n);
+
+ // copy as far as end of window
+ System.Array.Copy(window, q, z.next_out, p, n);
+ p += n;
+ q += n;
+
+ // see if more to copy at beginning of window
+ if (q == end){
+ // wrap pointers
+ q = 0;
+ if (write == end)
+ write = 0;
+
+ // compute bytes to copy
+ n = write - q;
+ if (n > z.avail_out) n = z.avail_out;
+ if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z.avail_out -= n;
+ z.total_out += n;
+
+ // update check information
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(check, window, q, n);
+
+ // copy
+ System.Array.Copy(window, q, z.next_out, p, n);
+ p += n;
+ q += n;
+ }
+
+ // update pointers
+ z.next_out_index = p;
+ read = q;
+
+ // done
+ return r;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/zlib/InfCodes.cs b/src/core/srcbc/util/zlib/InfCodes.cs
new file mode 100644
index 0000000..a31d858
--- /dev/null
+++ b/src/core/srcbc/util/zlib/InfCodes.cs
@@ -0,0 +1,611 @@
+using System;
+/*
+ * $Id: InfCodes.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfCodes{
+
+ private static readonly int[] inflate_mask = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+ 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+ 0x00007fff, 0x0000ffff
+ };
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ // waiting for "i:"=input,
+ // "o:"=output,
+ // "x:"=nothing
+ private const int START=0; // x: set up for LEN
+ private const int LEN=1; // i: get length/literal/eob next
+ private const int LENEXT=2; // i: getting length extra (have base)
+ private const int DIST=3; // i: get distance next
+ private const int DISTEXT=4;// i: getting distance extra
+ private const int COPY=5; // o: copying bytes in window, waiting for space
+ private const int LIT=6; // o: got literal, waiting for output space
+ private const int WASH=7; // o: got eob, possibly still output waiting
+ private const int END=8; // x: got eob and all data flushed
+ private const int BADCODE=9;// x: got error
+
+ int mode; // current inflate_codes mode
+
+ // mode dependent information
+ int len;
+
+ int[] tree; // pointer into tree
+ int tree_index=0;
+ int need; // bits needed
+
+ int lit;
+
+ // if EXT or COPY, where and how much
+ int get; // bits to get for extra
+ int dist; // distance back to copy from
+
+ byte lbits; // ltree bits decoded per branch
+ byte dbits; // dtree bits decoder per branch
+ int[] ltree; // literal/length/eob tree
+ int ltree_index; // literal/length/eob tree
+ int[] dtree; // distance tree
+ int dtree_index; // distance tree
+
+ internal InfCodes(){
+ }
+ internal void init(int bl, int bd,
+ int[] tl, int tl_index,
+ int[] td, int td_index, ZStream z){
+ mode=START;
+ lbits=(byte)bl;
+ dbits=(byte)bd;
+ ltree=tl;
+ ltree_index=tl_index;
+ dtree = td;
+ dtree_index=td_index;
+ tree=null;
+ }
+
+ internal int proc(InfBlocks s, ZStream z, int r){
+ int j; // temporary storage
+ int tindex; // temporary pointer
+ int e; // extra bits or operation
+ int b=0; // bit buffer
+ int k=0; // bits in bit buffer
+ int p=0; // input data pointer
+ int n; // bytes available there
+ int q; // output window write pointer
+ int m; // bytes to end of window or read pointer
+ int f; // pointer to copy strings from
+
+ // copy input/output information to locals (UPDATE macro restores)
+ p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+ q=s.write;m=q= 258 && n >= 10){
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ r = inflate_fast(lbits, dbits,
+ ltree, ltree_index,
+ dtree, dtree_index,
+ s, z);
+
+ p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+ q=s.write;m=q>=(tree[tindex+1]);
+ k-=(tree[tindex+1]);
+
+ e=tree[tindex];
+
+ if(e == 0){ // literal
+ lit = tree[tindex+2];
+ mode = LIT;
+ break;
+ }
+ if((e & 16)!=0 ){ // length
+ get = e & 15;
+ len = tree[tindex+2];
+ mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0){ // next table
+ need = e;
+ tree_index = tindex/3+tree[tindex+2];
+ break;
+ }
+ if ((e & 32)!=0){ // end of block
+ mode = WASH;
+ break;
+ }
+ mode = BADCODE; // invalid code
+ z.msg = "invalid literal/length code";
+ r = Z_DATA_ERROR;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+
+ case LENEXT: // i: getting length extra (have base)
+ j = get;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=j;
+ k-=j;
+
+ need = dbits;
+ tree = dtree;
+ tree_index=dtree_index;
+ mode = DIST;
+ goto case DIST;
+ case DIST: // i: get distance next
+ j = need;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1];
+ k-=tree[tindex+1];
+
+ e = (tree[tindex]);
+ if((e & 16)!=0){ // distance
+ get = e & 15;
+ dist = tree[tindex+2];
+ mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0){ // next table
+ need = e;
+ tree_index = tindex/3 + tree[tindex+2];
+ break;
+ }
+ mode = BADCODE; // invalid code
+ z.msg = "invalid distance code";
+ r = Z_DATA_ERROR;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+
+ case DISTEXT: // i: getting distance extra
+ j = get;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=j;
+ k-=j;
+
+ mode = COPY;
+ goto case COPY;
+ case COPY: // o: copying bytes in window, waiting for space
+ f = q - dist;
+ while(f < 0){ // modulo window size-"while" instead
+ f += s.end; // of "if" handles invalid distances
+ }
+ while (len!=0){
+
+ if(m==0){
+ if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any
+ k -= 8;
+ n++;
+ p--; // can always return one
+ }
+
+ s.write=q; r=s.inflate_flush(z,r);
+ q=s.write;m=q= 258 && n >= 10
+ // get literal/length code
+ while(k<(20)){ // max bits for literal/length code
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ s.window[q++] = (byte)tp[tp_index_t_3+2];
+ m--;
+ continue;
+ }
+ do {
+
+ b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ if((e&16)!=0){
+ e &= 15;
+ c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
+
+ b>>=e; k-=e;
+
+ // decode distance base of block to copy
+ while(k<(15)){ // max bits for distance code
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ if((e&16)!=0){
+ // get extra bits to add to distance base
+ e &= 15;
+ while(k<(e)){ // get extra bits (up to 13)
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(e); k-=(e);
+
+ // do the copy
+ m -= c;
+ if (q >= d){ // offset before dest
+ // just copy
+ r=q-d;
+ if(q-r>0 && 2>(q-r)){
+ s.window[q++]=s.window[r++]; // minimum count is three,
+ s.window[q++]=s.window[r++]; // so unroll loop a little
+ c-=2;
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, 2);
+ q+=2; r+=2; c-=2;
+ }
+ }
+ else{ // else offset after destination
+ r=q-d;
+ do{
+ r+=s.end; // force pointer in window
+ }while(r<0); // covers invalid distances
+ e=s.end-r;
+ if(c>e){ // if source crosses,
+ c-=e; // wrapped copy
+ if(q-r>0 && e>(q-r)){
+ do{s.window[q++] = s.window[r++];}
+ while(--e!=0);
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, e);
+ q+=e; r+=e; e=0;
+ }
+ r = 0; // copy rest from start of window
+ }
+
+ }
+
+ // copy all or what's left
+ if(q-r>0 && c>(q-r)){
+ do{s.window[q++] = s.window[r++];}
+ while(--c!=0);
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, c);
+ q+=c; r+=c; c=0;
+ }
+ break;
+ }
+ else if((e&64)==0){
+ t+=tp[tp_index_t_3+2];
+ t+=(b&inflate_mask[e]);
+ tp_index_t_3=(tp_index+t)*3;
+ e=tp[tp_index_t_3];
+ }
+ else{
+ z.msg = "invalid distance code";
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_DATA_ERROR;
+ }
+ }
+ while(true);
+ break;
+ }
+
+ if((e&64)==0){
+ t+=tp[tp_index_t_3+2];
+ t+=(b&inflate_mask[e]);
+ tp_index_t_3=(tp_index+t)*3;
+ if((e=tp[tp_index_t_3])==0){
+
+ b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ s.window[q++]=(byte)tp[tp_index_t_3+2];
+ m--;
+ break;
+ }
+ }
+ else if((e&32)!=0){
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_STREAM_END;
+ }
+ else{
+ z.msg="invalid literal/length code";
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_DATA_ERROR;
+ }
+ }
+ while(true);
+ }
+ while(m>=258 && n>= 10);
+
+ // not enough input or output--restore pointers and return
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_OK;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/zlib/InfTree.cs b/src/core/srcbc/util/zlib/InfTree.cs
new file mode 100644
index 0000000..e7ce3bb
--- /dev/null
+++ b/src/core/srcbc/util/zlib/InfTree.cs
@@ -0,0 +1,523 @@
+using System;
+/*
+ * $Id: InfTree.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfTree{
+
+ private const int MANY=1440;
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int fixed_bl = 9;
+ private const int fixed_bd = 5;
+
+ static readonly int[] fixed_tl = {
+ 96,7,256, 0,8,80, 0,8,16, 84,8,115,
+ 82,7,31, 0,8,112, 0,8,48, 0,9,192,
+ 80,7,10, 0,8,96, 0,8,32, 0,9,160,
+ 0,8,0, 0,8,128, 0,8,64, 0,9,224,
+ 80,7,6, 0,8,88, 0,8,24, 0,9,144,
+ 83,7,59, 0,8,120, 0,8,56, 0,9,208,
+ 81,7,17, 0,8,104, 0,8,40, 0,9,176,
+ 0,8,8, 0,8,136, 0,8,72, 0,9,240,
+ 80,7,4, 0,8,84, 0,8,20, 85,8,227,
+ 83,7,43, 0,8,116, 0,8,52, 0,9,200,
+ 81,7,13, 0,8,100, 0,8,36, 0,9,168,
+ 0,8,4, 0,8,132, 0,8,68, 0,9,232,
+ 80,7,8, 0,8,92, 0,8,28, 0,9,152,
+ 84,7,83, 0,8,124, 0,8,60, 0,9,216,
+ 82,7,23, 0,8,108, 0,8,44, 0,9,184,
+ 0,8,12, 0,8,140, 0,8,76, 0,9,248,
+ 80,7,3, 0,8,82, 0,8,18, 85,8,163,
+ 83,7,35, 0,8,114, 0,8,50, 0,9,196,
+ 81,7,11, 0,8,98, 0,8,34, 0,9,164,
+ 0,8,2, 0,8,130, 0,8,66, 0,9,228,
+ 80,7,7, 0,8,90, 0,8,26, 0,9,148,
+ 84,7,67, 0,8,122, 0,8,58, 0,9,212,
+ 82,7,19, 0,8,106, 0,8,42, 0,9,180,
+ 0,8,10, 0,8,138, 0,8,74, 0,9,244,
+ 80,7,5, 0,8,86, 0,8,22, 192,8,0,
+ 83,7,51, 0,8,118, 0,8,54, 0,9,204,
+ 81,7,15, 0,8,102, 0,8,38, 0,9,172,
+ 0,8,6, 0,8,134, 0,8,70, 0,9,236,
+ 80,7,9, 0,8,94, 0,8,30, 0,9,156,
+ 84,7,99, 0,8,126, 0,8,62, 0,9,220,
+ 82,7,27, 0,8,110, 0,8,46, 0,9,188,
+ 0,8,14, 0,8,142, 0,8,78, 0,9,252,
+ 96,7,256, 0,8,81, 0,8,17, 85,8,131,
+ 82,7,31, 0,8,113, 0,8,49, 0,9,194,
+ 80,7,10, 0,8,97, 0,8,33, 0,9,162,
+ 0,8,1, 0,8,129, 0,8,65, 0,9,226,
+ 80,7,6, 0,8,89, 0,8,25, 0,9,146,
+ 83,7,59, 0,8,121, 0,8,57, 0,9,210,
+ 81,7,17, 0,8,105, 0,8,41, 0,9,178,
+ 0,8,9, 0,8,137, 0,8,73, 0,9,242,
+ 80,7,4, 0,8,85, 0,8,21, 80,8,258,
+ 83,7,43, 0,8,117, 0,8,53, 0,9,202,
+ 81,7,13, 0,8,101, 0,8,37, 0,9,170,
+ 0,8,5, 0,8,133, 0,8,69, 0,9,234,
+ 80,7,8, 0,8,93, 0,8,29, 0,9,154,
+ 84,7,83, 0,8,125, 0,8,61, 0,9,218,
+ 82,7,23, 0,8,109, 0,8,45, 0,9,186,
+ 0,8,13, 0,8,141, 0,8,77, 0,9,250,
+ 80,7,3, 0,8,83, 0,8,19, 85,8,195,
+ 83,7,35, 0,8,115, 0,8,51, 0,9,198,
+ 81,7,11, 0,8,99, 0,8,35, 0,9,166,
+ 0,8,3, 0,8,131, 0,8,67, 0,9,230,
+ 80,7,7, 0,8,91, 0,8,27, 0,9,150,
+ 84,7,67, 0,8,123, 0,8,59, 0,9,214,
+ 82,7,19, 0,8,107, 0,8,43, 0,9,182,
+ 0,8,11, 0,8,139, 0,8,75, 0,9,246,
+ 80,7,5, 0,8,87, 0,8,23, 192,8,0,
+ 83,7,51, 0,8,119, 0,8,55, 0,9,206,
+ 81,7,15, 0,8,103, 0,8,39, 0,9,174,
+ 0,8,7, 0,8,135, 0,8,71, 0,9,238,
+ 80,7,9, 0,8,95, 0,8,31, 0,9,158,
+ 84,7,99, 0,8,127, 0,8,63, 0,9,222,
+ 82,7,27, 0,8,111, 0,8,47, 0,9,190,
+ 0,8,15, 0,8,143, 0,8,79, 0,9,254,
+ 96,7,256, 0,8,80, 0,8,16, 84,8,115,
+ 82,7,31, 0,8,112, 0,8,48, 0,9,193,
+
+ 80,7,10, 0,8,96, 0,8,32, 0,9,161,
+ 0,8,0, 0,8,128, 0,8,64, 0,9,225,
+ 80,7,6, 0,8,88, 0,8,24, 0,9,145,
+ 83,7,59, 0,8,120, 0,8,56, 0,9,209,
+ 81,7,17, 0,8,104, 0,8,40, 0,9,177,
+ 0,8,8, 0,8,136, 0,8,72, 0,9,241,
+ 80,7,4, 0,8,84, 0,8,20, 85,8,227,
+ 83,7,43, 0,8,116, 0,8,52, 0,9,201,
+ 81,7,13, 0,8,100, 0,8,36, 0,9,169,
+ 0,8,4, 0,8,132, 0,8,68, 0,9,233,
+ 80,7,8, 0,8,92, 0,8,28, 0,9,153,
+ 84,7,83, 0,8,124, 0,8,60, 0,9,217,
+ 82,7,23, 0,8,108, 0,8,44, 0,9,185,
+ 0,8,12, 0,8,140, 0,8,76, 0,9,249,
+ 80,7,3, 0,8,82, 0,8,18, 85,8,163,
+ 83,7,35, 0,8,114, 0,8,50, 0,9,197,
+ 81,7,11, 0,8,98, 0,8,34, 0,9,165,
+ 0,8,2, 0,8,130, 0,8,66, 0,9,229,
+ 80,7,7, 0,8,90, 0,8,26, 0,9,149,
+ 84,7,67, 0,8,122, 0,8,58, 0,9,213,
+ 82,7,19, 0,8,106, 0,8,42, 0,9,181,
+ 0,8,10, 0,8,138, 0,8,74, 0,9,245,
+ 80,7,5, 0,8,86, 0,8,22, 192,8,0,
+ 83,7,51, 0,8,118, 0,8,54, 0,9,205,
+ 81,7,15, 0,8,102, 0,8,38, 0,9,173,
+ 0,8,6, 0,8,134, 0,8,70, 0,9,237,
+ 80,7,9, 0,8,94, 0,8,30, 0,9,157,
+ 84,7,99, 0,8,126, 0,8,62, 0,9,221,
+ 82,7,27, 0,8,110, 0,8,46, 0,9,189,
+ 0,8,14, 0,8,142, 0,8,78, 0,9,253,
+ 96,7,256, 0,8,81, 0,8,17, 85,8,131,
+ 82,7,31, 0,8,113, 0,8,49, 0,9,195,
+ 80,7,10, 0,8,97, 0,8,33, 0,9,163,
+ 0,8,1, 0,8,129, 0,8,65, 0,9,227,
+ 80,7,6, 0,8,89, 0,8,25, 0,9,147,
+ 83,7,59, 0,8,121, 0,8,57, 0,9,211,
+ 81,7,17, 0,8,105, 0,8,41, 0,9,179,
+ 0,8,9, 0,8,137, 0,8,73, 0,9,243,
+ 80,7,4, 0,8,85, 0,8,21, 80,8,258,
+ 83,7,43, 0,8,117, 0,8,53, 0,9,203,
+ 81,7,13, 0,8,101, 0,8,37, 0,9,171,
+ 0,8,5, 0,8,133, 0,8,69, 0,9,235,
+ 80,7,8, 0,8,93, 0,8,29, 0,9,155,
+ 84,7,83, 0,8,125, 0,8,61, 0,9,219,
+ 82,7,23, 0,8,109, 0,8,45, 0,9,187,
+ 0,8,13, 0,8,141, 0,8,77, 0,9,251,
+ 80,7,3, 0,8,83, 0,8,19, 85,8,195,
+ 83,7,35, 0,8,115, 0,8,51, 0,9,199,
+ 81,7,11, 0,8,99, 0,8,35, 0,9,167,
+ 0,8,3, 0,8,131, 0,8,67, 0,9,231,
+ 80,7,7, 0,8,91, 0,8,27, 0,9,151,
+ 84,7,67, 0,8,123, 0,8,59, 0,9,215,
+ 82,7,19, 0,8,107, 0,8,43, 0,9,183,
+ 0,8,11, 0,8,139, 0,8,75, 0,9,247,
+ 80,7,5, 0,8,87, 0,8,23, 192,8,0,
+ 83,7,51, 0,8,119, 0,8,55, 0,9,207,
+ 81,7,15, 0,8,103, 0,8,39, 0,9,175,
+ 0,8,7, 0,8,135, 0,8,71, 0,9,239,
+ 80,7,9, 0,8,95, 0,8,31, 0,9,159,
+ 84,7,99, 0,8,127, 0,8,63, 0,9,223,
+ 82,7,27, 0,8,111, 0,8,47, 0,9,191,
+ 0,8,15, 0,8,143, 0,8,79, 0,9,255
+ };
+ static readonly int[] fixed_td = {
+ 80,5,1, 87,5,257, 83,5,17, 91,5,4097,
+ 81,5,5, 89,5,1025, 85,5,65, 93,5,16385,
+ 80,5,3, 88,5,513, 84,5,33, 92,5,8193,
+ 82,5,9, 90,5,2049, 86,5,129, 192,5,24577,
+ 80,5,2, 87,5,385, 83,5,25, 91,5,6145,
+ 81,5,7, 89,5,1537, 85,5,97, 93,5,24577,
+ 80,5,4, 88,5,769, 84,5,49, 92,5,12289,
+ 82,5,13, 90,5,3073, 86,5,193, 192,5,24577
+ };
+
+ // Tables for deflate from PKZIP's appnote.txt.
+ static readonly int[] cplens = { // Copy lengths for literal codes 257..285
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+ };
+
+ // see note #13 above about 258
+ static readonly int[] cplext = { // Extra bits for literal codes 257..285
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid
+ };
+
+ static readonly int[] cpdist = { // Copy offsets for distance codes 0..29
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+
+ static readonly int[] cpdext = { // Extra bits for distance codes
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ // If BMAX needs to be larger than 16, then h and x[] should be uLong.
+ const int BMAX=15; // maximum bit length of any code
+
+ int[] hn = null; // hufts used in space
+ int[] v = null; // work area for huft_build
+ int[] c = null; // bit length count table
+ int[] r = null; // table entry for structure assignment
+ int[] u = null; // table stack
+ int[] x = null; // bit offsets, then code stack
+
+ private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX)
+ int bindex,
+ int n, // number of codes (assumed <= 288)
+ int s, // number of simple-valued codes (0..s-1)
+ int[] d, // list of base values for non-simple codes
+ int[] e, // list of extra bits for non-simple codes
+ int[] t, // result: starting table
+ int[] m, // maximum lookup bits, returns actual
+ int[] hp,// space for trees
+ int[] hn,// hufts used in space
+ int[] v // working area: values in order of bit length
+ ){
+ // Given a list of code lengths and a maximum table size, make a set of
+ // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ // if the given code set is incomplete (the tables are still built in this
+ // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ // lengths), or Z_MEM_ERROR if not enough memory.
+
+ int a; // counter for codes of length k
+ int f; // i repeats in table every f entries
+ int g; // maximum code length
+ int h; // table level
+ int i; // counter, current code
+ int j; // counter
+ int k; // number of bits in current code
+ int l; // bits per table (returned in m)
+ int mask; // (1 << w) - 1, to avoid cc -O bug on HP
+ int p; // pointer into c[], b[], or v[]
+ int q; // points to current table
+ int w; // bits before this table == (l * h)
+ int xp; // pointer into x
+ int y; // number of dummy codes added
+ int z; // number of entries in current table
+
+ // Generate counts for each bit length
+
+ p = 0; i = n;
+ do {
+ c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX
+ }while(i!=0);
+
+ if(c[0] == n){ // null input--all zero length codes
+ t[0] = -1;
+ m[0] = 0;
+ return Z_OK;
+ }
+
+ // Find minimum and maximum length, bound *m by those
+ l = m[0];
+ for (j = 1; j <= BMAX; j++)
+ if(c[j]!=0) break;
+ k = j; // minimum code length
+ if(l < j){
+ l = j;
+ }
+ for (i = BMAX; i!=0; i--){
+ if(c[i]!=0) break;
+ }
+ g = i; // maximum code length
+ if(l > i){
+ l = i;
+ }
+ m[0] = l;
+
+ // Adjust last length count to fill out codes, if needed
+ for (y = 1 << j; j < i; j++, y <<= 1){
+ if ((y -= c[j]) < 0){
+ return Z_DATA_ERROR;
+ }
+ }
+ if ((y -= c[i]) < 0){
+ return Z_DATA_ERROR;
+ }
+ c[i] += y;
+
+ // Generate starting offsets into the value table for each length
+ x[1] = j = 0;
+ p = 1; xp = 2;
+ while (--i!=0) { // note that i == g from above
+ x[xp] = (j += c[p]);
+ xp++;
+ p++;
+ }
+
+ // Make a table of values in order of bit lengths
+ i = 0; p = 0;
+ do {
+ if ((j = b[bindex+p]) != 0){
+ v[x[j]++] = i;
+ }
+ p++;
+ }
+ while (++i < n);
+ n = x[g]; // set n to length of v
+
+ // Generate the Huffman codes and for each, make the table entries
+ x[0] = i = 0; // first Huffman code is zero
+ p = 0; // grab values in bit order
+ h = -1; // no tables yet--level -1
+ w = -l; // bits decoded == (l * h)
+ u[0] = 0; // just to keep compilers happy
+ q = 0; // ditto
+ z = 0; // ditto
+
+ // go through the bit lengths (k already is bits in shortest code)
+ for (; k <= g; k++){
+ a = c[k];
+ while (a--!=0){
+ // here i is the Huffman code of length k bits for value *p
+ // make tables up to required level
+ while (k > w + l){
+ h++;
+ w += l; // previous table always l bits
+ // compute minimum size table less than or equal to l bits
+ z = g - w;
+ z = (z > l) ? l : z; // table size upper limit
+ if((f=1<<(j=k-w))>a+1){ // try a k-w bit table
+ // too few codes for k-w bit table
+ f -= a + 1; // deduct codes from patterns left
+ xp = k;
+ if(j < z){
+ while (++j < z){ // try smaller tables up to z bits
+ if((f <<= 1) <= c[++xp])
+ break; // enough codes to use up j bits
+ f -= c[xp]; // else deduct codes from patterns
+ }
+ }
+ }
+ z = 1 << j; // table entries for j-bit table
+
+ // allocate new table
+ if (hn[0] + z > MANY){ // (note: doesn't matter for fixed)
+ return Z_DATA_ERROR; // overflow of MANY
+ }
+ u[h] = q = /*hp+*/ hn[0]; // DEBUG
+ hn[0] += z;
+
+ // connect to last table, if there is one
+ if(h!=0){
+ x[h]=i; // save pattern for backing up
+ r[0]=(byte)j; // bits in this table
+ r[1]=(byte)l; // bits to dump before this table
+ j=i>>(w - l);
+ r[2] = (int)(q - u[h-1] - j); // offset to this table
+ System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table
+ }
+ else{
+ t[0] = q; // first table is returned result
+ }
+ }
+
+ // set up table entry in r
+ r[1] = (byte)(k - w);
+ if (p >= n){
+ r[0] = 128 + 64; // out of values--invalid code
+ }
+ else if (v[p] < s){
+ r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
+ r[2] = v[p++]; // simple code is just the value
+ }
+ else{
+ r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists
+ r[2]=d[v[p++] - s];
+ }
+
+ // fill code-like entries with r
+ f=1<<(k-w);
+ for (j=i>>w;j>= 1){
+ i ^= j;
+ }
+ i ^= j;
+
+ // backup over finished tables
+ mask = (1 << w) - 1; // needed on HP, cc -O bug
+ while ((i & mask) != x[h]){
+ h--; // don't need to update q
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+ // Return Z_BUF_ERROR if we were given an incomplete table
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+ }
+
+ internal int inflate_trees_bits(int[] c, // 19 code lengths
+ int[] bb, // bits tree desired/actual depth
+ int[] tb, // bits tree result
+ int[] hp, // space for trees
+ ZStream z // for messages
+ ){
+ int result;
+ initWorkArea(19);
+ hn[0]=0;
+ result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
+
+ if(result == Z_DATA_ERROR){
+ z.msg = "oversubscribed dynamic bit lengths tree";
+ }
+ else if(result == Z_BUF_ERROR || bb[0] == 0){
+ z.msg = "incomplete dynamic bit lengths tree";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ internal int inflate_trees_dynamic(int nl, // number of literal/length codes
+ int nd, // number of distance codes
+ int[] c, // that many (total) code lengths
+ int[] bl, // literal desired/actual bit depth
+ int[] bd, // distance desired/actual bit depth
+ int[] tl, // literal/length tree result
+ int[] td, // distance tree result
+ int[] hp, // space for trees
+ ZStream z // for messages
+ ){
+ int result;
+
+ // build literal/length tree
+ initWorkArea(288);
+ hn[0]=0;
+ result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
+ if (result != Z_OK || bl[0] == 0){
+ if(result == Z_DATA_ERROR){
+ z.msg = "oversubscribed literal/length tree";
+ }
+ else if (result != Z_MEM_ERROR){
+ z.msg = "incomplete literal/length tree";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ // build distance tree
+ initWorkArea(288);
+ result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
+
+ if (result != Z_OK || (bd[0] == 0 && nl > 257)){
+ if (result == Z_DATA_ERROR){
+ z.msg = "oversubscribed distance tree";
+ }
+ else if (result == Z_BUF_ERROR) {
+ z.msg = "incomplete distance tree";
+ result = Z_DATA_ERROR;
+ }
+ else if (result != Z_MEM_ERROR){
+ z.msg = "empty distance tree with lengths";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ return Z_OK;
+ }
+
+ internal static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth
+ int[] bd, //distance desired/actual bit depth
+ int[][] tl,//literal/length tree result
+ int[][] td,//distance tree result
+ ZStream z //for memory allocation
+ ){
+ bl[0]=fixed_bl;
+ bd[0]=fixed_bd;
+ tl[0]=fixed_tl;
+ td[0]=fixed_td;
+ return Z_OK;
+ }
+
+ private void initWorkArea(int vsize){
+ if(hn==null){
+ hn=new int[1];
+ v=new int[vsize];
+ c=new int[BMAX+1];
+ r=new int[3];
+ u=new int[BMAX];
+ x=new int[BMAX+1];
+ }
+ if(v.Lengthstate);
+ return Z_OK;
+ }
+
+ internal int inflateInit(ZStream z, int w){
+ z.msg = null;
+ blocks = null;
+
+ // handle undocumented nowrap option (no zlib header or check)
+ nowrap = 0;
+ if(w < 0){
+ w = - w;
+ nowrap = 1;
+ }
+
+ // set window size
+ if(w<8 ||w>15){
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ wbits=w;
+
+ z.istate.blocks=new InfBlocks(z,
+ z.istate.nowrap!=0 ? null : this,
+ 1<>4)+8>z.istate.wbits){
+ z.istate.mode = BAD;
+ z.msg="invalid window size";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+ z.istate.mode=FLAG;
+ goto case FLAG;
+ case FLAG:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ b = (z.next_in[z.next_in_index++])&0xff;
+
+ if((((z.istate.method << 8)+b) % 31)!=0){
+ z.istate.mode = BAD;
+ z.msg = "incorrect header check";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+
+ if((b&PRESET_DICT)==0){
+ z.istate.mode = BLOCKS;
+ break;
+ }
+ z.istate.mode = DICT4;
+ goto case DICT4;
+ case DICT4:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+ z.istate.mode=DICT3;
+ goto case DICT3;
+ case DICT3:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+ z.istate.mode=DICT2;
+ goto case DICT2;
+ case DICT2:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+ z.istate.mode=DICT1;
+ goto case DICT1;
+ case DICT1:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
+ z.adler = z.istate.need;
+ z.istate.mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z.istate.mode = BAD;
+ z.msg = "need dictionary";
+ z.istate.marker = 0; // can try inflateSync
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+
+ r = z.istate.blocks.proc(z, r);
+ if(r == Z_DATA_ERROR){
+ z.istate.mode = BAD;
+ z.istate.marker = 0; // can try inflateSync
+ break;
+ }
+ if(r == Z_OK){
+ r = f;
+ }
+ if(r != Z_STREAM_END){
+ return r;
+ }
+ r = f;
+ z.istate.blocks.reset(z, z.istate.was);
+ if(z.istate.nowrap!=0){
+ z.istate.mode=DONE;
+ break;
+ }
+ z.istate.mode=CHECK4;
+ goto case CHECK4;
+ case CHECK4:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+ z.istate.mode=CHECK3;
+ goto case CHECK3;
+ case CHECK3:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+ z.istate.mode = CHECK2;
+ goto case CHECK2;
+ case CHECK2:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+ z.istate.mode = CHECK1;
+ goto case CHECK1;
+ case CHECK1:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
+
+ if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
+ z.istate.mode = BAD;
+ z.msg = "incorrect data check";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+
+ z.istate.mode = DONE;
+ goto case DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+ }
+ }
+
+
+ internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
+ int index=0;
+ int length = dictLength;
+ if(z==null || z.istate == null|| z.istate.mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
+ return Z_DATA_ERROR;
+ }
+
+ z.adler = z._adler.adler32(0, null, 0, 0);
+
+ if(length >= (1<>7)]);
+ }
+
+ internal short[] dyn_tree; // the dynamic tree
+ internal int max_code; // largest code with non zero frequency
+ internal StaticTree stat_desc; // the corresponding static tree
+
+ // Compute the optimal bit lengths for a tree and update the total bit length
+ // for the current block.
+ // IN assertion: the fields freq and dad are set, heap[heap_max] and
+ // above are the tree nodes sorted by increasing frequency.
+ // OUT assertions: the field len is set to the optimal bit length, the
+ // array bl_count contains the frequencies for each bit length.
+ // The length opt_len is updated; static_len is also updated if stree is
+ // not null.
+ internal void gen_bitlen(Deflate s){
+ short[] tree = dyn_tree;
+ short[] stree = stat_desc.static_tree;
+ int[] extra = stat_desc.extra_bits;
+ int based = stat_desc.extra_base;
+ int max_length = stat_desc.max_length;
+ int h; // heap index
+ int n, m; // iterate over the tree elements
+ int bits; // bit length
+ int xbits; // extra bits
+ short f; // frequency
+ int overflow = 0; // number of elements with bit length too large
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0;
+
+ // In a first pass, compute the optimal bit lengths (which may
+ // overflow in the case of the bit length tree).
+ tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap
+
+ for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; }
+ tree[n*2+1] = (short)bits;
+ // We overwrite tree[n*2+1] which is no longer needed
+
+ if (n > max_code) continue; // not a leaf node
+
+ s.bl_count[bits]++;
+ xbits = 0;
+ if (n >= based) xbits = extra[n-based];
+ f = tree[n*2];
+ s.opt_len += f * (bits + xbits);
+ if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits);
+ }
+ if (overflow == 0) return;
+
+ // This happens for example on obj2 and pic of the Calgary corpus
+ // Find the first bit length which could increase:
+ do {
+ bits = max_length-1;
+ while(s.bl_count[bits]==0) bits--;
+ s.bl_count[bits]--; // move one leaf down the tree
+ s.bl_count[bits+1]+=2; // move one overflow item as its brother
+ s.bl_count[max_length]--;
+ // The brother of the overflow item also moves one step up,
+ // but this does not affect bl_count[max_length]
+ overflow -= 2;
+ }
+ while (overflow > 0);
+
+ for (bits = max_length; bits != 0; bits--) {
+ n = s.bl_count[bits];
+ while (n != 0) {
+ m = s.heap[--h];
+ if (m > max_code) continue;
+ if (tree[m*2+1] != bits) {
+ s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]);
+ tree[m*2+1] = (short)bits;
+ }
+ n--;
+ }
+ }
+ }
+
+ // Construct one Huffman tree and assigns the code bit strings and lengths.
+ // Update the total bit length for the current block.
+ // IN assertion: the field freq is set for all tree elements.
+ // OUT assertions: the fields len and code are set to the optimal bit length
+ // and corresponding code. The length opt_len is updated; static_len is
+ // also updated if stree is not null. The field max_code is set.
+ internal void build_tree(Deflate s){
+ short[] tree=dyn_tree;
+ short[] stree=stat_desc.static_tree;
+ int elems=stat_desc.elems;
+ int n, m; // iterate over heap elements
+ int max_code=-1; // largest code with non zero frequency
+ int node; // new node being created
+
+ // Construct the initial heap, with least frequent element in
+ // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ // heap[0] is not used.
+ s.heap_len = 0;
+ s.heap_max = HEAP_SIZE;
+
+ for(n=0; n=1; n--)
+ s.pqdownheap(tree, n);
+
+ // Construct the Huffman tree by repeatedly combining the least two
+ // frequent nodes.
+
+ node=elems; // next internal node of the tree
+ do{
+ // n = node of least frequency
+ n=s.heap[1];
+ s.heap[1]=s.heap[s.heap_len--];
+ s.pqdownheap(tree, 1);
+ m=s.heap[1]; // m = node of next least frequency
+
+ s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
+ s.heap[--s.heap_max] = m;
+
+ // Create a new node father of n and m
+ tree[node*2] = (short)(tree[n*2] + tree[m*2]);
+ s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1);
+ tree[n*2+1] = tree[m*2+1] = (short)node;
+
+ // and insert the new node in the heap
+ s.heap[1] = node++;
+ s.pqdownheap(tree, 1);
+ }
+ while(s.heap_len>=2);
+
+ s.heap[--s.heap_max] = s.heap[1];
+
+ // At this point, the fields freq and dad are set. We can now
+ // generate the bit lengths.
+
+ gen_bitlen(s);
+
+ // The field len is now set, we can generate the bit codes
+ gen_codes(tree, max_code, s.bl_count);
+ }
+
+ // Generate the codes for a given tree and bit counts (which need not be
+ // optimal).
+ // IN assertion: the array bl_count contains the bit length statistics for
+ // the given tree and the field len is set for all tree elements.
+ // OUT assertion: the field code is set for all tree elements of non
+ // zero code length.
+ internal static void gen_codes(short[] tree, // the tree to decorate
+ int max_code, // largest code with non zero frequency
+ short[] bl_count // number of codes at each bit length
+ ){
+ short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+ short code = 0; // running code value
+ int bits; // bit index
+ int n; // code index
+
+ // The distribution counts are first used to generate the code values
+ // without bit reversal.
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
+ }
+
+ // Check that the bit counts in bl_count are consistent. The last code
+ // must be all ones.
+ //Assert (code + bl_count[MAX_BITS]-1 == (1<>=1;
+ res<<=1;
+ }
+ while(--len>0);
+ return res>>1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/util/zlib/ZDeflaterOutputStream.cs b/src/core/srcbc/util/zlib/ZDeflaterOutputStream.cs
new file mode 100644
index 0000000..687453b
--- /dev/null
+++ b/src/core/srcbc/util/zlib/ZDeflaterOutputStream.cs
@@ -0,0 +1,150 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+ ///
+ /// Summary description for DeflaterOutputStream.
+ ///
+ public class ZDeflaterOutputStream : Stream {
+ protected ZStream z=new ZStream();
+ protected int flushLevel=JZlib.Z_NO_FLUSH;
+ private const int BUFSIZE = 4192;
+ protected byte[] buf=new byte[BUFSIZE];
+ private byte[] buf1=new byte[1];
+
+ protected Stream outp;
+
+ public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) {
+ }
+
+ public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) {
+ }
+
+ public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) {
+ this.outp=outp;
+ z.deflateInit(level, nowrap);
+ }
+
+
+ public override bool CanRead {
+ get {
+ // TODO: Add DeflaterOutputStream.CanRead getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ // TODO: Add DeflaterOutputStream.CanSeek getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ // TODO: Add DeflaterOutputStream.CanWrite getter implementation
+ return true;
+ }
+ }
+
+ public override long Length {
+ get {
+ // TODO: Add DeflaterOutputStream.Length getter implementation
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ // TODO: Add DeflaterOutputStream.Position getter implementation
+ return 0;
+ }
+ set {
+ // TODO: Add DeflaterOutputStream.Position setter implementation
+ }
+ }
+
+ public override void Write(byte[] b, int off, int len) {
+ if(len==0)
+ return;
+ int err;
+ z.next_in=b;
+ z.next_in_index=off;
+ z.avail_in=len;
+ do{
+ z.next_out=buf;
+ z.next_out_index=0;
+ z.avail_out=BUFSIZE;
+ err=z.deflate(flushLevel);
+ if(err!=JZlib.Z_OK)
+ throw new IOException("deflating: "+z.msg);
+ if (z.avail_out < BUFSIZE)
+ {
+ outp.Write(buf, 0, BUFSIZE-z.avail_out);
+ }
+ }
+ while(z.avail_in>0 || z.avail_out==0);
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ // TODO: Add DeflaterOutputStream.Seek implementation
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ // TODO: Add DeflaterOutputStream.SetLength implementation
+
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ // TODO: Add DeflaterOutputStream.Read implementation
+ return 0;
+ }
+
+ public override void Flush() {
+ outp.Flush();
+ }
+
+ public override void WriteByte(byte b) {
+ buf1[0]=(byte)b;
+ Write(buf1, 0, 1);
+ }
+
+ public void Finish() {
+ int err;
+ do{
+ z.next_out=buf;
+ z.next_out_index=0;
+ z.avail_out=BUFSIZE;
+ err=z.deflate(JZlib.Z_FINISH);
+ if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
+ throw new IOException("deflating: "+z.msg);
+ if(BUFSIZE-z.avail_out>0){
+ outp.Write(buf, 0, BUFSIZE-z.avail_out);
+ }
+ }
+ while(z.avail_in>0 || z.avail_out==0);
+ Flush();
+ }
+
+ public void End() {
+ if(z==null)
+ return;
+ z.deflateEnd();
+ z.free();
+ z=null;
+ }
+
+ public override void Close() {
+ try{
+ try{Finish();}
+ catch (IOException) {}
+ }
+ finally{
+ End();
+ outp.Close();
+ outp=null;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/util/zlib/ZInflaterInputStream.cs b/src/core/srcbc/util/zlib/ZInflaterInputStream.cs
new file mode 100644
index 0000000..e846a20
--- /dev/null
+++ b/src/core/srcbc/util/zlib/ZInflaterInputStream.cs
@@ -0,0 +1,126 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+ ///
+ /// Summary description for DeflaterOutputStream.
+ ///
+ public class ZInflaterInputStream : Stream {
+ protected ZStream z=new ZStream();
+ protected int flushLevel=JZlib.Z_NO_FLUSH;
+ private const int BUFSIZE = 4192;
+ protected byte[] buf=new byte[BUFSIZE];
+ private byte[] buf1=new byte[1];
+
+ protected Stream inp=null;
+ private bool nomoreinput=false;
+
+ public ZInflaterInputStream(Stream inp) : this(inp, false) {
+ }
+
+ public ZInflaterInputStream(Stream inp, bool nowrap) {
+ this.inp=inp;
+ z.inflateInit(nowrap);
+ z.next_in=buf;
+ z.next_in_index=0;
+ z.avail_in=0;
+ }
+
+ public override bool CanRead {
+ get {
+ // TODO: Add DeflaterOutputStream.CanRead getter implementation
+ return true;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ // TODO: Add DeflaterOutputStream.CanSeek getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ // TODO: Add DeflaterOutputStream.CanWrite getter implementation
+ return false;
+ }
+ }
+
+ public override long Length {
+ get {
+ // TODO: Add DeflaterOutputStream.Length getter implementation
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ // TODO: Add DeflaterOutputStream.Position getter implementation
+ return 0;
+ }
+ set {
+ // TODO: Add DeflaterOutputStream.Position setter implementation
+ }
+ }
+
+ public override void Write(byte[] b, int off, int len) {
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ // TODO: Add DeflaterOutputStream.Seek implementation
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ // TODO: Add DeflaterOutputStream.SetLength implementation
+
+ }
+
+ public override int Read(byte[] b, int off, int len) {
+ if(len==0)
+ return(0);
+ int err;
+ z.next_out=b;
+ z.next_out_index=off;
+ z.avail_out=len;
+ do {
+ if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
+ z.next_in_index=0;
+ z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZEnext_out buffer and copying into it.
+ // (See also read_buf()).
+ internal void flush_pending(){
+ int len=dstate.pending;
+
+ if(len>avail_out) len=avail_out;
+ if(len==0) return;
+
+ if(dstate.pending_buf.Length<=dstate.pending_out ||
+ next_out.Length<=next_out_index ||
+ dstate.pending_buf.Length<(dstate.pending_out+len) ||
+ next_out.Length<(next_out_index+len)){
+ // System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
+ // ", "+next_out.length+", "+next_out_index+", "+len);
+ // System.out.println("avail_out="+avail_out);
+ }
+
+ System.Array.Copy(dstate.pending_buf, dstate.pending_out,
+ next_out, next_out_index, len);
+
+ next_out_index+=len;
+ dstate.pending_out+=len;
+ total_out+=len;
+ avail_out-=len;
+ dstate.pending-=len;
+ if(dstate.pending==0){
+ dstate.pending_out=0;
+ }
+ }
+
+ // Read a new buffer from the current input stream, update the adler32
+ // and total number of bytes read. All deflate() input goes through
+ // this function so some applications may wish to modify it to avoid
+ // allocating a large strm->next_in buffer and copying from it.
+ // (See also flush_pending()).
+ internal int read_buf(byte[] buf, int start, int size) {
+ int len=avail_in;
+
+ if(len>size) len=size;
+ if(len==0) return 0;
+
+ avail_in-=len;
+
+ if(dstate.noheader==0) {
+ adler=_adler.adler32(adler, next_in, next_in_index, len);
+ }
+ System.Array.Copy(next_in, next_in_index, buf, start, len);
+ next_in_index += len;
+ total_in += len;
+ return len;
+ }
+
+ public void free(){
+ next_in=null;
+ next_out=null;
+ msg=null;
+ _adler=null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/x509/AttributeCertificateHolder.cs b/src/core/srcbc/x509/AttributeCertificateHolder.cs
new file mode 100644
index 0000000..3572848
--- /dev/null
+++ b/src/core/srcbc/x509/AttributeCertificateHolder.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// The Holder object.
+ ///
+ /// Holder ::= SEQUENCE {
+ /// baseCertificateID [0] IssuerSerial OPTIONAL,
+ /// -- the issuer and serial number of
+ /// -- the holder's Public Key Certificate
+ /// entityName [1] GeneralNames OPTIONAL,
+ /// -- the name of the claimant or role
+ /// objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ /// -- used to directly authenticate the holder,
+ /// -- for example, an executable
+ /// }
+ ///
+ ///
+ public class AttributeCertificateHolder
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Holder holder;
+
+ internal AttributeCertificateHolder(
+ Asn1Sequence seq)
+ {
+ holder = Holder.GetInstance(seq);
+ }
+
+ public AttributeCertificateHolder(
+ X509Name issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new Holder(
+ new IssuerSerial(
+ GenerateGeneralNames(issuerName),
+ new DerInteger(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Certificate cert)
+ {
+ X509Name name;
+ try
+ {
+ name = PrincipalUtilities.GetIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+
+ holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Name principal)
+ {
+ holder = new Holder(GenerateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ *
+ * digestedObjectType
can be one of the following:
+ *
+ * - 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * - 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * - 2 - otherObjectDigest - A hash of some other object type must be
+ * passed.
otherObjectTypeID
must not be empty.
+ *
+ *
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * digestedObjectType
is
+ * otherObjectDigest
.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(
+ int digestedObjectType,
+ string digestAlgorithm,
+ string otherObjectTypeID,
+ byte[] objectDigest)
+ {
+ // TODO Allow 'objectDigest' to be null?
+
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID,
+ new AlgorithmIdentifier(digestAlgorithm), Arrays.Clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ *
+ *
+ * - 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * - 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * - 2 - otherObjectDigest - A hash of some other object type must be
+ * passed.
otherObjectTypeID
must not be empty.
+ *
+ *
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int DigestedObjectType
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? -1
+ : odi.DigestedObjectType.Value.IntValue;
+ }
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or null
if no object
+ * digest info is set.
+ */
+ public string DigestAlgorithm
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.DigestAlgorithm.ObjectID.Id;
+ }
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or null
if no object digest info is set.
+ */
+ public byte[] GetObjectDigest()
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.ObjectDigest.GetBytes();
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or null
if no object
+ * digest info is set.
+ */
+ public string OtherObjectTypeID
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.OtherObjectTypeID.Id;
+ }
+ }
+
+ private GeneralNames GenerateGeneralNames(
+ X509Name principal)
+ {
+// return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private object[] GetNames(
+ GeneralName[] names)
+ {
+ ArrayList l = new ArrayList(names.Length);
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ l.Add(X509Name.GetInstance(names[i].Name));
+ }
+ }
+
+ return l.ToArray();
+ }
+
+ private X509Name[] GetPrincipals(
+ GeneralNames names)
+ {
+ object[] p = this.GetNames(names.GetNames());
+ ArrayList l = new ArrayList(p.Length);
+
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ l.Add(p[i]);
+ }
+ }
+
+ return (X509Name[]) l.ToArray(typeof(X509Name));
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder entity names field.
+ *
+ * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
+ */
+ public X509Name[] GetEntityNames()
+ {
+ if (holder.EntityName != null)
+ {
+ return GetPrincipals(holder.EntityName);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public X509Name[] GetIssuer()
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return GetPrincipals(holder.BaseCertificateID.Issuer);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is set.
+ */
+ public BigInteger SerialNumber
+ {
+ get
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value;
+ }
+
+ return null;
+ }
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer);
+ }
+
+ if (holder.EntityName != null)
+ {
+ if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName))
+ {
+ return true;
+ }
+ }
+
+ if (holder.ObjectDigestInfo != null)
+ {
+ IDigest md = null;
+ try
+ {
+ md = DigestUtilities.GetDigest(DigestAlgorithm);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ switch (DigestedObjectType)
+ {
+ case ObjectDigestInfo.PublicKey:
+ {
+ // TODO: DSA Dss-parms
+
+ //byte[] b = x509Cert.GetPublicKey().getEncoded();
+ // TODO Is this the right way to encode?
+ byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ x509Cert.GetPublicKey()).GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ case ObjectDigestInfo.PublicKeyCert:
+ {
+ byte[] b = x509Cert.GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ // TODO Default handler?
+ }
+
+ // TODO Shouldn't this be the other way around?
+ if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.Equals(other.holder);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.holder.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+// return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/AttributeCertificateIssuer.cs b/src/core/srcbc/x509/AttributeCertificateIssuer.cs
new file mode 100644
index 0000000..4c0a076
--- /dev/null
+++ b/src/core/srcbc/x509/AttributeCertificateIssuer.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Carrying class for an attribute certificate issuer.
+ */
+ public class AttributeCertificateIssuer
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Asn1Encodable form;
+
+ /**
+ * Set the issuer directly with the ASN.1 structure.
+ *
+ * @param issuer The issuer
+ */
+ internal AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.Issuer;
+ }
+
+ public AttributeCertificateIssuer(
+ X509Name principal)
+ {
+// form = new V2Form(GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))));
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private object[] GetNames()
+ {
+ GeneralNames name;
+ if (form is V2Form)
+ {
+ name = ((V2Form)form).IssuerName;
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.GetNames();
+
+ ArrayList l = new ArrayList(names.Length);
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ l.Add(X509Name.GetInstance(names[i].Name));
+ }
+ }
+
+ return l.ToArray();
+ }
+
+ /// Return any principal objects inside the attribute certificate issuer object.
+ /// An array of IPrincipal objects (usually X509Principal).
+ public X509Name[] GetPrincipals()
+ {
+ object[] p = this.GetNames();
+ ArrayList l = new ArrayList(p.Length);
+
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ l.Add(p[i]);
+ }
+ }
+
+ return (X509Name[]) l.ToArray(typeof(X509Name));
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.GetInstance(form));
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ if (form is V2Form)
+ {
+ V2Form issuer = (V2Form) form;
+ if (issuer.BaseCertificateID != null)
+ {
+ return issuer.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(x509Cert.IssuerDN, issuer.BaseCertificateID.Issuer);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.Equals(other.form);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.form.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+ //return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/IX509AttributeCertificate.cs b/src/core/srcbc/x509/IX509AttributeCertificate.cs
new file mode 100644
index 0000000..58d062b
--- /dev/null
+++ b/src/core/srcbc/x509/IX509AttributeCertificate.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Interface for an X.509 Attribute Certificate.
+ public interface IX509AttributeCertificate
+ : IX509Extension
+ {
+ /// The version number for the certificate.
+ int Version { get; }
+
+ /// The serial number for the certificate.
+ BigInteger SerialNumber { get; }
+
+ /// The UTC DateTime before which the certificate is not valid.
+ DateTime NotBefore { get; }
+
+ /// The UTC DateTime after which the certificate is not valid.
+ DateTime NotAfter { get; }
+
+ /// The holder of the certificate.
+ AttributeCertificateHolder Holder { get; }
+
+ /// The issuer details for the certificate.
+ AttributeCertificateIssuer Issuer { get; }
+
+ /// Return the attributes contained in the attribute block in the certificate.
+ /// An array of attributes.
+ X509Attribute[] GetAttributes();
+
+ /// Return the attributes with the same type as the passed in oid.
+ /// The object identifier we wish to match.
+ /// An array of matched attributes, null if there is no match.
+ X509Attribute[] GetAttributes(string oid);
+
+ bool[] GetIssuerUniqueID();
+
+ bool IsValidNow { get; }
+ bool IsValid(DateTime date);
+
+ void CheckValidity();
+ void CheckValidity(DateTime date);
+
+ byte[] GetSignature();
+
+ void Verify(AsymmetricKeyParameter publicKey);
+
+ /// Return an ASN.1 encoded byte array representing the attribute certificate.
+ /// An ASN.1 encoded byte array.
+ /// If the certificate cannot be encoded.
+ byte[] GetEncoded();
+ }
+}
diff --git a/src/core/srcbc/x509/IX509Extension.cs b/src/core/srcbc/x509/IX509Extension.cs
new file mode 100644
index 0000000..62ed346
--- /dev/null
+++ b/src/core/srcbc/x509/IX509Extension.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public interface IX509Extension
+ {
+ ///
+ /// Get all critical extension values, by oid
+ ///
+ /// IDictionary with DerObjectIdentifier keys and Asn1OctetString values
+ ISet GetCriticalExtensionOids();
+
+ ///
+ /// Get all non-critical extension values, by oid
+ ///
+ /// IDictionary with DerObjectIdentifier keys and Asn1OctetString values
+ ISet GetNonCriticalExtensionOids();
+
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ Asn1OctetString GetExtensionValue(string oid);
+
+ Asn1OctetString GetExtensionValue(DerObjectIdentifier oid);
+ }
+}
diff --git a/src/core/srcbc/x509/PEMParser.cs b/src/core/srcbc/x509/PEMParser.cs
new file mode 100644
index 0000000..149e14f
--- /dev/null
+++ b/src/core/srcbc/x509/PEMParser.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.X509
+{
+ class PemParser
+ {
+ private readonly string _header1;
+ private readonly string _header2;
+ private readonly string _footer1;
+ private readonly string _footer2;
+
+ internal PemParser(
+ string type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private string ReadLine(
+ Stream inStream)
+ {
+ int c;
+ StringBuilder l = new StringBuilder();
+
+ do
+ {
+ while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.Append((char)c);
+ }
+ }
+ while (c >= 0 && l.Length == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.ToString();
+ }
+
+ internal Asn1Sequence ReadPemObject(
+ Stream inStream)
+ {
+ string line;
+ StringBuilder pemBuf = new StringBuilder();
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (line.Equals(_header1) || line.Equals(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (line.Equals(_footer1) || line.Equals(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.Append(line);
+ }
+
+ if (pemBuf.Length != 0)
+ {
+ Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString()));
+
+ if (!(o is Asn1Sequence))
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+
+ return (Asn1Sequence) o;
+ }
+
+ return null;
+ }
+ }
+}
+
diff --git a/src/core/srcbc/x509/PrincipalUtil.cs b/src/core/srcbc/x509/PrincipalUtil.cs
new file mode 100644
index 0000000..3f8239d
--- /dev/null
+++ b/src/core/srcbc/x509/PrincipalUtil.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A utility class that will extract X509Principal objects from X.509 certificates.
+ ///
+ /// Use this in preference to trying to recreate a principal from a string, not all
+ /// DNs are what they should be, so it's best to leave them encoded where they
+ /// can be.
+ ///
+ public class PrincipalUtilities
+ {
+ /// Return the issuer of the given cert as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract issuer", e);
+ }
+ }
+
+ /// Return the subject of the given cert as an X509Principal.
+ public static X509Name GetSubjectX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Subject;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract subject", e);
+ }
+ }
+
+ /// Return the issuer of the given CRL as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Crl crl)
+ {
+ try
+ {
+ TbsCertificateList tbsCertList = TbsCertificateList.GetInstance(
+ Asn1Object.FromByteArray(crl.GetTbsCertList()));
+
+ return tbsCertList.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("Could not extract issuer", e);
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/SubjectPublicKeyInfoFactory.cs b/src/core/srcbc/x509/SubjectPublicKeyInfoFactory.cs
new file mode 100644
index 0000000..f5a7c35
--- /dev/null
+++ b/src/core/srcbc/x509/SubjectPublicKeyInfoFactory.cs
@@ -0,0 +1,178 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A factory to produce Public Key Info Objects.
+ ///
+ public sealed class SubjectPublicKeyInfoFactory
+ {
+ private SubjectPublicKeyInfoFactory()
+ {
+ }
+
+ ///
+ /// Create a Subject Public Key Info object for a given public key.
+ ///
+ /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters
+ /// A subject public key info object.
+ /// Throw exception if object provided is not one of the above.
+ public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
+ AsymmetricKeyParameter key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (key.IsPrivate)
+ throw new ArgumentException("Private key passed - public key expected.", "key");
+
+ if (key is ElGamalPublicKeyParameters)
+ {
+ ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+ ElGamalParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ }
+
+ if (key is DsaPublicKeyParameters)
+ {
+ DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
+ DsaParameters kp = _key.Parameters;
+ Asn1Encodable ae = kp == null
+ ? null
+ : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
+
+ return new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
+ new DerInteger(_key.Y));
+ }
+
+ if (key is DHPublicKeyParameters)
+ {
+ DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+ DHParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ X9ObjectIdentifiers.DHPublicNumber,
+ new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ } // End of DH
+
+ if (key is RsaKeyParameters)
+ {
+ RsaKeyParameters _key = (RsaKeyParameters) key;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+ new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
+
+ return info;
+ } // End of RSA.
+
+ if (key is ECPublicKeyParameters)
+ {
+ ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
+
+ if (_key.AlgorithmName == "ECGOST3410")
+ {
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ ECPoint q = _key.Q;
+ BigInteger bX = q.X.ToBigInteger();
+ BigInteger bY = q.Y.ToBigInteger();
+
+ byte[] encKey = new byte[64];
+ ExtractBytes(encKey, 0, bX);
+ ExtractBytes(encKey, 32, bY);
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x2001,
+ gostParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
+ }
+ else
+ {
+ ECDomainParameters kp = _key.Parameters;
+
+ X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+ X962Parameters x962 = new X962Parameters(ecP);
+ Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, p.GetOctets());
+ }
+ } // End of EC
+
+ if (key is Gost3410PublicKeyParameters)
+ {
+ Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
+ }
+
+ private static void ExtractBytes(
+ byte[] encKey,
+ int offset,
+ BigInteger bI)
+ {
+ byte[] val = bI.ToByteArray();
+ int n = (bI.BitLength + 7) / 8;
+
+ for (int i = 0; i < n; ++i)
+ {
+ encKey[offset + i] = val[val.Length - 1 - i];
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509AttrCertParser.cs b/src/core/srcbc/x509/X509AttrCertParser.cs
new file mode 100644
index 0000000..8608b3f
--- /dev/null
+++ b/src/core/srcbc/x509/X509AttrCertParser.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509AttrCertParser
+ {
+ private static readonly PemParser PemAttrCertParser = new PemParser("ATTRIBUTE CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private IX509AttributeCertificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+// return new X509V2AttributeCertificate(seq.getEncoded());
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ private IX509AttributeCertificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 2)
+ {
+ //return new X509V2AttributeCertificate(
+ // Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false).GetEncoded());
+ return new X509V2AttributeCertificate(
+ AttributeCertificate.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false)));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private IX509AttributeCertificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemAttrCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ //: new X509V2AttributeCertificate(seq.getEncoded());
+ : new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public IX509AttributeCertificate ReadAttrCert(
+ byte[] input)
+ {
+ return ReadAttrCert(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadAttrCerts(
+ byte[] input)
+ {
+ return ReadAttrCerts(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public IX509AttributeCertificate ReadAttrCert(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadAttrCerts(
+ Stream inStream)
+ {
+ IX509AttributeCertificate attrCert;
+ IList attrCerts = new ArrayList();
+
+ while ((attrCert = ReadAttrCert(inStream)) != null)
+ {
+ attrCerts.Add(attrCert);
+ }
+
+ return attrCerts;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/srcbc/x509/X509Attribute.cs b/src/core/srcbc/x509/X509Attribute.cs
new file mode 100644
index 0000000..9c3d243
--- /dev/null
+++ b/src/core/srcbc/x509/X509Attribute.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+ public class X509Attribute
+ : Asn1Encodable
+ {
+ private readonly AttributeX509 attr;
+
+ /**
+ * @param at an object representing an attribute.
+ */
+ internal X509Attribute(
+ Asn1Encodable at)
+ {
+ this.attr = AttributeX509.GetInstance(at);
+ }
+
+ /**
+ * Create an X.509 Attribute with the type given by the passed in oid and
+ * the value represented by an ASN.1 Set containing value.
+ *
+ * @param oid type of the attribute
+ * @param value value object to go into the atribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1Encodable value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ /**
+ * Create an X.59 Attribute with the type given by the passed in oid and the
+ * value represented by an ASN.1 Set containing the objects in value.
+ *
+ * @param oid type of the attribute
+ * @param value vector of values to go in the attribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1EncodableVector value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ public string Oid
+ {
+ get { return attr.AttrType.Id; }
+ }
+
+ public Asn1Encodable[] GetValues()
+ {
+ Asn1Set s = attr.AttrValues;
+ Asn1Encodable[] values = new Asn1Encodable[s.Count];
+
+ for (int i = 0; i != s.Count; i++)
+ {
+ values[i] = (Asn1Encodable)s[i];
+ }
+
+ return values;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return attr.ToAsn1Object();
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509CertPairParser.cs b/src/core/srcbc/x509/X509CertPairParser.cs
new file mode 100644
index 0000000..e257794
--- /dev/null
+++ b/src/core/srcbc/x509/X509CertPairParser.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CertPairParser
+ {
+ private Stream currentStream;
+
+ private X509CertificatePair ReadDerCrossCertificatePair(
+ Stream inStream)
+ {
+ Asn1InputStream dIn = new Asn1InputStream(inStream);//, ProviderUtil.getReadLimit(in));
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+ CertificatePair pair = CertificatePair.GetInstance(seq);
+ return new X509CertificatePair(pair);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509CertificatePair ReadCertPair(
+ byte[] input)
+ {
+ return ReadCertPair(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertPairs(
+ byte[] input)
+ {
+ return ReadCertPairs(new MemoryStream(input, false));
+ }
+
+ public X509CertificatePair ReadCertPair(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ }
+
+ try
+ {
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ return ReadDerCrossCertificatePair(pis);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ public ICollection ReadCertPairs(
+ Stream inStream)
+ {
+ X509CertificatePair certPair;
+ IList certPairs = new ArrayList();
+
+ while ((certPair = ReadCertPair(inStream)) != null)
+ {
+ certPairs.Add(certPair);
+ }
+
+ return certPairs;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509Certificate.cs b/src/core/srcbc/x509/X509Certificate.cs
new file mode 100644
index 0000000..1126c40
--- /dev/null
+++ b/src/core/srcbc/x509/X509Certificate.cs
@@ -0,0 +1,579 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// An Object representing an X509 Certificate.
+ /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+ ///
+ public class X509Certificate
+ : X509ExtensionBase
+// , PKCS12BagAttributeCarrier
+ {
+ private readonly X509CertificateStructure c;
+// private Hashtable pkcs12Attributes = new Hashtable();
+// private ArrayList pkcs12Ordering = new ArrayList();
+ private readonly BasicConstraints basicConstraints;
+ private readonly bool[] keyUsage;
+
+ private bool hashValueSet;
+ private int hashValue;
+
+ protected X509Certificate()
+ {
+ }
+
+ public X509Certificate(
+ X509CertificateStructure c)
+ {
+ this.c = c;
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19"));
+
+ if (str != null)
+ {
+ basicConstraints = BasicConstraints.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15"));
+
+ if (str != null)
+ {
+ DerBitString bits = DerBitString.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+
+ byte[] bytes = bits.GetBytes();
+ int length = (bytes.Length * 8) - bits.PadBits;
+
+ keyUsage = new bool[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+// keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+// internal X509Certificate(
+// Asn1Sequence seq)
+// {
+// this.c = X509CertificateStructure.GetInstance(seq);
+// }
+
+// ///
+// /// Load certificate from byte array.
+// ///
+// /// Byte array containing encoded X509Certificate.
+// public X509Certificate(
+// byte[] encoded)
+// : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject())
+// {
+// }
+//
+// ///
+// /// Load certificate from Stream.
+// /// Must be positioned at start of certificate.
+// ///
+// ///
+// public X509Certificate(
+// Stream input)
+// : this((Asn1Sequence) new Asn1InputStream(input).ReadObject())
+// {
+// }
+
+ ///
+ /// Return true if the current time is within the start and end times nominated on the certificate.
+ ///
+ /// true id certificate is valid for the current time.
+ public virtual bool IsValidNow
+ {
+ get { return IsValid(DateTime.UtcNow); }
+ }
+
+ ///
+ /// Return true if the nominated time is within the start and end times nominated on the certificate.
+ ///
+ /// The time to test validity against.
+ /// True if certificate is valid for nominated time.
+ public virtual bool IsValid(
+ DateTime time)
+ {
+ return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0;
+ }
+
+ ///
+ /// Checks if the current date is within certificate's validity period.
+ ///
+ public virtual void CheckValidity()
+ {
+ this.CheckValidity(DateTime.UtcNow);
+ }
+
+ ///
+ /// Checks if the given date is within certificate's validity period.
+ ///
+ /// if the certificate is expired by given date
+ /// if the certificate is not yet valid on given date
+ public virtual void CheckValidity(
+ DateTime time)
+ {
+ if (time.CompareTo(NotAfter) > 0)
+ throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime());
+ if (time.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime());
+ }
+
+ ///
+ /// Return the certificate's version.
+ ///
+ /// An integer whose value Equals the version of the cerficate.
+ public virtual int Version
+ {
+ get { return c.Version; }
+ }
+
+ ///
+ /// Return a BigInteger containing the serial number.
+ ///
+ /// The Serial number.
+ public virtual BigInteger SerialNumber
+ {
+ get { return c.SerialNumber.Value; }
+ }
+
+ ///
+ /// Get the Issuer Distinguished Name. (Who signed the certificate.)
+ ///
+ /// And X509Object containing name and value pairs.
+// public IPrincipal IssuerDN
+ public virtual X509Name IssuerDN
+ {
+ get { return c.Issuer; }
+ }
+
+ ///
+ /// Get the subject of this certificate.
+ ///
+ /// An X509Name object containing name and value pairs.
+// public IPrincipal SubjectDN
+ public virtual X509Name SubjectDN
+ {
+ get { return c.Subject; }
+ }
+
+ ///
+ /// The time that this certificate is valid from.
+ ///
+ /// A DateTime object representing that time in the local time zone.
+ public virtual DateTime NotBefore
+ {
+ get { return c.StartDate.ToDateTime(); }
+ }
+
+ ///
+ /// The time that this certificate is valid up to.
+ ///
+ /// A DateTime object representing that time in the local time zone.
+ public virtual DateTime NotAfter
+ {
+ get { return c.EndDate.ToDateTime(); }
+ }
+
+ ///
+ /// Return the Der encoded TbsCertificate data.
+ /// This is the certificate component less the signature.
+ /// To Get the whole certificate call the GetEncoded() member.
+ ///
+ /// A byte array containing the Der encoded Certificate component.
+ public virtual byte[] GetTbsCertificate()
+ {
+ return c.TbsCertificate.GetDerEncoded();
+ }
+
+ ///
+ /// The signature.
+ ///
+ /// A byte array containg the signature of the certificate.
+ public virtual byte[] GetSignature()
+ {
+ return c.Signature.GetBytes();
+ }
+
+ ///
+ /// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+ ///
+ /// A sting representing the signature algorithm.
+ public virtual string SigAlgName
+ {
+ get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.ObjectID); }
+ }
+
+ ///
+ /// Get the Signature Algorithms Object ID.
+ ///
+ /// A string containg a '.' separated object id.
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.ObjectID.Id; }
+ }
+
+ ///
+ /// Get the signature algorithms parameters. (EG DSA Parameters)
+ ///
+ /// A byte array containing the Der encoded version of the parameters or null if there are none.
+ public virtual byte[] GetSigAlgParams()
+ {
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ return c.SignatureAlgorithm.Parameters.GetDerEncoded();
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get the issuers UID.
+ ///
+ /// A DerBitString.
+ public virtual DerBitString IssuerUniqueID
+ {
+ get { return c.TbsCertificate.IssuerUniqueID; }
+ }
+
+ ///
+ /// Get the subjects UID.
+ ///
+ /// A DerBitString.
+ public virtual DerBitString SubjectUniqueID
+ {
+ get { return c.TbsCertificate.SubjectUniqueID; }
+ }
+
+ ///
+ /// Get a key usage guidlines.
+ ///
+ public virtual bool[] GetKeyUsage()
+ {
+ return keyUsage == null ? null : (bool[]) keyUsage.Clone();
+ }
+
+ // TODO Replace with something that returns a list of DerObjectIdentifier
+ public virtual IList GetExtendedKeyUsage()
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37"));
+
+ if (str == null)
+ return null;
+
+ try
+ {
+ Asn1Sequence seq = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+
+ ArrayList list = new ArrayList();
+
+ foreach (DerObjectIdentifier oid in seq)
+ {
+ list.Add(oid.Id);
+ }
+
+ return list;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension", e);
+ }
+ }
+
+ public virtual int GetBasicConstraints()
+ {
+ if (basicConstraints != null && basicConstraints.IsCA())
+ {
+ if (basicConstraints.PathLenConstraint == null)
+ {
+ return int.MaxValue;
+ }
+
+ return basicConstraints.PathLenConstraint.IntValue;
+ }
+
+ return -1;
+ }
+
+ public virtual ICollection GetSubjectAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.17");
+ }
+
+ public virtual ICollection GetIssuerAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.18");
+ }
+
+ protected virtual ICollection GetAlternativeNames(
+ string oid)
+ {
+ Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid));
+
+ if (altNames == null)
+ return null;
+
+ Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
+
+ GeneralNames gns = GeneralNames.GetInstance(asn1Object);
+
+ ArrayList result = new ArrayList();
+ foreach (GeneralName gn in gns.GetNames())
+ {
+ ArrayList entry = new ArrayList();
+ entry.Add(gn.TagNo);
+ entry.Add(gn.Name.ToString());
+ result.Add(entry);
+ }
+ return result;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Version == 3
+ ? c.TbsCertificate.Extensions
+ : null;
+ }
+
+ ///
+ /// Get the public key of the subject of the certificate.
+ ///
+ /// The public key parameters.
+ public virtual AsymmetricKeyParameter GetPublicKey()
+ {
+ return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo);
+ }
+
+ ///
+ /// Return a Der encoded version of this certificate.
+ ///
+ /// A byte array.
+ public virtual byte[] GetEncoded()
+ {
+ return c.GetDerEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Certificate other = obj as X509Certificate;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+// return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ lock (this)
+ {
+ if (!hashValueSet)
+ {
+ hashValue = c.GetHashCode();
+ hashValueSet = true;
+ }
+ }
+
+ return hashValue;
+ }
+
+// public void setBagAttribute(
+// DERObjectIdentifier oid,
+// DEREncodable attribute)
+// {
+// pkcs12Attributes.put(oid, attribute);
+// pkcs12Ordering.addElement(oid);
+// }
+//
+// public DEREncodable getBagAttribute(
+// DERObjectIdentifier oid)
+// {
+// return (DEREncodable)pkcs12Attributes.get(oid);
+// }
+//
+// public Enumeration getBagAttributeKeys()
+// {
+// return pkcs12Ordering.elements();
+// }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" [0] Version: ").Append(this.Version).Append(nl);
+ buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl);
+ buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl);
+ buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl);
+ buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+ byte[] hex = Hex.Encode(sig, 0, 20);
+ string ascii = Encoding.ASCII.GetString(hex, 0, hex.Length);
+ buf.Append(" Signature: ").Append(ascii).Append(nl);
+
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ int len = System.Math.Min(20, sig.Length - i);
+ hex = Hex.Encode(sig, i, len);
+ ascii = Encoding.ASCII.GetString(hex, 0, hex.Length);
+ buf.Append(" ").Append(ascii).Append(nl);
+ }
+
+ X509Extensions extensions = c.TbsCertificate.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: \n");
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ byte[] octs = ext.Value.GetOctets();
+ Asn1Object obj = Asn1Object.FromByteArray(octs);
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.BasicConstraints))
+ {
+ buf.Append(BasicConstraints.GetInstance(obj));
+ }
+ else if (oid.Equals(X509Extensions.KeyUsage))
+ {
+ buf.Append(KeyUsage.GetInstance(obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType))
+ {
+ buf.Append(new NetscapeCertType((DerBitString) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl))
+ {
+ buf.Append(new NetscapeRevocationUrl((DerIA5String) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension))
+ {
+ buf.Append(new VerisignCzagExtension((DerIA5String) obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ //buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl);
+ buf.Append(" value = ").Append("*****");
+ }
+ }
+
+ buf.Append(nl);
+ }
+ while (e.MoveNext());
+ }
+
+ return buf.ToString();
+ }
+
+ ///
+ /// Verify the certificate's signature using the nominated public key.
+ ///
+ /// An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters
+ /// True if the signature is valid.
+ /// If key submitted is not of the above nominated types.
+ public virtual void Verify(
+ AsymmetricKeyParameter key)
+ {
+ string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+ ISigner signature = SignerUtilities.GetSigner(sigName);
+
+ CheckSignature(key, signature);
+ }
+
+ protected virtual void CheckSignature(
+ AsymmetricKeyParameter publicKey,
+ ISigner signature)
+ {
+ if (!c.SignatureAlgorithm.Equals(c.TbsCertificate.Signature))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+ X509SignatureUtilities.SetSignatureParameters(signature, parameters);
+
+ signature.Init(false, publicKey);
+
+ byte[] b = this.GetTbsCertificate();
+ signature.BlockUpdate(b, 0, b.Length);
+
+ byte[] sig = this.GetSignature();
+ if (!signature.VerifySignature(sig))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509CertificatePair.cs b/src/core/srcbc/x509/X509CertificatePair.cs
new file mode 100644
index 0000000..cfe8712
--- /dev/null
+++ b/src/core/srcbc/x509/X509CertificatePair.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// This class contains a cross certificate pair. Cross certificates pairs may
+ /// contain two cross signed certificates from two CAs. A certificate from the
+ /// other CA to this CA is contained in the forward certificate, the certificate
+ /// from this CA to the other CA is contained in the reverse certificate.
+ ///
+ public class X509CertificatePair
+ {
+ private readonly X509Certificate forward;
+ private readonly X509Certificate reverse;
+
+ /// Constructor
+ /// Certificate from the other CA to this CA.
+ /// Certificate from this CA to the other CA.
+ public X509CertificatePair(
+ X509Certificate forward,
+ X509Certificate reverse)
+ {
+ this.forward = forward;
+ this.reverse = reverse;
+ }
+
+ /// Constructor from a ASN.1 CertificatePair structure.
+ /// The CertificatePair ASN.1 object.
+ public X509CertificatePair(
+ CertificatePair pair)
+ {
+ if (pair.Forward != null)
+ {
+ this.forward = new X509Certificate(pair.Forward);
+ }
+ if (pair.Reverse != null)
+ {
+ this.reverse = new X509Certificate(pair.Reverse);
+ }
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ X509CertificateStructure f = null, r = null;
+
+ if (forward != null)
+ {
+ f = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(forward.GetEncoded()));
+ }
+
+ if (reverse != null)
+ {
+ r = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(reverse.GetEncoded()));
+ }
+
+ return new CertificatePair(f, r).GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException(e.toString(), e);
+ throw new CertificateEncodingException(e.Message, e);
+ }
+ }
+
+ /// Returns the certificate from the other CA to this CA.
+ public X509Certificate Forward
+ {
+ get { return forward; }
+ }
+
+ /// Returns the certificate from this CA to the other CA.
+ public X509Certificate Reverse
+ {
+ get { return reverse; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509CertificatePair other = obj as X509CertificatePair;
+
+ if (other == null)
+ return false;
+
+ return Platform.Equals(this.forward, other.forward)
+ && Platform.Equals(this.reverse, other.reverse);
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = -1;
+ if (forward != null)
+ {
+ hash ^= forward.GetHashCode();
+ }
+ if (reverse != null)
+ {
+ hash *= 17;
+ hash ^= reverse.GetHashCode();
+ }
+ return hash;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509CertificateParser.cs b/src/core/srcbc/x509/X509CertificateParser.cs
new file mode 100644
index 0000000..1811713
--- /dev/null
+++ b/src/core/srcbc/x509/X509CertificateParser.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class for dealing with X509 certificates.
+ *
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+ public class X509CertificateParser
+ {
+ private static readonly PemParser PemCertParser = new PemParser("CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private X509Certificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+ return CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ private X509Certificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1Sequence)
+ {
+ return CreateX509Certificate(
+ X509CertificateStructure.GetInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private X509Certificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ protected virtual X509Certificate CreateX509Certificate(
+ X509CertificateStructure c)
+ {
+ return new X509Certificate(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Certificate ReadCertificate(
+ byte[] input)
+ {
+ return ReadCertificate(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertificates(
+ byte[] input)
+ {
+ return ReadCertificates(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public X509Certificate ReadCertificate(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadCertificates(
+ Stream inStream)
+ {
+ X509Certificate cert;
+ IList certs = new ArrayList();
+
+ while ((cert = ReadCertificate(inStream)) != null)
+ {
+ certs.Add(cert);
+ }
+
+ return certs;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509Crl.cs b/src/core/srcbc/x509/X509Crl.cs
new file mode 100644
index 0000000..75b4587
--- /dev/null
+++ b/src/core/srcbc/x509/X509Crl.cs
@@ -0,0 +1,409 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+ public class X509Crl
+ : X509ExtensionBase
+ // TODO Add interface Crl?
+ {
+ private readonly CertificateList c;
+ private readonly string sigAlgName;
+ private readonly byte[] sigAlgParams;
+ private readonly bool isIndirect;
+
+ public X509Crl(
+ CertificateList c)
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ this.sigAlgParams = ((Asn1Encodable)c.SignatureAlgorithm.Parameters).GetDerEncoded();
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = IsIndirectCrl;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("CRL contents invalid: " + e);
+ }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return Version == 2
+ ? c.TbsCertList.Extensions
+ : null;
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+ {
+ throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+ }
+
+ ISigner sig = SignerUtilities.GetSigner(SigAlgName);
+ sig.Init(false, publicKey);
+
+ byte[] encoded = this.GetTbsCertList();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ if (!sig.VerifySignature(this.GetSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return c.Version; }
+ }
+
+ public virtual X509Name IssuerDN
+ {
+ get { return c.Issuer; }
+ }
+
+ public virtual DateTime ThisUpdate
+ {
+ get { return c.ThisUpdate.ToDateTime(); }
+ }
+
+ public virtual DateTimeObject NextUpdate
+ {
+ get
+ {
+ return c.NextUpdate == null
+ ? null
+ : new DateTimeObject(c.NextUpdate.ToDateTime());
+ }
+ }
+
+ private ISet LoadCrlEntries()
+ {
+ ISet entrySet = new HashSet();
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+ entrySet.Add(crlEntry);
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return entrySet;
+ }
+
+ public virtual X509CrlEntry GetRevokedCertificate(
+ BigInteger serialNumber)
+ {
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+
+ if (serialNumber.Equals(entry.UserCertificate.Value))
+ {
+ return crlEntry;
+ }
+
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return null;
+ }
+
+ public virtual ISet GetRevokedCertificates()
+ {
+ ISet entrySet = LoadCrlEntries();
+
+ if (entrySet.Count > 0)
+ {
+ return entrySet; // TODO? Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public virtual byte[] GetTbsCertList()
+ {
+ try
+ {
+ return c.TbsCertList.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return c.Signature.GetBytes();
+ }
+
+ public virtual string SigAlgName
+ {
+ get { return sigAlgName; }
+ }
+
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.ObjectID.Id; }
+ }
+
+ public virtual byte[] GetSigAlgParams()
+ {
+ return Arrays.Clone(sigAlgParams);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Crl other = obj as X509Crl;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return c.GetHashCode();
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" Version: ").Append(this.Version).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" This update: ").Append(this.ThisUpdate).Append(nl);
+ buf.Append(" Next update: ").Append(this.NextUpdate).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+
+ buf.Append(" Signature: ").Append(
+ Encoding.ASCII.GetString(Hex.Encode(sig, 0, 20))).Append(nl);
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ if (i < sig.Length - 20)
+ {
+ buf.Append(" ").Append(
+ Encoding.ASCII.GetString(Hex.Encode(sig, i, 20))).Append(nl);
+ }
+ else
+ {
+ buf.Append(" ").Append(
+ Encoding.ASCII.GetString(Hex.Encode(sig, i, sig.Length - i))).Append(nl);
+ }
+ }
+
+ X509Extensions extensions = c.TbsCertList.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: ").Append(nl);
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value);
+
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.CrlNumber))
+ {
+ buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.DeltaCrlIndicator))
+ {
+ buf.Append(
+ "Base CRL: "
+ + new CrlNumber(DerInteger.GetInstance(
+ asn1Value).PositiveValue))
+ .Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.IssuingDistributionPoint))
+ {
+ buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.CrlDistributionPoints))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.FreshestCrl))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(
+ Asn1Dump.DumpAsString(asn1Value))
+ .Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+
+ ISet certSet = GetRevokedCertificates();
+ if (certSet != null)
+ {
+ foreach (X509CrlEntry entry in certSet)
+ {
+ buf.Append(entry);
+ buf.Append(nl);
+ }
+ }
+
+ return buf.ToString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+// public bool IsRevoked(
+// Certificate cert)
+// {
+// if (!cert.getType().Equals("X.509"))
+// {
+// throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+// }
+ public virtual bool IsRevoked(
+ X509Certificate cert)
+ {
+ CrlEntry[] certs = c.GetRevokedCertificates();
+
+ if (certs != null)
+ {
+// BigInteger serial = ((X509Certificate)cert).SerialNumber;
+ BigInteger serial = cert.SerialNumber;
+
+ for (int i = 0; i < certs.Length; i++)
+ {
+ if (certs[i].UserCertificate.Value.Equals(serial))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual bool IsIndirectCrl
+ {
+ get
+ {
+ Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ bool isIndirect = false;
+
+ try
+ {
+ if (idp != null)
+ {
+ isIndirect = IssuingDistributionPoint.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl;
+ }
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCrlException("Exception reading IssuingDistributionPoint", e);
+ throw new CrlException("Exception reading IssuingDistributionPoint" + e);
+ }
+
+ return isIndirect;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509CrlEntry.cs b/src/core/srcbc/x509/X509CrlEntry.cs
new file mode 100644
index 0000000..a76e6e9
--- /dev/null
+++ b/src/core/srcbc/x509/X509CrlEntry.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+ public class X509CrlEntry
+ : X509ExtensionBase
+ {
+ private CrlEntry c;
+ private bool isIndirect;
+ private X509Name previousCertificateIssuer;
+ private X509Name certificateIssuer;
+
+ public X509CrlEntry(
+ CrlEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If isIndirect
+ * is false
{@link #getCertificateIssuer()} will always
+ * return null
, previousCertificateIssuer
is
+ * ignored. If this isIndirect
is specified and this CrlEntry
+ * has no certificate issuer CRL entry extension
+ * previousCertificateIssuer
is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TbsCertificateList.CrlEntry object.
+ * @param isIndirect
+ * true
if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CrlEntry.
+ */
+ public X509CrlEntry(
+ CrlEntry c,
+ bool isIndirect,
+ X509Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.isIndirect = isIndirect;
+ this.previousCertificateIssuer = previousCertificateIssuer;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ private X509Name loadCertificateIssuer()
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ Asn1OctetString ext = GetExtensionValue(X509Extensions.CertificateIssuer);
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(ext)).GetNames();
+
+ for (int i = 0; i < names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ return X509Name.GetInstance(names[i].Name);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+
+ return null;
+ }
+
+ public X509Name GetCertificateIssuer()
+ {
+ return certificateIssuer;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Extensions;
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return c.UserCertificate.Value; }
+ }
+
+ public DateTime RevocationDate
+ {
+ get { return c.RevocationDate.ToDateTime(); }
+ }
+
+ public bool HasExtensions
+ {
+ get { return c.Extensions != null; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" userCertificate: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" revocationDate: ").Append(this.RevocationDate).Append(nl);
+ buf.Append(" certificateIssuer: ").Append(this.GetCertificateIssuer()).Append(nl);
+
+ X509Extensions extensions = c.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+ if (e.MoveNext())
+ {
+ buf.Append(" crlEntryExtensions:").Append(nl);
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(ext.Value.GetOctets());
+
+ buf.Append(" critical(")
+ .Append(ext.IsCritical)
+ .Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.ReasonCode))
+ {
+ buf.Append(new CrlReason(DerEnumerated.GetInstance(obj)));
+ }
+ else if (oid.Equals(X509Extensions.CertificateIssuer))
+ {
+ buf.Append("Certificate issuer: ").Append(
+ GeneralNames.GetInstance((Asn1Sequence)obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ }
+ buf.Append(nl);
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509CrlParser.cs b/src/core/srcbc/x509/X509CrlParser.cs
new file mode 100644
index 0000000..5f7027d
--- /dev/null
+++ b/src/core/srcbc/x509/X509CrlParser.cs
@@ -0,0 +1,194 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CrlParser
+ {
+ private static readonly PemParser PemCrlParser = new PemParser("CRL");
+
+ private readonly bool lazyAsn1;
+
+ private Asn1Set sCrlData;
+ private int sCrlDataObjectCount;
+ private Stream currentCrlStream;
+
+ public X509CrlParser()
+ : this(false)
+ {
+ }
+
+ public X509CrlParser(
+ bool lazyAsn1)
+ {
+ this.lazyAsn1 = lazyAsn1;
+ }
+
+ private X509Crl ReadPemCrl(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCrlParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl ReadDerCrl(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sCrlData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Crls;
+
+ return GetCrl();
+ }
+ }
+
+ return CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl GetCrl()
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.Count)
+ {
+ return null;
+ }
+
+ return CreateX509Crl(
+ CertificateList.GetInstance(
+ sCrlData[sCrlDataObjectCount++]));
+ }
+
+ protected virtual X509Crl CreateX509Crl(
+ CertificateList c)
+ {
+ return new X509Crl(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Crl ReadCrl(
+ byte[] input)
+ {
+ return ReadCrl(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCrls(
+ byte[] input)
+ {
+ return ReadCrls(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public X509Crl ReadCrl(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.Count)
+ {
+ return GetCrl();
+ }
+
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCrl(pis);
+ }
+
+ Asn1InputStream asn1 = lazyAsn1
+ ? new LazyAsn1InputStream(pis)
+ : new Asn1InputStream(pis);
+
+ return ReadDerCrl(asn1);
+ }
+ catch (CrlException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only significant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public ICollection ReadCrls(
+ Stream inStream)
+ {
+ X509Crl crl;
+ IList crls = new ArrayList();
+
+ while ((crl = ReadCrl(inStream)) != null)
+ {
+ crls.Add(crl);
+ }
+
+ return crls;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509ExtensionBase.cs b/src/core/srcbc/x509/X509ExtensionBase.cs
new file mode 100644
index 0000000..05acdb5
--- /dev/null
+++ b/src/core/srcbc/x509/X509ExtensionBase.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public abstract class X509ExtensionBase
+ : IX509Extension
+ {
+ protected abstract X509Extensions GetX509Extensions();
+
+ protected virtual ISet GetExtensionOids(
+ bool critical)
+ {
+ X509Extensions extensions = GetX509Extensions();
+ if (extensions != null)
+ {
+ HashSet set = new HashSet();
+ foreach (DerObjectIdentifier oid in extensions.ExtensionOids)
+ {
+ X509Extension ext = extensions.GetExtension(oid);
+ if (ext.IsCritical == critical)
+ {
+ set.Add(oid.Id);
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get non critical extensions.
+ ///
+ /// A set of non critical extension oids.
+ public virtual ISet GetNonCriticalExtensionOids()
+ {
+ return GetExtensionOids(false);
+ }
+
+ ///
+ /// Get any critical extensions.
+ ///
+ /// A sorted list of critical entension.
+ public virtual ISet GetCriticalExtensionOids()
+ {
+ return GetExtensionOids(true);
+ }
+
+ ///
+ /// Get the value of a given extension.
+ ///
+ /// The object ID of the extension.
+ /// An Asn1OctetString object if that extension is found or null if not.
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ public Asn1OctetString GetExtensionValue(
+ string oid)
+ {
+ return GetExtensionValue(new DerObjectIdentifier(oid));
+ }
+
+ public virtual Asn1OctetString GetExtensionValue(
+ DerObjectIdentifier oid)
+ {
+ X509Extensions exts = GetX509Extensions();
+ if (exts != null)
+ {
+ X509Extension ext = exts.GetExtension(oid);
+ if (ext != null)
+ {
+ return ext.Value;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509KeyUsage.cs b/src/core/srcbc/x509/X509KeyUsage.cs
new file mode 100644
index 0000000..9e21c94
--- /dev/null
+++ b/src/core/srcbc/x509/X509KeyUsage.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * A holding class for constructing an X509 Key Usage extension.
+ *
+ *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ *
+ */
+ public class X509KeyUsage
+ : Asn1Encodable
+ {
+ public const int DigitalSignature = 1 << 7;
+ public const int NonRepudiation = 1 << 6;
+ public const int KeyEncipherment = 1 << 5;
+ public const int DataEncipherment = 1 << 4;
+ public const int KeyAgreement = 1 << 3;
+ public const int KeyCertSign = 1 << 2;
+ public const int CrlSign = 1 << 1;
+ public const int EncipherOnly = 1 << 0;
+ public const int DecipherOnly = 1 << 15;
+
+ private readonly int usage;
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+ */
+ public X509KeyUsage(
+ int usage)
+ {
+ this.usage = usage;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new KeyUsage(usage);
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509SignatureUtil.cs b/src/core/srcbc/x509/X509SignatureUtil.cs
new file mode 100644
index 0000000..9929e22
--- /dev/null
+++ b/src/core/srcbc/x509/X509SignatureUtil.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509SignatureUtilities
+ {
+ private static readonly Asn1Null derNull = DerNull.Instance;
+
+ internal static void SetSignatureParameters(
+ ISigner signature,
+ Asn1Encodable parameters)
+ {
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ // TODO Put back in
+// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+// try
+// {
+// sigParams.Init(parameters.ToAsn1Object().GetDerEncoded());
+// }
+// catch (IOException e)
+// {
+// throw new SignatureException("IOException decoding parameters: " + e.Message);
+// }
+//
+// if (signature.getAlgorithm().EndsWith("MGF1"))
+// {
+// try
+// {
+// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+// }
+// catch (GeneralSecurityException e)
+// {
+// throw new SignatureException("Exception extracting parameters: " + e.Message);
+// }
+// }
+ }
+ }
+
+ internal static string GetSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable parameters = sigAlgId.Parameters;
+
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+ return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+ }
+ if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ {
+ Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+ return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.ObjectID.Id;
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509Utilities.cs b/src/core/srcbc/x509/X509Utilities.cs
new file mode 100644
index 0000000..6b4cd62
--- /dev/null
+++ b/src/core/srcbc/x509/X509Utilities.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509Utilities
+ {
+ private static readonly Hashtable algorithms = new Hashtable();
+ private static readonly Hashtable exParams = new Hashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static X509Utilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture);
+
+ if (algorithms.ContainsKey(algorithmName))
+ {
+ return (DerObjectIdentifier) algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid,
+ string algorithmName)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture);
+
+ if (exParams.ContainsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable GetAlgNames()
+ {
+ return new EnumerableProxy(algorithms.Keys);
+ }
+
+ internal static byte[] GetSignatureForObject(
+ DerObjectIdentifier sigOid, // TODO Redundant now?
+ string sigName,
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random,
+ Asn1Encodable ae)
+ {
+ if (sigOid == null)
+ throw new ArgumentNullException("sigOid");
+
+ ISigner sig = SignerUtilities.GetSigner(sigName);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+
+ byte[] encoded = ae.GetDerEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ return sig.GenerateSignature();
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509V1CertificateGenerator.cs b/src/core/srcbc/x509/X509V1CertificateGenerator.cs
new file mode 100644
index 0000000..ed67d49
--- /dev/null
+++ b/src/core/srcbc/x509/X509V1CertificateGenerator.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// Class to Generate X509V1 Certificates.
+ ///
+ public class X509V1CertificateGenerator
+ {
+ private V1TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ ///
+ /// Default Constructor.
+ ///
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the issuer distinguished name.
+ /// The issuer is the entity whose private key is used to sign the certificate.
+ ///
+ /// The issuers DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the subject distinguished name.
+ /// The subject describes the entity associated with the public key.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ tbsGen.SetSubjectPublicKeyInfo(
+ SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("unable to process key - " + e.ToString());
+ }
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ /// This can be either a name or an OID, names are treated as case insensitive.
+ ///
+ /// string representation of the algorithm name
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested", "signatureAlgorithm");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Generate a new X509Certificate.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate a new X509Certificate specifying a SecureRandom instance that you would like to use.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// The Secure Random you want to use.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOID, signatureAlgorithm, privateKey, random, tbsCert);
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ throw new CertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return GenerateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ // TODO
+ // throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ throw new CertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509V2AttributeCertificate.cs b/src/core/srcbc/x509/X509V2AttributeCertificate.cs
new file mode 100644
index 0000000..b6a6430
--- /dev/null
+++ b/src/core/srcbc/x509/X509V2AttributeCertificate.cs
@@ -0,0 +1,239 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ /// An implementation of a version 2 X.509 Attribute Certificate.
+ public class X509V2AttributeCertificate
+ : X509ExtensionBase, IX509AttributeCertificate
+ {
+ private readonly AttributeCertificate cert;
+ private readonly DateTime notBefore;
+ private readonly DateTime notAfter;
+
+ public X509V2AttributeCertificate(
+ Stream encIn)
+ : this(new Asn1InputStream(encIn))
+ {
+ }
+
+ public X509V2AttributeCertificate(
+ byte[] encoded)
+ : this(new Asn1InputStream(encoded))
+ {
+ }
+
+ internal X509V2AttributeCertificate(
+ Asn1InputStream ais)
+ : this(AttributeCertificate.GetInstance(ais.ReadObject()))
+ {
+ }
+
+ internal X509V2AttributeCertificate(
+ AttributeCertificate cert)
+ {
+ this.cert = cert;
+
+ try
+ {
+ this.notAfter = cert.ACInfo.AttrCertValidityPeriod.NotAfterTime.ToDateTime();
+ this.notBefore = cert.ACInfo.AttrCertValidityPeriod.NotBeforeTime.ToDateTime();
+ }
+ catch (Exception e)
+ {
+ throw new IOException("invalid data structure in certificate!", e);
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return cert.ACInfo.Version.Value.IntValue + 1; }
+ }
+
+ public virtual BigInteger SerialNumber
+ {
+ get { return cert.ACInfo.SerialNumber.Value; }
+ }
+
+ public virtual AttributeCertificateHolder Holder
+ {
+ get
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)cert.ACInfo.Holder.ToAsn1Object());
+ }
+ }
+
+ public virtual AttributeCertificateIssuer Issuer
+ {
+ get
+ {
+ return new AttributeCertificateIssuer(cert.ACInfo.Issuer);
+ }
+ }
+
+ public virtual DateTime NotBefore
+ {
+ get { return notBefore; }
+ }
+
+ public virtual DateTime NotAfter
+ {
+ get { return notAfter; }
+ }
+
+ public virtual bool[] GetIssuerUniqueID()
+ {
+ DerBitString id = cert.ACInfo.IssuerUniqueID;
+
+ if (id != null)
+ {
+ byte[] bytes = id.GetBytes();
+ bool[] boolId = new bool[bytes.Length * 8 - id.PadBits];
+
+ for (int i = 0; i != boolId.Length; i++)
+ {
+ //boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ boolId[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public virtual bool IsValidNow
+ {
+ get { return IsValid(DateTime.UtcNow); }
+ }
+
+ public virtual bool IsValid(
+ DateTime date)
+ {
+ return date.CompareTo(NotBefore) >= 0 && date.CompareTo(NotAfter) <= 0;
+ }
+
+ public virtual void CheckValidity()
+ {
+ this.CheckValidity(DateTime.UtcNow);
+ }
+
+ public virtual void CheckValidity(
+ DateTime date)
+ {
+ if (date.CompareTo(NotAfter) > 0)
+ throw new CertificateExpiredException("certificate expired on " + NotAfter);
+ if (date.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + NotBefore);
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return cert.SignatureValue.GetBytes();
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+ {
+ throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+ }
+
+ ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id);
+
+ signature.Init(false, publicKey);
+
+ try
+ {
+ byte[] b = cert.ACInfo.GetEncoded();
+ signature.BlockUpdate(b, 0, b.Length);
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("Exception encoding certificate info object", e);
+ }
+
+ if (!signature.VerifySignature(this.GetSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ return cert.GetEncoded();
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return cert.ACInfo.Extensions;
+ }
+
+ public virtual X509Attribute[] GetAttributes()
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ X509Attribute[] attrs = new X509Attribute[seq.Count];
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ attrs[i] = new X509Attribute((Asn1Encodable)seq[i]);
+ }
+
+ return attrs;
+ }
+
+ public virtual X509Attribute[] GetAttributes(
+ string oid)
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ ArrayList list = new ArrayList();
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ X509Attribute attr = new X509Attribute((Asn1Encodable)seq[i]);
+ if (attr.Oid.Equals(oid))
+ {
+ list.Add(attr);
+ }
+ }
+
+ if (list.Count < 1)
+ {
+ return null;
+ }
+
+ return (X509Attribute[]) list.ToArray(typeof(X509Attribute));
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509V2AttributeCertificate other = obj as X509V2AttributeCertificate;
+
+ if (other == null)
+ return false;
+
+ return cert.Equals(other.cert);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return cert.GetHashCode();
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509V2AttributeCertificateGenerator.cs b/src/core/srcbc/x509/X509V2AttributeCertificateGenerator.cs
new file mode 100644
index 0000000..43bc840
--- /dev/null
+++ b/src/core/srcbc/x509/X509V2AttributeCertificateGenerator.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Class to produce an X.509 Version 2 AttributeCertificate.
+ public class X509V2AttributeCertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2AttributeCertificateGenerator()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ }
+
+ /// Reset the generator
+ public void Reset()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator.Reset();
+ }
+
+ /// Set the Holder of this Attribute Certificate.
+ public void SetHolder(
+ AttributeCertificateHolder holder)
+ {
+ acInfoGen.SetHolder(holder.holder);
+ }
+
+ /// Set the issuer.
+ public void SetIssuer(
+ AttributeCertificateIssuer issuer)
+ {
+ acInfoGen.SetIssuer(AttCertIssuer.GetInstance(issuer.form));
+ }
+
+ /// Set the serial number for the certificate.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ acInfoGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ public void SetNotBefore(
+ DateTime date)
+ {
+ acInfoGen.SetStartDate(new DerGeneralizedTime(date));
+ }
+
+ public void SetNotAfter(
+ DateTime date)
+ {
+ acInfoGen.SetEndDate(new DerGeneralizedTime(date));
+ }
+
+ ///
+ /// Set the signature algorithm. This can be either a name or an OID, names
+ /// are treated as case insensitive.
+ ///
+ /// The algorithm name.
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ acInfoGen.SetSignature(sigAlgId);
+ }
+
+ /// Add an attribute.
+ public void AddAttribute(
+ X509Attribute attribute)
+ {
+ acInfoGen.AddAttribute(AttributeX509.GetInstance(attribute.ToAsn1Object()));
+ }
+
+ public void SetIssuerUniqueId(
+ bool[] iui)
+ {
+ // TODO convert bool array to bit string
+ //acInfoGen.SetIssuerUniqueID(iui);
+ throw Platform.CreateNotImplementedException("SetIssuerUniqueId()");
+ }
+
+ /// Add a given extension field for the standard extensions tag.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag.
+ /// The value parameter becomes the contents of the octet string associated
+ /// with the extension.
+ ///
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject.
+ ///
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter publicKey)
+ {
+ return Generate(publicKey, null);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject,
+ /// using the supplied source of randomness, if required.
+ ///
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter publicKey,
+ SecureRandom random)
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ acInfoGen.SetExtensions(extGenerator.Generate());
+ }
+
+ AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ v.Add(acInfo, sigAlgId);
+
+ try
+ {
+ v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo)));
+
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("constructed invalid certificate", e);
+ throw new CertificateEncodingException("constructed invalid certificate", e);
+ }
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509V2CRLGenerator.cs b/src/core/srcbc/x509/X509V2CRLGenerator.cs
new file mode 100644
index 0000000..2d2c2fc
--- /dev/null
+++ b/src/core/srcbc/x509/X509V2CRLGenerator.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class to produce an X.509 Version 2 CRL.
+ */
+ public class X509V2CrlGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2TbsCertListGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2CrlGenerator()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void Reset()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ extGenerator.Reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ public void SetThisUpdate(
+ DateTime date)
+ {
+ tbsGen.SetThisUpdate(new Time(date));
+ }
+
+ public void SetNextUpdate(
+ DateTime date)
+ {
+ tbsGen.SetNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CrlReason extension.
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason,
+ DateTime invalidityDate)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ X509Extensions extensions)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), extensions);
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509Crl to source the other entries from.
+ */
+ public void AddCrl(
+ X509Crl other)
+ {
+ if (other == null)
+ throw new ArgumentNullException("other");
+
+ ISet revocations = other.GetRevokedCertificates();
+
+ if (revocations != null)
+ {
+ foreach (X509CrlEntry entry in revocations)
+ {
+ try
+ {
+ tbsGen.AddCrlEntry(
+ Asn1Sequence.GetInstance(
+ Asn1Object.FromByteArray(entry.GetEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new CrlException("exception processing encoding of CRL", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an oid, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Unknown signature type requested", e);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ /// Generate an X509 CRL, based on the current issuer and subject.
+ /// The key used for signing.
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ /// Generate an X509 CRL, based on the current issuer and subject.
+ /// The key used for signing.
+ /// A user-defined source of randomness.
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateList tbsCrl = GenerateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOID, signatureAlgorithm, privateKey, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ // TODO
+// throw new ExtCrlException("cannot generate CRL encoding", e);
+ throw new CrlException("cannot generate CRL encoding", e);
+ }
+
+ return GenerateJcaObject(tbsCrl, signature);
+ }
+
+ private TbsCertificateList GenerateCertList()
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ return tbsGen.GenerateTbsCertList();
+ }
+
+ private X509Crl GenerateJcaObject(
+ TbsCertificateList tbsCrl,
+ byte[] signature)
+ {
+ return new X509Crl(
+ CertificateList.GetInstance(
+ new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature))));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/X509V3CertificateGenerator.cs b/src/core/srcbc/x509/X509V3CertificateGenerator.cs
new file mode 100644
index 0000000..443f045
--- /dev/null
+++ b/src/core/srcbc/x509/X509V3CertificateGenerator.cs
@@ -0,0 +1,303 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A class to Generate Version 3 X509Certificates.
+ ///
+ public class X509V3CertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V3TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOid;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the Generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ extGenerator.Reset();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can Get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the distinguished name of the issuer.
+ /// The issuer is the entity which is signing the certificate.
+ ///
+ /// The issuer's DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the DN of the entity that this certificate is about.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ ///
+ ///
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3).
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension using a string with a dotted decimal OID.
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3),
+ /// copying the extension value from another certificate.
+ ///
+ public void CopyAndAddExtension(
+ string oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void CopyAndAddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ Asn1OctetString extValue = cert.GetExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+ this.AddExtension(oid, critical, value);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message, e);
+ }
+ }
+
+ ///
+ /// Generate an X509Certificate.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate an X509Certificate using your own SecureRandom.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// You Secure Random instance.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateStructure tbsCert = GenerateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOid, signatureAlgorithm, privateKey, random, tbsCert);
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ throw new CertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return GenerateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ // TODO
+ // throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ throw new CertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TbsCertificateStructure GenerateTbsCert()
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ return tbsGen.GenerateTbsCertificate();
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs b/src/core/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs
new file mode 100644
index 0000000..f827517
--- /dev/null
+++ b/src/core/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs
@@ -0,0 +1,105 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /// A high level authority key identifier.
+ public class AuthorityKeyIdentifierStructure
+ : AuthorityKeyIdentifier
+ {
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ // TODO Add a functional constructor from byte[]?
+ public AuthorityKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1Sequence) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1Sequence FromCertificate(
+ X509Certificate certificate)
+ {
+ try
+ {
+ GeneralName genName = new GeneralName(
+ PrincipalUtilities.GetIssuerX509Principal(certificate));
+
+ if (certificate.Version == 3)
+ {
+ Asn1OctetString ext = certificate.GetExtensionValue(X509Extensions.SubjectKeyIdentifier);
+
+ if (ext != null)
+ {
+ Asn1OctetString str = (Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(ext);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ str.GetOctets(), new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ }
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ certificate.GetPublicKey());
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details", e);
+ }
+ }
+
+ private static Asn1Sequence FromKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+// SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+// (Asn1Sequence) Asn1Object.FromByteArray(
+// pubKey.GetEncoded()));
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't process key: " + e);
+ }
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using the passed in certificate's public
+ * key, issuer and serial number.
+ *
+ * @param certificate the certificate providing the information.
+ * @throws CertificateParsingException if there is a problem processing the certificate
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Certificate certificate)
+ : base(FromCertificate(certificate))
+ {
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using just the hash of the
+ * public key.
+ *
+ * @param pubKey the key to generate the hash from.
+ * @throws InvalidKeyException if there is a problem using the key.
+ */
+ public AuthorityKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs b/src/core/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs
new file mode 100644
index 0000000..7ea4089
--- /dev/null
+++ b/src/core/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /**
+ * A high level subject key identifier.
+ */
+ public class SubjectKeyIdentifierStructure
+ : SubjectKeyIdentifier
+ {
+// private AuthorityKeyIdentifier authKeyID;
+
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ public SubjectKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1OctetString FromPublicKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1OctetString) new SubjectKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details: " + e.ToString());
+ }
+ }
+
+ public SubjectKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromPublicKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/extension/X509ExtensionUtil.cs b/src/core/srcbc/x509/extension/X509ExtensionUtil.cs
new file mode 100644
index 0000000..34f0eab
--- /dev/null
+++ b/src/core/srcbc/x509/extension/X509ExtensionUtil.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ public class X509ExtensionUtilities
+ {
+ public static Asn1Object FromExtensionValue(
+ Asn1OctetString extensionValue)
+ {
+ return Asn1Object.FromByteArray(extensionValue.GetOctets());
+ }
+
+ public static ICollection GetIssuerAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.IssuerAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ public static ICollection GetSubjectAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.SubjectAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ private static ICollection GetAlternativeName(
+ Asn1OctetString extVal)
+ {
+ ArrayList temp = new ArrayList();
+
+ if (extVal != null)
+ {
+ try
+ {
+ Asn1Sequence seq = DerSequence.GetInstance(FromExtensionValue(extVal));
+
+ foreach (GeneralName genName in seq)
+ {
+ ArrayList list = new ArrayList();
+ list.Add(genName.TagNo);
+
+ switch (genName.TagNo)
+ {
+ case GeneralName.EdiPartyName:
+ case GeneralName.X400Address:
+ case GeneralName.OtherName:
+ list.Add(genName.Name.ToAsn1Object());
+ break;
+ case GeneralName.DirectoryName:
+ list.Add(X509Name.GetInstance(genName.Name).ToString());
+ break;
+ case GeneralName.DnsName:
+ case GeneralName.Rfc822Name:
+ case GeneralName.UniformResourceIdentifier:
+ list.Add(((IAsn1String)genName.Name).GetString());
+ break;
+ case GeneralName.RegisteredID:
+ list.Add(DerObjectIdentifier.GetInstance(genName.Name).Id);
+ break;
+ case GeneralName.IPAddress:
+ list.Add(DerOctetString.GetInstance(genName.Name).GetOctets());
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.TagNo);
+ }
+
+ temp.Add(list);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+ }
+
+ return temp;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/IX509Selector.cs b/src/core/srcbc/x509/store/IX509Selector.cs
new file mode 100644
index 0000000..41e7031
--- /dev/null
+++ b/src/core/srcbc/x509/store/IX509Selector.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Selector
+ : ICloneable
+ {
+ bool Match(object obj);
+ }
+}
diff --git a/src/core/srcbc/x509/store/IX509Store.cs b/src/core/srcbc/x509/store/IX509Store.cs
new file mode 100644
index 0000000..eaf9c54
--- /dev/null
+++ b/src/core/srcbc/x509/store/IX509Store.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Store
+ {
+// void Init(IX509StoreParameters parameters);
+ ICollection GetMatches(IX509Selector selector);
+ }
+}
diff --git a/src/core/srcbc/x509/store/IX509StoreParameters.cs b/src/core/srcbc/x509/store/IX509StoreParameters.cs
new file mode 100644
index 0000000..ad93734
--- /dev/null
+++ b/src/core/srcbc/x509/store/IX509StoreParameters.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509StoreParameters
+ {
+ }
+}
diff --git a/src/core/srcbc/x509/store/NoSuchStoreException.cs b/src/core/srcbc/x509/store/NoSuchStoreException.cs
new file mode 100644
index 0000000..2c36f0d
--- /dev/null
+++ b/src/core/srcbc/x509/store/NoSuchStoreException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class NoSuchStoreException
+ : X509StoreException
+ {
+ public NoSuchStoreException()
+ {
+ }
+
+ public NoSuchStoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public NoSuchStoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509AttrCertStoreSelector.cs b/src/core/srcbc/x509/store/X509AttrCertStoreSelector.cs
new file mode 100644
index 0000000..a0f85a4
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509AttrCertStoreSelector.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * This class is an Selector
like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.bouncycastle.x509.X509AttributeCertificate
+ * @see org.bouncycastle.x509.X509Store
+ */
+ public class X509AttrCertStoreSelector
+ : IX509Selector
+ {
+ // TODO: name constraints???
+
+ private IX509AttributeCertificate attributeCert;
+ private DateTimeObject attributeCertificateValid;
+ private AttributeCertificateHolder holder;
+ private AttributeCertificateIssuer issuer;
+ private BigInteger serialNumber;
+ private ISet targetNames = new HashSet();
+ private ISet targetGroups = new HashSet();
+
+ public X509AttrCertStoreSelector()
+ {
+ }
+
+ private X509AttrCertStoreSelector(
+ X509AttrCertStoreSelector o)
+ {
+ this.attributeCert = o.attributeCert;
+ this.attributeCertificateValid = o.attributeCertificateValid;
+ this.holder = o.holder;
+ this.issuer = o.issuer;
+ this.serialNumber = o.serialNumber;
+ this.targetGroups = new HashSet(o.targetGroups);
+ this.targetNames = new HashSet(o.targetNames);
+ }
+
+ ///
+ /// Decides if the given attribute certificate should be selected.
+ ///
+ /// The attribute certificate to be checked.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ IX509AttributeCertificate attrCert = obj as IX509AttributeCertificate;
+
+ if (attrCert == null)
+ return false;
+
+ if (this.attributeCert != null && !this.attributeCert.Equals(attrCert))
+ return false;
+
+ if (serialNumber != null && !attrCert.SerialNumber.Equals(serialNumber))
+ return false;
+
+ if (holder != null && !attrCert.Holder.Equals(holder))
+ return false;
+
+ if (issuer != null && !attrCert.Issuer.Equals(issuer))
+ return false;
+
+ if (attributeCertificateValid != null && !attrCert.IsValid(attributeCertificateValid.Value))
+ return false;
+
+ if (targetNames.Count > 0 || targetGroups.Count > 0)
+ {
+ Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(
+ X509Extensions.TargetInformation);
+
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(targetInfoExt));
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ Targets[] targetss = targetinfo.GetTargetsObjects();
+
+ if (targetNames.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetName = targets[j].TargetName;
+
+ if (targetName != null && targetNames.Contains(targetName))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ if (targetGroups.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetGroup = targets[j].TargetGroup;
+
+ if (targetGroup != null && targetGroups.Contains(targetGroup))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509AttrCertStoreSelector(this);
+ }
+
+ /// The attribute certificate which must be matched.
+ /// If null is given, any will do.
+ public IX509AttributeCertificate AttributeCert
+ {
+ get { return attributeCert; }
+ set { this.attributeCert = value; }
+ }
+
+ [Obsolete("Use AttributeCertificateValid instead")]
+ public DateTimeObject AttribueCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The criteria for validity
+ /// If null is given any will do.
+ public DateTimeObject AttributeCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The holder.
+ /// If null is given any will do.
+ public AttributeCertificateHolder Holder
+ {
+ get { return holder; }
+ set { this.holder = value; }
+ }
+
+ /// The issuer.
+ /// If null is given any will do.
+ public AttributeCertificateIssuer Issuer
+ {
+ get { return issuer; }
+ set { this.issuer = value; }
+ }
+
+ /// The serial number.
+ /// If null is given any will do.
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { this.serialNumber = value; }
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name The name as a GeneralName (not null
)
+ */
+ public void AddTargetName(
+ GeneralName name)
+ {
+ targetNames.Add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetName(
+ byte[] name)
+ {
+ AddTargetName(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetName(byte[])
+ * @see #AddTargetName(GeneralName)
+ */
+ public void SetTargetNames(
+ IEnumerable names)
+ {
+ targetNames = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public IEnumerable GetTargetNames()
+ {
+ return new EnumerableProxy(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param group The group as GeneralName form (not null
)
+ */
+ public void AddTargetGroup(
+ GeneralName group)
+ {
+ targetGroups.Add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetGroup(
+ byte[] name)
+ {
+ AddTargetGroup(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of GeneralName
objects or byte[]
+ * representing DER encoded GeneralNames.
+ *
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetGroup(byte[])
+ * @see #AddTargetGroup(GeneralName)
+ */
+ public void SetTargetGroups(
+ IEnumerable names)
+ {
+ targetGroups = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target groups. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public IEnumerable GetTargetGroups()
+ {
+ return new EnumerableProxy(targetGroups);
+ }
+
+ private ISet ExtractGeneralNames(
+ IEnumerable names)
+ {
+ ISet result = new HashSet();
+
+ if (names != null)
+ {
+ foreach (object o in names)
+ {
+ if (o is GeneralName)
+ {
+ result.Add(o);
+ }
+ else
+ {
+ result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray((byte[]) o)));
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509CertPairStoreSelector.cs b/src/core/srcbc/x509/store/X509CertPairStoreSelector.cs
new file mode 100644
index 0000000..86f6c5c
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509CertPairStoreSelector.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ ///
+ /// This class is an IX509Selector
implementation to select
+ /// certificate pairs, which are e.g. used for cross certificates. The set of
+ /// criteria is given from two X509CertStoreSelector
objects,
+ /// each of which, if present, must match the respective component of a pair.
+ ///
+ public class X509CertPairStoreSelector
+ : IX509Selector
+ {
+ private static X509CertStoreSelector CloneSelector(
+ X509CertStoreSelector s)
+ {
+ return s == null ? null : (X509CertStoreSelector) s.Clone();
+ }
+
+ private X509CertificatePair certPair;
+ private X509CertStoreSelector forwardSelector;
+ private X509CertStoreSelector reverseSelector;
+
+ public X509CertPairStoreSelector()
+ {
+ }
+
+ private X509CertPairStoreSelector(
+ X509CertPairStoreSelector o)
+ {
+ this.certPair = o.CertPair;
+ this.forwardSelector = o.ForwardSelector;
+ this.reverseSelector = o.ReverseSelector;
+ }
+
+ /// The certificate pair which is used for testing on equality.
+ public X509CertificatePair CertPair
+ {
+ get { return certPair; }
+ set { this.certPair = value; }
+ }
+
+ /// The certificate selector for the forward part.
+ public X509CertStoreSelector ForwardSelector
+ {
+ get { return CloneSelector(forwardSelector); }
+ set { this.forwardSelector = CloneSelector(value); }
+ }
+
+ /// The certificate selector for the reverse part.
+ public X509CertStoreSelector ReverseSelector
+ {
+ get { return CloneSelector(reverseSelector); }
+ set { this.reverseSelector = CloneSelector(value); }
+ }
+
+ ///
+ /// Decides if the given certificate pair should be selected. If
+ /// obj is not a X509CertificatePair
, this method
+ /// returns false
.
+ ///
+ /// The X509CertificatePair
to be tested.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ X509CertificatePair pair = obj as X509CertificatePair;
+
+ if (pair == null)
+ return false;
+
+ if (certPair != null && !certPair.Equals(pair))
+ return false;
+
+ if (forwardSelector != null && !forwardSelector.Match(pair.Forward))
+ return false;
+
+ if (reverseSelector != null && !reverseSelector.Match(pair.Reverse))
+ return false;
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509CertPairStoreSelector(this);
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509CertStoreSelector.cs b/src/core/srcbc/x509/store/X509CertStoreSelector.cs
new file mode 100644
index 0000000..b9c2ff6
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509CertStoreSelector.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CertStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private byte[] authorityKeyIdentifier;
+ private int basicConstraints = -1;
+ private X509Certificate certificate;
+ private DateTimeObject certificateValid;
+ private ISet extendedKeyUsage;
+ private X509Name issuer;
+ private bool[] keyUsage;
+ private ISet policy;
+ private DateTimeObject privateKeyValid;
+ private BigInteger serialNumber;
+ private X509Name subject;
+ private byte[] subjectKeyIdentifier;
+ private SubjectPublicKeyInfo subjectPublicKey;
+ private DerObjectIdentifier subjectPublicKeyAlgID;
+
+ public X509CertStoreSelector()
+ {
+ }
+
+ public X509CertStoreSelector(
+ X509CertStoreSelector o)
+ {
+ this.authorityKeyIdentifier = o.AuthorityKeyIdentifier;
+ this.basicConstraints = o.BasicConstraints;
+ this.certificate = o.Certificate;
+ this.certificateValid = o.CertificateValid;
+ this.extendedKeyUsage = o.ExtendedKeyUsage;
+ this.issuer = o.Issuer;
+ this.keyUsage = o.KeyUsage;
+ this.policy = o.Policy;
+ this.privateKeyValid = o.PrivateKeyValid;
+ this.serialNumber = o.SerialNumber;
+ this.subject = o.Subject;
+ this.subjectKeyIdentifier = o.SubjectKeyIdentifier;
+ this.subjectPublicKey = o.SubjectPublicKey;
+ this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CertStoreSelector(this);
+ }
+
+ public byte[] AuthorityKeyIdentifier
+ {
+ get { return Arrays.Clone(authorityKeyIdentifier); }
+ set { authorityKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public int BasicConstraints
+ {
+ get { return basicConstraints; }
+ set
+ {
+ if (value < -2)
+ throw new ArgumentException("value can't be less than -2", "value");
+
+ basicConstraints = value;
+ }
+ }
+
+ public X509Certificate Certificate
+ {
+ get { return certificate; }
+ set { this.certificate = value; }
+ }
+
+ public DateTimeObject CertificateValid
+ {
+ get { return certificateValid; }
+ set { certificateValid = value; }
+ }
+
+ public ISet ExtendedKeyUsage
+ {
+ get { return CopySet(extendedKeyUsage); }
+ set { extendedKeyUsage = CopySet(value); }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ set { issuer = value; }
+ }
+
+ [Obsolete("Avoid working with X509Name objects in string form")]
+ public string IssuerAsString
+ {
+ get { return issuer != null ? issuer.ToString() : null; }
+ }
+
+ public bool[] KeyUsage
+ {
+ get { return CopyBoolArray(keyUsage); }
+ set { keyUsage = CopyBoolArray(value); }
+ }
+
+ ///
+ /// An ISet
of DerObjectIdentifier
objects.
+ ///
+ public ISet Policy
+ {
+ get { return CopySet(policy); }
+ set { policy = CopySet(value); }
+ }
+
+ public DateTimeObject PrivateKeyValid
+ {
+ get { return privateKeyValid; }
+ set { privateKeyValid = value; }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { serialNumber = value; }
+ }
+
+ public X509Name Subject
+ {
+ get { return subject; }
+ set { subject = value; }
+ }
+
+ public string SubjectAsString
+ {
+ get { return subject != null ? subject.ToString() : null; }
+ }
+
+ public byte[] SubjectKeyIdentifier
+ {
+ get { return Arrays.Clone(subjectKeyIdentifier); }
+ set { subjectKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKey
+ {
+ get { return subjectPublicKey; }
+ set { subjectPublicKey = value; }
+ }
+
+ public DerObjectIdentifier SubjectPublicKeyAlgID
+ {
+ get { return subjectPublicKeyAlgID; }
+ set { subjectPublicKeyAlgID = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Certificate c = obj as X509Certificate;
+
+ if (c == null)
+ return false;
+
+ if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier))
+ return false;
+
+ if (basicConstraints != -1)
+ {
+ int bc = c.GetBasicConstraints();
+
+ if (basicConstraints == -2)
+ {
+ if (bc != -1)
+ return false;
+ }
+ else
+ {
+ if (bc < basicConstraints)
+ return false;
+ }
+ }
+
+ if (certificate != null && !certificate.Equals(c))
+ return false;
+
+ if (certificateValid != null && !c.IsValid(certificateValid.Value))
+ return false;
+
+ if (extendedKeyUsage != null)
+ {
+ IList eku = c.GetExtendedKeyUsage();
+
+ // Note: if no extended key usage set, all key purposes are implicitly allowed
+
+ if (eku != null)
+ {
+ foreach (DerObjectIdentifier oid in extendedKeyUsage)
+ {
+ if (!eku.Contains(oid.Id))
+ return false;
+ }
+ }
+ }
+
+ if (issuer != null && !issuer.Equivalent(c.IssuerDN))
+ return false;
+
+ if (keyUsage != null)
+ {
+ bool[] ku = c.GetKeyUsage();
+
+ // Note: if no key usage set, all key purposes are implicitly allowed
+
+ if (ku != null)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ if (keyUsage[i] && !ku[i])
+ return false;
+ }
+ }
+ }
+
+ if (policy != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies);
+ if (extVal == null)
+ return false;
+
+ Asn1Sequence certPolicies = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ if (policy.Count < 1 && certPolicies.Count < 1)
+ return false;
+
+ bool found = false;
+ foreach (PolicyInformation pi in certPolicies)
+ {
+ if (policy.Contains(pi.PolicyIdentifier))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (privateKeyValid != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod);
+ if (extVal == null)
+ return false;
+
+ PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ DateTime dt = privateKeyValid.Value;
+ DateTime notAfter = pkup.NotAfter.ToDateTime();
+ DateTime notBefore = pkup.NotBefore.ToDateTime();
+
+ if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0)
+ return false;
+ }
+
+ if (serialNumber != null && !serialNumber.Equals(c.SerialNumber))
+ return false;
+
+ if (subject != null && !subject.Equivalent(c.SubjectDN))
+ return false;
+
+ if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier))
+ return false;
+
+ if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c)))
+ return false;
+
+ if (subjectPublicKeyAlgID != null
+ && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID))
+ return false;
+
+ return true;
+ }
+
+ internal static bool IssuersMatch(
+ X509Name a,
+ X509Name b)
+ {
+ return a == null ? b == null : a.Equivalent(b);
+ }
+
+ private static bool[] CopyBoolArray(
+ bool[] b)
+ {
+ return b == null ? null : (bool[]) b.Clone();
+ }
+
+ private static ISet CopySet(
+ ISet s)
+ {
+ return s == null ? null : new HashSet(s);
+ }
+
+ private static SubjectPublicKeyInfo GetSubjectPublicKey(
+ X509Certificate c)
+ {
+ return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey());
+ }
+
+ private static bool MatchExtension(
+ byte[] b,
+ X509Certificate c,
+ DerObjectIdentifier oid)
+ {
+ if (b == null)
+ return true;
+
+ Asn1OctetString extVal = c.GetExtensionValue(oid);
+
+ if (extVal == null)
+ return false;
+
+ return extVal != null && Arrays.AreEqual(b, extVal.GetEncoded());
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509CollectionStore.cs b/src/core/srcbc/x509/store/X509CollectionStore.cs
new file mode 100644
index 0000000..7a93fca
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509CollectionStore.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * A simple collection backed store.
+ */
+ internal class X509CollectionStore
+ : IX509Store
+ {
+ private ICollection _local;
+
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ internal X509CollectionStore(
+ ICollection collection)
+ {
+ _local = new ArrayList(collection);
+ }
+
+ /**
+ * Return the matches in the collection for the passed in selector.
+ *
+ * @param selector the selector to match against.
+ * @return a possibly empty collection of matching objects.
+ */
+ public ICollection GetMatches(
+ IX509Selector selector)
+ {
+ if (selector == null)
+ {
+ return new ArrayList(_local);
+ }
+
+ IList result = new ArrayList();
+ foreach (object obj in _local)
+ {
+ if (selector.Match(obj))
+ result.Add(obj);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509CollectionStoreParameters.cs b/src/core/srcbc/x509/store/X509CollectionStoreParameters.cs
new file mode 100644
index 0000000..6019618
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509CollectionStoreParameters.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /// This class contains a collection for collection based X509Store
s.
+ public class X509CollectionStoreParameters
+ : IX509StoreParameters
+ {
+ private readonly ArrayList collection;
+
+ ///
+ /// Constructor.
+ ///
+ /// The collection is copied.
+ ///
+ ///
+ /// The collection containing X.509 object types.
+ /// If collection is null.
+ public X509CollectionStoreParameters(
+ ICollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this.collection = new ArrayList(collection);
+ }
+
+ // TODO Do we need to be able to Clone() these, and should it really be shallow?
+// /**
+// * Returns a shallow clone. The returned contents are not copied, so adding
+// * or removing objects will effect this.
+// *
+// * @return a shallow clone.
+// */
+// public object Clone()
+// {
+// return new X509CollectionStoreParameters(collection);
+// }
+
+ /// Returns a copy of the ICollection
.
+ public ICollection GetCollection()
+ {
+ return new ArrayList(collection);
+ }
+
+ /// Returns a formatted string describing the parameters.
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("X509CollectionStoreParameters: [\n");
+ sb.Append(" collection: " + collection + "\n");
+ sb.Append("]");
+ return sb.ToString();
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509CrlStoreSelector.cs b/src/core/srcbc/x509/store/X509CrlStoreSelector.cs
new file mode 100644
index 0000000..a09229e
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509CrlStoreSelector.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CrlStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private X509Certificate certificateChecking;
+ private DateTimeObject dateAndTime;
+ private ICollection issuers;
+ private BigInteger maxCrlNumber;
+ private BigInteger minCrlNumber;
+
+ private IX509AttributeCertificate attrCertChecking;
+ private bool completeCrlEnabled;
+ private bool deltaCrlIndicatorEnabled;
+ private byte[] issuingDistributionPoint;
+ private bool issuingDistributionPointEnabled;
+ private BigInteger maxBaseCrlNumber;
+
+ public X509CrlStoreSelector()
+ {
+ }
+
+ public X509CrlStoreSelector(
+ X509CrlStoreSelector o)
+ {
+ this.certificateChecking = o.CertificateChecking;
+ this.dateAndTime = o.DateAndTime;
+ this.issuers = o.Issuers;
+ this.maxCrlNumber = o.MaxCrlNumber;
+ this.minCrlNumber = o.MinCrlNumber;
+
+ this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled;
+ this.completeCrlEnabled = o.CompleteCrlEnabled;
+ this.maxBaseCrlNumber = o.MaxBaseCrlNumber;
+ this.attrCertChecking = o.AttrCertChecking;
+ this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled;
+ this.issuingDistributionPoint = o.IssuingDistributionPoint;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CrlStoreSelector(this);
+ }
+
+ public X509Certificate CertificateChecking
+ {
+ get { return certificateChecking; }
+ set { certificateChecking = value; }
+ }
+
+ public DateTimeObject DateAndTime
+ {
+ get { return dateAndTime; }
+ set { dateAndTime = value; }
+ }
+
+ ///
+ /// An ICollection
of X509Name
objects
+ ///
+ public ICollection Issuers
+ {
+ get { return new ArrayList(issuers); }
+ set { issuers = new ArrayList(value); }
+ }
+
+ public BigInteger MaxCrlNumber
+ {
+ get { return maxCrlNumber; }
+ set { maxCrlNumber = value; }
+ }
+
+ public BigInteger MinCrlNumber
+ {
+ get { return minCrlNumber; }
+ set { minCrlNumber = value; }
+ }
+
+ /**
+ * The attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If null
is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the IX509AttributeCertificate
being checked (or
+ * null
)
+ * @see #getAttrCertificateChecking()
+ */
+ public IX509AttributeCertificate AttrCertChecking
+ {
+ get { return attrCertChecking; }
+ set { this.attrCertChecking = value; }
+ }
+
+ /**
+ * If true
only complete CRLs are returned. Defaults to
+ * false
.
+ *
+ * @return true
if only complete CRLs are returned.
+ */
+ public bool CompleteCrlEnabled
+ {
+ get { return completeCrlEnabled; }
+ set { this.completeCrlEnabled = value; }
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to false
.
+ *
+ * @return Returns true
if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public bool DeltaCrlIndicatorEnabled
+ {
+ get { return deltaCrlIndicatorEnabled; }
+ set { this.deltaCrlIndicatorEnabled = value; }
+ }
+
+ /**
+ * The issuing distribution point.
+ *
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ *
+ * The byte array is cloned to protect against subsequent modifications.
+ *
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(bool)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public byte[] IssuingDistributionPoint
+ {
+ get { return Arrays.Clone(issuingDistributionPoint); }
+ set { this.issuingDistributionPoint = Arrays.Clone(value); }
+ }
+
+ /**
+ * Whether the issuing distribution point criteria should be applied.
+ * Defaults to false
.
+ *
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public bool IssuingDistributionPointEnabled
+ {
+ get { return issuingDistributionPointEnabled; }
+ set { this.issuingDistributionPointEnabled = value; }
+ }
+
+ /**
+ * The maximum base CRL number. Defaults to null
.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger MaxBaseCrlNumber
+ {
+ get { return maxBaseCrlNumber; }
+ set { this.maxBaseCrlNumber = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Crl c = obj as X509Crl;
+
+ if (c == null)
+ return false;
+
+ if (dateAndTime != null)
+ {
+ DateTime dt = dateAndTime.Value;
+ DateTime tu = c.ThisUpdate;
+ DateTimeObject nu = c.NextUpdate;
+
+ if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0)
+ return false;
+ }
+
+ if (issuers != null)
+ {
+ X509Name i = c.IssuerDN;
+
+ bool found = false;
+
+ foreach (X509Name issuer in issuers)
+ {
+ if (issuer.Equivalent(i))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (maxCrlNumber != null || minCrlNumber != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber);
+ if (extVal == null)
+ return false;
+
+ BigInteger cn = CrlNumber.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue;
+
+ if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0)
+ return false;
+
+ if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0)
+ return false;
+ }
+
+ DerInteger dci = null;
+ try
+ {
+ Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator);
+ if (bytes != null)
+ {
+ dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes));
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (dci == null)
+ {
+ if (DeltaCrlIndicatorEnabled)
+ return false;
+ }
+ else
+ {
+ if (CompleteCrlEnabled)
+ return false;
+
+ if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0)
+ return false;
+ }
+
+ if (issuingDistributionPointEnabled)
+ {
+ Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ return false;
+ }
+ else
+ {
+ if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint))
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509StoreException.cs b/src/core/srcbc/x509/store/X509StoreException.cs
new file mode 100644
index 0000000..cd6e47d
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509StoreException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509StoreException
+ : Exception
+ {
+ public X509StoreException()
+ {
+ }
+
+ public X509StoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public X509StoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/src/core/srcbc/x509/store/X509StoreFactory.cs b/src/core/srcbc/x509/store/X509StoreFactory.cs
new file mode 100644
index 0000000..2a2c818
--- /dev/null
+++ b/src/core/srcbc/x509/store/X509StoreFactory.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Globalization;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public sealed class X509StoreFactory
+ {
+ private X509StoreFactory()
+ {
+ }
+
+ public static IX509Store Create(
+ string type,
+ IX509StoreParameters parameters)
+ {
+ if (type == null)
+ throw new ArgumentNullException("type");
+
+ string[] parts = type.ToUpper(CultureInfo.InvariantCulture).Split('/');
+
+ if (parts.Length < 2)
+ throw new ArgumentException("type");
+
+
+ switch (parts[0])
+ {
+ case "ATTRIBUTECERTIFICATE":
+ case "CERTIFICATE":
+ case "CERTIFICATEPAIR":
+ case "CRL":
+ {
+ if (parts[1] == "COLLECTION")
+ {
+ X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters;
+ return new X509CollectionStore(p.GetCollection());
+ }
+ break;
+ }
+ }
+
+ throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+ }
+ }
+}