diff options
189 files changed, 13012 insertions, 2303 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 7a69c92cb..3c34c5e1b 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -388,6 +388,7 @@ <Compile Include="src\asn1\tsp\TSTInfo.cs" /> <Compile Include="src\asn1\tsp\TimeStampReq.cs" /> <Compile Include="src\asn1\tsp\TimeStampResp.cs" /> + <Compile Include="src\asn1\ua\UAObjectIdentifiers.cs" /> <Compile Include="src\asn1\util\Asn1Dump.cs" /> <Compile Include="src\asn1\util\Dump.cs" /> <Compile Include="src\asn1\util\FilterStream.cs" /> @@ -714,6 +715,8 @@ <Compile Include="src\crypto\agreement\srp\SRP6StandardGroups.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6Utilities.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6VerifierGenerator.cs" /> + <Compile Include="src\crypto\digests\Blake2bDigest.cs" /> + <Compile Include="src\crypto\digests\Blake2sDigest.cs" /> <Compile Include="src\crypto\digests\DSTU7564Digest.cs" /> <Compile Include="src\crypto\digests\GeneralDigest.cs" /> <Compile Include="src\crypto\digests\GOST3411Digest.cs" /> @@ -999,6 +1002,7 @@ <Compile Include="src\crypto\tls\DefaultTlsAgreementCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsCipherFactory.cs" /> <Compile Include="src\crypto\tls\DefaultTlsClient.cs" /> + <Compile Include="src\crypto\tls\DefaultTlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\DefaultTlsEncryptionCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsServer.cs" /> <Compile Include="src\crypto\tls\DefaultTlsSignerCredentials.cs" /> @@ -1042,7 +1046,6 @@ <Compile Include="src\crypto\tls\PskTlsServer.cs" /> <Compile Include="src\crypto\tls\RecordStream.cs" /> <Compile Include="src\crypto\tls\SecurityParameters.cs" /> - <Compile Include="src\crypto\tls\ServerDHParams.cs" /> <Compile Include="src\crypto\tls\ServerName.cs" /> <Compile Include="src\crypto\tls\ServerNameList.cs" /> <Compile Include="src\crypto\tls\ServerOnlyTlsAuthentication.cs" /> @@ -1073,6 +1076,7 @@ <Compile Include="src\crypto\tls\TlsCredentials.cs" /> <Compile Include="src\crypto\tls\TlsDHKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDHUtilities.cs" /> + <Compile Include="src\crypto\tls\TlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\TlsDeflateCompression.cs" /> <Compile Include="src\crypto\tls\TlsDheKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDsaSigner.cs" /> @@ -1127,11 +1131,13 @@ <Compile Include="src\math\ec\ECAlgorithms.cs" /> <Compile Include="src\math\ec\ECCurve.cs" /> <Compile Include="src\math\ec\ECFieldElement.cs" /> + <Compile Include="src\math\ec\ECLookupTable.cs" /> <Compile Include="src\math\ec\ECPoint.cs" /> <Compile Include="src\math\ec\ECPointMap.cs" /> <Compile Include="src\math\ec\LongArray.cs" /> <Compile Include="src\math\ec\ScaleXPointMap.cs" /> <Compile Include="src\math\ec\ScaleYPointMap.cs" /> + <Compile Include="src\math\ec\SimpleLookupTable.cs" /> <Compile Include="src\math\ec\abc\SimpleBigDecimal.cs" /> <Compile Include="src\math\ec\abc\Tnaf.cs" /> <Compile Include="src\math\ec\abc\ZTauElement.cs" /> @@ -1254,12 +1260,14 @@ <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" /> <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" /> <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" /> @@ -1267,6 +1275,12 @@ <Compile Include="src\math\ec\multiplier\WTauNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitR2LMultiplier.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519Field.cs" /> + <Compile Include="src\math\ec\rfc7748\X448.cs" /> + <Compile Include="src\math\ec\rfc7748\X448Field.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed25519.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed448.cs" /> <Compile Include="src\math\field\FiniteFields.cs" /> <Compile Include="src\math\field\GF2Polynomial.cs" /> <Compile Include="src\math\field\GenericPolynomialExtensionField.cs" /> diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index 9e1150c00..95d42bc8b 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -382,6 +382,7 @@ <Compile Include="src\asn1\tsp\TSTInfo.cs" /> <Compile Include="src\asn1\tsp\TimeStampReq.cs" /> <Compile Include="src\asn1\tsp\TimeStampResp.cs" /> + <Compile Include="src\asn1\ua\UAObjectIdentifiers.cs" /> <Compile Include="src\asn1\util\Asn1Dump.cs" /> <Compile Include="src\asn1\util\Dump.cs" /> <Compile Include="src\asn1\util\FilterStream.cs" /> @@ -708,6 +709,8 @@ <Compile Include="src\crypto\agreement\srp\SRP6StandardGroups.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6Utilities.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6VerifierGenerator.cs" /> + <Compile Include="src\crypto\digests\Blake2bDigest.cs" /> + <Compile Include="src\crypto\digests\Blake2sDigest.cs" /> <Compile Include="src\crypto\digests\DSTU7564Digest.cs" /> <Compile Include="src\crypto\digests\GeneralDigest.cs" /> <Compile Include="src\crypto\digests\GOST3411Digest.cs" /> @@ -993,6 +996,7 @@ <Compile Include="src\crypto\tls\DefaultTlsAgreementCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsCipherFactory.cs" /> <Compile Include="src\crypto\tls\DefaultTlsClient.cs" /> + <Compile Include="src\crypto\tls\DefaultTlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\DefaultTlsEncryptionCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsServer.cs" /> <Compile Include="src\crypto\tls\DefaultTlsSignerCredentials.cs" /> @@ -1036,7 +1040,6 @@ <Compile Include="src\crypto\tls\PskTlsServer.cs" /> <Compile Include="src\crypto\tls\RecordStream.cs" /> <Compile Include="src\crypto\tls\SecurityParameters.cs" /> - <Compile Include="src\crypto\tls\ServerDHParams.cs" /> <Compile Include="src\crypto\tls\ServerName.cs" /> <Compile Include="src\crypto\tls\ServerNameList.cs" /> <Compile Include="src\crypto\tls\ServerOnlyTlsAuthentication.cs" /> @@ -1067,6 +1070,7 @@ <Compile Include="src\crypto\tls\TlsCredentials.cs" /> <Compile Include="src\crypto\tls\TlsDHKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDHUtilities.cs" /> + <Compile Include="src\crypto\tls\TlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\TlsDeflateCompression.cs" /> <Compile Include="src\crypto\tls\TlsDheKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDsaSigner.cs" /> @@ -1121,11 +1125,13 @@ <Compile Include="src\math\ec\ECAlgorithms.cs" /> <Compile Include="src\math\ec\ECCurve.cs" /> <Compile Include="src\math\ec\ECFieldElement.cs" /> + <Compile Include="src\math\ec\ECLookupTable.cs" /> <Compile Include="src\math\ec\ECPoint.cs" /> <Compile Include="src\math\ec\ECPointMap.cs" /> <Compile Include="src\math\ec\LongArray.cs" /> <Compile Include="src\math\ec\ScaleXPointMap.cs" /> <Compile Include="src\math\ec\ScaleYPointMap.cs" /> + <Compile Include="src\math\ec\SimpleLookupTable.cs" /> <Compile Include="src\math\ec\abc\SimpleBigDecimal.cs" /> <Compile Include="src\math\ec\abc\Tnaf.cs" /> <Compile Include="src\math\ec\abc\ZTauElement.cs" /> @@ -1248,12 +1254,14 @@ <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" /> <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" /> <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" /> @@ -1261,6 +1269,12 @@ <Compile Include="src\math\ec\multiplier\WTauNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitR2LMultiplier.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519Field.cs" /> + <Compile Include="src\math\ec\rfc7748\X448.cs" /> + <Compile Include="src\math\ec\rfc7748\X448Field.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed25519.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed448.cs" /> <Compile Include="src\math\field\FiniteFields.cs" /> <Compile Include="src\math\field\GF2Polynomial.cs" /> <Compile Include="src\math\field\GenericPolynomialExtensionField.cs" /> diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 56dd59ea7..f9cebdc86 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -383,6 +383,7 @@ <Compile Include="src\asn1\tsp\TSTInfo.cs" /> <Compile Include="src\asn1\tsp\TimeStampReq.cs" /> <Compile Include="src\asn1\tsp\TimeStampResp.cs" /> + <Compile Include="src\asn1\ua\UAObjectIdentifiers.cs" /> <Compile Include="src\asn1\util\Asn1Dump.cs" /> <Compile Include="src\asn1\util\Dump.cs" /> <Compile Include="src\asn1\util\FilterStream.cs" /> @@ -709,6 +710,8 @@ <Compile Include="src\crypto\agreement\srp\SRP6StandardGroups.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6Utilities.cs" /> <Compile Include="src\crypto\agreement\srp\SRP6VerifierGenerator.cs" /> + <Compile Include="src\crypto\digests\Blake2bDigest.cs" /> + <Compile Include="src\crypto\digests\Blake2sDigest.cs" /> <Compile Include="src\crypto\digests\DSTU7564Digest.cs" /> <Compile Include="src\crypto\digests\GeneralDigest.cs" /> <Compile Include="src\crypto\digests\GOST3411Digest.cs" /> @@ -994,6 +997,7 @@ <Compile Include="src\crypto\tls\DefaultTlsAgreementCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsCipherFactory.cs" /> <Compile Include="src\crypto\tls\DefaultTlsClient.cs" /> + <Compile Include="src\crypto\tls\DefaultTlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\DefaultTlsEncryptionCredentials.cs" /> <Compile Include="src\crypto\tls\DefaultTlsServer.cs" /> <Compile Include="src\crypto\tls\DefaultTlsSignerCredentials.cs" /> @@ -1037,7 +1041,6 @@ <Compile Include="src\crypto\tls\PskTlsServer.cs" /> <Compile Include="src\crypto\tls\RecordStream.cs" /> <Compile Include="src\crypto\tls\SecurityParameters.cs" /> - <Compile Include="src\crypto\tls\ServerDHParams.cs" /> <Compile Include="src\crypto\tls\ServerName.cs" /> <Compile Include="src\crypto\tls\ServerNameList.cs" /> <Compile Include="src\crypto\tls\ServerOnlyTlsAuthentication.cs" /> @@ -1068,6 +1071,7 @@ <Compile Include="src\crypto\tls\TlsCredentials.cs" /> <Compile Include="src\crypto\tls\TlsDHKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDHUtilities.cs" /> + <Compile Include="src\crypto\tls\TlsDHVerifier.cs" /> <Compile Include="src\crypto\tls\TlsDeflateCompression.cs" /> <Compile Include="src\crypto\tls\TlsDheKeyExchange.cs" /> <Compile Include="src\crypto\tls\TlsDsaSigner.cs" /> @@ -1122,11 +1126,13 @@ <Compile Include="src\math\ec\ECAlgorithms.cs" /> <Compile Include="src\math\ec\ECCurve.cs" /> <Compile Include="src\math\ec\ECFieldElement.cs" /> + <Compile Include="src\math\ec\ECLookupTable.cs" /> <Compile Include="src\math\ec\ECPoint.cs" /> <Compile Include="src\math\ec\ECPointMap.cs" /> <Compile Include="src\math\ec\LongArray.cs" /> <Compile Include="src\math\ec\ScaleXPointMap.cs" /> <Compile Include="src\math\ec\ScaleYPointMap.cs" /> + <Compile Include="src\math\ec\SimpleLookupTable.cs" /> <Compile Include="src\math\ec\abc\SimpleBigDecimal.cs" /> <Compile Include="src\math\ec\abc\Tnaf.cs" /> <Compile Include="src\math\ec\abc\ZTauElement.cs" /> @@ -1249,12 +1255,14 @@ <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" /> <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" /> <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" /> + <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" /> @@ -1262,6 +1270,12 @@ <Compile Include="src\math\ec\multiplier\WTauNafPreCompInfo.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitL2RMultiplier.cs" /> <Compile Include="src\math\ec\multiplier\ZSignedDigitR2LMultiplier.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519.cs" /> + <Compile Include="src\math\ec\rfc7748\X25519Field.cs" /> + <Compile Include="src\math\ec\rfc7748\X448.cs" /> + <Compile Include="src\math\ec\rfc7748\X448Field.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed25519.cs" /> + <Compile Include="src\math\ec\rfc8032\Ed448.cs" /> <Compile Include="src\math\field\FiniteFields.cs" /> <Compile Include="src\math\field\GF2Polynomial.cs" /> <Compile Include="src\math\field\GenericPolynomialExtensionField.cs" /> diff --git a/crypto/License.html b/crypto/License.html index 0050331dc..829aa6ba3 100644 --- a/crypto/License.html +++ b/crypto/License.html @@ -9,7 +9,7 @@ <h2>The Bouncy Castle Cryptographic C#® API</h2> <h3>License:</h3> The Bouncy Castle License<br> -Copyright (c) 2000-2017 The Legion of the Bouncy Castle Inc. +Copyright (c) 2000-2018 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)<br> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the diff --git a/crypto/NBuild.build b/crypto/NBuild.build index 71096cbf0..89c557702 100644 --- a/crypto/NBuild.build +++ b/crypto/NBuild.build @@ -3,7 +3,7 @@ <!-- Source control properties --> <property name="GITURL" value="bcgit@git.bouncycastle.org:bc-csharp" /> - <property name="GITCMD" value="C:/Program Files (x86)/Git/bin/git.exe" /> + <property name="GITCMD" value="C:/Program Files/Git/bin/git.exe" /> <property name="api-debugpath" value="./api/bin/debug" /> <property name="api-releasepath" value="./api/bin/release" /> @@ -16,7 +16,7 @@ <property name="dist-path" value="./dist"/> <!-- Version --> - <property name="version" value="1.8.1"/> + <property name="version" value="1.8.2"/> <property name="name" value="BouncyCastle.Crypto"/> <property name="OPTIONAL_STRONG_NAME" value="" /> diff --git a/crypto/Readme.html b/crypto/Readme.html index b26937714..9f4705f00 100644 --- a/crypto/Readme.html +++ b/crypto/Readme.html @@ -31,6 +31,8 @@ <a href="#mozTocId3413">Notes:</a> <ol> <li> + <a href="#mozTocId85317">Release 1.8.3</a> + <li> <a href="#mozTocId85316">Release 1.8.2</a> <li> <a href="#mozTocId85315">Release 1.8.1</a> @@ -292,7 +294,24 @@ We state, where EC MQV has not otherwise been disabled or removed: <hr style="WIDTH: 100%; HEIGHT: 2px"> <h3><a class="mozTocH3" name="mozTocId3413"></a>Notes:</h3> - <h4><a class="mozTocH4" name="mozTocId85316"></a>Release 1.8.2, Release Date TBD</h4> + <h4><a class="mozTocH4" name="mozTocId85317"></a>Release 1.8.3, TBD</h4> + + <h5>Additional Features and Functionality</h5> + <ul> + <li>Further work has been done on improving SHA-3 performance.</li> + <li>EC key generation and signing now use cache-timing resistant table lookups.</li> + <li>RFC 7748: Added low-level implementations of X25519 and X448.</li> + <li>RFC 8032: Added low-level implementations of Ed25519 and Ed448.</li> + </ul> + <h5>Additional Notes</h5> + <ul> + <li> + See the (cumulative) list of GitHub pull requests that we have accepted at + <a href="https://github.com/bcgit/bc-csharp/pulls?q=is%3Apr+is%3Aclosed">bcgit/bc-csharp</a>. + </li> + </ul> + + <h4><a class="mozTocH4" name="mozTocId85316"></a>Release 1.8.2, Monday April 9, 2018</h4> <h5>Security Advisory</h5> <ul> @@ -315,11 +334,26 @@ We state, where EC MQV has not otherwise been disabled or removed: </li> </ul> + <h5>Defects Fixed</h5> + <ul> + <li>DTLS now supports records containing multiple handshake messages.</li> + </ul> <h5>Additional Features and Functionality</h5> <ul> <li>TLS: support for ClientHello Padding Extension (RFC 7685).</li> <li>TLS: support for ECDH_anon key exchange.</li> <li>BCrypt implementation added.</li> + <li>BLAKE2b and BLAKE2s implementations added.</li> + <li>GOST R 34.11-2012 implementation added.</li> + <li>DSTU-7564 message digest implementation added.</li> + <li>SM2 signatures, key exchange, and public key encryption implementations added.</li> + </ul> + <h5>Additional Notes</h5> + <ul> + <li> + See the (cumulative) list of GitHub pull requests that we have accepted at + <a href="https://github.com/bcgit/bc-csharp/pulls?q=is%3Apr+is%3Aclosed">bcgit/bc-csharp</a>. + </li> </ul> <h4><a class="mozTocH4" name="mozTocId85315"></a>Release 1.8.1, Monday December 28, 2015</h4> diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index e2ad3ea69..b6dfb3963 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -1799,6 +1799,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\asn1\ua\UAObjectIdentifiers.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\asn1\util\ASN1Dump.cs" SubType = "Code" BuildAction = "Compile" @@ -3324,6 +3329,16 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\digests\Blake2bDigest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\crypto\digests\Blake2sDigest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\digests\DSTU7564Digest.cs" SubType = "Code" BuildAction = "Compile" @@ -4854,6 +4869,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\DefaultTlsDHVerifier.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\DefaultTlsEncryptionCredentials.cs" SubType = "Code" BuildAction = "Compile" @@ -5069,11 +5089,6 @@ BuildAction = "Compile" /> <File - RelPath = "src\crypto\tls\ServerDHParams.cs" - SubType = "Code" - BuildAction = "Compile" - /> - <File RelPath = "src\crypto\tls\ServerSrpParams.cs" SubType = "Code" BuildAction = "Compile" @@ -5234,6 +5249,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\tls\TlsDHVerifier.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\tls\TlsDsaSigner.cs" SubType = "Code" BuildAction = "Compile" @@ -5494,6 +5514,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\math\ec\ECLookupTable.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\math\ec\ECPoint.cs" SubType = "Code" BuildAction = "Compile" @@ -5519,6 +5544,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\math\ec\SimpleLookupTable.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\math\ec\abc\SimpleBigDecimal.cs" SubType = "Code" BuildAction = "Compile" @@ -6129,6 +6159,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\math\ec\multiplier\IPreCompCallback.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\math\ec\multiplier\MixedNafR2LMultiplier.cs" SubType = "Code" BuildAction = "Compile" @@ -6159,6 +6194,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\math\ec\multiplier\ValidityPreCompInfo.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\math\ec\multiplier\WNafL2RMultiplier.cs" SubType = "Code" BuildAction = "Compile" @@ -6194,6 +6234,36 @@ BuildAction = "Compile" /> <File + RelPath = "src\math\ec\rfc7748\X25519.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\math\ec\rfc7748\X25519Field.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\math\ec\rfc7748\X448.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\math\ec\rfc7748\X448Field.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\math\ec\rfc8032\Ed25519.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\math\ec\rfc8032\Ed448.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\math\field\FiniteFields.cs" SubType = "Code" BuildAction = "Compile" @@ -11445,6 +11515,16 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\test\Blake2bDigestTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\crypto\test\Blake2sDigestTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\test\BlockCipherMonteCarloTest.cs" SubType = "Code" BuildAction = "Compile" @@ -12275,6 +12355,26 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\math\ec\rfc7748\test\X25519Test.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\math\ec\rfc7748\test\X448Test.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\math\ec\rfc8032\test\Ed25519Test.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\math\ec\rfc8032\test\Ed448Test.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\math\ec\test\AllTests.cs" SubType = "Code" BuildAction = "Compile" @@ -12300,6 +12400,11 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\math\ec\test\FixedPointTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\math\ec\test\TnafTest.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs index 4887b00b0..d95dca5ab 100644 --- a/crypto/src/AssemblyInfo.cs +++ b/crypto/src/AssemblyInfo.cs @@ -18,7 +18,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Legion of the Bouncy Castle Inc.")] [assembly: AssemblyProduct("Bouncy Castle for .NET")] -[assembly: AssemblyCopyright("Copyright (C) 2000-2017")] +[assembly: AssemblyCopyright("Copyright (C) 2000-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -33,9 +33,9 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.8.1.0")] -[assembly: AssemblyFileVersion("1.8.15362.1")] -[assembly: AssemblyInformationalVersion("1.8.1")] +[assembly: AssemblyVersion("1.8.2.0")] +[assembly: AssemblyFileVersion("1.8.18099.1")] +[assembly: AssemblyInformationalVersion("1.8.2")] // // In order to sign your assembly you must specify a key to use. Refer to the diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs index 075e5384c..4f23c101a 100644 --- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs +++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs @@ -4,36 +4,105 @@ namespace Org.BouncyCastle.Asn1.BC { public abstract class BCObjectIdentifiers { - // iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle - // 1.3.6.1.4.1.22554 - public static readonly DerObjectIdentifier bc = new DerObjectIdentifier("1.3.6.1.4.1.22554"); - - // pbe(1) algorithms - public static readonly DerObjectIdentifier bc_pbe = new DerObjectIdentifier(bc + ".1"); - - // SHA-1(1) - public static readonly DerObjectIdentifier bc_pbe_sha1 = new DerObjectIdentifier(bc_pbe + ".1"); - - // SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4)) - public static readonly DerObjectIdentifier bc_pbe_sha256 = new DerObjectIdentifier(bc_pbe + ".2.1"); - public static readonly DerObjectIdentifier bc_pbe_sha384 = new DerObjectIdentifier(bc_pbe + ".2.2"); - public static readonly DerObjectIdentifier bc_pbe_sha512 = new DerObjectIdentifier(bc_pbe + ".2.3"); - public static readonly DerObjectIdentifier bc_pbe_sha224 = new DerObjectIdentifier(bc_pbe + ".2.4"); - - // PKCS-5(1)|PKCS-12(2) - public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs5 = new DerObjectIdentifier(bc_pbe_sha1 + ".1"); - public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12 = new DerObjectIdentifier(bc_pbe_sha1 + ".2"); - - public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs5 = new DerObjectIdentifier(bc_pbe_sha256 + ".1"); - public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12 = new DerObjectIdentifier(bc_pbe_sha256 + ".2"); - - // AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42)) - public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.2"); - public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.22"); - public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.42"); - - public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.2"); - public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.22"); - public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.42"); + /** + * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle + *<p> + * 1.3.6.1.4.1.22554 + */ + public static readonly DerObjectIdentifier bc = new DerObjectIdentifier("1.3.6.1.4.1.22554"); + + /** + * pbe(1) algorithms + * <p> + * 1.3.6.1.4.1.22554.1 + */ + public static readonly DerObjectIdentifier bc_pbe = bc.Branch("1"); + + /** + * SHA-1(1) + * <p> + * 1.3.6.1.4.1.22554.1.1 + */ + public static readonly DerObjectIdentifier bc_pbe_sha1 = bc_pbe.Branch("1"); + + /** SHA-2.SHA-256; 1.3.6.1.4.1.22554.1.2.1 */ + public static readonly DerObjectIdentifier bc_pbe_sha256 = bc_pbe.Branch("2.1"); + /** SHA-2.SHA-384; 1.3.6.1.4.1.22554.1.2.2 */ + public static readonly DerObjectIdentifier bc_pbe_sha384 = bc_pbe.Branch("2.2"); + /** SHA-2.SHA-512; 1.3.6.1.4.1.22554.1.2.3 */ + public static readonly DerObjectIdentifier bc_pbe_sha512 = bc_pbe.Branch("2.3"); + /** SHA-2.SHA-224; 1.3.6.1.4.1.22554.1.2.4 */ + public static readonly DerObjectIdentifier bc_pbe_sha224 = bc_pbe.Branch("2.4"); + + /** + * PKCS-5(1)|PKCS-12(2) + */ + /** SHA-1.PKCS5; 1.3.6.1.4.1.22554.1.1.1 */ + public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs5 = bc_pbe_sha1.Branch("1"); + /** SHA-1.PKCS12; 1.3.6.1.4.1.22554.1.1.2 */ + public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12 = bc_pbe_sha1.Branch("2"); + + /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.1 */ + public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs5 = bc_pbe_sha256.Branch("1"); + /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.2 */ + public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12 = bc_pbe_sha256.Branch("2"); + + /** + * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42)) + */ + /** 1.3.6.1.4.1.22554.1.1.2.1.2 */ + public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = bc_pbe_sha1_pkcs12.Branch("1.2"); + /** 1.3.6.1.4.1.22554.1.1.2.1.22 */ + public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = bc_pbe_sha1_pkcs12.Branch("1.22"); + /** 1.3.6.1.4.1.22554.1.1.2.1.42 */ + public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = bc_pbe_sha1_pkcs12.Branch("1.42"); + + /** 1.3.6.1.4.1.22554.1.1.2.2.2 */ + public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = bc_pbe_sha256_pkcs12.Branch("1.2"); + /** 1.3.6.1.4.1.22554.1.1.2.2.22 */ + public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = bc_pbe_sha256_pkcs12.Branch("1.22"); + /** 1.3.6.1.4.1.22554.1.1.2.2.42 */ + public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = bc_pbe_sha256_pkcs12.Branch("1.42"); + + /** + * signature(2) algorithms + */ + public static readonly DerObjectIdentifier bc_sig = bc.Branch("2"); + + /** + * Sphincs-256 + */ + public static readonly DerObjectIdentifier sphincs256 = bc_sig.Branch("1"); + public static readonly DerObjectIdentifier sphincs256_with_BLAKE512 = sphincs256.Branch("1"); + public static readonly DerObjectIdentifier sphincs256_with_SHA512 = sphincs256.Branch("2"); + public static readonly DerObjectIdentifier sphincs256_with_SHA3_512 = sphincs256.Branch("3"); + + /** + * XMSS + */ + public static readonly DerObjectIdentifier xmss = bc_sig.Branch("2"); + public static readonly DerObjectIdentifier xmss_with_SHA256 = xmss.Branch("1"); + public static readonly DerObjectIdentifier xmss_with_SHA512 = xmss.Branch("2"); + public static readonly DerObjectIdentifier xmss_with_SHAKE128 = xmss.Branch("3"); + public static readonly DerObjectIdentifier xmss_with_SHAKE256 = xmss.Branch("4"); + + /** + * XMSS^MT + */ + public static readonly DerObjectIdentifier xmss_mt = bc_sig.Branch("3"); + public static readonly DerObjectIdentifier xmss_mt_with_SHA256 = xmss_mt.Branch("1"); + public static readonly DerObjectIdentifier xmss_mt_with_SHA512 = xmss_mt.Branch("2"); + public static readonly DerObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt.Branch("3"); + public static readonly DerObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt.Branch("4"); + + /** + * key_exchange(3) algorithms + */ + public static readonly DerObjectIdentifier bc_exch = bc.Branch("3"); + + /** + * NewHope + */ + public static readonly DerObjectIdentifier newHope = bc_exch.Branch("1"); } } \ No newline at end of file diff --git a/crypto/src/asn1/cmp/PollRepContent.cs b/crypto/src/asn1/cmp/PollRepContent.cs index f8bb098a2..ff75d7d6d 100644 --- a/crypto/src/asn1/cmp/PollRepContent.cs +++ b/crypto/src/asn1/cmp/PollRepContent.cs @@ -33,6 +33,25 @@ namespace Org.BouncyCastle.Asn1.Cmp throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj"); } + public PollRepContent( + DerInteger certReqId, + DerInteger checkAfter) + { + this.certReqId = certReqId; + this.checkAfter = checkAfter; + this.reason = null; + } + + public PollRepContent( + DerInteger certReqId, + DerInteger checkAfter, + PkiFreeText reason) + { + this.certReqId = certReqId; + this.checkAfter = checkAfter; + this.reason = reason; + } + public virtual DerInteger CertReqID { get { return certReqId; } diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs index 9c366503d..b61da6b57 100644 --- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs +++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs @@ -32,15 +32,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a new BigInteger("166"), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ECDomainParameters ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); + mod_q, BigInteger.One); parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams; @@ -51,15 +50,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), new BigInteger("166"), - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); + mod_q, BigInteger.One); parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams; @@ -70,15 +68,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("1"), // x new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y - mod_q); // q + mod_q, BigInteger.One); parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams; @@ -89,15 +86,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), new BigInteger("32858"), - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("0"), new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), - mod_q); + mod_q, BigInteger.One); parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams; @@ -107,15 +103,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a new BigInteger("32858"), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("0"), // x new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y - mod_q); // q + mod_q, BigInteger.One); parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams; @@ -126,15 +121,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a new BigInteger("166"), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); // q + mod_q, BigInteger.One); parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA] = ecParams; @@ -144,15 +138,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y - mod_q); // q + mod_q, BigInteger.One); parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA] = ecParams; @@ -162,15 +155,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y - mod_q); // q + mod_q, BigInteger.One); parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB] = ecParams; @@ -180,15 +172,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro mod_p, // p new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b - mod_q, - BigInteger.One); + mod_q, BigInteger.One); ecParams = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y - mod_q); // q + mod_q, BigInteger.One); parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC] = ecParams; diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs index 8128b6952..d344393dd 100644 --- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs +++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs @@ -75,5 +75,14 @@ namespace Org.BouncyCastle.Asn1.Misc public static readonly DerObjectIdentifier id_blake2b256 = blake2.Branch("1.8"); public static readonly DerObjectIdentifier id_blake2b384 = blake2.Branch("1.12"); public static readonly DerObjectIdentifier id_blake2b512 = blake2.Branch("1.16"); + + public static readonly DerObjectIdentifier id_blake2s128 = blake2.Branch("2.4"); + public static readonly DerObjectIdentifier id_blake2s160 = blake2.Branch("2.5"); + public static readonly DerObjectIdentifier id_blake2s224 = blake2.Branch("2.7"); + public static readonly DerObjectIdentifier id_blake2s256 = blake2.Branch("2.8"); + + // + // Scrypt + public static readonly DerObjectIdentifier id_scrypt = new DerObjectIdentifier("1.3.6.1.4.1.11591.4.11"); } } diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs index 55b9d8e68..b5002d28c 100644 --- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs +++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs @@ -31,6 +31,10 @@ namespace Org.BouncyCastle.Asn1.Nist public static readonly DerObjectIdentifier IdSha3_512 = HashAlgs.Branch("10"); public static readonly DerObjectIdentifier IdShake128 = HashAlgs.Branch("11"); public static readonly DerObjectIdentifier IdShake256 = HashAlgs.Branch("12"); + public static readonly DerObjectIdentifier IdHMacWithSha3_224 = HashAlgs.Branch("13"); + public static readonly DerObjectIdentifier IdHMacWithSha3_256 = HashAlgs.Branch("14"); + public static readonly DerObjectIdentifier IdHMacWithSha3_384 = HashAlgs.Branch("15"); + public static readonly DerObjectIdentifier IdHMacWithSha3_512 = HashAlgs.Branch("16"); public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1"); diff --git a/crypto/src/asn1/ua/UAObjectIdentifiers.cs b/crypto/src/asn1/ua/UAObjectIdentifiers.cs new file mode 100644 index 000000000..9beca3af5 --- /dev/null +++ b/crypto/src/asn1/ua/UAObjectIdentifiers.cs @@ -0,0 +1,107 @@ +namespace Org.BouncyCastle.Asn1.UA +{ + /** + * Ukrainian object identifiers + * <p> + * {iso(1) member-body(2) Ukraine(804) root(2) security(1) cryptography(1) pki(1)} + * <p> + * { ... pki-alg(1) pki-alg-sym(3) Dstu4145WithGost34311(1) PB(1)} + * <p> + * DSTU4145 in polynomial basis has 2 oids, one for little-endian representation and one for big-endian + */ + public abstract class UAObjectIdentifiers + { + /** Base OID: 1.2.804.2.1.1.1 */ + public static readonly DerObjectIdentifier UaOid = new DerObjectIdentifier("1.2.804.2.1.1.1"); + + /** DSTU4145 Little Endian presentation. OID: 1.2.804.2.1.1.1.1.3.1.1 */ + public static readonly DerObjectIdentifier dstu4145le = UaOid.Branch("1.3.1.1"); + /** DSTU4145 Big Endian presentation. OID: 1.2.804.2.1.1.1.1.3.1.1.1 */ + public static readonly DerObjectIdentifier dstu4145be = UaOid.Branch("1.3.1.1.1.1"); + + /** DSTU7564 256-bit digest presentation. */ + public static readonly DerObjectIdentifier dstu7564digest_256 = UaOid.Branch("1.2.2.1"); + /** DSTU7564 384-bit digest presentation. */ + public static readonly DerObjectIdentifier dstu7564digest_384 = UaOid.Branch("1.2.2.2"); + /** DSTU7564 512-bit digest presentation. */ + public static readonly DerObjectIdentifier dstu7564digest_512 = UaOid.Branch("1.2.2.3"); + + /** DSTU7564 256-bit mac presentation. */ + public static readonly DerObjectIdentifier dstu7564mac_256 = UaOid.Branch("1.2.2.4"); + /** DSTU7564 384-bit mac presentation. */ + public static readonly DerObjectIdentifier dstu7564mac_384 = UaOid.Branch("1.2.2.5"); + /** DSTU7564 512-bit mac presentation. */ + public static readonly DerObjectIdentifier dstu7564mac_512 = UaOid.Branch("1.2.2.6"); + + + /** DSTU7624 in ECB mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ecb_128 = UaOid.Branch("1.1.3.1.1"); + /** DSTU7624 in ECB mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ecb_256 = UaOid.Branch("1.1.3.1.2"); + /** DSTU7624 in ECB mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ecb_512 = UaOid.Branch("1.1.3.1.3"); + + /** DSTU7624 in CTR mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ctr_128 = UaOid.Branch("1.1.3.2.1"); + /** DSTU7624 in CTR mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ctr_256 = UaOid.Branch("1.1.3.2.2"); + /** DSTU7624 in CTR mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ctr_512 = UaOid.Branch("1.1.3.2.3"); + + /** DSTU7624 in CFB mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cfb_128 = UaOid.Branch("1.1.3.3.1"); + /** DSTU7624 in CFB mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cfb_256 = UaOid.Branch("1.1.3.3.2"); + /** DSTU7624 in CFB mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cfb_512 = UaOid.Branch("1.1.3.3.3"); + + /** DSTU7624 in MAC mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cmac_128 = UaOid.Branch("1.1.3.4.1"); + /** DSTU7624 in MAC mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cmac_256 = UaOid.Branch("1.1.3.4.2"); + /** DSTU7624 in MAC mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cmac_512 = UaOid.Branch("1.1.3.4.3"); + + /** DSTU7624 in CBC mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cbc_128 = UaOid.Branch("1.1.3.5.1"); + /** DSTU7624 in CBC mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cbc_256 = UaOid.Branch("1.1.3.5.2"); + /** DSTU7624 in CBC mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624cbc_512 = UaOid.Branch("1.1.3.5.3"); + + /** DSTU7624 in OFB mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ofb_128 = UaOid.Branch("1.1.3.6.1"); + /** DSTU7624 in OFB mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ofb_256 = UaOid.Branch("1.1.3.6.2"); + /** DSTU7624 in OFB mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ofb_512 = UaOid.Branch("1.1.3.6.3"); + + /** DSTU7624 in GMAC (GCM witout encryption) mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624gmac_128 = UaOid.Branch("1.1.3.7.1"); + /** DSTU7624 in GMAC (GCM witout encryption) mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624gmac_256 = UaOid.Branch("1.1.3.7.2"); + /** DSTU7624 in GMAC (GCM witout encryption) mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624gmac_512 = UaOid.Branch("1.1.3.7.3"); + + /** DSTU7624 in CCM mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ccm_128 = UaOid.Branch("1.1.3.8.1"); + /** DSTU7624 in CCM mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ccm_256 = UaOid.Branch("1.1.3.8.2"); + /** DSTU7624 in CCM mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624ccm_512 = UaOid.Branch("1.1.3.8.3"); + + /** DSTU7624 in XTS mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624xts_128 = UaOid.Branch("1.1.3.9.1"); + /** DSTU7624 in XTS mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624xts_256 = UaOid.Branch("1.1.3.9.2"); + /** DSTU7624 in XTS mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624xts_512 = UaOid.Branch("1.1.3.9.3"); + + /** DSTU7624 in key wrap (KW) mode with 128 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624kw_128 = UaOid.Branch("1.1.3.10.1"); + /** DSTU7624 in key wrap (KW) mode with 256 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624kw_256 = UaOid.Branch("1.1.3.10.2"); + /** DSTU7624 in key wrap (KW) mode with 512 bit block/key presentation */ + public static readonly DerObjectIdentifier dstu7624kw_512 = UaOid.Branch("1.1.3.10.3"); + } +} diff --git a/crypto/src/asn1/x509/TBSCertificateStructure.cs b/crypto/src/asn1/x509/TBSCertificateStructure.cs index fc7c39ba2..9df078539 100644 --- a/crypto/src/asn1/x509/TBSCertificateStructure.cs +++ b/crypto/src/asn1/x509/TBSCertificateStructure.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Asn1.X509 { @@ -78,6 +79,22 @@ namespace Org.BouncyCastle.Asn1.X509 version = new DerInteger(0); } + bool isV1 = false; + bool isV2 = false; + + if (version.Value.Equals(BigInteger.Zero)) + { + isV1 = true; + } + else if (version.Value.Equals(BigInteger.One)) + { + isV2 = true; + } + else if (!version.Value.Equals(BigInteger.Two)) + { + throw new ArgumentException("version number not recognised"); + } + serialNumber = DerInteger.GetInstance(seq[seqStart + 1]); signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]); @@ -98,22 +115,36 @@ namespace Org.BouncyCastle.Asn1.X509 // subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]); - for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--) + int extras = seq.Count - (seqStart + 6) - 1; + if (extras != 0 && isV1) + throw new ArgumentException("version 1 certificate contains extra data"); + + while (extras > 0) { DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras]; switch (extra.TagNo) { - case 1: - issuerUniqueID = DerBitString.GetInstance(extra, false); - break; - case 2: - subjectUniqueID = DerBitString.GetInstance(extra, false); - break; - case 3: - extensions = X509Extensions.GetInstance(extra); - break; - } + case 1: + { + issuerUniqueID = DerBitString.GetInstance(extra, false); + break; + } + case 2: + { + subjectUniqueID = DerBitString.GetInstance(extra, false); + break; + } + case 3: + { + if (isV2) + throw new ArgumentException("version 2 certificate cannot contain extensions"); + + extensions = X509Extensions.GetInstance(extra); + break; + } + } + extras--; } } diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs index 049d728bb..d1b9fa39a 100644 --- a/crypto/src/asn1/x509/X509Extensions.cs +++ b/crypto/src/asn1/x509/X509Extensions.cs @@ -224,7 +224,10 @@ namespace Org.BouncyCastle.Asn1.X509 Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object()); - extensions.Add(oid, new X509Extension(isCritical, octets)); + if (extensions.Contains(oid)) + throw new ArgumentException("repeated extension found: " + oid); + + extensions.Add(oid, new X509Extension(isCritical, octets)); ordering.Add(oid); } } diff --git a/crypto/src/asn1/x509/X509Name.cs b/crypto/src/asn1/x509/X509Name.cs index 01a7ec04a..aa46caaac 100644 --- a/crypto/src/asn1/x509/X509Name.cs +++ b/crypto/src/asn1/x509/X509Name.cs @@ -159,6 +159,11 @@ namespace Org.BouncyCastle.Asn1.X509 public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber; /** + * id-at-organizationIdentifier + */ + public static readonly DerObjectIdentifier OrganizationIdentifier = X509ObjectIdentifiers.id_at_organizationIdentifier; + + /** * id-at-name */ public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name; diff --git a/crypto/src/asn1/x509/X509ObjectIdentifiers.cs b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs index f00e31475..4df5bba69 100644 --- a/crypto/src/asn1/x509/X509ObjectIdentifiers.cs +++ b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs @@ -17,7 +17,9 @@ namespace Org.BouncyCastle.Asn1.X509 public static readonly DerObjectIdentifier id_at_telephoneNumber = new DerObjectIdentifier(ID + ".20"); public static readonly DerObjectIdentifier id_at_name = new DerObjectIdentifier(ID + ".41"); - // id-SHA1 OBJECT IDENTIFIER ::= + public static readonly DerObjectIdentifier id_at_organizationIdentifier = new DerObjectIdentifier("2.5.4.97"); + + // id-SHA1 OBJECT IDENTIFIER ::= // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26"); diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs index 14f7f818a..1609774f1 100644 --- a/crypto/src/asn1/x9/X962NamedCurves.cs +++ b/crypto/src/asn1/x9/X962NamedCurves.cs @@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Asn1.X9 BigInteger h = BigInteger.One; ECCurve cFp192v1 = new FpCurve( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), n, h); @@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Asn1.X9 BigInteger h = BigInteger.One; ECCurve cFp192v2 = new FpCurve( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16), n, h); @@ -85,7 +85,7 @@ namespace Org.BouncyCastle.Asn1.X9 BigInteger h = BigInteger.One; ECCurve cFp192v3 = new FpCurve( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16), n, h); diff --git a/crypto/src/asn1/x9/X9Curve.cs b/crypto/src/asn1/x9/X9Curve.cs index f05a946c2..eab94def8 100644 --- a/crypto/src/asn1/x9/X9Curve.cs +++ b/crypto/src/asn1/x9/X9Curve.cs @@ -47,9 +47,19 @@ namespace Org.BouncyCastle.Asn1.X9 } } + [Obsolete("Use constructor including order/cofactor")] public X9Curve( X9FieldID fieldID, Asn1Sequence seq) + : this(fieldID, null, null, seq) + { + } + + public X9Curve( + X9FieldID fieldID, + BigInteger order, + BigInteger cofactor, + Asn1Sequence seq) { if (fieldID == null) throw new ArgumentNullException("fieldID"); @@ -60,47 +70,47 @@ namespace Org.BouncyCastle.Asn1.X9 if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)) { - BigInteger q = ((DerInteger) fieldID.Parameters).Value; - X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]); - X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]); - curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger()); + BigInteger p = ((DerInteger)fieldID.Parameters).Value; + BigInteger A = new BigInteger(1, Asn1OctetString.GetInstance(seq[0]).GetOctets()); + BigInteger B = new BigInteger(1, Asn1OctetString.GetInstance(seq[1]).GetOctets()); + curve = new FpCurve(p, A, B, order, cofactor); } - else + else if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) { - if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) + // Characteristic two field + DerSequence parameters = (DerSequence)fieldID.Parameters; + int m = ((DerInteger)parameters[0]).Value.IntValue; + DerObjectIdentifier representation + = (DerObjectIdentifier)parameters[1]; + + int k1 = 0; + int k2 = 0; + int k3 = 0; + if (representation.Equals(X9ObjectIdentifiers.TPBasis)) { - // Characteristic two field - DerSequence parameters = (DerSequence)fieldID.Parameters; - int m = ((DerInteger)parameters[0]).Value.IntValue; - DerObjectIdentifier representation - = (DerObjectIdentifier)parameters[1]; - - int k1 = 0; - int k2 = 0; - int k3 = 0; - if (representation.Equals(X9ObjectIdentifiers.TPBasis)) - { - // Trinomial basis representation - k1 = ((DerInteger)parameters[2]).Value.IntValue; - } - else - { - // Pentanomial basis representation - DerSequence pentanomial = (DerSequence) parameters[2]; - k1 = ((DerInteger) pentanomial[0]).Value.IntValue; - k2 = ((DerInteger) pentanomial[1]).Value.IntValue; - k3 = ((DerInteger) pentanomial[2]).Value.IntValue; - } - X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]); - X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]); - // TODO Is it possible to get the order (n) and cofactor(h) too? - curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger()); + // Trinomial basis representation + k1 = ((DerInteger)parameters[2]).Value.IntValue; } + else + { + // Pentanomial basis representation + DerSequence pentanomial = (DerSequence) parameters[2]; + k1 = ((DerInteger) pentanomial[0]).Value.IntValue; + k2 = ((DerInteger) pentanomial[1]).Value.IntValue; + k3 = ((DerInteger) pentanomial[2]).Value.IntValue; + } + BigInteger A = new BigInteger(1, Asn1OctetString.GetInstance(seq[0]).GetOctets()); + BigInteger B = new BigInteger(1, Asn1OctetString.GetInstance(seq[1]).GetOctets()); + curve = new F2mCurve(m, k1, k2, k3, A, B, order, cofactor); + } + else + { + throw new ArgumentException("This type of ECCurve is not implemented"); } if (seq.Count == 3) { - seed = ((DerBitString) seq[2]).GetBytes(); + seed = ((DerBitString)seq[2]).GetBytes(); } } diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs index 0fa343768..e1b29ca13 100644 --- a/crypto/src/asn1/x9/X9ECParameters.cs +++ b/crypto/src/asn1/x9/X9ECParameters.cs @@ -23,29 +23,32 @@ namespace Org.BouncyCastle.Asn1.X9 public static X9ECParameters GetInstance(Object obj) { if (obj is X9ECParameters) - { return (X9ECParameters)obj; - } - if (obj != null) - { + if (obj != null) return new X9ECParameters(Asn1Sequence.GetInstance(obj)); - } - return null; + return null; } public X9ECParameters( Asn1Sequence seq) { if (!(seq[0] is DerInteger) - || !((DerInteger) seq[0]).Value.Equals(BigInteger.One)) + || !((DerInteger)seq[0]).Value.Equals(BigInteger.One)) { throw new ArgumentException("bad version in X9ECParameters"); } + this.n = ((DerInteger)seq[4]).Value; + + if (seq.Count == 6) + { + this.h = ((DerInteger)seq[5]).Value; + } + X9Curve x9c = new X9Curve( - X9FieldID.GetInstance(seq[1]), + X9FieldID.GetInstance(seq[1]), n, h, Asn1Sequence.GetInstance(seq[2])); this.curve = x9c.Curve; @@ -53,20 +56,14 @@ namespace Org.BouncyCastle.Asn1.X9 if (p is X9ECPoint) { - this.g = ((X9ECPoint)p); + this.g = (X9ECPoint)p; } else { this.g = new X9ECPoint(curve, (Asn1OctetString)p); } - this.n = ((DerInteger)seq[4]).Value; this.seed = x9c.GetSeed(); - - if (seq.Count == 6) - { - this.h = ((DerInteger)seq[5]).Value; - } } public X9ECParameters( diff --git a/crypto/src/asn1/x9/X9FieldElement.cs b/crypto/src/asn1/x9/X9FieldElement.cs index 94bd96b24..222b4cfc8 100644 --- a/crypto/src/asn1/x9/X9FieldElement.cs +++ b/crypto/src/asn1/x9/X9FieldElement.cs @@ -19,6 +19,7 @@ namespace Org.BouncyCastle.Asn1.X9 this.f = f; } + [Obsolete("Will be removed")] public X9FieldElement( BigInteger p, Asn1OctetString s) @@ -26,6 +27,7 @@ namespace Org.BouncyCastle.Asn1.X9 { } + [Obsolete("Will be removed")] public X9FieldElement( int m, int k1, diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs index f63ed874e..5aa5f92ab 100644 --- a/crypto/src/cms/CMSSignedDataGenerator.cs +++ b/crypto/src/cms/CMSSignedDataGenerator.cs @@ -513,15 +513,19 @@ namespace Org.BouncyCastle.Cms if (_certs.Count != 0) { - certificates = CmsUtilities.CreateBerSetFromList(_certs); + certificates = UseDerForCerts + ? CmsUtilities.CreateDerSetFromList(_certs) + : CmsUtilities.CreateBerSetFromList(_certs); } Asn1Set certrevlist = null; if (_crls.Count != 0) { - certrevlist = CmsUtilities.CreateBerSetFromList(_crls); - } + certrevlist = UseDerForCrls + ? CmsUtilities.CreateDerSetFromList(_crls) + : CmsUtilities.CreateBerSetFromList(_crls); + } Asn1OctetString octs = null; if (encapsulate) diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs index d0ab7428a..1cea087f3 100644 --- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs @@ -838,14 +838,18 @@ namespace Org.BouncyCastle.Cms if (outer._certs.Count > 0) { - Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs); + Asn1Set certs = outer.UseDerForCerts + ? CmsUtilities.CreateDerSetFromList(outer._certs) + : CmsUtilities.CreateBerSetFromList(outer._certs); WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs)); } if (outer._crls.Count > 0) { - Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls); + Asn1Set crls = outer.UseDerForCrls + ? CmsUtilities.CreateDerSetFromList(outer._crls) + : CmsUtilities.CreateBerSetFromList(outer._crls); WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls)); } diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs index eec2e875b..249d70499 100644 --- a/crypto/src/cms/CMSSignedGenerator.cs +++ b/crypto/src/cms/CMSSignedGenerator.cs @@ -147,6 +147,8 @@ namespace Org.BouncyCastle.Cms internal IList _crls = Platform.CreateArrayList(); internal IList _signers = Platform.CreateArrayList(); internal IDictionary _digests = Platform.CreateHashtable(); + internal bool _useDerForCerts = false; + internal bool _useDerForCrls = false; protected readonly SecureRandom rand; @@ -251,6 +253,18 @@ namespace Org.BouncyCastle.Cms return Platform.CreateHashtable(_digests); } + public bool UseDerForCerts + { + get { return _useDerForCerts; } + set { this._useDerForCerts = value; } + } + + public bool UseDerForCrls + { + get { return _useDerForCrls; } + set { this._useDerForCrls = value; } + } + internal virtual void AddSignerCallback( SignerInformation si) { diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs index ca7b3fa3f..1358db0cf 100644 --- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs @@ -45,12 +45,26 @@ namespace Org.BouncyCastle.Crypto.Agreement public virtual BigInteger CalculateAgreement( ICipherParameters pubKey) { - ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; - if (!pub.Parameters.Equals(privKey.Parameters)) + ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; + ECDomainParameters dp = privKey.Parameters; + if (!dp.Equals(pub.Parameters)) throw new InvalidOperationException("ECDH public key has wrong domain parameters"); - ECPoint P = pub.Q.Multiply(privKey.D).Normalize(); + BigInteger d = privKey.D; + // Always perform calculations on the exact curve specified by our private key's parameters + ECPoint Q = ECAlgorithms.CleanPoint(dp.Curve, pub.Q); + if (Q.IsInfinity) + throw new InvalidOperationException("Infinity is not a valid public key for ECDH"); + + BigInteger h = dp.H; + if (!h.Equals(BigInteger.One)) + { + d = dp.HInv.Multiply(d).Mod(dp.N); + Q = ECAlgorithms.ReferenceMultiply(Q, h); + } + + ECPoint P = Q.Multiply(d).Normalize(); if (P.IsInfinity) throw new InvalidOperationException("Infinity is not a valid agreement value for ECDH"); diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs index 1c9ae45f9..f0b5d1e02 100644 --- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs @@ -50,15 +50,19 @@ namespace Org.BouncyCastle.Crypto.Agreement public virtual BigInteger CalculateAgreement( ICipherParameters pubKey) { - ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; - ECDomainParameters parameters = pub.Parameters; - if (!parameters.Equals(privKey.Parameters)) + ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; + ECDomainParameters dp = privKey.Parameters; + if (!dp.Equals(pub.Parameters)) throw new InvalidOperationException("ECDHC public key has wrong domain parameters"); - BigInteger hd = parameters.H.Multiply(privKey.D).Mod(parameters.N); + BigInteger hd = dp.H.Multiply(privKey.D).Mod(dp.N); - ECPoint P = pub.Q.Multiply(hd).Normalize(); + // Always perform calculations on the exact curve specified by our private key's parameters + ECPoint pubPoint = ECAlgorithms.CleanPoint(dp.Curve, pub.Q); + if (pubPoint.IsInfinity) + throw new InvalidOperationException("Infinity is not a valid public key for ECDHC"); + ECPoint P = pubPoint.Multiply(hd).Normalize(); if (P.IsInfinity) throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC"); diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs index 8d5cebb13..b71f5a7d2 100644 --- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs @@ -64,16 +64,9 @@ namespace Org.BouncyCastle.Crypto.Agreement ECCurve curve = parameters.Curve; - ECPoint[] points = new ECPoint[]{ - // The Q2U public key is optional - but will be calculated for us if it wasn't present - ECAlgorithms.ImportPoint(curve, Q2U.Q), - ECAlgorithms.ImportPoint(curve, Q1V.Q), - ECAlgorithms.ImportPoint(curve, Q2V.Q) - }; - - curve.NormalizeAll(points); - - ECPoint q2u = points[0], q1v = points[1], q2v = points[2]; + ECPoint q2u = ECAlgorithms.CleanPoint(curve, Q2U.Q); + ECPoint q1v = ECAlgorithms.CleanPoint(curve, Q1V.Q); + ECPoint q2v = ECAlgorithms.CleanPoint(curve, Q2V.Q); BigInteger x = q2u.AffineXCoord.ToBigInteger(); BigInteger xBar = x.Mod(powE); diff --git a/crypto/src/crypto/agreement/SM2KeyExchange.cs b/crypto/src/crypto/agreement/SM2KeyExchange.cs index 1cfcd6a3a..986d98421 100644 --- a/crypto/src/crypto/agreement/SM2KeyExchange.cs +++ b/crypto/src/crypto/agreement/SM2KeyExchange.cs @@ -144,8 +144,10 @@ namespace Org.BouncyCastle.Crypto.Agreement protected virtual ECPoint CalculateU(SM2KeyExchangePublicParameters otherPub) { - ECPoint p1 = otherPub.StaticPublicKey.Q; - ECPoint p2 = otherPub.EphemeralPublicKey.Q; + ECDomainParameters dp = mStaticKey.Parameters; + + ECPoint p1 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.StaticPublicKey.Q); + ECPoint p2 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.EphemeralPublicKey.Q); BigInteger x1 = Reduce(mEphemeralPubPoint.AffineXCoord.ToBigInteger()); BigInteger x2 = Reduce(p2.AffineXCoord.ToBigInteger()); diff --git a/crypto/src/crypto/digests/Blake2bDigest.cs b/crypto/src/crypto/digests/Blake2bDigest.cs new file mode 100644 index 000000000..b8e4f272e --- /dev/null +++ b/crypto/src/crypto/digests/Blake2bDigest.cs @@ -0,0 +1,531 @@ +using System; + +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /* The BLAKE2 cryptographic hash function was designed by Jean- + Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian + Winnerlein. + + Reference Implementation and Description can be found at: https://blake2.net/ + Internet Draft: https://tools.ietf.org/html/draft-saarinen-blake2-02 + + This implementation does not support the Tree Hashing Mode. + + For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based + message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2. + + Algorithm | Target | Collision | Hash | Hash ASN.1 | + Identifier | Arch | Security | nn | OID Suffix | + ---------------+--------+-----------+------+------------+ + id-blake2b160 | 64-bit | 2**80 | 20 | x.1.20 | + id-blake2b256 | 64-bit | 2**128 | 32 | x.1.32 | + id-blake2b384 | 64-bit | 2**192 | 48 | x.1.48 | + id-blake2b512 | 64-bit | 2**256 | 64 | x.1.64 | + ---------------+--------+-----------+------+------------+ + */ + + /** + * Implementation of the cryptographic hash function Blakbe2b. + * <p> + * Blake2b offers a built-in keying mechanism to be used directly + * for authentication ("Prefix-MAC") rather than a HMAC construction. + * <p> + * Blake2b offers a built-in support for a salt for randomized hashing + * and a personal string for defining a unique hash function for each application. + * <p> + * BLAKE2b is optimized for 64-bit platforms and produces digests of any size + * between 1 and 64 bytes. + */ + public class Blake2bDigest + : IDigest + { + // Blake2b Initialization Vector: + private static readonly ulong[] blake2b_IV = + // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. + // The same as SHA-512 IV. + { + 0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL, 0x3c6ef372fe94f82bUL, + 0xa54ff53a5f1d36f1UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, + 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL + }; + + // Message word permutations: + private static readonly byte[,] blake2b_sigma = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } + }; + + private const int ROUNDS = 12; // to use for Catenas H' + private const int BLOCK_LENGTH_BYTES = 128;// bytes + + // General parameters: + private int digestLength = 64; // 1- 64 bytes + private int keyLength = 0; // 0 - 64 bytes for keyed hashing for MAC + private byte[] salt = null;// new byte[16]; + private byte[] personalization = null;// new byte[16]; + + // the key + private byte[] key = null; + + // Tree hashing parameters: + // Because this class does not implement the Tree Hashing Mode, + // these parameters can be treated as constants (see init() function) + /* + * private int fanout = 1; // 0-255 private int depth = 1; // 1 - 255 + * private int leafLength= 0; private long nodeOffset = 0L; private int + * nodeDepth = 0; private int innerHashLength = 0; + */ + + // whenever this buffer overflows, it will be processed + // in the Compress() function. + // For performance issues, long messages will not use this buffer. + private byte[] buffer = null;// new byte[BLOCK_LENGTH_BYTES]; + // Position of last inserted byte: + private int bufferPos = 0;// a value from 0 up to 128 + + private ulong[] internalState = new ulong[16]; // In the Blake2b paper it is + // called: v + private ulong[] chainValue = null; // state vector, in the Blake2b paper it + // is called: h + + private ulong t0 = 0UL; // holds last significant bits, counter (counts bytes) + private ulong t1 = 0UL; // counter: Length up to 2^128 are supported + private ulong f0 = 0UL; // finalization flag, for last block: ~0L + + // For Tree Hashing Mode, not used here: + // private long f1 = 0L; // finalization flag, for last node: ~0L + + public Blake2bDigest() + : this(512) + { + } + + public Blake2bDigest(Blake2bDigest digest) + { + this.bufferPos = digest.bufferPos; + this.buffer = Arrays.Clone(digest.buffer); + this.keyLength = digest.keyLength; + this.key = Arrays.Clone(digest.key); + this.digestLength = digest.digestLength; + this.chainValue = Arrays.Clone(digest.chainValue); + this.personalization = Arrays.Clone(digest.personalization); + this.salt = Arrays.Clone(digest.salt); + this.t0 = digest.t0; + this.t1 = digest.t1; + this.f0 = digest.f0; + } + + /** + * Basic sized constructor - size in bits. + * + * @param digestSize size of the digest in bits + */ + public Blake2bDigest(int digestSize) + { + if (digestSize != 160 && digestSize != 256 && digestSize != 384 && digestSize != 512) + throw new ArgumentException("BLAKE2b digest restricted to one of [160, 256, 384, 512]"); + + buffer = new byte[BLOCK_LENGTH_BYTES]; + keyLength = 0; + this.digestLength = digestSize / 8; + Init(); + } + + /** + * Blake2b for authentication ("Prefix-MAC mode"). + * After calling the doFinal() method, the key will + * remain to be used for further computations of + * this instance. + * The key can be overwritten using the clearKey() method. + * + * @param key A key up to 64 bytes or null + */ + public Blake2bDigest(byte[] key) + { + buffer = new byte[BLOCK_LENGTH_BYTES]; + if (key != null) + { + this.key = new byte[key.Length]; + Array.Copy(key, 0, this.key, 0, key.Length); + + if (key.Length > 64) + throw new ArgumentException("Keys > 64 are not supported"); + + keyLength = key.Length; + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + digestLength = 64; + Init(); + } + + /** + * Blake2b with key, required digest length (in bytes), salt and personalization. + * After calling the doFinal() method, the key, the salt and the personal string + * will remain and might be used for further computations with this instance. + * The key can be overwritten using the clearKey() method, the salt (pepper) + * can be overwritten using the clearSalt() method. + * + * @param key A key up to 64 bytes or null + * @param digestLength from 1 up to 64 bytes + * @param salt 16 bytes or null + * @param personalization 16 bytes or null + */ + public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization) + { + if (digestLength < 1 || digestLength > 64) + throw new ArgumentException("Invalid digest length (required: 1 - 64)"); + + this.digestLength = digestLength; + this.buffer = new byte[BLOCK_LENGTH_BYTES]; + + if (salt != null) + { + if (salt.Length != 16) + throw new ArgumentException("salt length must be exactly 16 bytes"); + + this.salt = new byte[16]; + Array.Copy(salt, 0, this.salt, 0, salt.Length); + } + if (personalization != null) + { + if (personalization.Length != 16) + throw new ArgumentException("personalization length must be exactly 16 bytes"); + + this.personalization = new byte[16]; + Array.Copy(personalization, 0, this.personalization, 0, personalization.Length); + } + if (key != null) + { + if (key.Length > 64) + throw new ArgumentException("Keys > 64 are not supported"); + + this.key = new byte[key.Length]; + Array.Copy(key, 0, this.key, 0, key.Length); + + keyLength = key.Length; + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + Init(); + } + + // initialize chainValue + private void Init() + { + if (chainValue == null) + { + chainValue = new ulong[8]; + + chainValue[0] = blake2b_IV[0] ^ (ulong)(digestLength | (keyLength << 8) | 0x1010000); + + // 0x1010000 = ((fanout << 16) | (depth << 24) | (leafLength << + // 32)); + // with fanout = 1; depth = 0; leafLength = 0; + chainValue[1] = blake2b_IV[1];// ^ nodeOffset; with nodeOffset = 0; + chainValue[2] = blake2b_IV[2];// ^ ( nodeDepth | (innerHashLength << 8) ); + // with nodeDepth = 0; innerHashLength = 0; + + chainValue[3] = blake2b_IV[3]; + + chainValue[4] = blake2b_IV[4]; + chainValue[5] = blake2b_IV[5]; + if (salt != null) + { + chainValue[4] ^= Pack.LE_To_UInt64(salt, 0); + chainValue[5] ^= Pack.LE_To_UInt64(salt, 8); + } + + chainValue[6] = blake2b_IV[6]; + chainValue[7] = blake2b_IV[7]; + if (personalization != null) + { + chainValue[6] ^= Pack.LE_To_UInt64(personalization, 0); + chainValue[7] ^= Pack.LE_To_UInt64(personalization, 8); + } + } + } + + private void InitializeInternalState() + { + // initialize v: + Array.Copy(chainValue, 0, internalState, 0, chainValue.Length); + Array.Copy(blake2b_IV, 0, internalState, chainValue.Length, 4); + internalState[12] = t0 ^ blake2b_IV[4]; + internalState[13] = t1 ^ blake2b_IV[5]; + internalState[14] = f0 ^ blake2b_IV[6]; + internalState[15] = blake2b_IV[7];// ^ f1 with f1 = 0 + } + + /** + * update the message digest with a single byte. + * + * @param b the input byte to be entered. + */ + public virtual void Update(byte b) + { + int remainingLength = 0; // left bytes of buffer + + // process the buffer if full else add to buffer: + remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + if (remainingLength == 0) + { // full buffer + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { // if message > 2^64 + t1++; + } + Compress(buffer, 0); + Array.Clear(buffer, 0, buffer.Length);// clear buffer + buffer[0] = b; + bufferPos = 1; + } + else + { + buffer[bufferPos] = b; + bufferPos++; + return; + } + } + + /** + * update the message digest with a block of bytes. + * + * @param message the byte array containing the data. + * @param offset the offset into the byte array where the data starts. + * @param len the length of the data. + */ + public virtual void BlockUpdate(byte[] message, int offset, int len) + { + if (message == null || len == 0) + return; + + int remainingLength = 0; // left bytes of buffer + + if (bufferPos != 0) + { // commenced, incomplete buffer + + // complete the buffer: + remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + if (remainingLength < len) + { // full buffer + at least 1 byte + Array.Copy(message, offset, buffer, bufferPos, + remainingLength); + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { // if message > 2^64 + t1++; + } + Compress(buffer, 0); + bufferPos = 0; + Array.Clear(buffer, 0, buffer.Length);// clear buffer + } + else + { + Array.Copy(message, offset, buffer, bufferPos, len); + bufferPos += len; + return; + } + } + + // process blocks except last block (also if last block is full) + int messagePos; + int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES; + for (messagePos = offset + remainingLength; messagePos < blockWiseLastPos; messagePos += BLOCK_LENGTH_BYTES) + { // block wise 128 bytes + // without buffer: + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { + t1++; + } + Compress(message, messagePos); + } + + // fill the buffer with left bytes, this might be a full block + Array.Copy(message, messagePos, buffer, 0, offset + len + - messagePos); + bufferPos += offset + len - messagePos; + } + + /** + * close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * Key, salt and personal string remain. + * + * @param out the array the digest is to be copied into. + * @param outOffset the offset into the out array the digest is to start at. + */ + public virtual int DoFinal(byte[] output, int outOffset) + { + f0 = 0xFFFFFFFFFFFFFFFFUL; + t0 += (ulong)bufferPos; + if (bufferPos > 0 && t0 == 0) + { + t1++; + } + Compress(buffer, 0); + Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null + Array.Clear(internalState, 0, internalState.Length); + + for (int i = 0; i < chainValue.Length && (i * 8 < digestLength); i++) + { + byte[] bytes = Pack.UInt64_To_LE(chainValue[i]); + + if (i * 8 < digestLength - 8) + { + Array.Copy(bytes, 0, output, outOffset + i * 8, 8); + } + else + { + Array.Copy(bytes, 0, output, outOffset + i * 8, digestLength - (i * 8)); + } + } + + Array.Clear(chainValue, 0, chainValue.Length); + + Reset(); + + return digestLength; + } + + /** + * Reset the digest back to it's initial state. + * The key, the salt and the personal string will + * remain for further computations. + */ + public virtual void Reset() + { + bufferPos = 0; + f0 = 0L; + t0 = 0L; + t1 = 0L; + chainValue = null; + Array.Clear(buffer, 0, buffer.Length); + if (key != null) + { + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + Init(); + } + + private void Compress(byte[] message, int messagePos) + { + InitializeInternalState(); + + ulong[] m = new ulong[16]; + for (int j = 0; j < 16; j++) + { + m[j] = Pack.LE_To_UInt64(message, messagePos + j * 8); + } + + for (int round = 0; round < ROUNDS; round++) + { + // G apply to columns of internalState:m[blake2b_sigma[round][2 * blockPos]] /+1 + G(m[blake2b_sigma[round,0]], m[blake2b_sigma[round,1]], 0, 4, 8, 12); + G(m[blake2b_sigma[round,2]], m[blake2b_sigma[round,3]], 1, 5, 9, 13); + G(m[blake2b_sigma[round,4]], m[blake2b_sigma[round,5]], 2, 6, 10, 14); + G(m[blake2b_sigma[round,6]], m[blake2b_sigma[round,7]], 3, 7, 11, 15); + // G apply to diagonals of internalState: + G(m[blake2b_sigma[round,8]], m[blake2b_sigma[round,9]], 0, 5, 10, 15); + G(m[blake2b_sigma[round,10]], m[blake2b_sigma[round,11]], 1, 6, 11, 12); + G(m[blake2b_sigma[round,12]], m[blake2b_sigma[round,13]], 2, 7, 8, 13); + G(m[blake2b_sigma[round,14]], m[blake2b_sigma[round,15]], 3, 4, 9, 14); + } + + // update chain values: + for (int offset = 0; offset < chainValue.Length; offset++) + { + chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8]; + } + } + + private void G(ulong m1, ulong m2, int posA, int posB, int posC, int posD) + { + internalState[posA] = internalState[posA] + internalState[posB] + m1; + internalState[posD] = Rotr64(internalState[posD] ^ internalState[posA], 32); + internalState[posC] = internalState[posC] + internalState[posD]; + internalState[posB] = Rotr64(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE + internalState[posA] = internalState[posA] + internalState[posB] + m2; + internalState[posD] = Rotr64(internalState[posD] ^ internalState[posA], 16); + internalState[posC] = internalState[posC] + internalState[posD]; + internalState[posB] = Rotr64(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE + } + + private static ulong Rotr64(ulong x, int rot) + { + return x >> rot | x << -rot; + } + + /** + * return the algorithm name + * + * @return the algorithm name + */ + public virtual string AlgorithmName + { + get { return "BLAKE2b"; } + } + + /** + * 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. + */ + public virtual int GetDigestSize() + { + return digestLength; + } + + /** + * Return the size in bytes of the internal buffer the digest applies it's compression + * function to. + * + * @return byte length of the digests internal buffer. + */ + public virtual int GetByteLength() + { + return BLOCK_LENGTH_BYTES; + } + + /** + * Overwrite the key + * if it is no longer used (zeroization) + */ + public virtual void ClearKey() + { + if (key != null) + { + Array.Clear(key, 0, key.Length); + Array.Clear(buffer, 0, buffer.Length); + } + } + + /** + * Overwrite the salt (pepper) if it + * is secret and no longer used (zeroization) + */ + public virtual void ClearSalt() + { + if (salt != null) + { + Array.Clear(salt, 0, salt.Length); + } + } + } +} diff --git a/crypto/src/crypto/digests/Blake2sDigest.cs b/crypto/src/crypto/digests/Blake2sDigest.cs new file mode 100644 index 000000000..f31032874 --- /dev/null +++ b/crypto/src/crypto/digests/Blake2sDigest.cs @@ -0,0 +1,552 @@ +using System; + +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /* + The BLAKE2 cryptographic hash function was designed by Jean- + Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian + Winnerlein. + + Reference Implementation and Description can be found at: https://blake2.net/ + RFC: https://tools.ietf.org/html/rfc7693 + + This implementation does not support the Tree Hashing Mode. + + For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based + message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2. + + Algorithm | Target | Collision | Hash | Hash ASN.1 | + Identifier | Arch | Security | nn | OID Suffix | + ---------------+--------+-----------+------+------------+ + id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 | + id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 | + id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 | + id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 | + ---------------+--------+-----------+------+------------+ + */ + + /** + * Implementation of the cryptographic hash function BLAKE2s. + * <p/> + * BLAKE2s offers a built-in keying mechanism to be used directly + * for authentication ("Prefix-MAC") rather than a HMAC construction. + * <p/> + * BLAKE2s offers a built-in support for a salt for randomized hashing + * and a personal string for defining a unique hash function for each application. + * <p/> + * BLAKE2s is optimized for 32-bit platforms and produces digests of any size + * between 1 and 32 bytes. + */ + public class Blake2sDigest + : IDigest + { + /** + * BLAKE2s Initialization Vector + **/ + private static readonly uint[] blake2s_IV = + // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. + // The same as SHA-256 IV. + { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, + 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 + }; + + /** + * Message word permutations + **/ + private static readonly byte[,] blake2s_sigma = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } + }; + + private const int ROUNDS = 10; // to use for Catenas H' + private const int BLOCK_LENGTH_BYTES = 64;// bytes + + // General parameters: + private int digestLength = 32; // 1- 32 bytes + private int keyLength = 0; // 0 - 32 bytes for keyed hashing for MAC + private byte[] salt = null; + private byte[] personalization = null; + private byte[] key = null; + + // Tree hashing parameters: + // Because this class does not implement the Tree Hashing Mode, + // these parameters can be treated as constants (see Init() function) + /* + * private int fanout = 1; // 0-255 + * private int depth = 1; // 1 - 255 + * private int leafLength= 0; + * private long nodeOffset = 0L; + * private int nodeDepth = 0; + * private int innerHashLength = 0; + */ + + /** + * Whenever this buffer overflows, it will be processed in the Compress() + * function. For performance issues, long messages will not use this buffer. + */ + private byte[] buffer = null; + /** + * Position of last inserted byte + **/ + private int bufferPos = 0;// a value from 0 up to BLOCK_LENGTH_BYTES + + /** + * Internal state, in the BLAKE2 paper it is called v + **/ + private uint[] internalState = new uint[16]; + /** + * State vector, in the BLAKE2 paper it is called h + **/ + private uint[] chainValue = null; + + // counter (counts bytes): Length up to 2^64 are supported + /** + * holds least significant bits of counter + **/ + private uint t0 = 0; + /** + * holds most significant bits of counter + **/ + private uint t1 = 0; + /** + * finalization flag, for last block: ~0 + **/ + private uint f0 = 0; + + // For Tree Hashing Mode, not used here: + // private long f1 = 0L; // finalization flag, for last node: ~0L + + /** + * BLAKE2s-256 for hashing. + */ + public Blake2sDigest() + : this(256) + { + } + + public Blake2sDigest(Blake2sDigest digest) + { + this.bufferPos = digest.bufferPos; + this.buffer = Arrays.Clone(digest.buffer); + this.keyLength = digest.keyLength; + this.key = Arrays.Clone(digest.key); + this.digestLength = digest.digestLength; + this.chainValue = Arrays.Clone(digest.chainValue); + this.personalization = Arrays.Clone(digest.personalization); + } + + /** + * BLAKE2s for hashing. + * + * @param digestBits the desired digest length in bits. Must be one of + * [128, 160, 224, 256]. + */ + public Blake2sDigest(int digestBits) + { + if (digestBits != 128 && digestBits != 160 && digestBits != 224 && digestBits != 256) + throw new ArgumentException("BLAKE2s digest restricted to one of [128, 160, 224, 256]"); + + buffer = new byte[BLOCK_LENGTH_BYTES]; + keyLength = 0; + digestLength = digestBits / 8; + Init(); + } + + /** + * BLAKE2s for authentication ("Prefix-MAC mode"). + * <p/> + * After calling the doFinal() method, the key will remain to be used for + * further computations of this instance. The key can be overwritten using + * the clearKey() method. + * + * @param key a key up to 32 bytes or null + */ + public Blake2sDigest(byte[] key) + { + buffer = new byte[BLOCK_LENGTH_BYTES]; + if (key != null) + { + if (key.Length > 32) + throw new ArgumentException("Keys > 32 are not supported"); + + this.key = new byte[key.Length]; + Array.Copy(key, 0, this.key, 0, key.Length); + + keyLength = key.Length; + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + digestLength = 32; + Init(); + } + + /** + * BLAKE2s with key, required digest length, salt and personalization. + * <p/> + * After calling the doFinal() method, the key, the salt and the personal + * string will remain and might be used for further computations with this + * instance. The key can be overwritten using the clearKey() method, the + * salt (pepper) can be overwritten using the clearSalt() method. + * + * @param key a key up to 32 bytes or null + * @param digestBytes from 1 up to 32 bytes + * @param salt 8 bytes or null + * @param personalization 8 bytes or null + */ + public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, + byte[] personalization) + { + if (digestBytes < 1 || digestBytes > 32) + throw new ArgumentException("Invalid digest length (required: 1 - 32)"); + + this.digestLength = digestBytes; + this.buffer = new byte[BLOCK_LENGTH_BYTES]; + + if (salt != null) + { + if (salt.Length != 8) + throw new ArgumentException("Salt length must be exactly 8 bytes"); + + this.salt = new byte[8]; + Array.Copy(salt, 0, this.salt, 0, salt.Length); + } + if (personalization != null) + { + if (personalization.Length != 8) + throw new ArgumentException("Personalization length must be exactly 8 bytes"); + + this.personalization = new byte[8]; + Array.Copy(personalization, 0, this.personalization, 0, personalization.Length); + } + if (key != null) + { + if (key.Length > 32) + throw new ArgumentException("Keys > 32 bytes are not supported"); + + this.key = new byte[key.Length]; + Array.Copy(key, 0, this.key, 0, key.Length); + + keyLength = key.Length; + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + Init(); + } + + // initialize chainValue + private void Init() + { + if (chainValue == null) + { + chainValue = new uint[8]; + + chainValue[0] = blake2s_IV[0] ^ (uint)(digestLength | (keyLength << 8) | 0x1010000); + // 0x1010000 = ((fanout << 16) | (depth << 24)); + // with fanout = 1; depth = 0; + chainValue[1] = blake2s_IV[1];// ^ leafLength; with leafLength = 0; + chainValue[2] = blake2s_IV[2];// ^ nodeOffset; with nodeOffset = 0; + chainValue[3] = blake2s_IV[3];// ^ ( (nodeOffset << 32) | (nodeDepth << 16) | (innerHashLength << 24) ); + // with nodeDepth = 0; innerHashLength = 0; + + chainValue[4] = blake2s_IV[4]; + chainValue[5] = blake2s_IV[5]; + if (salt != null) + { + chainValue[4] ^= Pack.LE_To_UInt32(salt, 0); + chainValue[5] ^= Pack.LE_To_UInt32(salt, 4); + } + + chainValue[6] = blake2s_IV[6]; + chainValue[7] = blake2s_IV[7]; + if (personalization != null) + { + chainValue[6] ^= Pack.LE_To_UInt32(personalization, 0); + chainValue[7] ^= Pack.LE_To_UInt32(personalization, 4); + } + } + } + + private void InitializeInternalState() + { + // initialize v: + Array.Copy(chainValue, 0, internalState, 0, chainValue.Length); + Array.Copy(blake2s_IV, 0, internalState, chainValue.Length, 4); + internalState[12] = t0 ^ blake2s_IV[4]; + internalState[13] = t1 ^ blake2s_IV[5]; + internalState[14] = f0 ^ blake2s_IV[6]; + internalState[15] = blake2s_IV[7];// ^ f1 with f1 = 0 + } + + /** + * Update the message digest with a single byte. + * + * @param b the input byte to be entered. + */ + public virtual void Update(byte b) + { + int remainingLength; // left bytes of buffer + + // process the buffer if full else add to buffer: + remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + if (remainingLength == 0) + { // full buffer + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { // if message > 2^32 + t1++; + } + Compress(buffer, 0); + Array.Clear(buffer, 0, buffer.Length);// clear buffer + buffer[0] = b; + bufferPos = 1; + } + else + { + buffer[bufferPos] = b; + bufferPos++; + } + } + + /** + * Update the message digest with a block of bytes. + * + * @param message the byte array containing the data. + * @param offset the offset into the byte array where the data starts. + * @param len the length of the data. + */ + public virtual void BlockUpdate(byte[] message, int offset, int len) + { + if (message == null || len == 0) + return; + + int remainingLength = 0; // left bytes of buffer + + if (bufferPos != 0) + { // commenced, incomplete buffer + + // complete the buffer: + remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + if (remainingLength < len) + { // full buffer + at least 1 byte + Array.Copy(message, offset, buffer, bufferPos, remainingLength); + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { // if message > 2^32 + t1++; + } + Compress(buffer, 0); + bufferPos = 0; + Array.Clear(buffer, 0, buffer.Length);// clear buffer + } + else + { + Array.Copy(message, offset, buffer, bufferPos, len); + bufferPos += len; + return; + } + } + + // process blocks except last block (also if last block is full) + int messagePos; + int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES; + for (messagePos = offset + remainingLength; + messagePos < blockWiseLastPos; + messagePos += BLOCK_LENGTH_BYTES) + { // block wise 64 bytes + // without buffer: + t0 += BLOCK_LENGTH_BYTES; + if (t0 == 0) + { + t1++; + } + Compress(message, messagePos); + } + + // fill the buffer with left bytes, this might be a full block + Array.Copy(message, messagePos, buffer, 0, offset + len + - messagePos); + bufferPos += offset + len - messagePos; + } + + /** + * Close the digest, producing the final digest value. The doFinal() call + * leaves the digest reset. Key, salt and personal string remain. + * + * @param out the array the digest is to be copied into. + * @param outOffset the offset into the out array the digest is to start at. + */ + public virtual int DoFinal(byte[] output, int outOffset) + { + f0 = 0xFFFFFFFFU; + t0 += (uint)bufferPos; + // bufferPos may be < 64, so (t0 == 0) does not work + // for 2^32 < message length > 2^32 - 63 + if ((t0 < 0) && (bufferPos > -t0)) + { + t1++; + } + Compress(buffer, 0); + Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null + Array.Clear(internalState, 0, internalState.Length); + + for (int i = 0; i < chainValue.Length && (i * 4 < digestLength); i++) + { + byte[] bytes = Pack.UInt32_To_LE(chainValue[i]); + + if (i * 4 < digestLength - 4) + { + Array.Copy(bytes, 0, output, outOffset + i * 4, 4); + } + else + { + Array.Copy(bytes, 0, output, outOffset + i * 4, digestLength - (i * 4)); + } + } + + Array.Clear(chainValue, 0, chainValue.Length); + + Reset(); + + return digestLength; + } + + /** + * Reset the digest back to its initial state. The key, the salt and the + * personal string will remain for further computations. + */ + public virtual void Reset() + { + bufferPos = 0; + f0 = 0; + t0 = 0; + t1 = 0; + chainValue = null; + Array.Clear(buffer, 0, buffer.Length); + if (key != null) + { + Array.Copy(key, 0, buffer, 0, key.Length); + bufferPos = BLOCK_LENGTH_BYTES; // zero padding + } + Init(); + } + + private void Compress(byte[] message, int messagePos) + { + InitializeInternalState(); + + uint[] m = new uint[16]; + for (int j = 0; j < 16; j++) + { + m[j] = Pack.LE_To_UInt32(message, messagePos + j * 4); + } + + for (int round = 0; round < ROUNDS; round++) + { + + // G apply to columns of internalState:m[blake2s_sigma[round][2 * + // blockPos]] /+1 + G(m[blake2s_sigma[round,0]], m[blake2s_sigma[round,1]], 0, 4, 8, 12); + G(m[blake2s_sigma[round,2]], m[blake2s_sigma[round,3]], 1, 5, 9, 13); + G(m[blake2s_sigma[round,4]], m[blake2s_sigma[round,5]], 2, 6, 10, 14); + G(m[blake2s_sigma[round,6]], m[blake2s_sigma[round,7]], 3, 7, 11, 15); + // G apply to diagonals of internalState: + G(m[blake2s_sigma[round,8]], m[blake2s_sigma[round,9]], 0, 5, 10, 15); + G(m[blake2s_sigma[round,10]], m[blake2s_sigma[round,11]], 1, 6, 11, 12); + G(m[blake2s_sigma[round,12]], m[blake2s_sigma[round,13]], 2, 7, 8, 13); + G(m[blake2s_sigma[round,14]], m[blake2s_sigma[round,15]], 3, 4, 9, 14); + } + + // update chain values: + for (int offset = 0; offset < chainValue.Length; offset++) + { + chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8]; + } + } + + private void G(uint m1, uint m2, int posA, int posB, int posC, int posD) + { + internalState[posA] = internalState[posA] + internalState[posB] + m1; + internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 16); + internalState[posC] = internalState[posC] + internalState[posD]; + internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 12); + internalState[posA] = internalState[posA] + internalState[posB] + m2; + internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 8); + internalState[posC] = internalState[posC] + internalState[posD]; + internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 7); + } + + private uint rotr32(uint x, int rot) + { + return x >> rot | x << -rot; + } + + /** + * Return the algorithm name. + * + * @return the algorithm name + */ + public virtual string AlgorithmName + { + get { return "BLAKE2s"; } + } + + /** + * 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. + */ + public virtual int GetDigestSize() + { + return digestLength; + } + + /** + * Return the size in bytes of the internal buffer the digest applies its + * compression function to. + * + * @return byte length of the digest's internal buffer. + */ + public virtual int GetByteLength() + { + return BLOCK_LENGTH_BYTES; + } + + /** + * Overwrite the key if it is no longer used (zeroization). + */ + public virtual void ClearKey() + { + if (key != null) + { + Array.Clear(key, 0, key.Length); + Array.Clear(buffer, 0, buffer.Length); + } + } + + /** + * Overwrite the salt (pepper) if it is secret and no longer used + * (zeroization). + */ + public virtual void ClearSalt() + { + if (salt != null) + { + Array.Clear(salt, 0, salt.Length); + } + } + } +} diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs index e641af6c2..b2d90799d 100644 --- a/crypto/src/crypto/digests/DSTU7564Digest.cs +++ b/crypto/src/crypto/digests/DSTU7564Digest.cs @@ -3,38 +3,36 @@ using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; -//using Org.BouncyCastle.Utilities; - -using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Crypto.Digests { /** * implementation of Ukrainian DSTU 7564 hash function */ - public class Dstu7564Digest : IDigest, IMemoable + public class Dstu7564Digest + : IDigest, IMemoable { - private const int ROWS = 8; - private const int BITS_IN_BYTE = 8; - private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code. private const int NB_1024 = 16; //Number of 8-byte words in state for <=512-bit hash code. private const int NR_512 = 10; //Number of rounds for 512-bit state. private const int NR_1024 = 14; //Number of rounds for 1024-bit state. - private const int STATE_BYTE_SIZE_512 = ROWS * NB_512; - private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024; - private int hashSize; private int blockSize; + private int columns; private int rounds; - private byte[] padded_; - private byte[][] state_; - private ulong inputLength; + + private ulong[] state; + private ulong[] tempState1; + private ulong[] tempState2; + + // TODO Guard against 'inputBlocks' overflow (2^64 blocks) + private ulong inputBlocks; private int bufOff; private byte[] buf; @@ -48,20 +46,23 @@ namespace Org.BouncyCastle.Crypto.Digests this.hashSize = digest.hashSize; this.blockSize = digest.blockSize; - this.columns = digest.columns; this.rounds = digest.rounds; - - this.padded_ = Arrays.Clone(digest.padded_); - this.state_ = new byte[digest.state_.Length][]; - - for (int i = 0; i != this.state_.Length; i++) + if (columns > 0 && columns == digest.columns) { - this.state_[i] = Arrays.Clone(digest.state_[i]); + Array.Copy(digest.state, 0, state, 0, columns); + Array.Copy(digest.buf, 0, buf, 0, blockSize); + } + else + { + this.columns = digest.columns; + this.state = Arrays.Clone(digest.state); + this.tempState1 = new ulong[columns]; + this.tempState2 = new ulong[columns]; + this.buf = Arrays.Clone(digest.buf); } - this.inputLength = digest.inputLength; + this.inputBlocks = digest.inputBlocks; this.bufOff = digest.bufOff; - this.buf = Arrays.Clone(digest.buf); } public Dstu7564Digest(int hashSizeBits) @@ -72,34 +73,28 @@ namespace Org.BouncyCastle.Crypto.Digests } else { - throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size"); + throw new ArgumentException("Hash size is not recommended. Use 256/384/512 instead"); } if (hashSizeBits > 256) { - this.blockSize = 1024 / 8; this.columns = NB_1024; this.rounds = NR_1024; - this.state_ = new byte[STATE_BYTE_SIZE_1024][]; } else { - this.blockSize = 512 / 8; this.columns = NB_512; this.rounds = NR_512; - this.state_ = new byte[STATE_BYTE_SIZE_512][]; } - for (int i = 0; i < state_.Length; i++) - { - this.state_[i] = new byte[columns]; - } + this.blockSize = columns << 3; - this.state_[0][0] = (byte)state_.Length; + this.state = new ulong[columns]; + this.state[0] = (ulong)blockSize; - this.hashSize = hashSizeBits / 8; + this.tempState1 = new ulong[columns]; + this.tempState2 = new ulong[columns]; - this.padded_ = null; this.buf = new byte[blockSize]; } @@ -108,128 +103,104 @@ namespace Org.BouncyCastle.Crypto.Digests get { return "DSTU7564"; } } + public virtual int GetDigestSize() + { + return hashSize; + } + + public virtual int GetByteLength() + { + return blockSize; + } + + public virtual void Update(byte input) + { + buf[bufOff++] = input; + if (bufOff == blockSize) + { + ProcessBlock(buf, 0); + bufOff = 0; + ++inputBlocks; + } + } + public virtual void BlockUpdate(byte[] input, int inOff, int length) { while (bufOff != 0 && length > 0) { Update(input[inOff++]); - length--; + --length; } if (length > 0) { - while (length > blockSize) + while (length >= blockSize) { ProcessBlock(input, inOff); inOff += blockSize; - inputLength += (ulong)blockSize; length -= blockSize; + ++inputBlocks; } while (length > 0) { Update(input[inOff++]); - length--; + --length; } } } - protected virtual byte[] Pad(byte[] input, int inOff, int length) - { - byte[] padded; - if (blockSize - length < 13) // terminator byte + 96 bits of length - { - padded = new byte[2 * blockSize]; - } - else - { - padded = new byte[blockSize]; - } - - Array.Copy(input, inOff, padded, 0, length); - padded[length] = 0x80; - Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12); - - return padded; - } - - protected virtual void ProcessBlock(byte[] input, int inOff) + public virtual int DoFinal(byte[] output, int outOff) { - byte[][] temp1 = new byte[columns][]; - byte[][] temp2 = new byte[columns][]; - - int pos = inOff; - for (int i = 0; i < columns; i++) + // Apply padding: terminator byte and 96-bit length field { - byte[] S = state_[i]; - byte[] T1 = temp1[i] = new byte[ROWS]; - byte[] T2 = temp2[i] = new byte[ROWS]; + int inputBytes = bufOff; + buf[bufOff++] = (byte)0x80; - for (int j = 0; j < ROWS; ++j) + int lenPos = blockSize - 12; + if (bufOff > lenPos) { - byte inVal = input[pos++]; - T1[j] = (byte)(S[j] ^ inVal); - T2[j] = inVal; + while (bufOff < blockSize) + { + buf[bufOff++] = 0; + } + bufOff = 0; + ProcessBlock(buf, 0); } - } - P(temp1); - Q(temp2); - - for (int i = 0; i < columns; ++i) - { - byte[] S = state_[i], T1 = temp1[i], T2 = temp2[i]; - for (int j = 0; j < ROWS; ++j) + while (bufOff < lenPos) { - S[j] ^= (byte)(T1[j] ^ T2[j]); + buf[bufOff++] = 0; } - } - } - - public virtual int DoFinal(byte[] output, int outOff) - { - padded_ = Pad(buf, 0, bufOff); - - int paddedLen = padded_.Length; - int paddedOff = 0; - while (paddedLen != 0) - { - ProcessBlock(padded_, paddedOff); - paddedOff += blockSize; - paddedLen -= blockSize; + ulong c = ((inputBlocks & 0xFFFFFFFFUL) * (ulong)blockSize + (uint)inputBytes) << 3; + Pack.UInt32_To_LE((uint)c, buf, bufOff); + bufOff += 4; + c >>= 32; + c += ((inputBlocks >> 32) * (ulong)blockSize) << 3; + Pack.UInt64_To_LE(c, buf, bufOff); + // bufOff += 8; + ProcessBlock(buf, 0); } - byte[][] temp = new byte[STATE_BYTE_SIZE_1024][]; - for (int i = 0; i < state_.Length; i++) { - temp[i] = new byte[ROWS]; - Array.Copy(state_[i], temp[i], ROWS); - } + Array.Copy(state, 0, tempState1, 0, columns); - P(temp); + P(tempState1); - for (int i = 0; i < ROWS; ++i) - { - for (int j = 0; j < columns; ++j) + for (int col = 0; col < columns; ++col) { - state_[j][i] ^= temp[j][i]; + state[col] ^= tempState1[col]; } } - byte[] stateLine = new byte[ROWS * columns]; - int stateLineIndex = 0; - for (int j = 0; j < columns; ++j) + int neededColumns = hashSize / 8; + for (int col = columns - neededColumns; col < columns; ++col) { - for (int i = 0; i < ROWS; ++i) - { - stateLine[stateLineIndex] = state_[j][i]; - stateLineIndex++; - } + Pack.UInt64_To_LE(state[col], output, outOff); + outOff += 8; } - Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize); - Reset(); return hashSize; @@ -237,183 +208,313 @@ namespace Org.BouncyCastle.Crypto.Digests public virtual void Reset() { - for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++) - { - state_[bufferIndex] = new byte[columns]; - } + Array.Clear(state, 0, state.Length); + state[0] = (ulong)blockSize; - state_[0][0] = (byte)state_.Length; - - inputLength = 0; + inputBlocks = 0; bufOff = 0; - - Arrays.Fill(buf, (byte)0); - - if (padded_ != null) - { - Arrays.Fill(padded_, (byte)0); - } } - public virtual int GetDigestSize() + protected virtual void ProcessBlock(byte[] input, int inOff) { - return hashSize; - } + int pos = inOff; + for (int col = 0; col < columns; ++col) + { + ulong word = Pack.LE_To_UInt64(input, pos); + pos += 8; - public virtual int GetByteLength() - { - return blockSize; - } + tempState1[col] = state[col] ^ word; + tempState2[col] = word; + } - public virtual void Update(byte input) - { - buf[bufOff++] = input; - if (bufOff == blockSize) + P(tempState1); + Q(tempState2); + + for (int col = 0; col < columns; ++col) { - ProcessBlock(buf, 0); - bufOff = 0; + state[col] ^= tempState1[col] ^ tempState2[col]; } - inputLength++; } - private void SubBytes(byte[][] state) + private void P(ulong[] s) { - int i, j; - for (i = 0; i < ROWS; ++i) + for (int round = 0; round < rounds; ++round) { - for (j = 0; j < columns; ++j) + ulong rc = (ulong)round; + + /* AddRoundConstants */ + for (int col = 0; col < columns; ++col) { - state[j][i] = sBoxes[i % 4][state[j][i]]; + s[col] ^= rc; + rc += 0x10L; } + + ShiftRows(s); + SubBytes(s); + MixColumns(s); } } - private void ShiftBytes(byte[][] state) + private void Q(ulong[] s) { - int i, j; - byte[] temp = new byte[NB_1024]; - int shift = -1; - for (i = 0; i < ROWS; ++i) + for (int round = 0; round < rounds; ++round) { - if ((i == ROWS - 1) && (columns == NB_1024)) - { - shift = 11; - } - else - { - ++shift; - } - for (j = 0; j < columns; ++j) - { - temp[(j + shift) % columns] = state[j][i]; - } - for (j = 0; j < columns; ++j) + /* AddRoundConstantsQ */ + ulong rc = ((ulong)(((columns - 1) << 4) ^ round) << 56) | 0x00F0F0F0F0F0F0F3UL; + + for (int col = 0; col < columns; ++col) { - state[j][i] = temp[j]; + s[col] += rc; + rc -= 0x1000000000000000L; } + + ShiftRows(s); + SubBytes(s); + MixColumns(s); } } - /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */ - private static ulong MultiplyGFx4(ulong u, ulong v) + private static ulong MixColumn(ulong c) { - ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL); - - for (int i = 1; i < 8; ++i) - { - u <<= 1; - v >>= 1; - r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL); - } - - // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ - - ulong hi = r & 0xFF00FF00FF00FF00UL; - r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - hi = r & 0x0F000F000F000F00UL; - r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - return r; + //// Calculate column multiplied by powers of 'x' + //ulong x0 = c; + //ulong x1 = ((x0 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x0 & 0x8080808080808080UL) >> 7) * 0x1DUL); + //ulong x2 = ((x1 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x1 & 0x8080808080808080UL) >> 7) * 0x1DUL); + //ulong x3 = ((x2 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x2 & 0x8080808080808080UL) >> 7) * 0x1DUL); + + //// Calculate products with circulant matrix from (0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04) + //ulong m0 = x0; + //ulong m1 = x0; + //ulong m2 = x0 ^ x2; + //ulong m3 = x0; + //ulong m4 = x3; + //ulong m5 = x1 ^ x2; + //ulong m6 = x0 ^ x1 ^ x2; + //ulong m7 = x2; + + //// Assemble the rotated products + //return m0 + // ^ Rotate(8, m1) + // ^ Rotate(16, m2) + // ^ Rotate(24, m3) + // ^ Rotate(32, m4) + // ^ Rotate(40, m5) + // ^ Rotate(48, m6) + // ^ Rotate(56, m7); + + // Multiply elements by 'x' + ulong x1 = ((c & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((c & 0x8080808080808080UL) >> 7) * 0x1DUL); + ulong u, v; + + u = Rotate(8, c) ^ c; + u ^= Rotate(16, u); + u ^= Rotate(48, c); + + v = u ^ c ^ x1; + + // Multiply elements by 'x^2' + v = ((v & 0x3F3F3F3F3F3F3F3FUL) << 2) ^ (((v & 0x8080808080808080UL) >> 6) * 0x1DUL) ^ (((v & 0x4040404040404040UL) >> 6) * 0x1DUL); + + return u ^ Rotate(32, v) ^ Rotate(40, x1) ^ Rotate(48, x1); } - private void MixColumns(byte[][] state) + private void MixColumns(ulong[] s) { for (int col = 0; col < columns; ++col) { - ulong colVal = Pack.LE_To_UInt64(state[col]); - ulong colEven = colVal & 0x00FF00FF00FF00FFUL; - ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL; - - //ulong rowMatrix = (mdsMatrix >> 8) | (mdsMatrix << 56); - ulong rowMatrix = mdsMatrix; - - ulong result = 0; - for (int row = 7; row >= 0; --row) - { - ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL); - - rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56); - - product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL); - - product ^= (product >> 32); - product ^= (product >> 16); - - result <<= 8; - result |= (product & 0xFFUL); - } - - Pack.UInt64_To_LE(result, state[col]); + s[col] = MixColumn(s[col]); } } - private void AddRoundConstantP(byte[][] state, int round) + private static ulong Rotate(int n, ulong x) { - int i; - for (i = 0; i < columns; ++i) - { - state[i][0] ^= (byte)((i * 0x10) ^ round); - } + return (x >> n) | (x << -n); } - private void AddRoundConstantQ(byte[][] state, int round) + private void ShiftRows(ulong[] s) { - int j; - UInt64[] s = new UInt64[columns]; - - for (j = 0; j < columns; j++) + switch (columns) { - s[j] = Pack.LE_To_UInt64(state[j]); - - s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8))); - - state[j] = Pack.UInt64_To_LE(s[j]); + case NB_512: + { + ulong c0 = s[0], c1 = s[1], c2 = s[2], c3 = s[3]; + ulong c4 = s[4], c5 = s[5], c6 = s[6], c7 = s[7]; + ulong d; + + d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d; + d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d; + d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d; + d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d; + + d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d; + d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d; + d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d; + d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d; + + d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d; + d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d; + d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d; + d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d; + + s[0] = c0; s[1] = c1; s[2] = c2; s[3] = c3; + s[4] = c4; s[5] = c5; s[6] = c6; s[7] = c7; + break; } - } - - private void P(byte[][] state) - { - int i; - for (i = 0; i < rounds; ++i) + case NB_1024: { - AddRoundConstantP(state, i); - SubBytes(state); - ShiftBytes(state); - MixColumns(state); + ulong c00 = s[0], c01 = s[1], c02 = s[2], c03 = s[3]; + ulong c04 = s[4], c05 = s[5], c06 = s[6], c07 = s[7]; + ulong c08 = s[8], c09 = s[9], c10 = s[10], c11 = s[11]; + ulong c12 = s[12], c13 = s[13], c14 = s[14], c15 = s[15]; + ulong d; + + // NOTE: Row 7 is shifted by 11 + + d = (c00 ^ c08) & 0xFF00000000000000UL; c00 ^= d; c08 ^= d; + d = (c01 ^ c09) & 0xFF00000000000000UL; c01 ^= d; c09 ^= d; + d = (c02 ^ c10) & 0xFFFF000000000000UL; c02 ^= d; c10 ^= d; + d = (c03 ^ c11) & 0xFFFFFF0000000000UL; c03 ^= d; c11 ^= d; + d = (c04 ^ c12) & 0xFFFFFFFF00000000UL; c04 ^= d; c12 ^= d; + d = (c05 ^ c13) & 0x00FFFFFFFF000000UL; c05 ^= d; c13 ^= d; + d = (c06 ^ c14) & 0x00FFFFFFFFFF0000UL; c06 ^= d; c14 ^= d; + d = (c07 ^ c15) & 0x00FFFFFFFFFFFF00UL; c07 ^= d; c15 ^= d; + + d = (c00 ^ c04) & 0x00FFFFFF00000000UL; c00 ^= d; c04 ^= d; + d = (c01 ^ c05) & 0xFFFFFFFFFF000000UL; c01 ^= d; c05 ^= d; + d = (c02 ^ c06) & 0xFF00FFFFFFFF0000UL; c02 ^= d; c06 ^= d; + d = (c03 ^ c07) & 0xFF0000FFFFFFFF00UL; c03 ^= d; c07 ^= d; + d = (c08 ^ c12) & 0x00FFFFFF00000000UL; c08 ^= d; c12 ^= d; + d = (c09 ^ c13) & 0xFFFFFFFFFF000000UL; c09 ^= d; c13 ^= d; + d = (c10 ^ c14) & 0xFF00FFFFFFFF0000UL; c10 ^= d; c14 ^= d; + d = (c11 ^ c15) & 0xFF0000FFFFFFFF00UL; c11 ^= d; c15 ^= d; + + d = (c00 ^ c02) & 0xFFFF0000FFFF0000UL; c00 ^= d; c02 ^= d; + d = (c01 ^ c03) & 0x00FFFF0000FFFF00UL; c01 ^= d; c03 ^= d; + d = (c04 ^ c06) & 0xFFFF0000FFFF0000UL; c04 ^= d; c06 ^= d; + d = (c05 ^ c07) & 0x00FFFF0000FFFF00UL; c05 ^= d; c07 ^= d; + d = (c08 ^ c10) & 0xFFFF0000FFFF0000UL; c08 ^= d; c10 ^= d; + d = (c09 ^ c11) & 0x00FFFF0000FFFF00UL; c09 ^= d; c11 ^= d; + d = (c12 ^ c14) & 0xFFFF0000FFFF0000UL; c12 ^= d; c14 ^= d; + d = (c13 ^ c15) & 0x00FFFF0000FFFF00UL; c13 ^= d; c15 ^= d; + + d = (c00 ^ c01) & 0xFF00FF00FF00FF00UL; c00 ^= d; c01 ^= d; + d = (c02 ^ c03) & 0xFF00FF00FF00FF00UL; c02 ^= d; c03 ^= d; + d = (c04 ^ c05) & 0xFF00FF00FF00FF00UL; c04 ^= d; c05 ^= d; + d = (c06 ^ c07) & 0xFF00FF00FF00FF00UL; c06 ^= d; c07 ^= d; + d = (c08 ^ c09) & 0xFF00FF00FF00FF00UL; c08 ^= d; c09 ^= d; + d = (c10 ^ c11) & 0xFF00FF00FF00FF00UL; c10 ^= d; c11 ^= d; + d = (c12 ^ c13) & 0xFF00FF00FF00FF00UL; c12 ^= d; c13 ^= d; + d = (c14 ^ c15) & 0xFF00FF00FF00FF00UL; c14 ^= d; c15 ^= d; + + s[0] = c00; s[1] = c01; s[2] = c02; s[3] = c03; + s[4] = c04; s[5] = c05; s[6] = c06; s[7] = c07; + s[8] = c08; s[9] = c09; s[10] = c10; s[11] = c11; + s[12] = c12; s[13] = c13; s[14] = c14; s[15] = c15; + break; + } + default: + { + throw new InvalidOperationException("unsupported state size: only 512/1024 are allowed"); + } } } - private void Q(byte[][] state) + private void SubBytes(ulong[] s) { - int i; - for (i = 0; i < rounds; ++i) + for (int i = 0; i < columns; ++i) { - AddRoundConstantQ(state, i); - SubBytes(state); - ShiftBytes(state); - MixColumns(state); + ulong u = s[i]; + uint lo = (uint)u, hi = (uint)(u >> 32); + byte t0 = S0[lo & 0xFF]; + byte t1 = S1[(lo >> 8) & 0xFF]; + byte t2 = S2[(lo >> 16) & 0xFF]; + byte t3 = S3[lo >> 24]; + lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = S0[hi & 0xFF]; + byte t5 = S1[(hi >> 8) & 0xFF]; + byte t6 = S2[(hi >> 16) & 0xFF]; + byte t7 = S3[hi >> 24]; + hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + s[i] = (ulong)lo | ((ulong)hi << 32); } } + private static readonly byte[] S0 = new byte[] { + 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, + 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, + 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, + 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, + 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, + 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, + 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, + 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, + 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, + 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, + 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, + 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, + 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, + 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, + 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, + 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 + }; + + private static readonly byte[] S1 = new byte[] { + 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, + 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, + 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, + 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, + 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, + 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, + 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, + 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, + 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, + 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, + 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, + 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, + 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, + 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, + 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, + 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 + }; + + private static readonly byte[] S2 = new byte[] { + 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, + 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, + 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, + 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, + 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, + 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, + 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, + 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, + 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, + 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, + 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, + 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, + 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, + 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, + 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, + 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 + }; + + private static readonly byte[] S3 = new byte[] { + 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, + 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, + 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, + 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, + 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, + 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, + 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, + 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, + 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, + 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, + 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, + 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, + 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, + 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, + 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, + 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 + }; + public virtual IMemoable Copy() { return new Dstu7564Digest(this); @@ -425,87 +526,5 @@ namespace Org.BouncyCastle.Crypto.Digests CopyIn(d); } - - //private const ulong mdsMatrix = 0x0407060801050101UL; - private const ulong mdsMatrix = 0x0104070608010501UL; - - private static readonly byte[][] sBoxes = new byte[][] - { - new byte[] { - 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, - 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, - 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, - 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, - 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, - 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, - 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, - 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, - 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, - 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, - 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, - 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, - 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, - 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, - 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, - 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 - }, - - new byte[] { - 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, - 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, - 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, - 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, - 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, - 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, - 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, - 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, - 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, - 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, - 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, - 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, - 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, - 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, - 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, - 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 - }, - - new byte[]{ - 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, - 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, - 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, - 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, - 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, - 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, - 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, - 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, - 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, - 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, - 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, - 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, - 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, - 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, - 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, - 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 - }, - - new byte[]{ - 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, - 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, - 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, - 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, - 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, - 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, - 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, - 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, - 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, - 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, - 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, - 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, - 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, - 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, - 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, - 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 - } - }; } } diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs index 8b16e5d3a..3cb5e8957 100644 --- a/crypto/src/crypto/digests/KeccakDigest.cs +++ b/crypto/src/crypto/digests/KeccakDigest.cs @@ -15,74 +15,21 @@ namespace Org.BouncyCastle.Crypto.Digests public class KeccakDigest : IDigest, IMemoable { - private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants(); - - private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets(); - - private static ulong[] KeccakInitializeRoundConstants() - { - ulong[] keccakRoundConstants = new ulong[24]; - byte LFSRState = 0x01; - - for (int i = 0; i < 24; i++) - { - keccakRoundConstants[i] = 0; - for (int j = 0; j < 7; j++) - { - int bitPosition = (1 << j) - 1; - - // LFSR86540 - - bool loBit = (LFSRState & 0x01) != 0; - if (loBit) - { - keccakRoundConstants[i] ^= 1UL << bitPosition; - } - - bool hiBit = (LFSRState & 0x80) != 0; - LFSRState <<= 1; - if (hiBit) - { - LFSRState ^= 0x71; - } - - } - } - - return keccakRoundConstants; - } - - private static int[] KeccakInitializeRhoOffsets() - { - int[] keccakRhoOffsets = new int[25]; - int x, y, t, newX, newY; - - int rhoOffset = 0; - keccakRhoOffsets[0] = rhoOffset; - x = 1; - y = 0; - for (t = 1; t < 25; t++) - { - rhoOffset = (rhoOffset + t) & 63; - keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset; - newX = (0 * x + 1 * y) % 5; - newY = (2 * x + 3 * y) % 5; - x = newX; - y = newY; - } - - return keccakRhoOffsets; - } - - private static readonly int STATE_LENGTH = (1600 / 8); - - private ulong[] state = new ulong[STATE_LENGTH / 8]; - protected byte[] dataQueue = new byte[1536 / 8]; + private static readonly ulong[] KeccakRoundConstants = new ulong[]{ + 0x0000000000000001UL, 0x0000000000008082UL, 0x800000000000808aUL, 0x8000000080008000UL, + 0x000000000000808bUL, 0x0000000080000001UL, 0x8000000080008081UL, 0x8000000000008009UL, + 0x000000000000008aUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000aUL, + 0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL, + 0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL, + 0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL + }; + + private ulong[] state = new ulong[25]; + protected byte[] dataQueue = new byte[192]; protected int rate; protected int bitsInQueue; protected int fixedOutputLength; protected bool squeezing; - protected int bitsAvailableForSqueezing; public KeccakDigest() : this(288) @@ -107,7 +54,6 @@ namespace Org.BouncyCastle.Crypto.Digests this.bitsInQueue = source.bitsInQueue; this.fixedOutputLength = source.fixedOutputLength; this.squeezing = source.squeezing; - this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; } public virtual string AlgorithmName @@ -132,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Digests public virtual int DoFinal(byte[] output, int outOff) { - Squeeze(output, outOff, fixedOutputLength >> 3); + Squeeze(output, outOff, fixedOutputLength); Reset(); @@ -149,7 +95,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(partialByte, partialBits); } - Squeeze(output, outOff, fixedOutputLength >> 3); + Squeeze(output, outOff, fixedOutputLength); Reset(); @@ -198,7 +144,6 @@ namespace Org.BouncyCastle.Crypto.Digests Arrays.Fill(this.dataQueue, (byte)0); this.bitsInQueue = 0; this.squeezing = false; - this.bitsAvailableForSqueezing = 0; this.fixedOutputLength = (1600 - rate) >> 1; } @@ -288,34 +233,34 @@ namespace Org.BouncyCastle.Crypto.Digests } KeccakPermutation(); + KeccakExtract(); - bitsAvailableForSqueezing = rate; + bitsInQueue = rate; - bitsInQueue = 0; squeezing = true; } - protected void Squeeze(byte[] output, int off, int len) + protected void Squeeze(byte[] output, int offset, long outputLength) { if (!squeezing) { PadAndSwitchToSqueezingPhase(); } + if ((outputLength & 7L) != 0L) + throw new InvalidOperationException("outputLength not a multiple of 8"); - long outputLength = (long)len << 3; long i = 0; while (i < outputLength) { - if (bitsAvailableForSqueezing == 0) + if (bitsInQueue == 0) { KeccakPermutation(); KeccakExtract(); - bitsAvailableForSqueezing = rate; + bitsInQueue = rate; } - - int partialBlock = (int)System.Math.Min((long)bitsAvailableForSqueezing, outputLength - i); - Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) >> 3, output, off + (int)(i >> 3), partialBlock >> 3); - bitsAvailableForSqueezing -= partialBlock; + int partialBlock = (int)System.Math.Min((long)bitsInQueue, outputLength - i); + Array.Copy(dataQueue, (rate - bitsInQueue) >> 3, output, offset + (int)(i >> 3), partialBlock >> 3); + bitsInQueue -= partialBlock; i += partialBlock; } } @@ -339,131 +284,112 @@ namespace Org.BouncyCastle.Crypto.Digests private void KeccakPermutation() { - for (int i = 0; i < 24; i++) - { - Theta(state); - Rho(state); - Pi(state); - Chi(state); - Iota(state, i); - } - } + ulong[] A = state; - private static ulong leftRotate(ulong v, int r) - { - return (v << r) | (v >> -r); - } - - private static void Theta(ulong[] A) - { - ulong C0 = A[0 + 0] ^ A[0 + 5] ^ A[0 + 10] ^ A[0 + 15] ^ A[0 + 20]; - ulong C1 = A[1 + 0] ^ A[1 + 5] ^ A[1 + 10] ^ A[1 + 15] ^ A[1 + 20]; - ulong C2 = A[2 + 0] ^ A[2 + 5] ^ A[2 + 10] ^ A[2 + 15] ^ A[2 + 20]; - ulong C3 = A[3 + 0] ^ A[3 + 5] ^ A[3 + 10] ^ A[3 + 15] ^ A[3 + 20]; - ulong C4 = A[4 + 0] ^ A[4 + 5] ^ A[4 + 10] ^ A[4 + 15] ^ A[4 + 20]; - - ulong dX = leftRotate(C1, 1) ^ C4; - - A[0] ^= dX; - A[5] ^= dX; - A[10] ^= dX; - A[15] ^= dX; - A[20] ^= dX; - - dX = leftRotate(C2, 1) ^ C0; - - A[1] ^= dX; - A[6] ^= dX; - A[11] ^= dX; - A[16] ^= dX; - A[21] ^= dX; - - dX = leftRotate(C3, 1) ^ C1; - - A[2] ^= dX; - A[7] ^= dX; - A[12] ^= dX; - A[17] ^= dX; - A[22] ^= dX; - - dX = leftRotate(C4, 1) ^ C2; - - A[3] ^= dX; - A[8] ^= dX; - A[13] ^= dX; - A[18] ^= dX; - A[23] ^= dX; - - dX = leftRotate(C0, 1) ^ C3; - - A[4] ^= dX; - A[9] ^= dX; - A[14] ^= dX; - A[19] ^= dX; - A[24] ^= dX; - } + ulong a00 = A[ 0], a01 = A[ 1], a02 = A[ 2], a03 = A[ 3], a04 = A[ 4]; + ulong a05 = A[ 5], a06 = A[ 6], a07 = A[ 7], a08 = A[ 8], a09 = A[ 9]; + ulong a10 = A[10], a11 = A[11], a12 = A[12], a13 = A[13], a14 = A[14]; + ulong a15 = A[15], a16 = A[16], a17 = A[17], a18 = A[18], a19 = A[19]; + ulong a20 = A[20], a21 = A[21], a22 = A[22], a23 = A[23], a24 = A[24]; - private static void Rho(ulong[] A) - { - // KeccakRhoOffsets[0] == 0 - for (int x = 1; x < 25; x++) - { - A[x] = leftRotate(A[x], KeccakRhoOffsets[x]); - } - } - - private static void Pi(ulong[] A) - { - ulong a1 = A[1]; - A[1] = A[6]; - A[6] = A[9]; - A[9] = A[22]; - A[22] = A[14]; - A[14] = A[20]; - A[20] = A[2]; - A[2] = A[12]; - A[12] = A[13]; - A[13] = A[19]; - A[19] = A[23]; - A[23] = A[15]; - A[15] = A[4]; - A[4] = A[24]; - A[24] = A[21]; - A[21] = A[8]; - A[8] = A[16]; - A[16] = A[5]; - A[5] = A[3]; - A[3] = A[18]; - A[18] = A[17]; - A[17] = A[11]; - A[11] = A[7]; - A[7] = A[10]; - A[10] = a1; - } - - private static void Chi(ulong[] A) - { - ulong chiC0, chiC1, chiC2, chiC3, chiC4; - - for (int yBy5 = 0; yBy5 < 25; yBy5 += 5) + for (int i = 0; i < 24; i++) { - chiC0 = A[0 + yBy5] ^ ((~A[(((0 + 1) % 5) + yBy5)]) & A[(((0 + 2) % 5) + yBy5)]); - chiC1 = A[1 + yBy5] ^ ((~A[(((1 + 1) % 5) + yBy5)]) & A[(((1 + 2) % 5) + yBy5)]); - chiC2 = A[2 + yBy5] ^ ((~A[(((2 + 1) % 5) + yBy5)]) & A[(((2 + 2) % 5) + yBy5)]); - chiC3 = A[3 + yBy5] ^ ((~A[(((3 + 1) % 5) + yBy5)]) & A[(((3 + 2) % 5) + yBy5)]); - chiC4 = A[4 + yBy5] ^ ((~A[(((4 + 1) % 5) + yBy5)]) & A[(((4 + 2) % 5) + yBy5)]); - - A[0 + yBy5] = chiC0; - A[1 + yBy5] = chiC1; - A[2 + yBy5] = chiC2; - A[3 + yBy5] = chiC3; - A[4 + yBy5] = chiC4; + // theta + ulong c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20; + ulong c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21; + ulong c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22; + ulong c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23; + ulong c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24; + + ulong d1 = (c1 << 1 | c1 >> -1) ^ c4; + ulong d2 = (c2 << 1 | c2 >> -1) ^ c0; + ulong d3 = (c3 << 1 | c3 >> -1) ^ c1; + ulong d4 = (c4 << 1 | c4 >> -1) ^ c2; + ulong d0 = (c0 << 1 | c0 >> -1) ^ c3; + + a00 ^= d1; a05 ^= d1; a10 ^= d1; a15 ^= d1; a20 ^= d1; + a01 ^= d2; a06 ^= d2; a11 ^= d2; a16 ^= d2; a21 ^= d2; + a02 ^= d3; a07 ^= d3; a12 ^= d3; a17 ^= d3; a22 ^= d3; + a03 ^= d4; a08 ^= d4; a13 ^= d4; a18 ^= d4; a23 ^= d4; + a04 ^= d0; a09 ^= d0; a14 ^= d0; a19 ^= d0; a24 ^= d0; + + // rho/pi + c1 = a01 << 1 | a01 >> 63; + a01 = a06 << 44 | a06 >> 20; + a06 = a09 << 20 | a09 >> 44; + a09 = a22 << 61 | a22 >> 3; + a22 = a14 << 39 | a14 >> 25; + a14 = a20 << 18 | a20 >> 46; + a20 = a02 << 62 | a02 >> 2; + a02 = a12 << 43 | a12 >> 21; + a12 = a13 << 25 | a13 >> 39; + a13 = a19 << 8 | a19 >> 56; + a19 = a23 << 56 | a23 >> 8; + a23 = a15 << 41 | a15 >> 23; + a15 = a04 << 27 | a04 >> 37; + a04 = a24 << 14 | a24 >> 50; + a24 = a21 << 2 | a21 >> 62; + a21 = a08 << 55 | a08 >> 9; + a08 = a16 << 45 | a16 >> 19; + a16 = a05 << 36 | a05 >> 28; + a05 = a03 << 28 | a03 >> 36; + a03 = a18 << 21 | a18 >> 43; + a18 = a17 << 15 | a17 >> 49; + a17 = a11 << 10 | a11 >> 54; + a11 = a07 << 6 | a07 >> 58; + a07 = a10 << 3 | a10 >> 61; + a10 = c1; + + // chi + c0 = a00 ^ (~a01 & a02); + c1 = a01 ^ (~a02 & a03); + a02 ^= ~a03 & a04; + a03 ^= ~a04 & a00; + a04 ^= ~a00 & a01; + a00 = c0; + a01 = c1; + + c0 = a05 ^ (~a06 & a07); + c1 = a06 ^ (~a07 & a08); + a07 ^= ~a08 & a09; + a08 ^= ~a09 & a05; + a09 ^= ~a05 & a06; + a05 = c0; + a06 = c1; + + c0 = a10 ^ (~a11 & a12); + c1 = a11 ^ (~a12 & a13); + a12 ^= ~a13 & a14; + a13 ^= ~a14 & a10; + a14 ^= ~a10 & a11; + a10 = c0; + a11 = c1; + + c0 = a15 ^ (~a16 & a17); + c1 = a16 ^ (~a17 & a18); + a17 ^= ~a18 & a19; + a18 ^= ~a19 & a15; + a19 ^= ~a15 & a16; + a15 = c0; + a16 = c1; + + c0 = a20 ^ (~a21 & a22); + c1 = a21 ^ (~a22 & a23); + a22 ^= ~a23 & a24; + a23 ^= ~a24 & a20; + a24 ^= ~a20 & a21; + a20 = c0; + a21 = c1; + + // iota + a00 ^= KeccakRoundConstants[i]; } - } - private static void Iota(ulong[] A, int indexRound) - { - A[0] ^= KeccakRoundConstants[indexRound]; + A[ 0] = a00; A[ 1] = a01; A[ 2] = a02; A[ 3] = a03; A[ 4] = a04; + A[ 5] = a05; A[ 6] = a06; A[ 7] = a07; A[ 8] = a08; A[ 9] = a09; + A[10] = a10; A[11] = a11; A[12] = a12; A[13] = a13; A[14] = a14; + A[15] = a15; A[16] = a16; A[17] = a17; A[18] = a18; A[19] = a19; + A[20] = a20; A[21] = a21; A[22] = a22; A[23] = a23; A[24] = a24; } public virtual IMemoable Copy() diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs index 13e8838c1..e58452c36 100644 --- a/crypto/src/crypto/digests/ShakeDigest.cs +++ b/crypto/src/crypto/digests/ShakeDigest.cs @@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(0x0F, 4); } - Squeeze(output, outOff, outLen); + Squeeze(output, outOff, (long)outLen << 3); return outLen; } @@ -104,7 +104,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(finalInput, finalBits); } - Squeeze(output, outOff, outLen); + Squeeze(output, outOff, (long)outLen << 3); Reset(); diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs index 53836db02..398f6d43a 100644 --- a/crypto/src/crypto/engines/Cast5Engine.cs +++ b/crypto/src/crypto/engines/Cast5Engine.cs @@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Engines public class Cast5Engine : IBlockCipher { - internal static readonly uint[] S1 = + private static readonly uint[] S1 = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs index 534a23bbf..4242d3a7a 100644 --- a/crypto/src/crypto/engines/Dstu7624Engine.cs +++ b/crypto/src/crypto/engines/Dstu7624Engine.cs @@ -13,9 +13,6 @@ namespace Org.BouncyCastle.Crypto.Engines public class Dstu7624Engine : IBlockCipher { - private static readonly int BITS_IN_WORD = 64; - private static readonly int BITS_IN_BYTE = 8; - private ulong[] internalState; private ulong[] workingKey; private ulong[][] roundKeys; @@ -27,126 +24,91 @@ namespace Org.BouncyCastle.Crypto.Engines private int wordsInKey; /* Number of encryption rounds depending on key length */ - private static int ROUNDS_128 = 10; - private static int ROUNDS_256 = 14; - private static int ROUNDS_512 = 18; + private const int ROUNDS_128 = 10; + private const int ROUNDS_256 = 14; + private const int ROUNDS_512 = 18; - private int blockSizeBits; private int roundsAmount; private bool forEncryption; - private byte[] internalStateBytes; - private byte[] tempInternalStateBytes; - public Dstu7624Engine(int blockSizeBits) { /* DSTU7624 supports 128 | 256 | 512 key/block sizes */ if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512) { - throw new ArgumentException("Unsupported block length: only 128/256/512 are allowed"); + throw new ArgumentException("unsupported block length: only 128/256/512 are allowed"); } - this.blockSizeBits = blockSizeBits; - wordsInBlock = blockSizeBits / BITS_IN_WORD; + wordsInBlock = blockSizeBits / 64; internalState = new ulong[wordsInBlock]; - - internalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE]; - tempInternalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE]; } #region INITIALIZATION + public virtual void Init(bool forEncryption, ICipherParameters parameters) { - if (parameters is KeyParameter) - { - this.forEncryption = forEncryption; - - byte[] keyBytes = ((KeyParameter)parameters).GetKey(); - int keyBitLength = keyBytes.Length * BITS_IN_BYTE; - int blockBitLength = wordsInBlock * BITS_IN_WORD; - - if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512) - { - throw new ArgumentException("unsupported key length: only 128/256/512 are allowed"); - } - - /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */ - if (blockBitLength == 128) - { - if (keyBitLength == 512) - { - throw new ArgumentException("Unsupported key length"); - } - } - - if (blockBitLength == 256) - { - if (keyBitLength == 128) - { - throw new ArgumentException("Unsupported key length"); - } - } - - if (blockBitLength == 512) - { - if (keyBitLength != 512) - { - throw new ArgumentException("Unsupported key length"); - } - } + if (!(parameters is KeyParameter)) + throw new ArgumentException("Invalid parameter passed to Dstu7624Engine Init"); - switch (keyBitLength) - { - case 128: - roundsAmount = ROUNDS_128; - break; - case 256: - roundsAmount = ROUNDS_256; - break; - case 512: - roundsAmount = ROUNDS_512; - break; - } - - wordsInKey = keyBitLength / BITS_IN_WORD; - - /* +1 round key as defined in standard */ - roundKeys = new ulong[roundsAmount + 1][]; - for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++) - { - roundKeys[roundKeyIndex] = new ulong[wordsInBlock]; - } + this.forEncryption = forEncryption; - workingKey = new ulong[wordsInKey]; + byte[] keyBytes = ((KeyParameter)parameters).GetKey(); + int keyBitLength = keyBytes.Length << 3; + int blockBitLength = wordsInBlock << 6; - if (keyBytes.Length != wordsInKey * BITS_IN_WORD / BITS_IN_BYTE) - { - throw new ArgumentException("Invalid key parameter passed to DSTU7624Engine init"); - } + if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512) + { + throw new ArgumentException("unsupported key length: only 128/256/512 are allowed"); + } - /* Unpack encryption key bytes to words */ - Pack.LE_To_UInt64(keyBytes, 0, workingKey); + /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */ + if (keyBitLength != blockBitLength && keyBitLength != (2 * blockBitLength)) + { + throw new ArgumentException("Unsupported key length"); + } - ulong[] kt = new ulong[wordsInBlock]; + switch (keyBitLength) + { + case 128: + roundsAmount = ROUNDS_128; + break; + case 256: + roundsAmount = ROUNDS_256; + break; + case 512: + roundsAmount = ROUNDS_512; + break; + } - KeyExpandKT(workingKey, kt); + wordsInKey = keyBitLength / 64; - KeyExpandEven(workingKey, kt); + /* +1 round key as defined in standard */ + roundKeys = new ulong[roundsAmount + 1][]; + for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++) + { + roundKeys[roundKeyIndex] = new ulong[wordsInBlock]; + } - KeyExpandOdd(); + workingKey = new ulong[wordsInKey]; - } - else if (parameters != null) + if (keyBytes.Length != wordsInKey * 8) { - throw new ArgumentException("invalid parameter passed to Dstu7624 init - " - + Platform.GetTypeName(parameters)); + throw new ArgumentException("Invalid key parameter passed to Dstu7624Engine Init"); } - this.forEncryption = forEncryption; + /* Unpack encryption key bytes to words */ + Pack.LE_To_UInt64(keyBytes, 0, workingKey); + + ulong[] tempKeys = new ulong[wordsInBlock]; + + /* KSA in DSTU7624 is strengthened to mitigate known weaknesses in AES KSA (eprint.iacr.org/2012/260.pdf) */ + WorkingKeyExpandKT(workingKey, tempKeys); + WorkingKeyExpandEven(workingKey, tempKeys); + WorkingKeyExpandOdd(); } - private void KeyExpandKT(ulong[] key, ulong[] kt) + private void WorkingKeyExpandKT(ulong[] workingKey, ulong[] tempKeys) { ulong[] k0 = new ulong[wordsInBlock]; ulong[] k1 = new ulong[wordsInBlock]; @@ -156,96 +118,114 @@ namespace Org.BouncyCastle.Crypto.Engines if (wordsInBlock == wordsInKey) { - Array.Copy(key, k0, k0.Length); - Array.Copy(key, k1, k1.Length); + Array.Copy(workingKey, 0, k0, 0, k0.Length); + Array.Copy(workingKey, 0, k1, 0, k1.Length); } else { - Array.Copy(key, 0, k0, 0, wordsInBlock); - Array.Copy(key, wordsInBlock, k1, 0, wordsInBlock); + Array.Copy(workingKey, 0, k0, 0, wordsInBlock); + Array.Copy(workingKey, wordsInBlock, k1, 0, wordsInBlock); } - AddRoundKeyExpand(k0); + + for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++) + { + internalState[wordIndex] += k0[wordIndex]; + } EncryptionRound(); - XorRoundKeyExpand(k1); + for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++) + { + internalState[wordIndex] ^= k1[wordIndex]; + } EncryptionRound(); - AddRoundKeyExpand(k0); + for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++) + { + internalState[wordIndex] += k0[wordIndex]; + } EncryptionRound(); - Array.Copy(internalState, kt, wordsInBlock); + Array.Copy(internalState, 0, tempKeys, 0, wordsInBlock); } - private void KeyExpandEven(ulong[] key, ulong[] kt) + private void WorkingKeyExpandEven(ulong[] workingKey, ulong[] tempKey) { - ulong[] initial_data = new ulong[wordsInKey]; - - ulong[] kt_round = new ulong[wordsInBlock]; - - ulong[] tmv = new ulong[wordsInBlock]; + ulong[] initialData = new ulong[wordsInKey]; + ulong[] tempRoundKey = new ulong[wordsInBlock]; int round = 0; - Array.Copy(key, initial_data, wordsInKey); + Array.Copy(workingKey, 0, initialData, 0, wordsInKey); - for (int i = 0; i < wordsInBlock; i++) - { - tmv[i] = 0x0001000100010001; - } + ulong tmv = 0x0001000100010001UL; while (true) { - Array.Copy(kt, internalState, wordsInBlock); - - AddRoundKeyExpand(tmv); - - Array.Copy(internalState, kt_round, wordsInBlock); - Array.Copy(initial_data, internalState, wordsInBlock); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv; + } - AddRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] = initialData[wordIndex] + tempRoundKey[wordIndex]; + } EncryptionRound(); - XorRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] ^= tempRoundKey[wordIndex]; + } EncryptionRound(); - AddRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] += tempRoundKey[wordIndex]; + } - Array.Copy(internalState, roundKeys[round], wordsInBlock); + Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock); if (roundsAmount == round) { break; } + if (wordsInKey != wordsInBlock) { round += 2; + tmv <<= 1; - ShiftLeft(tmv); - - Array.Copy(kt, internalState, wordsInBlock); - - AddRoundKeyExpand(tmv); - - Array.Copy(internalState, kt_round, wordsInBlock); - Array.Copy(initial_data, wordsInBlock, internalState, 0, wordsInBlock); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv; + } - AddRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] = initialData[wordsInBlock + wordIndex] + tempRoundKey[wordIndex]; + } EncryptionRound(); - XorRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] ^= tempRoundKey[wordIndex]; + } EncryptionRound(); - AddRoundKeyExpand(kt_round); + for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++) + { + internalState[wordIndex] += tempRoundKey[wordIndex]; + } - Array.Copy(internalState, roundKeys[round], wordsInBlock); + Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock); if (roundsAmount == round) { @@ -254,89 +234,99 @@ namespace Org.BouncyCastle.Crypto.Engines } round += 2; - ShiftLeft(tmv); + tmv <<= 1; - //Rotate initial data array on 1 element left - ulong temp = initial_data[0]; - Array.Copy(initial_data, 1, initial_data, 0, initial_data.Length - 1); - initial_data[initial_data.Length - 1] = temp; + ulong temp = initialData[0]; + for (int i = 1; i < initialData.Length; ++i) + { + initialData[i - 1] = initialData[i]; + } + initialData[initialData.Length - 1] = temp; } } - private void KeyExpandOdd() + + private void WorkingKeyExpandOdd() { - for (int i = 1; i < roundsAmount; i += 2) + for (int roundIndex = 1; roundIndex < roundsAmount; roundIndex += 2) { - Array.Copy(roundKeys[i - 1], roundKeys[i], wordsInBlock); - RotateLeft(roundKeys[i]); + RotateLeft(roundKeys[roundIndex - 1], roundKeys[roundIndex]); } } - #endregion + #endregion public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { if (workingKey == null) - throw new InvalidOperationException("Dstu7624 engine not initialised"); + throw new InvalidOperationException("Dstu7624Engine not initialised"); Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short"); Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short"); if (forEncryption) { - Encrypt(input, inOff, output, outOff); - } - else - { - Decrypt(input, inOff, output, outOff); - } - - return GetBlockSize(); - } - - private void Encrypt(byte[] plain, int inOff, byte[] cipherText, int outOff) - { - Pack.LE_To_UInt64(plain, inOff, internalState); + /* Encrypt */ + switch (wordsInBlock) + { + case 2: + { + EncryptBlock_128(input, inOff, output, outOff); + break; + } + default: + { + Pack.LE_To_UInt64(input, inOff, internalState); + AddRoundKey(0); + for (int round = 0;;) + { + EncryptionRound(); - int round = 0; - AddRoundKey(round); + if (++round == roundsAmount) + { + break; + } - while (++round < roundsAmount) - { - EncryptionRound(); - XorRoundKey(round); + XorRoundKey(round); + } + AddRoundKey(roundsAmount); + Pack.UInt64_To_LE(internalState, output, outOff); + break; + } + } } - - EncryptionRound(); - AddRoundKey(round); - - Pack.UInt64_To_LE(internalState, cipherText, outOff); - } - - private void Decrypt(byte[] cipherText, int inOff, byte[] decryptedText, int outOff) - { - Pack.LE_To_UInt64(cipherText, inOff, internalState); - - int round = roundsAmount; - SubRoundKey(round); - - while (--round > 0) + else { - DecryptionRound(); - XorRoundKey(round); + /* Decrypt */ + switch (wordsInBlock) + { + case 2: + { + DecryptBlock_128(input, inOff, output, outOff); + break; + } + default: + { + Pack.LE_To_UInt64(input, inOff, internalState); + SubRoundKey(roundsAmount); + for (int round = roundsAmount;;) + { + DecryptionRound(); + + if (--round == 0) + { + break; + } + + XorRoundKey(round); + } + SubRoundKey(0); + Pack.UInt64_To_LE(internalState, output, outOff); + break; + } + } } - DecryptionRound(); - SubRoundKey(round); - - Pack.UInt64_To_LE(internalState, decryptedText, outOff); - } - - private void AddRoundKeyExpand(ulong[] value) - { - for (int i = 0; i < wordsInBlock; i++) - { - internalState[i] += value[i]; - } + return GetBlockSize(); } private void EncryptionRound() @@ -348,393 +338,737 @@ namespace Org.BouncyCastle.Crypto.Engines private void DecryptionRound() { - InvMixColumns(); + MixColumnsInv(); InvShiftRows(); InvSubBytes(); } - private void RotateLeft(ulong[] state_value) + private void DecryptBlock_128(byte[] input, int inOff, byte[] output, int outOff) { - int rotateBytesLength = 2 * state_value.Length + 3; - int bytesLength = state_value.Length * (BITS_IN_WORD / BITS_IN_BYTE); + ulong c0 = Pack.LE_To_UInt64(input, inOff); + ulong c1 = Pack.LE_To_UInt64(input, inOff + 8); - byte[] bytes = Pack.UInt64_To_LE(state_value); - byte[] buffer = new byte[rotateBytesLength]; + ulong[] roundKey = roundKeys[roundsAmount]; + c0 -= roundKey[0]; + c1 -= roundKey[1]; + + for (int round = roundsAmount;;) + { + c0 = MixColumnInv(c0); + c1 = MixColumnInv(c1); + + uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32); + uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32); + + { + byte t0 = T0[lo0 & 0xFF]; + byte t1 = T1[(lo0 >> 8) & 0xFF]; + byte t2 = T2[(lo0 >> 16) & 0xFF]; + byte t3 = T3[lo0 >> 24]; + lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = T0[hi1 & 0xFF]; + byte t5 = T1[(hi1 >> 8) & 0xFF]; + byte t6 = T2[(hi1 >> 16) & 0xFF]; + byte t7 = T3[hi1 >> 24]; + hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + c0 = (ulong)lo0 | ((ulong)hi1 << 32); + } + + { + byte t0 = T0[lo1 & 0xFF]; + byte t1 = T1[(lo1 >> 8) & 0xFF]; + byte t2 = T2[(lo1 >> 16) & 0xFF]; + byte t3 = T3[lo1 >> 24]; + lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = T0[hi0 & 0xFF]; + byte t5 = T1[(hi0 >> 8) & 0xFF]; + byte t6 = T2[(hi0 >> 16) & 0xFF]; + byte t7 = T3[hi0 >> 24]; + hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + c1 = (ulong)lo1 | ((ulong)hi0 << 32); + } - Array.Copy(bytes, buffer, rotateBytesLength); + if (--round == 0) + { + break; + } - Buffer.BlockCopy(bytes, rotateBytesLength, bytes, 0, bytesLength - rotateBytesLength); + roundKey = roundKeys[round]; + c0 ^= roundKey[0]; + c1 ^= roundKey[1]; + } - Array.Copy(buffer, 0, bytes, bytesLength - rotateBytesLength, rotateBytesLength); + roundKey = roundKeys[0]; + c0 -= roundKey[0]; + c1 -= roundKey[1]; - Pack.LE_To_UInt64(bytes, 0, state_value); + Pack.UInt64_To_LE(c0, output, outOff); + Pack.UInt64_To_LE(c1, output, outOff + 8); } - private void ShiftLeft(ulong[] state_value) + private void EncryptBlock_128(byte[] input, int inOff, byte[] output, int outOff) { - for (int i = 0; i < state_value.Length; i++) + ulong c0 = Pack.LE_To_UInt64(input, inOff); + ulong c1 = Pack.LE_To_UInt64(input, inOff + 8); + + ulong[] roundKey = roundKeys[0]; + c0 += roundKey[0]; + c1 += roundKey[1]; + + for (int round = 0;;) { - state_value[i] <<= 1; + uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32); + uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32); + + { + byte t0 = S0[lo0 & 0xFF]; + byte t1 = S1[(lo0 >> 8) & 0xFF]; + byte t2 = S2[(lo0 >> 16) & 0xFF]; + byte t3 = S3[lo0 >> 24]; + lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = S0[hi1 & 0xFF]; + byte t5 = S1[(hi1 >> 8) & 0xFF]; + byte t6 = S2[(hi1 >> 16) & 0xFF]; + byte t7 = S3[hi1 >> 24]; + hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + c0 = (ulong)lo0 | ((ulong)hi1 << 32); + } + + { + byte t0 = S0[lo1 & 0xFF]; + byte t1 = S1[(lo1 >> 8) & 0xFF]; + byte t2 = S2[(lo1 >> 16) & 0xFF]; + byte t3 = S3[lo1 >> 24]; + lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = S0[hi0 & 0xFF]; + byte t5 = S1[(hi0 >> 8) & 0xFF]; + byte t6 = S2[(hi0 >> 16) & 0xFF]; + byte t7 = S3[hi0 >> 24]; + hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + c1 = (ulong)lo1 | ((ulong)hi0 << 32); + } + + c0 = MixColumn(c0); + c1 = MixColumn(c1); + + if (++round == roundsAmount) + { + break; + } + + roundKey = roundKeys[round]; + c0 ^= roundKey[0]; + c1 ^= roundKey[1]; } - Array.Reverse(state_value); + + roundKey = roundKeys[roundsAmount]; + c0 += roundKey[0]; + c1 += roundKey[1]; + + Pack.UInt64_To_LE(c0, output, outOff); + Pack.UInt64_To_LE(c1, output, outOff + 8); } - private void XorRoundKeyExpand(ulong[] value) + private void SubBytes() { for (int i = 0; i < wordsInBlock; i++) { - internalState[i] ^= value[i]; + ulong u = internalState[i]; + uint lo = (uint)u, hi = (uint)(u >> 32); + byte t0 = S0[lo & 0xFF]; + byte t1 = S1[(lo >> 8) & 0xFF]; + byte t2 = S2[(lo >> 16) & 0xFF]; + byte t3 = S3[lo >> 24]; + lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = S0[hi & 0xFF]; + byte t5 = S1[(hi >> 8) & 0xFF]; + byte t6 = S2[(hi >> 16) & 0xFF]; + byte t7 = S3[hi >> 24]; + hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + internalState[i] = (ulong)lo | ((ulong)hi << 32); } } - private void XorRoundKey(int round) + private void InvSubBytes() { - ulong[] roundKey = roundKeys[round]; for (int i = 0; i < wordsInBlock; i++) { - internalState[i] ^= roundKey[i]; + ulong u = internalState[i]; + uint lo = (uint)u, hi = (uint)(u >> 32); + byte t0 = T0[lo & 0xFF]; + byte t1 = T1[(lo >> 8) & 0xFF]; + byte t2 = T2[(lo >> 16) & 0xFF]; + byte t3 = T3[lo >> 24]; + lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24); + byte t4 = T0[hi & 0xFF]; + byte t5 = T1[(hi >> 8) & 0xFF]; + byte t6 = T2[(hi >> 16) & 0xFF]; + byte t7 = T3[hi >> 24]; + hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24); + internalState[i] = (ulong)lo | ((ulong)hi << 32); } } private void ShiftRows() { - int row, col; - int shift = -1; + switch (wordsInBlock) + { + case 2: + { + ulong c0 = internalState[0], c1 = internalState[1]; + ulong d; - byte[] stateBytes = Pack.UInt64_To_LE(internalState); - byte[] nstate = new byte[wordsInBlock * 8]; + d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d; - for (row = 0; row < 8; row++) + internalState[0] = c0; + internalState[1] = c1; + break; + } + case 4: { - if (row % (8 / wordsInBlock) == 0) - { - shift += 1; - } + ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3]; + ulong d; - for (col = 0; col < wordsInBlock; col++) - { - nstate[row + ((col + shift) % wordsInBlock) * 8] = stateBytes[row + col * 8]; - } - } + d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d; + d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d; - Pack.LE_To_UInt64(nstate, 0, internalState); + d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d; + d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d; + + internalState[0] = c0; + internalState[1] = c1; + internalState[2] = c2; + internalState[3] = c3; + break; + } + case 8: + { + ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3]; + ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7]; + ulong d; + + d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d; + d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d; + d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d; + d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d; + + d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d; + d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d; + d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d; + d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d; + + d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d; + d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d; + d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d; + d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d; + + internalState[0] = c0; + internalState[1] = c1; + internalState[2] = c2; + internalState[3] = c3; + internalState[4] = c4; + internalState[5] = c5; + internalState[6] = c6; + internalState[7] = c7; + break; + } + default: + { + throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed"); + } + } } private void InvShiftRows() { - int row, col; - int shift = -1; + switch (wordsInBlock) + { + case 2: + { + ulong c0 = internalState[0], c1 = internalState[1]; + ulong d; - byte[] stateBytes = Pack.UInt64_To_LE(internalState); - byte[] nstate = new byte[wordsInBlock * 8]; + d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d; - for (row = 0; row < 8; row++) + internalState[0] = c0; + internalState[1] = c1; + break; + } + case 4: { - if (row % (8 / wordsInBlock) == 0) - { - shift += 1; - } + ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3]; + ulong d; - for (col = 0; col < wordsInBlock; col++) - { - nstate[row + col * 8] = stateBytes[row + ((col + shift) % wordsInBlock) * 8]; - } - } + d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d; + d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d; + + d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d; + d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d; - Pack.LE_To_UInt64(nstate, 0, internalState); + internalState[0] = c0; + internalState[1] = c1; + internalState[2] = c2; + internalState[3] = c3; + break; + } + case 8: + { + ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3]; + ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7]; + ulong d; + + d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d; + d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d; + d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d; + d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d; + + d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d; + d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d; + d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d; + d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d; + + d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d; + d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d; + d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d; + d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d; + + internalState[0] = c0; + internalState[1] = c1; + internalState[2] = c2; + internalState[3] = c3; + internalState[4] = c4; + internalState[5] = c5; + internalState[6] = c6; + internalState[7] = c7; + break; + } + default: + { + throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed"); + } + } } private void AddRoundKey(int round) { + ulong[] roundKey = roundKeys[round]; for (int i = 0; i < wordsInBlock; ++i) { - internalState[i] += roundKeys[round][i]; + internalState[i] += roundKey[i]; } } private void SubRoundKey(int round) { + ulong[] roundKey = roundKeys[round]; for (int i = 0; i < wordsInBlock; ++i) { - internalState[i] -= roundKeys[round][i]; + internalState[i] -= roundKey[i]; } } - private void MixColumns() + private void XorRoundKey(int round) { - MatrixMultiply(mdsMatrix); + ulong[] roundKey = roundKeys[round]; + for (int i = 0; i < wordsInBlock; i++) + { + internalState[i] ^= roundKey[i]; + } } - private void InvMixColumns() + private static ulong MixColumn(ulong c) { - MatrixMultiply(mdsInvMatrix); + //// Calculate column multiplied by powers of 'x' + //ulong x0 = c; + //ulong x1 = MulX(x0); + //ulong x2 = MulX(x1); + //ulong x3 = MulX(x2); + + //// Calculate products with circulant matrix from (0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04) + //ulong m0 = x0; + //ulong m1 = x0; + //ulong m2 = x0 ^ x2; + //ulong m3 = x0; + //ulong m4 = x3; + //ulong m5 = x1 ^ x2; + //ulong m6 = x0 ^ x1 ^ x2; + //ulong m7 = x2; + + //// Assemble the rotated products + //return m0 + // ^ Rotate(8, m1) + // ^ Rotate(16, m2) + // ^ Rotate(24, m3) + // ^ Rotate(32, m4) + // ^ Rotate(40, m5) + // ^ Rotate(48, m6) + // ^ Rotate(56, m7); + + ulong x1 = MulX(c); + ulong u, v; + + u = Rotate(8, c) ^ c; + u ^= Rotate(16, u); + u ^= Rotate(48, c); + + v = MulX2(u ^ c ^ x1); + + return u ^ Rotate(32, v) ^ Rotate(40, x1) ^ Rotate(48, x1); } - private void MatrixMultiply(ulong matrix) + private void MixColumns() { for (int col = 0; col < wordsInBlock; ++col) { - ulong colVal = internalState[col]; - ulong colEven = colVal & 0x00FF00FF00FF00FFUL; - ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL; - - //ulong rowMatrix = (matrix >> 8) | (matrix << 56); - ulong rowMatrix = matrix; - - ulong result = 0; - for (int row = 7; row >= 0; --row) - { - ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL); - - rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56); - - product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL); - - product ^= (product >> 32); - product ^= (product >> 16); - - result <<= 8; - result |= (product & 0xFFUL); - } - - internalState[col] = result; + internalState[col] = MixColumn(internalState[col]); } } - /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */ - private static ulong MultiplyGFx4(ulong u, ulong v) + private static ulong MixColumnInv(ulong c) { - ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL); +/* + // Calculate column multiplied by powers of 'x' + ulong x0 = c; + ulong x1 = MulX(x0); + ulong x2 = MulX(x1); + ulong x3 = MulX(x2); + ulong x4 = MulX(x3); + ulong x5 = MulX(x4); + ulong x6 = MulX(x5); + ulong x7 = MulX(x6); + + // Calculate products with circulant matrix from (0xAD,0x95,0x76,0xA8,0x2F,0x49,0xD7,0xCA) + //long m0 = x0 ^ x2 ^ x3 ^ x5 ^ x7; + //long m1 = x0 ^ x2 ^ x4 ^ x7; + //long m2 = x1 ^ x2 ^ x4 ^ x5 ^ x6; + //long m3 = x3 ^ x5 ^ x7; + //long m4 = x0 ^ x1 ^ x2 ^ x3 ^ x5; + //long m5 = x0 ^ x3 ^ x6; + //long m6 = x0 ^ x1 ^ x2 ^ x4 ^ x6 ^ x7; + //long m7 = x1 ^ x3 ^ x6 ^ x7; + + ulong m5 = x0 ^ x3 ^ x6; + x0 ^= x2; + ulong m3 = x3 ^ x5 ^ x7; + ulong m0 = m3 ^ x0; + ulong m6 = x0 ^ x4; + ulong m1 = m6 ^ x7; + x5 ^= x1; + x7 ^= x1 ^ x6; + ulong m2 = x2 ^ x4 ^ x5 ^ x6; + ulong m4 = x0 ^ x3 ^ x5; + m6 ^= x7; + ulong m7 = x3 ^ x7; + + // Assemble the rotated products + return m0 + ^ Rotate(8, m1) + ^ Rotate(16, m2) + ^ Rotate(24, m3) + ^ Rotate(32, m4) + ^ Rotate(40, m5) + ^ Rotate(48, m6) + ^ Rotate(56, m7); +*/ + + ulong u0 = c; + u0 ^= Rotate( 8, u0); + u0 ^= Rotate(32, u0); + u0 ^= Rotate(48, c); + + ulong t = u0 ^ c; + + ulong c48 = Rotate(48, c); + ulong c56 = Rotate(56, c); + + ulong u7 = t ^ c56; + ulong u6 = Rotate(56, t); + u6 ^= MulX(u7); + ulong u5 = Rotate(16, t) ^ c; + u5 ^= Rotate(40, MulX(u6) ^ c); + ulong u4 = t ^ c48; + u4 ^= MulX(u5); + ulong u3 = Rotate(16, u0); + u3 ^= MulX(u4); + ulong u2 = t ^ Rotate(24, c) ^ c48 ^ c56; + u2 ^= MulX(u3); + ulong u1 = Rotate(32, t) ^ c ^ c56; + u1 ^= MulX(u2); + u0 ^= MulX(Rotate(40, u1)); + + return u0; + } - for (int i = 1; i < 8; ++i) + private void MixColumnsInv() + { + for (int col = 0; col < wordsInBlock; ++col) { - u <<= 1; - v >>= 1; - r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL); + internalState[col] = MixColumnInv(internalState[col]); } + } - // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */ + private static ulong MulX(ulong n) + { + return ((n & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((n & 0x8080808080808080UL) >> 7) * 0x1DUL); + } - ulong hi = r & 0xFF00FF00FF00FF00UL; - r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - hi = r & 0x0F000F000F000F00UL; - r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8); - return r; + private static ulong MulX2(ulong n) + { + return ((n & 0x3F3F3F3F3F3F3F3FUL) << 2) ^ (((n & 0x8080808080808080UL) >> 6) * 0x1DUL) ^ (((n & 0x4040404040404040UL) >> 6) * 0x1DUL); } - private void SubBytes() + //private static ulong MulX4(ulong n) + //{ + // ulong u = n & 0xF0F0F0F0F0F0F0F0UL; + // return ((n & 0x0F0F0F0F0F0F0F0FUL) << 4) ^ u ^ (u >> 1) ^ (u >> 2) ^ (u >> 4); + //} + + /* + * Pair-wise modular multiplication of 8 byte-pairs. + * + * REDUCTION_POLYNOMIAL is x^8 + x^4 + x^3 + x^2 + 1 + */ + //private static ulong MultiplyGFx8(ulong u, ulong v, int vMaxDegree) + //{ + // ulong r = u & ((v & 0x0101010101010101UL) * 0xFFUL); + // for (int i = 1; i <= vMaxDegree; ++i) + // { + // u = ((u & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((u >> 7) & 0x0101010101010101UL) * 0x1DUL); + // v >>= 1; + + // r ^= u & ((v & 0x0101010101010101UL) * 0xFFUL); + // } + + // return r; + //} + + //private static ulong MultiplyMds(ulong u) + //{ + // ulong r = 0, s = 0, t = (u >> 8); + // r ^= u & 0x0000001F00000000UL; r <<= 1; + // s ^= t & 0x00000000E0000000UL; s <<= 1; + // r ^= u & 0x3F3F3F00003F0000UL; r <<= 1; + // s ^= t & 0x00C0C0C00000C000UL; s <<= 1; + // r ^= u & 0x007F7F0000000000UL; r <<= 1; + // s ^= t & 0x0000808000000000UL; s <<= 1; + // r ^= u & 0x00FF0000FFFFFFFFUL; + // r ^= s ^ (s << 2) ^ (s << 3) ^ (s << 4); + // return r; + //} + + private static ulong Rotate(int n, ulong x) { - for (int i = 0; i < wordsInBlock; i++) - { - internalState[i] = sboxesForEncryption[0][internalState[i] & 0x00000000000000FF] | - ((ulong)sboxesForEncryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) | - ((ulong)sboxesForEncryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) | - ((ulong)sboxesForEncryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) | - ((ulong)sboxesForEncryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) | - ((ulong)sboxesForEncryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) | - ((ulong)sboxesForEncryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) | - ((ulong)sboxesForEncryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56); - } + return (x >> n) | (x << -n); } - private void InvSubBytes() + private void RotateLeft(ulong[] x, ulong[] z) { - for (int i = 0; i < wordsInBlock; i++) + switch (wordsInBlock) { - internalState[i] = sboxesForDecryption[0][internalState[i] & 0x00000000000000FF] | - ((ulong)sboxesForDecryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) | - ((ulong)sboxesForDecryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) | - ((ulong)sboxesForDecryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) | - ((ulong)sboxesForDecryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) | - ((ulong)sboxesForDecryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) | - ((ulong)sboxesForDecryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) | - ((ulong)sboxesForDecryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56); + case 2: + { + ulong x0 = x[0], x1 = x[1]; + z[0] = (x0 >> 56) | (x1 << 8); + z[1] = (x1 >> 56) | (x0 << 8); + break; + } + case 4: + { + ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + z[0] = (x1 >> 24) | (x2 << 40); + z[1] = (x2 >> 24) | (x3 << 40); + z[2] = (x3 >> 24) | (x0 << 40); + z[3] = (x0 >> 24) | (x1 << 40); + break; + } + case 8: + { + ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + ulong x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7]; + z[0] = (x2 >> 24) | (x3 << 40); + z[1] = (x3 >> 24) | (x4 << 40); + z[2] = (x4 >> 24) | (x5 << 40); + z[3] = (x5 >> 24) | (x6 << 40); + z[4] = (x6 >> 24) | (x7 << 40); + z[5] = (x7 >> 24) | (x0 << 40); + z[6] = (x0 >> 24) | (x1 << 40); + z[7] = (x1 >> 24) | (x2 << 40); + break; + } + default: + { + throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed"); + } } } #region TABLES AND S-BOXES - //private const ulong mdsMatrix = 0x0407060801050101UL; - //private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL; - private const ulong mdsMatrix = 0x0104070608010501UL; - private const ulong mdsInvMatrix = 0xADCAD7492FA87695UL; + private const ulong mdsMatrix = 0x0407060801050101UL; + private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL; + + private static readonly byte[] S0 = new byte[]{ + 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, + 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, + 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, + 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, + 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, + 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, + 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, + 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, + 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, + 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, + 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, + 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, + 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, + 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, + 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, + 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 + }; - private byte[][] sboxesForEncryption = - { - new byte[] - { - 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, - 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, - 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, - 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, - 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, - 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, - 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, - 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, - 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, - 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, - 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, - 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, - 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, - 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, - 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, - 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 - }, - - new byte[] - { - 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, - 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, - 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, - 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, - 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, - 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, - 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, - 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, - 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, - 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, - 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, - 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, - 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, - 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, - 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, - 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 - }, - - new byte[] - { - 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, - 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, - 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, - 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, - 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, - 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, - 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, - 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, - 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, - 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, - 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, - 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, - 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, - 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, - 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, - 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 - }, - - new byte[] - { - 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, - 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, - 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, - 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, - 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, - 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, - 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, - 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, - 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, - 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, - 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, - 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, - 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, - 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, - 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, - 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 - } + private static readonly byte[] S1 = new byte[]{ + 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, + 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, + 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, + 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, + 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, + 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, + 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, + 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, + 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, + 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, + 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, + 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, + 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, + 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, + 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, + 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 }; - private byte[][] sboxesForDecryption = - { - new byte[] - { - 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b, - 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28, - 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0, - 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c, - 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23, - 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02, - 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c, - 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7, - 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c, - 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d, - 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17, - 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29, - 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec, - 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09, - 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1, - 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f - }, - - new byte[] - { - 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29, - 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc, - 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2, - 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76, - 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8, - 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f, - 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c, - 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9, - 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99, - 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38, - 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7, - 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87, - 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b, - 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c, - 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4, - 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa - }, - - new byte[] - { - 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95, - 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3, - 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a, - 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85, - 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52, - 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5, - 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb, - 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7, - 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62, - 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c, - 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d, - 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3, - 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91, - 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a, - 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49, - 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1 - }, - - new byte[] - { - 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3, - 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f, - 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21, - 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba, - 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49, - 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66, - 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4, - 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8, - 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85, - 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91, - 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb, - 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d, - 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d, - 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f, - 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf, - 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d - } + private static readonly byte[] S2 = new byte[]{ + 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, + 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, + 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, + 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, + 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, + 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, + 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, + 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, + 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, + 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, + 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, + 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, + 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, + 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, + 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, + 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 + }; + + private static readonly byte[] S3 = new byte[]{ + 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, + 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, + 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, + 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, + 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, + 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, + 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, + 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, + 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, + 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, + 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, + 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, + 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, + 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, + 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, + 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 + }; + + private static readonly byte[] T0 = new byte[]{ + 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b, + 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28, + 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0, + 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c, + 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23, + 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02, + 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c, + 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7, + 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c, + 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d, + 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17, + 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29, + 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec, + 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09, + 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1, + 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f + }; + + private static readonly byte[] T1 = new byte[]{ + 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29, + 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc, + 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2, + 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76, + 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8, + 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f, + 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c, + 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9, + 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99, + 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38, + 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7, + 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87, + 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b, + 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c, + 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4, + 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa + }; + + private static readonly byte[] T2 = new byte[]{ + 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95, + 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3, + 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a, + 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85, + 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52, + 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5, + 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb, + 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7, + 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62, + 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c, + 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d, + 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3, + 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91, + 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a, + 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49, + 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1 + }; + + private static readonly byte[] T3 = new byte[]{ + 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3, + 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f, + 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21, + 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba, + 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49, + 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66, + 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4, + 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8, + 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85, + 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91, + 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb, + 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d, + 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d, + 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f, + 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf, + 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d }; #endregion public virtual string AlgorithmName { - get { return "Dstu7624"; } + get { return "DSTU7624"; } } public virtual int GetBlockSize() { - return blockSizeBits / BITS_IN_BYTE; + return wordsInBlock << 3; } public virtual bool IsPartialBlockOkay @@ -744,6 +1078,7 @@ namespace Org.BouncyCastle.Crypto.Engines public virtual void Reset() { + Array.Clear(internalState, 0, internalState.Length); } } } diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs index 71e6d9e44..acf0be27b 100644 --- a/crypto/src/crypto/engines/GOST28147Engine.cs +++ b/crypto/src/crypto/engines/GOST28147Engine.cs @@ -364,5 +364,19 @@ namespace Org.BouncyCastle.Crypto.Engines return Arrays.Clone(sBox); } - } + + public static string GetSBoxName(byte[] sBox) + { + foreach (string name in sBoxes.Keys) + { + byte[] sb = (byte[])sBoxes[name]; + if (Arrays.AreEqual(sb, sBox)) + { + return name; + } + } + + throw new ArgumentException("SBOX provided did not map to a known one"); + } + } } diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs index 18a151c93..6c0379174 100644 --- a/crypto/src/crypto/engines/IdeaEngine.cs +++ b/crypto/src/crypto/engines/IdeaEngine.cs @@ -9,24 +9,14 @@ namespace Org.BouncyCastle.Crypto.Engines * A class that provides a basic International Data Encryption Algorithm (IDEA) engine. * <p> * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" - * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the - * end of the mulinv function!). + * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (barring 1 typo at the + * end of the MulInv function!). * </p> * <p> * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ * </p> * <p> - * Note 1: This algorithm is patented in the USA, Japan, and Europe including - * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland - * and the United Kingdom. Non-commercial use is free, however any commercial - * products are liable for royalties. Please see - * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for - * further details. This announcement has been included at the request of - * the patent holders. - * </p> - * <p> - * Note 2: Due to the requests concerning the above, this algorithm is now only - * included in the extended assembly. It is not included in the default distributions. + * Note: This algorithm was patented in the USA, Japan and Europe. These patents expired in 2011/2012. * </p> */ public class IdeaEngine diff --git a/crypto/src/crypto/engines/SM2Engine.cs b/crypto/src/crypto/engines/SM2Engine.cs index e5f12bbbb..90a5e4d6f 100644 --- a/crypto/src/crypto/engines/SM2Engine.cs +++ b/crypto/src/crypto/engines/SM2Engine.cs @@ -139,7 +139,7 @@ namespace Org.BouncyCastle.Crypto.Engines int check = 0; for (int i = 0; i != c3.Length; i++) { - check |= c3[i] ^ input[c1.Length + c2.Length + i]; + check |= c3[i] ^ input[inOff + c1.Length + c2.Length + i]; } Arrays.Fill(c1, 0); diff --git a/crypto/src/crypto/generators/BCrypt.cs b/crypto/src/crypto/generators/BCrypt.cs index af8029a1b..6e9611ad2 100644 --- a/crypto/src/crypto/generators/BCrypt.cs +++ b/crypto/src/crypto/generators/BCrypt.cs @@ -587,6 +587,17 @@ namespace Org.BouncyCastle.Crypto.Generators internal const int MAX_PASSWORD_BYTES = 72; /** + * Converts a character password to bytes incorporating the required trailing zero byte. + * + * @param password the password to be encoded. + * @return a byte representation of the password in UTF8 + trailing zero. + */ + public static byte[] PasswordToByteArray(char[] password) + { + return Arrays.Append(Strings.ToUtf8ByteArray(password), 0); + } + + /** * Calculates the <b>bcrypt</b> hash of a password. * <p> * This implements the raw <b>bcrypt</b> function as defined in the bcrypt specification, not diff --git a/crypto/src/crypto/generators/OpenBsdBCrypt.cs b/crypto/src/crypto/generators/OpenBsdBCrypt.cs index 85c34d769..49f79f95b 100644 --- a/crypto/src/crypto/generators/OpenBsdBCrypt.cs +++ b/crypto/src/crypto/generators/OpenBsdBCrypt.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; namespace Org.BouncyCastle.Crypto.Generators { @@ -33,10 +34,16 @@ namespace Org.BouncyCastle.Crypto.Generators * set up the decoding table. */ private static readonly byte[] DecodingTable = new byte[128]; - private static readonly string Version = "2a"; // previous version was not UTF-8 + private static readonly string DefaultVersion = "2y"; + private static readonly ISet AllowedVersions = new HashSet(); static OpenBsdBCrypt() { + // Presently just the Bcrypt versions. + AllowedVersions.Add("2a"); + AllowedVersions.Add("2y"); + AllowedVersions.Add("2b"); + for (int i = 0; i < DecodingTable.Length; i++) { DecodingTable[i] = (byte)0xff; @@ -56,16 +63,20 @@ namespace Org.BouncyCastle.Crypto.Generators * Creates a 60 character Bcrypt String, including * version, cost factor, salt and hash, separated by '$' * + * @param version the version, 2y,2b or 2a. (2a is not backwards compatible.) * @param cost the cost factor, treated as an exponent of 2 * @param salt a 16 byte salt * @param password the password * @return a 60 character Bcrypt String */ - private static string CreateBcryptString(byte[] password, byte[] salt, int cost) + private static string CreateBcryptString(string version, byte[] password, byte[] salt, int cost) { + if (!AllowedVersions.Contains(version)) + throw new ArgumentException("Version " + version + " is not accepted by this implementation.", "version"); + StringBuilder sb = new StringBuilder(60); sb.Append('$'); - sb.Append(Version); + sb.Append(version); sb.Append('$'); sb.Append(cost < 10 ? ("0" + cost) : cost.ToString()); sb.Append('$'); @@ -80,7 +91,8 @@ namespace Org.BouncyCastle.Crypto.Generators /** * Creates a 60 character Bcrypt String, including - * version, cost factor, salt and hash, separated by '$' + * version, cost factor, salt and hash, separated by '$' using version + * '2y'. * * @param cost the cost factor, treated as an exponent of 2 * @param salt a 16 byte salt @@ -89,6 +101,23 @@ namespace Org.BouncyCastle.Crypto.Generators */ public static string Generate(char[] password, byte[] salt, int cost) { + return Generate(DefaultVersion, password, salt, cost); + } + + /** + * Creates a 60 character Bcrypt String, including + * version, cost factor, salt and hash, separated by '$' + * + * @param version the version, may be 2b, 2y or 2a. (2a is not backwards compatible.) + * @param cost the cost factor, treated as an exponent of 2 + * @param salt a 16 byte salt + * @param password the password + * @return a 60 character Bcrypt String + */ + public static string Generate(string version, char[] password, byte[] salt, int cost) + { + if (!AllowedVersions.Contains(version)) + throw new ArgumentException("Version " + version + " is not accepted by this implementation.", "version"); if (password == null) throw new ArgumentNullException("password"); if (salt == null) @@ -109,7 +138,7 @@ namespace Org.BouncyCastle.Crypto.Generators Array.Clear(psw, 0, psw.Length); - string rv = CreateBcryptString(tmp, salt, cost); + string rv = CreateBcryptString(version, tmp, salt, cost); Array.Clear(tmp, 0, tmp.Length); @@ -133,8 +162,10 @@ namespace Org.BouncyCastle.Crypto.Generators throw new DataLengthException("Bcrypt String length: " + bcryptString.Length + ", 60 required."); if (bcryptString[0] != '$' || bcryptString[3] != '$' || bcryptString[6] != '$') throw new ArgumentException("Invalid Bcrypt String format.", "bcryptString"); - if (!bcryptString.Substring(1, 2).Equals(Version)) - throw new ArgumentException("Wrong Bcrypt version, 2a expected.", "bcryptString"); + + string version = bcryptString.Substring(1, 2); + if (!AllowedVersions.Contains(version)) + throw new ArgumentException("Bcrypt version '" + version + "' is not supported by this implementation", "bcryptString"); int cost = 0; try @@ -143,7 +174,7 @@ namespace Org.BouncyCastle.Crypto.Generators } catch (Exception nfe) { - throw new ArgumentException("Invalid cost factor: " + bcryptString.Substring(4, 2), "bcryptString"); + throw new ArgumentException("Invalid cost factor: " + bcryptString.Substring(4, 2), "bcryptString", nfe); } if (cost < 4 || cost > 31) throw new ArgumentException("Invalid cost factor: " + cost + ", 4 < cost < 31 expected."); @@ -155,7 +186,7 @@ namespace Org.BouncyCastle.Crypto.Generators int start = bcryptString.LastIndexOf('$') + 1, end = bcryptString.Length - 31; byte[] salt = DecodeSaltString(bcryptString.Substring(start, end - start)); - string newBcryptString = Generate(password, salt, cost); + string newBcryptString = Generate(version, password, salt, cost); return bcryptString.Equals(newBcryptString); } diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs index efa74d735..4d15bb3d7 100644 --- a/crypto/src/crypto/generators/SCrypt.cs +++ b/crypto/src/crypto/generators/SCrypt.cs @@ -1,5 +1,5 @@ using System; -using System.Threading; +using System.Diagnostics; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; @@ -8,12 +8,46 @@ using Org.BouncyCastle.Crypto.Utilities; namespace Org.BouncyCastle.Crypto.Generators { - public class SCrypt + /// <summary>Implementation of the scrypt a password-based key derivation function.</summary> + /// <remarks> + /// Scrypt was created by Colin Percival and is specified in + /// <a href="http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01">draft-josefsson-scrypt-kd</a>. + /// </remarks> + public class SCrypt { - // TODO Validate arguments - public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen) + /// <summary>Generate a key using the scrypt key derivation function.</summary> + /// <param name="P">the bytes of the pass phrase.</param> + /// <param name="S">the salt to use for this invocation.</param> + /// <param name="N">CPU/Memory cost parameter. Must be larger than 1, a power of 2 and less than + /// <code>2^(128 * r / 8)</code>.</param> + /// <param name="r">the block size, must be >= 1.</param> + /// <param name="p">Parallelization parameter. Must be a positive integer less than or equal to + /// <code>Int32.MaxValue / (128 * r * 8)</code>.</param> + /// <param name="dkLen">the length of the key to generate.</param> + /// <returns>the generated key.</returns> + public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen) { - return MFcrypt(P, S, N, r, p, dkLen); + if (P == null) + throw new ArgumentNullException("Passphrase P must be provided."); + if (S == null) + throw new ArgumentNullException("Salt S must be provided."); + if (N <= 1 || !IsPowerOf2(N)) + throw new ArgumentException("Cost parameter N must be > 1 and a power of 2."); + // Only value of r that cost (as an int) could be exceeded for is 1 + if (r == 1 && N >= 65536) + throw new ArgumentException("Cost parameter N must be > 1 and < 65536."); + if (r < 1) + throw new ArgumentException("Block size r must be >= 1."); + int maxParallel = Int32.MaxValue / (128 * r * 8); + if (p < 1 || p > maxParallel) + { + throw new ArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel + + " (based on block size r of " + r + ")"); + } + if (dkLen < 1) + throw new ArgumentException("Generated key length dkLen must be >= 1."); + + return MFcrypt(P, S, N, r, p, dkLen); } private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen) @@ -136,5 +170,13 @@ namespace Org.BouncyCastle.Crypto.Generators Clear(array); } } - } + + // note: we know X is non-zero + private static bool IsPowerOf2(int x) + { + Debug.Assert(x != 0); + + return (x & (x - 1)) == 0; + } + } } diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs index cc6b723d6..33c2d67ee 100644 --- a/crypto/src/crypto/macs/GOST28147Mac.cs +++ b/crypto/src/crypto/macs/GOST28147Mac.cs @@ -18,6 +18,7 @@ namespace Org.BouncyCastle.Crypto.Macs private byte[] mac; private bool firstStep = true; private int[] workingKey; + private byte[] macIV = null; // // This is default S-box - E_A. @@ -40,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Macs bufOff = 0; } - private static int[] generateWorkingKey( + private static int[] GenerateWorkingKey( byte[] userKey) { if (userKey.Length != 32) @@ -60,7 +61,8 @@ namespace Org.BouncyCastle.Crypto.Macs { Reset(); buf = new byte[blockSize]; - if (parameters is ParametersWithSBox) + macIV = null; + if (parameters is ParametersWithSBox) { ParametersWithSBox param = (ParametersWithSBox)parameters; @@ -74,13 +76,21 @@ namespace Org.BouncyCastle.Crypto.Macs // if (param.Parameters != null) { - workingKey = generateWorkingKey(((KeyParameter)param.Parameters).GetKey()); + workingKey = GenerateWorkingKey(((KeyParameter)param.Parameters).GetKey()); } } else if (parameters is KeyParameter) { - workingKey = generateWorkingKey(((KeyParameter)parameters).GetKey()); + workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey()); } + else if (parameters is ParametersWithIV) + { + ParametersWithIV p = (ParametersWithIV)parameters; + + workingKey = GenerateWorkingKey(((KeyParameter)p.Parameters).GetKey()); + Array.Copy(p.GetIV(), 0, mac, 0, mac.Length); + macIV = p.GetIV(); // don't skip the initial CM5Func + } else { throw new ArgumentException("invalid parameter passed to Gost28147 init - " @@ -194,7 +204,11 @@ namespace Org.BouncyCastle.Crypto.Macs if (firstStep) { firstStep = false; - } + if (macIV != null) + { + sumbuf = CM5func(buf, 0, macIV); + } + } else { sumbuf = CM5func(buf, 0, mac); @@ -227,7 +241,11 @@ namespace Org.BouncyCastle.Crypto.Macs if (firstStep) { firstStep = false; - } + if (macIV != null) + { + sumbuf = CM5func(buf, 0, macIV); + } + } else { sumbuf = CM5func(buf, 0, mac); diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs index 732fbdfa4..e377f7760 100644 --- a/crypto/src/crypto/parameters/ECDomainParameters.cs +++ b/crypto/src/crypto/parameters/ECDomainParameters.cs @@ -13,12 +13,13 @@ namespace Org.BouncyCastle.Crypto.Parameters internal ECPoint g; internal BigInteger n; internal BigInteger h; + internal BigInteger hInv; public ECDomainParameters( ECCurve curve, ECPoint g, BigInteger n) - : this(curve, g, n, BigInteger.One) + : this(curve, g, n, BigInteger.One, null) { } @@ -44,11 +45,10 @@ namespace Org.BouncyCastle.Crypto.Parameters throw new ArgumentNullException("g"); if (n == null) throw new ArgumentNullException("n"); - if (h == null) - throw new ArgumentNullException("h"); + // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA this.curve = curve; - this.g = g.Normalize(); + this.g = Validate(curve, g); this.n = n; this.h = h; this.seed = Arrays.Clone(seed); @@ -74,6 +74,21 @@ namespace Org.BouncyCastle.Crypto.Parameters get { return h; } } + public BigInteger HInv + { + get + { + lock (this) + { + if (hInv == null) + { + hInv = h.ModInverse(n); + } + return hInv; + } + } + } + public byte[] GetSeed() { return Arrays.Clone(seed); @@ -99,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Parameters return curve.Equals(other.curve) && g.Equals(other.g) && n.Equals(other.n) - && h.Equals(other.h); + && h.Equals(other.h); } public override int GetHashCode() @@ -113,5 +128,21 @@ namespace Org.BouncyCastle.Crypto.Parameters hc ^= h.GetHashCode(); return hc; } + + internal static ECPoint Validate(ECCurve c, ECPoint q) + { + if (q == null) + throw new ArgumentException("Point has null value", "q"); + + q = ECAlgorithms.ImportPoint(c, q).Normalize(); + + if (q.IsInfinity) + throw new ArgumentException("Point at infinity", "q"); + + if (!q.IsValid()) + throw new ArgumentException("Point not on curve", "q"); + + return q; + } } } diff --git a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs index 474e5d82c..69916e525 100644 --- a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs +++ b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs @@ -9,21 +9,6 @@ namespace Org.BouncyCastle.Crypto.Parameters public class ECPublicKeyParameters : ECKeyParameters { - private static ECPoint Validate(ECPoint q) - { - if (q == null) - throw new ArgumentNullException("q"); - if (q.IsInfinity) - throw new ArgumentException("point at infinity", "q"); - - q = q.Normalize(); - - if (!q.IsValid()) - throw new ArgumentException("point not on curve", "q"); - - return q; - } - private readonly ECPoint q; public ECPublicKeyParameters( @@ -42,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Parameters if (q == null) throw new ArgumentNullException("q"); - this.q = Validate(q); + this.q = ECDomainParameters.Validate(Parameters.Curve, q); } public ECPublicKeyParameters( @@ -54,7 +39,7 @@ namespace Org.BouncyCastle.Crypto.Parameters if (q == null) throw new ArgumentNullException("q"); - this.q = Validate(q); + this.q = ECDomainParameters.Validate(Parameters.Curve, q); } public ECPublicKeyParameters( @@ -66,7 +51,7 @@ namespace Org.BouncyCastle.Crypto.Parameters if (q == null) throw new ArgumentNullException("q"); - this.q = Validate(q); + this.q = ECDomainParameters.Validate(Parameters.Curve, q); } public ECPoint Q diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs index 32a86e503..154a2c94b 100644 --- a/crypto/src/crypto/tls/DefaultTlsClient.cs +++ b/crypto/src/crypto/tls/DefaultTlsClient.cs @@ -14,14 +14,22 @@ namespace Org.BouncyCastle.Crypto.Tls public abstract class DefaultTlsClient : AbstractTlsClient { + protected TlsDHVerifier mDHVerifier; + public DefaultTlsClient() - : base() + : this(new DefaultTlsCipherFactory()) { } public DefaultTlsClient(TlsCipherFactory cipherFactory) - : base(cipherFactory) + : this(cipherFactory, new DefaultTlsDHVerifier()) + { + } + + public DefaultTlsClient(TlsCipherFactory cipherFactory, TlsDHVerifier dhVerifier) + : base(cipherFactory) { + this.mDHVerifier = dhVerifier; } public override int[] GetCipherSuites() @@ -85,12 +93,12 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange) { - return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null); + return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mDHVerifier, null); } protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange) { - return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null); + return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mDHVerifier, null); } protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange) diff --git a/crypto/src/crypto/tls/DefaultTlsDHVerifier.cs b/crypto/src/crypto/tls/DefaultTlsDHVerifier.cs new file mode 100644 index 000000000..ae26d04c3 --- /dev/null +++ b/crypto/src/crypto/tls/DefaultTlsDHVerifier.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class DefaultTlsDHVerifier + : TlsDHVerifier + { + public static readonly int DefaultMinimumPrimeBits = 2048; + + protected static readonly IList DefaultGroups = Platform.CreateArrayList(); + + private static void AddDefaultGroup(DHParameters dhParameters) + { + DefaultGroups.Add(dhParameters); + } + + static DefaultTlsDHVerifier() + { + AddDefaultGroup(DHStandardGroups.rfc7919_ffdhe2048); + AddDefaultGroup(DHStandardGroups.rfc7919_ffdhe3072); + AddDefaultGroup(DHStandardGroups.rfc7919_ffdhe4096); + AddDefaultGroup(DHStandardGroups.rfc7919_ffdhe6144); + AddDefaultGroup(DHStandardGroups.rfc7919_ffdhe8192); + + AddDefaultGroup(DHStandardGroups.rfc3526_1536); + AddDefaultGroup(DHStandardGroups.rfc3526_2048); + AddDefaultGroup(DHStandardGroups.rfc3526_3072); + AddDefaultGroup(DHStandardGroups.rfc3526_4096); + AddDefaultGroup(DHStandardGroups.rfc3526_6144); + AddDefaultGroup(DHStandardGroups.rfc3526_8192); + } + + // IList is (DHParameters) + protected readonly IList mGroups; + protected readonly int mMinimumPrimeBits; + + /// <summary>Accept various standard DH groups with 'P' at least <c>DefaultMinimumPrimeBits</c> bits.</summary> + public DefaultTlsDHVerifier() + : this(DefaultMinimumPrimeBits) + { + } + + /// <summary>Accept various standard DH groups with 'P' at least the specified number of bits.</summary> + public DefaultTlsDHVerifier(int minimumPrimeBits) + : this(DefaultGroups, minimumPrimeBits) + { + } + + /// <summary>Accept a custom set of group parameters, subject to a minimum bitlength for 'P'.</summary> + /// <param name="groups">An <c>IList</c> of acceptable <c>DHParameters</c>.</param> + /// <param name="minimumPrimeBits">The minimum acceptable bitlength of the 'P' parameter.</param> + public DefaultTlsDHVerifier(IList groups, int minimumPrimeBits) + { + this.mGroups = groups; + this.mMinimumPrimeBits = minimumPrimeBits; + } + + public virtual bool Accept(DHParameters dhParameters) + { + return CheckMinimumPrimeBits(dhParameters) && CheckGroup(dhParameters); + } + + public virtual int MinimumPrimeBits + { + get { return mMinimumPrimeBits; } + } + + protected virtual bool AreGroupsEqual(DHParameters a, DHParameters b) + { + return a == b || (AreParametersEqual(a.P, b.P) && AreParametersEqual(a.G, b.G)); + } + + protected virtual bool AreParametersEqual(BigInteger a, BigInteger b) + { + return a == b || a.Equals(b); + } + + protected virtual bool CheckGroup(DHParameters dhParameters) + { + foreach (DHParameters group in mGroups) + { + if (AreGroupsEqual(dhParameters, group)) + { + return true; + } + } + return false; + } + + protected virtual bool CheckMinimumPrimeBits(DHParameters dhParameters) + { + return dhParameters.P.BitLength >= MinimumPrimeBits; + } + } +} diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs index 97eaa079d..90f357687 100644 --- a/crypto/src/crypto/tls/DefaultTlsServer.cs +++ b/crypto/src/crypto/tls/DefaultTlsServer.cs @@ -138,12 +138,12 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange) { - return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters()); + return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, GetDHParameters()); } protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange) { - return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters()); + return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, GetDHParameters()); } protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange) diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs index 2ef80dcfd..1dc119d7b 100644 --- a/crypto/src/crypto/tls/PskTlsClient.cs +++ b/crypto/src/crypto/tls/PskTlsClient.cs @@ -6,16 +6,23 @@ namespace Org.BouncyCastle.Crypto.Tls public class PskTlsClient : AbstractTlsClient { + protected TlsDHVerifier mDHVerifier; protected TlsPskIdentity mPskIdentity; public PskTlsClient(TlsPskIdentity pskIdentity) - : this(new DefaultTlsCipherFactory(), pskIdentity) + : this(new DefaultTlsCipherFactory(), pskIdentity) { } public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity) - : base(cipherFactory) + : this(cipherFactory, new DefaultTlsDHVerifier(), pskIdentity) { + } + + public PskTlsClient(TlsCipherFactory cipherFactory, TlsDHVerifier dhVerifier, TlsPskIdentity pskIdentity) + : base(cipherFactory) + { + this.mDHVerifier = dhVerifier; this.mPskIdentity = pskIdentity; } @@ -63,8 +70,8 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange) { - return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, null, mNamedCurves, - mClientECPointFormats, mServerECPointFormats); + return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, mDHVerifier, null, + mNamedCurves, mClientECPointFormats, mServerECPointFormats); } } } diff --git a/crypto/src/crypto/tls/PskTlsServer.cs b/crypto/src/crypto/tls/PskTlsServer.cs index b0fb67c04..a3778420d 100644 --- a/crypto/src/crypto/tls/PskTlsServer.cs +++ b/crypto/src/crypto/tls/PskTlsServer.cs @@ -87,7 +87,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange) { return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, mPskIdentityManager, - GetDHParameters(), mNamedCurves, mClientECPointFormats, mServerECPointFormats); + null, GetDHParameters(), mNamedCurves, mClientECPointFormats, mServerECPointFormats); } } } diff --git a/crypto/src/crypto/tls/ServerDHParams.cs b/crypto/src/crypto/tls/ServerDHParams.cs deleted file mode 100644 index b09262771..000000000 --- a/crypto/src/crypto/tls/ServerDHParams.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Crypto.Tls -{ - public class ServerDHParams - { - protected readonly DHPublicKeyParameters mPublicKey; - - public ServerDHParams(DHPublicKeyParameters publicKey) - { - if (publicKey == null) - throw new ArgumentNullException("publicKey"); - - this.mPublicKey = publicKey; - } - - public virtual DHPublicKeyParameters PublicKey - { - get { return mPublicKey; } - } - - /** - * Encode this {@link ServerDHParams} to a {@link Stream}. - * - * @param output - * the {@link Stream} to encode to. - * @throws IOException - */ - public virtual void Encode(Stream output) - { - DHParameters dhParameters = mPublicKey.Parameters; - BigInteger Ys = mPublicKey.Y; - - TlsDHUtilities.WriteDHParameter(dhParameters.P, output); - TlsDHUtilities.WriteDHParameter(dhParameters.G, output); - TlsDHUtilities.WriteDHParameter(Ys, output); - } - - /** - * Parse a {@link ServerDHParams} from a {@link Stream}. - * - * @param input - * the {@link Stream} to parse from. - * @return a {@link ServerDHParams} object. - * @throws IOException - */ - public static ServerDHParams Parse(Stream input) - { - BigInteger p = TlsDHUtilities.ReadDHParameter(input); - BigInteger g = TlsDHUtilities.ReadDHParameter(input); - BigInteger Ys = TlsDHUtilities.ReadDHParameter(input); - - return new ServerDHParams( - TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Ys, new DHParameters(p, g)))); - } - } -} diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs index d179068bb..59d52265b 100644 --- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs @@ -4,7 +4,6 @@ using System.IO; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Tls @@ -14,6 +13,7 @@ namespace Org.BouncyCastle.Crypto.Tls : AbstractTlsKeyExchange { protected TlsSigner mTlsSigner; + protected TlsDHVerifier mDHVerifier; protected DHParameters mDHParameters; protected AsymmetricKeyParameter mServerPublicKey; @@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected DHPrivateKeyParameters mDHAgreePrivateKey; protected DHPublicKeyParameters mDHAgreePublicKey; - public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters) + public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters) : base(keyExchange, supportedSignatureAlgorithms) { switch (keyExchange) @@ -42,6 +42,7 @@ namespace Org.BouncyCastle.Crypto.Tls throw new InvalidOperationException("unsupported key exchange algorithm"); } + this.mDHVerifier = dhVerifier; this.mDHParameters = dhParameters; } @@ -84,8 +85,8 @@ namespace Org.BouncyCastle.Crypto.Tls { try { - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey); - this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters); + this.mDHAgreePublicKey = (DHPublicKeyParameters)this.mServerPublicKey; + this.mDHParameters = mDHAgreePublicKey.Parameters; } catch (InvalidCastException e) { @@ -143,10 +144,8 @@ namespace Org.BouncyCastle.Crypto.Tls // DH_anon is handled here, DHE_* in a subclass - ServerDHParams dhParams = ServerDHParams.Parse(input); - - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey); - this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters); + this.mDHParameters = TlsDHUtilities.ReceiveDHParameters(mDHVerifier, input); + this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters); } public override void ValidateCertificateRequest(CertificateRequest certificateRequest) @@ -223,9 +222,7 @@ namespace Org.BouncyCastle.Crypto.Tls return; } - BigInteger Yc = TlsDHUtilities.ReadDHParameter(input); - - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters)); + this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters); } public override byte[] GeneratePremasterSecret() @@ -242,18 +239,5 @@ namespace Org.BouncyCastle.Crypto.Tls throw new TlsFatalAlert(AlertDescription.internal_error); } - - protected virtual int MinimumPrimeBits - { - get { return 1024; } - } - - protected virtual DHParameters ValidateDHParameters(DHParameters parameters) - { - if (parameters.P.BitLength < MinimumPrimeBits) - throw new TlsFatalAlert(AlertDescription.insufficient_security); - - return TlsDHUtilities.ValidateDHParameters(parameters); - } } } diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs index 6df61cbed..9567ee062 100644 --- a/crypto/src/crypto/tls/TlsDHUtilities.cs +++ b/crypto/src/crypto/tls/TlsDHUtilities.cs @@ -417,46 +417,43 @@ namespace Org.BouncyCastle.Crypto.Tls AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams); DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public; - new ServerDHParams(dhPublic).Encode(output); + WriteDHParameters(dhParams, output); + WriteDHParameter(dhPublic.Y, output); return (DHPrivateKeyParameters)kp.Private; } - public static DHParameters ValidateDHParameters(DHParameters parameters) + public static BigInteger ReadDHParameter(Stream input) { - BigInteger p = parameters.P; - BigInteger g = parameters.G; - - if (!p.IsProbablePrime(2)) - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - if (g.CompareTo(Two) < 0 || g.CompareTo(p.Subtract(Two)) > 0) - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - - - return parameters; + return new BigInteger(1, TlsUtilities.ReadOpaque16(input)); } - public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key) + public static DHParameters ReadDHParameters(Stream input) { - DHParameters parameters = ValidateDHParameters(key.Parameters); - - BigInteger Y = key.Y; - if (Y.CompareTo(Two) < 0 || Y.CompareTo(parameters.P.Subtract(Two)) > 0) - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + BigInteger p = ReadDHParameter(input); + BigInteger g = ReadDHParameter(input); - // TODO See RFC 2631 for more discussion of Diffie-Hellman validation - - return key; + return new DHParameters(p, g); } - public static BigInteger ReadDHParameter(Stream input) + public static DHParameters ReceiveDHParameters(TlsDHVerifier dhVerifier, Stream input) { - return new BigInteger(1, TlsUtilities.ReadOpaque16(input)); + DHParameters dhParameters = ReadDHParameters(input); + if (!dhVerifier.Accept(dhParameters)) + throw new TlsFatalAlert(AlertDescription.insufficient_security); + + return dhParameters; } public static void WriteDHParameter(BigInteger x, Stream output) { TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output); } + + public static void WriteDHParameters(DHParameters dhParameters, Stream output) + { + WriteDHParameter(dhParameters.P, output); + WriteDHParameter(dhParameters.G, output); + } } } diff --git a/crypto/src/crypto/tls/TlsDHVerifier.cs b/crypto/src/crypto/tls/TlsDHVerifier.cs new file mode 100644 index 000000000..867403c3c --- /dev/null +++ b/crypto/src/crypto/tls/TlsDHVerifier.cs @@ -0,0 +1,15 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// <summary>An interface for verifying that Diffie-Hellman parameters are acceptable.</summary> + public interface TlsDHVerifier + { + /// <summary>Verify that the given <c>DHParameters</c> are acceptable.</summary> + /// <param name="dhParameters">The <c>DHParameters</c> to verify.</param> + /// <returns>true if (and only if) the specified parameters are acceptable.</returns> + bool Accept(DHParameters dhParameters); + } +} diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs index cdd629247..402c74720 100644 --- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs @@ -3,7 +3,6 @@ using System.Collections; using System.IO; using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; @@ -14,8 +13,8 @@ namespace Org.BouncyCastle.Crypto.Tls { protected TlsSignerCredentials mServerCredentials = null; - public TlsDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters) - : base(keyExchange, supportedSignatureAlgorithms, dhParameters) + public TlsDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters) + : base(keyExchange, supportedSignatureAlgorithms, dhVerifier, dhParameters) { } @@ -69,7 +68,8 @@ namespace Org.BouncyCastle.Crypto.Tls SignerInputBuffer buf = new SignerInputBuffer(); Stream teeIn = new TeeInputStream(input, buf); - ServerDHParams dhParams = ServerDHParams.Parse(teeIn); + this.mDHParameters = TlsDHUtilities.ReceiveDHParameters(mDHVerifier, teeIn); + this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(teeIn), mDHParameters); DigitallySigned signed_params = ParseSignature(input); @@ -77,9 +77,6 @@ namespace Org.BouncyCastle.Crypto.Tls buf.UpdateSigner(signer); if (!signer.VerifySignature(signed_params.Signature)) throw new TlsFatalAlert(AlertDescription.decrypt_error); - - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey); - this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters); } protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm, diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs index 0af7f7a69..36ef09e85 100644 --- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs @@ -4,7 +4,6 @@ using System.IO; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; @@ -18,6 +17,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected TlsPskIdentity mPskIdentity; protected TlsPskIdentityManager mPskIdentityManager; + protected TlsDHVerifier mDHVerifier; protected DHParameters mDHParameters; protected int[] mNamedCurves; protected byte[] mClientECPointFormats, mServerECPointFormats; @@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected byte[] mPremasterSecret; public TlsPskKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsPskIdentity pskIdentity, - TlsPskIdentityManager pskIdentityManager, DHParameters dhParameters, int[] namedCurves, + TlsPskIdentityManager pskIdentityManager, TlsDHVerifier dhVerifier, DHParameters dhParameters, int[] namedCurves, byte[] clientECPointFormats, byte[] serverECPointFormats) : base(keyExchange, supportedSignatureAlgorithms) { @@ -54,6 +54,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.mPskIdentity = pskIdentity; this.mPskIdentityManager = pskIdentityManager; + this.mDHVerifier = dhVerifier; this.mDHParameters = dhParameters; this.mNamedCurves = namedCurves; this.mClientECPointFormats = clientECPointFormats; @@ -162,10 +163,8 @@ namespace Org.BouncyCastle.Crypto.Tls if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK) { - ServerDHParams serverDHParams = ServerDHParams.Parse(input); - - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey); - this.mDHParameters = mDHAgreePublicKey.Parameters; + this.mDHParameters = TlsDHUtilities.ReceiveDHParameters(mDHVerifier, input); + this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters); } else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { @@ -240,9 +239,7 @@ namespace Org.BouncyCastle.Crypto.Tls if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK) { - BigInteger Yc = TlsDHUtilities.ReadDHParameter(input); - - this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters)); + this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters); } else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs index b35701fb3..a182c43e8 100644 --- a/crypto/src/math/BigInteger.cs +++ b/crypto/src/math/BigInteger.cs @@ -3269,34 +3269,20 @@ namespace Org.BouncyCastle.Math break; } - // Based on algorithm 1a from chapter 4.4 in Seminumerical Algorithms (Knuth) - - // Work out the largest power of 'rdx' that is a positive 64-bit integer - // TODO possibly cache power/exponent against radix? - long limit = Int64.MaxValue / radix; - long power = radix; - int exponent = 1; - while (power <= limit) + // TODO Could cache the moduli for each radix (soft reference?) + IList moduli = Platform.CreateArrayList(); + BigInteger R = BigInteger.ValueOf(radix); + while (R.CompareTo(q) <= 0) { - power *= radix; - ++exponent; + moduli.Add(R); + R = R.Square(); } - BigInteger bigPower = BigInteger.ValueOf(power); + int scale = moduli.Count; + sb.EnsureCapacity(sb.Length + (1 << scale)); - IList S = Platform.CreateArrayList(); - while (q.CompareTo(bigPower) >= 0) - { - BigInteger[] qr = q.DivideAndRemainder(bigPower); - S.Add(Convert.ToString(qr[1].LongValue, radix)); - q = qr[0]; - } + ToString(sb, radix, moduli, scale, q); - sb.Append(Convert.ToString(q.LongValue, radix)); - for (int i = S.Count - 1; i >= 0; --i) - { - AppendZeroExtendedString(sb, (string)S[i], exponent); - } break; } } @@ -3304,6 +3290,28 @@ namespace Org.BouncyCastle.Math return sb.ToString(); } + private static void ToString(StringBuilder sb, int radix, IList moduli, int scale, BigInteger pos) + { + if (pos.BitLength < 64) + { + string s = Convert.ToString(pos.LongValue, radix); + if (sb.Length > 1 || (sb.Length == 1 && sb[0] != '-')) + { + AppendZeroExtendedString(sb, s, 1 << scale); + } + else if (pos.SignValue != 0) + { + sb.Append(s); + } + return; + } + + BigInteger[] qr = pos.DivideAndRemainder((BigInteger)moduli[--scale]); + + ToString(sb, radix, moduli, scale, qr[0]); + ToString(sb, radix, moduli, scale, qr[1]); + } + private static void AppendZeroExtendedString(StringBuilder sb, string s, int minLength) { for (int len = s.Length; len < minLength; ++len) diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs index 5d60de40f..b05c0201a 100644 --- a/crypto/src/math/ec/ECAlgorithms.cs +++ b/crypto/src/math/ec/ECAlgorithms.cs @@ -58,10 +58,10 @@ namespace Org.BouncyCastle.Math.EC GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism; if (glvEndomorphism != null) { - return ValidatePoint(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism)); + return ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism)); } - return ValidatePoint(ImplSumOfMultiplies(imported, ks)); + return ImplCheckResult(ImplSumOfMultiplies(imported, ks)); } public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b) @@ -74,18 +74,18 @@ namespace Org.BouncyCastle.Math.EC AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve; if (f2mCurve != null && f2mCurve.IsKoblitz) { - return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b))); + return ImplCheckResult(P.Multiply(a).Add(Q.Multiply(b))); } } GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism; if (glvEndomorphism != null) { - return ValidatePoint( + return ImplCheckResult( ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism)); } - return ValidatePoint(ImplShamirsTrickWNaf(P, a, Q, b)); + return ImplCheckResult(ImplShamirsTrickWNaf(P, a, Q, b)); } /* @@ -111,7 +111,7 @@ namespace Org.BouncyCastle.Math.EC ECCurve cp = P.Curve; Q = ImportPoint(cp, Q); - return ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l)); + return ImplCheckResult(ImplShamirsTrickJsf(P, k, Q, l)); } public static ECPoint ImportPoint(ECCurve c, ECPoint p) @@ -202,7 +202,24 @@ namespace Org.BouncyCastle.Math.EC public static ECPoint ValidatePoint(ECPoint p) { if (!p.IsValid()) - throw new ArgumentException("Invalid point", "p"); + throw new InvalidOperationException("Invalid point"); + + return p; + } + + public static ECPoint CleanPoint(ECCurve c, ECPoint p) + { + ECCurve cp = p.Curve; + if (!c.Equals(cp)) + throw new ArgumentException("Point must be on the same curve", "p"); + + return c.DecodePoint(p.GetEncoded(false)); + } + + internal static ECPoint ImplCheckResult(ECPoint p) + { + if (!p.IsValidPartial()) + throw new InvalidOperationException("Invalid result"); return p; } diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs index 6ccd97e7b..993b69149 100644 --- a/crypto/src/math/ec/ECCurve.cs +++ b/crypto/src/math/ec/ECCurve.cs @@ -5,6 +5,7 @@ using Org.BouncyCastle.Math.EC.Abc; using Org.BouncyCastle.Math.EC.Endo; using Org.BouncyCastle.Math.EC.Multiplier; using Org.BouncyCastle.Math.Field; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC @@ -160,15 +161,24 @@ namespace Org.BouncyCastle.Math.EC public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name) { CheckPoint(point); + + IDictionary table; lock (point) { - IDictionary table = point.m_preCompTable; - return table == null ? null : (PreCompInfo)table[name]; + table = point.m_preCompTable; + } + + if (null == table) + return null; + + lock (table) + { + return (PreCompInfo)table[name]; } } /** - * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by + * Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use * by subsequent multiplication. * @@ -176,20 +186,34 @@ namespace Org.BouncyCastle.Math.EC * The <code>ECPoint</code> to store precomputations for. * @param name * A <code>String</code> used to index precomputations of different types. - * @param preCompInfo - * The values precomputed by the <code>ECMultiplier</code>. + * @param callback + * Called to calculate the <code>PreCompInfo</code>. */ - public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo) + public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback) { CheckPoint(point); + + IDictionary table; lock (point) { - IDictionary table = point.m_preCompTable; + table = point.m_preCompTable; if (null == table) { point.m_preCompTable = table = Platform.CreateHashtable(4); } - table[name] = preCompInfo; + } + + lock (table) + { + PreCompInfo existing = (PreCompInfo)table[name]; + PreCompInfo result = callback.Precompute(existing); + + if (result != existing) + { + table[name] = result; + } + + return result; } } @@ -207,7 +231,7 @@ namespace Org.BouncyCastle.Math.EC // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. p = p.Normalize(); - return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed); + return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed); } /** @@ -321,6 +345,33 @@ namespace Org.BouncyCastle.Math.EC get { return m_coord; } } + /** + * Create a cache-safe lookup table for the specified sequence of points. All the points MUST + * belong to this <code>ECCurve</code> instance, and MUST already be normalized. + */ + public virtual ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + int FE_BYTES = (FieldSize + 7) / 8; + byte[] table = new byte[len * FE_BYTES * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + byte[] px = p.RawXCoord.ToBigInteger().ToByteArray(); + byte[] py = p.RawYCoord.ToBigInteger().ToByteArray(); + + int pxStart = px.Length > FE_BYTES ? 1 : 0, pxLen = px.Length - pxStart; + int pyStart = py.Length > FE_BYTES ? 1 : 0, pyLen = py.Length - pyStart; + + Array.Copy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES; + Array.Copy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES; + } + } + + return new DefaultLookupTable(this, table, len); + } + protected virtual void CheckPoint(ECPoint point) { if (null == point || (this != point.Curve)) @@ -425,7 +476,7 @@ namespace Org.BouncyCastle.Math.EC BigInteger X = new BigInteger(1, encoded, 1, expectedLength); p = DecompressPoint(yTilde, X); - if (!p.SatisfiesCofactor()) + if (!p.ImplIsValid(true, true)) throw new ArgumentException("Invalid point"); break; @@ -468,6 +519,50 @@ namespace Org.BouncyCastle.Math.EC return p; } + + private class DefaultLookupTable + : ECLookupTable + { + private readonly ECCurve m_outer; + private readonly byte[] m_table; + private readonly int m_size; + + internal DefaultLookupTable(ECCurve outer, byte[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + int FE_BYTES = (m_outer.FieldSize + 7) / 8; + byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES]; + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + byte MASK = (byte)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < FE_BYTES; ++j) + { + x[j] ^= (byte)(m_table[pos + j] & MASK); + y[j] ^= (byte)(m_table[pos + FE_BYTES + j] & MASK); + } + + pos += (FE_BYTES * 2); + } + + ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x)); + ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y)); + return m_outer.CreateRawPoint(X, Y, false); + } + } } public abstract class AbstractFpCurve @@ -516,6 +611,7 @@ namespace Org.BouncyCastle.Math.EC protected readonly BigInteger m_q, m_r; protected readonly FpPoint m_infinity; + [Obsolete("Use constructor taking order/cofactor")] public FpCurve(BigInteger q, BigInteger a, BigInteger b) : this(q, a, b, null, null) { @@ -526,7 +622,7 @@ namespace Org.BouncyCastle.Math.EC { this.m_q = q; this.m_r = FpFieldElement.CalculateResidue(q); - this.m_infinity = new FpPoint(this, null, null); + this.m_infinity = new FpPoint(this, null, null, false); this.m_a = FromBigInteger(a); this.m_b = FromBigInteger(b); @@ -535,6 +631,7 @@ namespace Org.BouncyCastle.Math.EC this.m_coord = FP_DEFAULT_COORDS; } + [Obsolete("Use constructor taking order/cofactor")] protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) : this(q, r, a, b, null, null) { @@ -545,7 +642,7 @@ namespace Org.BouncyCastle.Math.EC { this.m_q = q; this.m_r = r; - this.m_infinity = new FpPoint(this, null, null); + this.m_infinity = new FpPoint(this, null, null, false); this.m_a = a; this.m_b = b; @@ -722,7 +819,7 @@ namespace Org.BouncyCastle.Math.EC else { ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp); - ECFieldElement z = SolveQuadradicEquation(beta); + ECFieldElement z = SolveQuadraticEquation(beta); if (z != null) { @@ -759,11 +856,11 @@ namespace Org.BouncyCastle.Math.EC * D.1.6) The other solution is <code>z + 1</code>. * * @param beta - * The value to solve the qradratic equation for. + * The value to solve the quadratic equation for. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or * <code>null</code> if no solution exists. */ - private ECFieldElement SolveQuadradicEquation(ECFieldElement beta) + internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta) { if (beta.IsZero) return beta; @@ -885,6 +982,7 @@ namespace Org.BouncyCastle.Math.EC * for non-supersingular elliptic curves over * <code>F<sub>2<sup>m</sup></sub></code>. */ + [Obsolete("Use constructor taking order/cofactor")] public F2mCurve( int m, int k, @@ -942,6 +1040,7 @@ namespace Org.BouncyCastle.Math.EC * for non-supersingular elliptic curves over * <code>F<sub>2<sup>m</sup></sub></code>. */ + [Obsolete("Use constructor taking order/cofactor")] public F2mCurve( int m, int k1, @@ -993,7 +1092,7 @@ namespace Org.BouncyCastle.Math.EC this.k3 = k3; this.m_order = order; this.m_cofactor = cofactor; - this.m_infinity = new F2mPoint(this, null, null); + this.m_infinity = new F2mPoint(this, null, null, false); if (k1 == 0) throw new ArgumentException("k1 must be > 0"); @@ -1027,7 +1126,7 @@ namespace Org.BouncyCastle.Math.EC this.m_order = order; this.m_cofactor = cofactor; - this.m_infinity = new F2mPoint(this, null, null); + this.m_infinity = new F2mPoint(this, null, null, false); this.m_a = a; this.m_b = b; this.m_coord = F2M_DEFAULT_COORDS; @@ -1116,16 +1215,69 @@ namespace Org.BouncyCastle.Math.EC get { return k3; } } - [Obsolete("Use 'Order' property instead")] - public BigInteger N + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) { - get { return m_order; } + int FE_LONGS = (m + 63) / 64; + + long[] table = new long[len * FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + ((F2mFieldElement)p.RawXCoord).x.CopyTo(table, pos); pos += FE_LONGS; + ((F2mFieldElement)p.RawYCoord).x.CopyTo(table, pos); pos += FE_LONGS; + } + } + + return new DefaultF2mLookupTable(this, table, len); } - [Obsolete("Use 'Cofactor' property instead")] - public BigInteger H + private class DefaultF2mLookupTable + : ECLookupTable { - get { return m_cofactor; } + private readonly F2mCurve m_outer; + private readonly long[] m_table; + private readonly int m_size; + + internal DefaultF2mLookupTable(F2mCurve outer, long[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + int m = m_outer.m; + int[] ks = m_outer.IsTrinomial() ? new int[]{ m_outer.k1 } : new int[]{ m_outer.k1, m_outer.k2, m_outer.k3 }; + + int FE_LONGS = (m_outer.m + 63) / 64; + long[] x = new long[FE_LONGS], y = new long[FE_LONGS]; + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + long MASK =((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + FE_LONGS + j] & MASK; + } + + pos += (FE_LONGS * 2); + } + + ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x)); + ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y)); + return m_outer.CreateRawPoint(X, Y, false); + } } } } diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs index d0e008aab..350e8c6d4 100644 --- a/crypto/src/math/ec/ECFieldElement.cs +++ b/crypto/src/math/ec/ECFieldElement.cs @@ -101,9 +101,14 @@ namespace Org.BouncyCastle.Math.EC } } - public class FpFieldElement + public abstract class AbstractFpFieldElement : ECFieldElement { + } + + public class FpFieldElement + : AbstractFpFieldElement + { private readonly BigInteger q, r, x; internal static BigInteger CalculateResidue(BigInteger p) @@ -536,6 +541,45 @@ namespace Org.BouncyCastle.Math.EC } } + public abstract class AbstractF2mFieldElement + : ECFieldElement + { + public virtual ECFieldElement HalfTrace() + { + int m = FieldSize; + if ((m & 1) == 0) + throw new InvalidOperationException("Half-trace only defined for odd m"); + + ECFieldElement fe = this; + ECFieldElement ht = fe; + for (int i = 2; i < m; i += 2) + { + fe = fe.SquarePow(2); + ht = ht.Add(fe); + } + + return ht; + } + + public virtual int Trace() + { + int m = FieldSize; + ECFieldElement fe = this; + ECFieldElement tr = fe; + for (int i = 1; i < m; ++i) + { + fe = fe.Square(); + tr = tr.Add(fe); + } + if (tr.IsZero) + return 0; + if (tr.IsOne) + return 1; + + throw new InvalidOperationException("Internal error in trace calculation"); + } + } + /** * Class representing the Elements of the finite field * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB) @@ -544,7 +588,7 @@ namespace Org.BouncyCastle.Math.EC * representation is not supported. */ public class F2mFieldElement - : ECFieldElement + : AbstractF2mFieldElement { /** * Indicates gaussian normal basis representation (GNB). Number chosen @@ -579,23 +623,24 @@ namespace Org.BouncyCastle.Math.EC /** * The <code>LongArray</code> holding the bits. */ - private LongArray x; + internal LongArray x; /** - * Constructor for Ppb. - * @param m The exponent <code>m</code> of - * <code>F<sub>2<sup>m</sup></sub></code>. - * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>. - * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>. - * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>. - * @param x The BigInteger representing the value of the field element. - */ + * Constructor for Ppb. + * @param m The exponent <code>m</code> of + * <code>F<sub>2<sup>m</sup></sub></code>. + * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>. + * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>. + * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>. + * @param x The BigInteger representing the value of the field element. + */ + [Obsolete("Use ECCurve.FromBigInteger to construct field elements")] public F2mFieldElement( int m, int k1, @@ -627,14 +672,15 @@ namespace Org.BouncyCastle.Math.EC } /** - * Constructor for Tpb. - * @param m The exponent <code>m</code> of - * <code>F<sub>2<sup>m</sup></sub></code>. - * @param k The integer <code>k</code> where <code>x<sup>m</sup> + - * x<sup>k</sup> + 1</code> represents the reduction - * polynomial <code>f(z)</code>. - * @param x The BigInteger representing the value of the field element. - */ + * Constructor for Tpb. + * @param m The exponent <code>m</code> of + * <code>F<sub>2<sup>m</sup></sub></code>. + * @param k The integer <code>k</code> where <code>x<sup>m</sup> + + * x<sup>k</sup> + 1</code> represents the reduction + * polynomial <code>f(z)</code>. + * @param x The BigInteger representing the value of the field element. + */ + [Obsolete("Use ECCurve.FromBigInteger to construct field elements")] public F2mFieldElement( int m, int k, @@ -644,7 +690,7 @@ namespace Org.BouncyCastle.Math.EC // Set k1 to k, and set k2 and k3 to 0 } - private F2mFieldElement(int m, int[] ks, LongArray x) + internal F2mFieldElement(int m, int[] ks, LongArray x) { this.m = m; this.representation = (ks.Length == 1) ? Tpb : Ppb; diff --git a/crypto/src/math/ec/ECLookupTable.cs b/crypto/src/math/ec/ECLookupTable.cs new file mode 100644 index 000000000..35995d426 --- /dev/null +++ b/crypto/src/math/ec/ECLookupTable.cs @@ -0,0 +1,10 @@ +using System; + +namespace Org.BouncyCastle.Math.EC +{ + public interface ECLookupTable + { + int Size { get; } + ECPoint Lookup(int index); + } +} diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs index a5ba515c5..2acc9f5c0 100644 --- a/crypto/src/math/ec/ECPoint.cs +++ b/crypto/src/math/ec/ECPoint.cs @@ -67,13 +67,19 @@ namespace Org.BouncyCastle.Math.EC this.m_withCompression = withCompression; } - protected internal bool SatisfiesCofactor() + protected abstract bool SatisfiesCurveEquation(); + + protected virtual bool SatisfiesOrder() { - BigInteger h = Curve.Cofactor; - return h == null || h.Equals(BigInteger.One) || !ECAlgorithms.ReferenceMultiply(this, h).IsInfinity; - } + if (BigInteger.One.Equals(Curve.Cofactor)) + return true; - protected abstract bool SatisfiesCurveEquation(); + BigInteger n = Curve.Order; + + // TODO Require order to be available for all curves + + return n == null || ECAlgorithms.ReferenceMultiply(this, n).IsInfinity; + } public ECPoint GetDetachedPoint() { @@ -97,30 +103,6 @@ namespace Org.BouncyCastle.Math.EC } /** - * Normalizes this point, and then returns the affine x-coordinate. - * - * Note: normalization can be expensive, this method is deprecated in favour - * of caller-controlled normalization. - */ - [Obsolete("Use AffineXCoord, or Normalize() and XCoord, instead")] - public virtual ECFieldElement X - { - get { return Normalize().XCoord; } - } - - /** - * Normalizes this point, and then returns the affine y-coordinate. - * - * Note: normalization can be expensive, this method is deprecated in favour - * of caller-controlled normalization. - */ - [Obsolete("Use AffineYCoord, or Normalize() and YCoord, instead")] - public virtual ECFieldElement Y - { - get { return Normalize().YCoord; } - } - - /** * Returns the affine x-coordinate after checking that this point is normalized. * * @return The affine x-coordinate of this point @@ -299,22 +281,22 @@ namespace Org.BouncyCastle.Math.EC public bool IsValid() { - if (IsInfinity) - return true; - - // TODO Sanity-check the field elements + return ImplIsValid(false, true); + } - ECCurve curve = Curve; - if (curve != null) - { - if (!SatisfiesCurveEquation()) - return false; + internal bool IsValidPartial() + { + return ImplIsValid(false, false); + } - if (!SatisfiesCofactor()) - return false; - } + internal bool ImplIsValid(bool decompressed, bool checkOrder) + { + if (IsInfinity) + return true; - return true; + ValidityCallback callback = new ValidityCallback(this, decompressed, checkOrder); + ValidityPreCompInfo validity = (ValidityPreCompInfo)Curve.Precompute(this, ValidityPreCompInfo.PRECOMP_NAME, callback); + return !validity.HasFailed(); } public virtual ECPoint ScaleX(ECFieldElement scale) @@ -462,6 +444,52 @@ namespace Org.BouncyCastle.Math.EC { return TwicePlus(this); } + + private class ValidityCallback + : IPreCompCallback + { + private readonly ECPoint m_outer; + private readonly bool m_decompressed, m_checkOrder; + + internal ValidityCallback(ECPoint outer, bool decompressed, bool checkOrder) + { + this.m_outer = outer; + this.m_decompressed = decompressed; + this.m_checkOrder = checkOrder; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + ValidityPreCompInfo info = existing as ValidityPreCompInfo; + if (info == null) + { + info = new ValidityPreCompInfo(); + } + + if (info.HasFailed()) + return info; + + if (!info.HasCurveEquationPassed()) + { + if (!m_decompressed && !m_outer.SatisfiesCurveEquation()) + { + info.ReportFailed(); + return info; + } + info.ReportCurveEquationPassed(); + } + if (m_checkOrder && !info.HasOrderPassed()) + { + if (!m_outer.SatisfiesOrder()) + { + info.ReportFailed(); + return info; + } + info.ReportOrderPassed(); + } + return info; + } + } } public abstract class ECPointBase @@ -608,6 +636,7 @@ namespace Org.BouncyCastle.Math.EC * @param x affine x co-ordinate * @param y affine y co-ordinate */ + [Obsolete("Use ECCurve.CreatePoint to construct points")] public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y) : this(curve, x, y, false) { @@ -621,6 +650,7 @@ namespace Org.BouncyCastle.Math.EC * @param y affine y co-ordinate * @param withCompression if true encode with point compression */ + [Obsolete("Per-point compression property will be removed, see GetEncoded(bool)")] public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { @@ -635,7 +665,7 @@ namespace Org.BouncyCastle.Math.EC protected override ECPoint Detach() { - return new FpPoint(null, AffineXCoord, AffineYCoord); + return new FpPoint(null, AffineXCoord, AffineYCoord, false); } public override ECFieldElement GetZCoord(int index) @@ -1384,6 +1414,46 @@ namespace Org.BouncyCastle.Math.EC return lhs.Equals(rhs); } + protected override bool SatisfiesOrder() + { + ECCurve curve = Curve; + BigInteger cofactor = curve.Cofactor; + if (BigInteger.Two.Equals(cofactor)) + { + /* + * Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A, + * and so a halving is possible, so this point is the double of another. + */ + ECPoint N = this.Normalize(); + ECFieldElement X = N.AffineXCoord; + ECFieldElement rhs = X.Add(curve.A); + return ((AbstractF2mFieldElement)rhs).Trace() == 0; + } + if (BigInteger.ValueOf(4).Equals(cofactor)) + { + /* + * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not). + * Generate both possibilities for the square of the half-point's x-coordinate (w), + * and check if Tr(w + A) == 0 for at least one; then a second halving is possible + * (see comments for cofactor 2 above), so this point is four times another. + * + * Note: Tr(x^2) == Tr(x). + */ + ECPoint N = this.Normalize(); + ECFieldElement X = N.AffineXCoord; + ECFieldElement lambda = ((AbstractF2mCurve)curve).SolveQuadraticEquation(X.Add(curve.A)); + if (lambda == null) + return false; + + ECFieldElement w = X.Multiply(lambda).Add(N.AffineYCoord); + ECFieldElement t = w.Add(curve.A); + return ((AbstractF2mFieldElement)t).Trace() == 0 + || ((AbstractF2mFieldElement)(t.Add(X))).Trace() == 0; + } + + return base.SatisfiesOrder(); + } + public override ECPoint ScaleX(ECFieldElement scale) { if (this.IsInfinity) @@ -1529,6 +1599,7 @@ namespace Org.BouncyCastle.Math.EC * @param x x point * @param y y point */ + [Obsolete("Use ECCurve.CreatePoint to construct points")] public F2mPoint( ECCurve curve, ECFieldElement x, @@ -1543,6 +1614,7 @@ namespace Org.BouncyCastle.Math.EC * @param y y point * @param withCompression true if encode with point compression. */ + [Obsolete("Per-point compression property will be removed, see GetEncoded(bool)")] public F2mPoint( ECCurve curve, ECFieldElement x, @@ -1573,19 +1645,9 @@ namespace Org.BouncyCastle.Math.EC { } - /** - * Constructor for point at infinity - */ - [Obsolete("Use ECCurve.Infinity property")] - public F2mPoint( - ECCurve curve) - : this(curve, null, null) - { - } - protected override ECPoint Detach() { - return new F2mPoint(null, AffineXCoord, AffineYCoord); + return new F2mPoint(null, AffineXCoord, AffineYCoord, false); } public override ECFieldElement YCoord diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs index 84462e0ea..a6b834fbe 100644 --- a/crypto/src/math/ec/LongArray.cs +++ b/crypto/src/math/ec/LongArray.cs @@ -372,6 +372,11 @@ namespace Org.BouncyCastle.Math.EC } } + internal void CopyTo(long[] z, int zOff) + { + Array.Copy(m_ints, 0, z, zOff, m_ints.Length); + } + public bool IsOne() { long[] a = m_ints; diff --git a/crypto/src/math/ec/SimpleLookupTable.cs b/crypto/src/math/ec/SimpleLookupTable.cs new file mode 100644 index 000000000..f1e32f215 --- /dev/null +++ b/crypto/src/math/ec/SimpleLookupTable.cs @@ -0,0 +1,35 @@ +using System; + +namespace Org.BouncyCastle.Math.EC +{ + public class SimpleLookupTable + : ECLookupTable + { + private static ECPoint[] Copy(ECPoint[] points, int off, int len) + { + ECPoint[] result = new ECPoint[len]; + for (int i = 0; i < len; ++i) + { + result[i] = points[off + i]; + } + return result; + } + + private readonly ECPoint[] points; + + public SimpleLookupTable(ECPoint[] points, int off, int len) + { + this.points = Copy(points, off, len); + } + + public virtual int Size + { + get { return points.Length; } + } + + public virtual ECPoint Lookup(int index) + { + return points[index]; + } + } +} diff --git a/crypto/src/math/ec/custom/djb/Curve25519.cs b/crypto/src/math/ec/custom/djb/Curve25519.cs index 6ed7c0648..c0f911a9c 100644 --- a/crypto/src/math/ec/custom/djb/Curve25519.cs +++ b/crypto/src/math/ec/custom/djb/Curve25519.cs @@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb public static readonly BigInteger q = Nat256.ToBigInteger(Curve25519Field.P); private const int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + private const int CURVE25519_FE_INTS = 8; protected readonly Curve25519Point m_infinity; @@ -73,5 +74,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb { return new Curve25519Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * CURVE25519_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy(((Curve25519FieldElement)p.RawXCoord).x, 0, table, pos); pos += CURVE25519_FE_INTS; + Nat256.Copy(((Curve25519FieldElement)p.RawYCoord).x, 0, table, pos); pos += CURVE25519_FE_INTS; + } + } + + return new Curve25519LookupTable(this, table, len); + } + + private class Curve25519LookupTable + : ECLookupTable + { + private readonly Curve25519 m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal Curve25519LookupTable(Curve25519 outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat256.Create(), y = Nat256.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < CURVE25519_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + CURVE25519_FE_INTS + j] & MASK; + } + + pos += (CURVE25519_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new Curve25519FieldElement(x), new Curve25519FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs index 732e9e468..37256a550 100644 --- a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs +++ b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Djb { internal class Curve25519FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = Curve25519.q; diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs index 70b1190c9..2c5d8f3a3 100644 --- a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs +++ b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.GM @@ -11,6 +12,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF")); private const int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SM2P256V1_FE_INTS = 8; protected readonly SM2P256V1Point m_infinity; @@ -73,5 +75,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM { return new SM2P256V1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SM2P256V1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy(((SM2P256V1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SM2P256V1_FE_INTS; + Nat256.Copy(((SM2P256V1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SM2P256V1_FE_INTS; + } + } + + return new SM2P256V1LookupTable(this, table, len); + } + + private class SM2P256V1LookupTable + : ECLookupTable + { + private readonly SM2P256V1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SM2P256V1LookupTable(SM2P256V1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat256.Create(), y = Nat256.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SM2P256V1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SM2P256V1_FE_INTS + j] & MASK; + } + + pos += (SM2P256V1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SM2P256V1FieldElement(x), new SM2P256V1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs index 4f6428f9e..087a040f2 100644 --- a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs +++ b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.GM { internal class SM2P256V1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SM2P256V1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs index 9da27b470..cc50f50d2 100644 --- a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF")); - private const int SecP128R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP128R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP128R1_FE_INTS = 4; protected readonly SecP128R1Point m_infinity; @@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFE0000000075A30D1B9038A115")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP128R1_DEFAULT_COORDS; + this.m_coord = SECP128R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -74,5 +76,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP128R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP128R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat128.Copy(((SecP128R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP128R1_FE_INTS; + Nat128.Copy(((SecP128R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP128R1_FE_INTS; + } + } + + return new SecP128R1LookupTable(this, table, len); + } + + private class SecP128R1LookupTable + : ECLookupTable + { + private readonly SecP128R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP128R1LookupTable(SecP128R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat128.Create(), y = Nat128.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP128R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP128R1_FE_INTS + j] & MASK; + } + + pos += (SECP128R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP128R1FieldElement(x), new SecP128R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs index fa7951d5d..5912a87e8 100644 --- a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP128R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP128R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs index 7d45c6227..234c86b87 100644 --- a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = SecP160R2Curve.q; private const int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP160K1_FE_INTS = 5; protected readonly SecP160K1Point m_infinity; @@ -70,5 +72,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP160K1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP160K1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat160.Copy(((SecP160R2FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP160K1_FE_INTS; + Nat160.Copy(((SecP160R2FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP160K1_FE_INTS; + } + } + + return new SecP160K1LookupTable(this, table, len); + } + + private class SecP160K1LookupTable + : ECLookupTable + { + private readonly SecP160K1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP160K1LookupTable(SecP160K1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat256.Create(), y = Nat256.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP160K1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP160K1_FE_INTS + j] & MASK; + } + + pos += (SECP160K1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs index 87389af36..958eb2765 100644 --- a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF")); - private const int SecP160R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP160R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP160R1_FE_INTS = 5; protected readonly SecP160R1Point m_infinity; @@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001F4C8F927AED3CA752257")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP160R1_DEFAULT_COORDS; + this.m_coord = SECP160R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -74,5 +76,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP160R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP160R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat160.Copy(((SecP160R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP160R1_FE_INTS; + Nat160.Copy(((SecP160R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP160R1_FE_INTS; + } + } + + return new SecP160R1LookupTable(this, table, len); + } + + private class SecP160R1LookupTable + : ECLookupTable + { + private readonly SecP160R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP160R1LookupTable(SecP160R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat160.Create(), y = Nat160.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP160R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP160R1_FE_INTS + j] & MASK; + } + + pos += (SECP160R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP160R1FieldElement(x), new SecP160R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs index d1fc75644..3ab11bdae 100644 --- a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP160R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP160R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs index 100561453..252312e62 100644 --- a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73")); - private const int SecP160R2_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP160R2_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP160R2_FE_INTS = 5; protected readonly SecP160R2Point m_infinity; @@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000000351EE786A818F3A1A16B")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP160R2_DEFAULT_COORDS; + this.m_coord = SECP160R2_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -74,5 +76,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP160R2Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP160R2_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat160.Copy(((SecP160R2FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP160R2_FE_INTS; + Nat160.Copy(((SecP160R2FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP160R2_FE_INTS; + } + } + + return new SecP160R2LookupTable(this, table, len); + } + + private class SecP160R2LookupTable + : ECLookupTable + { + private readonly SecP160R2Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP160R2LookupTable(SecP160R2Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat160.Create(), y = Nat160.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP160R2_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP160R2_FE_INTS + j] & MASK; + } + + pos += (SECP160R2_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs index bdb5245b2..9d8131857 100644 --- a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP160R2FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP160R2Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs index 81f77197e..518e0a131 100644 --- a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -11,6 +12,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37")); private const int SECP192K1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP192K1_FE_INTS = 6; protected readonly SecP192K1Point m_infinity; @@ -71,5 +73,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP192K1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP192K1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy(((SecP192K1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP192K1_FE_INTS; + Nat192.Copy(((SecP192K1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP192K1_FE_INTS; + } + } + + return new SecP192K1LookupTable(this, table, len); + } + + private class SecP192K1LookupTable + : ECLookupTable + { + private readonly SecP192K1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP192K1LookupTable(SecP192K1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat192.Create(), y = Nat192.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP192K1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP192K1_FE_INTS + j] & MASK; + } + + pos += (SECP192K1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs index dce377035..54b72573c 100644 --- a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs @@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP192K1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP192K1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs index cb3a981c8..91d31932a 100644 --- a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF")); - private const int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP192R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP192R1_FE_INTS = 6; protected readonly SecP192R1Point m_infinity; @@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP192R1_DEFAULT_COORDS; + this.m_coord = SECP192R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -74,5 +76,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP192R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP192R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy(((SecP192R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP192R1_FE_INTS; + Nat192.Copy(((SecP192R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP192R1_FE_INTS; + } + } + + return new SecP192R1LookupTable(this, table, len); + } + + private class SecP192R1LookupTable + : ECLookupTable + { + private readonly SecP192R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP192R1LookupTable(SecP192R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat192.Create(), y = Nat192.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP192R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP192R1_FE_INTS + j] & MASK; + } + + pos += (SECP192R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs index 45bcb00f0..f3e12b542 100644 --- a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP192R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP192R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs index d4be7d8de..a9c55090f 100644 --- a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -11,6 +12,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D")); private const int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP224K1_FE_INTS = 7; protected readonly SecP224K1Point m_infinity; @@ -71,5 +73,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP224K1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP224K1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat224.Copy(((SecP224K1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP224K1_FE_INTS; + Nat224.Copy(((SecP224K1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP224K1_FE_INTS; + } + } + + return new SecP224K1LookupTable(this, table, len); + } + + private class SecP224K1LookupTable + : ECLookupTable + { + private readonly SecP224K1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP224K1LookupTable(SecP224K1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat224.Create(), y = Nat224.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP224K1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP224K1_FE_INTS + j] & MASK; + } + + pos += (SECP224K1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs index fec07436a..ef53a88d6 100644 --- a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs @@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP224K1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP224K1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs index cda8781ff..ec34390aa 100644 --- a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")); - private const int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP224R1_FE_INTS = 7; protected readonly SecP224R1Point m_infinity; @@ -26,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP224R1_DEFAULT_COORDS; + this.m_coord = SECP224R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -74,5 +76,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP224R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP224R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat224.Copy(((SecP224R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP224R1_FE_INTS; + Nat224.Copy(((SecP224R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP224R1_FE_INTS; + } + } + + return new SecP224R1LookupTable(this, table, len); + } + + private class SecP224R1LookupTable + : ECLookupTable + { + private readonly SecP224R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP224R1LookupTable(SecP224R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat224.Create(), y = Nat224.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP224R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP224R1_FE_INTS + j] & MASK; + } + + pos += (SECP224R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs index 2b9a06564..5780b7481 100644 --- a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP224R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP224R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs index 59e2cefb2..b3a5dd646 100644 --- a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -11,6 +12,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")); private const int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP256K1_FE_INTS = 8; protected readonly SecP256K1Point m_infinity; @@ -71,5 +73,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP256K1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP256K1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy(((SecP256K1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP256K1_FE_INTS; + Nat256.Copy(((SecP256K1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP256K1_FE_INTS; + } + } + + return new SecP256K1LookupTable(this, table, len); + } + + private class SecP256K1LookupTable + : ECLookupTable + { + private readonly SecP256K1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP256K1LookupTable(SecP256K1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat256.Create(), y = Nat256.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP256K1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP256K1_FE_INTS + j] & MASK; + } + + pos += (SECP256K1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs index 473113d0f..9a604bdb7 100644 --- a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs @@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP256K1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP256K1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs index 6b3448f06..2d9a88b72 100644 --- a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")); - private const int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP256R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP256R1_FE_INTS = 8; protected readonly SecP256R1Point m_infinity; @@ -25,7 +27,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"))); this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP256R1_DEFAULT_COORDS; + this.m_coord = SECP256R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -73,5 +75,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP256R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP256R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy(((SecP256R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP256R1_FE_INTS; + Nat256.Copy(((SecP256R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP256R1_FE_INTS; + } + } + + return new SecP256R1LookupTable(this, table, len); + } + + private class SecP256R1LookupTable + : ECLookupTable + { + private readonly SecP256R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP256R1LookupTable(SecP256R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat256.Create(), y = Nat256.Create(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP256R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP256R1_FE_INTS + j] & MASK; + } + + pos += (SECP256R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs index d7838aead..808e99ea6 100644 --- a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP256R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP256R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs index 7fd58276a..26b057198 100644 --- a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")); - private const int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP384R1_FE_INTS = 12; protected readonly SecP384R1Point m_infinity; @@ -25,7 +27,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"))); this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP384R1_DEFAULT_COORDS; + this.m_coord = SECP384R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -73,5 +75,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP384R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP384R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat.Copy(SECP384R1_FE_INTS, ((SecP384R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP384R1_FE_INTS; + Nat.Copy(SECP384R1_FE_INTS, ((SecP384R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP384R1_FE_INTS; + } + } + + return new SecP384R1LookupTable(this, table, len); + } + + private class SecP384R1LookupTable + : ECLookupTable + { + private readonly SecP384R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP384R1LookupTable(SecP384R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat.Create(SECP384R1_FE_INTS), y = Nat.Create(SECP384R1_FE_INTS); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP384R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP384R1_FE_INTS + j] & MASK; + } + + pos += (SECP384R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs index 18d48a57d..7eedccae6 100644 --- a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP384R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP384R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs index e5083c7f0..810be85b5 100644 --- a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -10,7 +11,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public static readonly BigInteger q = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); - private const int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP521R1_DEFAULT_COORDS = COORD_JACOBIAN; + private const int SECP521R1_FE_INTS = 17; protected readonly SecP521R1Point m_infinity; @@ -25,7 +27,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec Hex.Decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"))); this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409")); this.m_cofactor = BigInteger.One; - this.m_coord = SecP521R1_DEFAULT_COORDS; + this.m_coord = SECP521R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -73,5 +75,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { return new SecP521R1Point(this, x, y, zs, withCompression); } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + uint[] table = new uint[len * SECP521R1_FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat.Copy(SECP521R1_FE_INTS, ((SecP521R1FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECP521R1_FE_INTS; + Nat.Copy(SECP521R1_FE_INTS, ((SecP521R1FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECP521R1_FE_INTS; + } + } + + return new SecP521R1LookupTable(this, table, len); + } + + private class SecP521R1LookupTable + : ECLookupTable + { + private readonly SecP521R1Curve m_outer; + private readonly uint[] m_table; + private readonly int m_size; + + internal SecP521R1LookupTable(SecP521R1Curve outer, uint[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + uint[] x = Nat.Create(SECP521R1_FE_INTS), y = Nat.Create(SECP521R1_FE_INTS); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + uint MASK = (uint)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECP521R1_FE_INTS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECP521R1_FE_INTS + j] & MASK; + } + + pos += (SECP521R1_FE_INTS * 2); + } + + return m_outer.CreateRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs index 6f02a7eb5..96658a8e5 100644 --- a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecP521R1FieldElement - : ECFieldElement + : AbstractFpFieldElement { public static readonly BigInteger Q = SecP521R1Curve.q; diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs index 9ba25d987..bb87b00fc 100644 --- a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT113FieldElement - : ECFieldElement + : AbstractF2mFieldElement { protected internal readonly ulong[] x; @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT113FieldElement(z); } + public override int Trace() + { + return (int)SecT113Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat128.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs index 2705c94aa..e85f68e60 100644 --- a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT113R1Curve : AbstractF2mCurve { - private const int SecT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT113R1_FE_LONGS = 2; protected readonly SecT113R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("0100000000000000D9CCEC8A39E56F")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT113R1_DEFAULT_COORDS; + this.m_coord = SECT113R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT113R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat128.Copy64(((SecT113FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT113R1_FE_LONGS; + Nat128.Copy64(((SecT113FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT113R1_FE_LONGS; + } + } + + return new SecT113R1LookupTable(this, table, len); + } + + private class SecT113R1LookupTable + : ECLookupTable + { + private readonly SecT113R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT113R1LookupTable(SecT113R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat128.Create64(), y = Nat128.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT113R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT113R1_FE_LONGS + j] & MASK; + } + + pos += (SECT113R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs index abfd26d5b..efe422806 100644 --- a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT113R2Curve : AbstractF2mCurve { - private const int SecT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT113R2_FE_LONGS = 2; protected readonly SecT113R2Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("010000000000000108789B2496AF93")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT113R2_DEFAULT_COORDS; + this.m_coord = SECT113R2_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT113R2_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat128.Copy64(((SecT113FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT113R2_FE_LONGS; + Nat128.Copy64(((SecT113FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT113R2_FE_LONGS; + } + } + + return new SecT113R2LookupTable(this, table, len); + } + + private class SecT113R2LookupTable + : ECLookupTable + { + private readonly SecT113R2Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT113R2LookupTable(SecT113R2Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat128.Create64(), y = Nat128.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT113R2_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT113R2_FE_LONGS + j] & MASK; + } + + pos += (SECT113R2_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs index e0ecc100f..f96c7ca39 100644 --- a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT131FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT131FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT131FieldElement(z); } + public override int Trace() + { + return (int)SecT131Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat192.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs index b73964c39..06f0a79ae 100644 --- a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT131R1Curve : AbstractF2mCurve { - private const int SecT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT131R1_FE_LONGS = 3; protected readonly SecT131R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("0400000000000000023123953A9464B54D")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT131R1_DEFAULT_COORDS; + this.m_coord = SECT131R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 8; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT131R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy64(((SecT131FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT131R1_FE_LONGS; + Nat192.Copy64(((SecT131FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT131R1_FE_LONGS; + } + } + + return new SecT131R1LookupTable(this, table, len); + } + + private class SecT131R1LookupTable + : ECLookupTable + { + private readonly SecT131R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT131R1LookupTable(SecT131R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat192.Create64(), y = Nat192.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT131R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT131R1_FE_LONGS + j] & MASK; + } + + pos += (SECT131R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs index 724921c94..0120b3059 100644 --- a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT131R2Curve : AbstractF2mCurve { - private const int SecT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT131R2_FE_LONGS = 3; protected readonly SecT131R2Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("0400000000000000016954A233049BA98F")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT131R2_DEFAULT_COORDS; + this.m_coord = SECT131R2_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 8; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT131R2_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy64(((SecT131FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT131R2_FE_LONGS; + Nat192.Copy64(((SecT131FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT131R2_FE_LONGS; + } + } + + return new SecT131R2LookupTable(this, table, len); + } + + private class SecT131R2LookupTable + : ECLookupTable + { + private readonly SecT131R2Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT131R2LookupTable(SecT131R2Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat192.Create64(), y = Nat192.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT131R2_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT131R2_FE_LONGS + j] & MASK; + } + + pos += (SECT131R2_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs index 8953fb529..903645999 100644 --- a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT163FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT163FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT163FieldElement(z); } + public override int Trace() + { + return (int)SecT163Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat192.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs index 68ff646ca..5e1431f46 100644 --- a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT163K1Curve : AbstractF2mCurve { - private const int SecT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163K1_FE_LONGS = 3; protected readonly SecT163K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("04000000000000000000020108A2E0CC0D99F8A5EF")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT163K1_DEFAULT_COORDS; + this.m_coord = SECT163K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 7; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT163K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy64(((SecT163FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT163K1_FE_LONGS; + Nat192.Copy64(((SecT163FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT163K1_FE_LONGS; + } + } + + return new SecT163K1LookupTable(this, table, len); + } + + private class SecT163K1LookupTable + : ECLookupTable + { + private readonly SecT163K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT163K1LookupTable(SecT163K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat192.Create64(), y = Nat192.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT163K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT163K1_FE_LONGS + j] & MASK; + } + + pos += (SECT163K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs index 8ae58ccef..e212ad4ea 100644 --- a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT163R1Curve : AbstractF2mCurve { - private const int SecT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163R1_FE_LONGS = 3; protected readonly SecT163R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT163R1_DEFAULT_COORDS; + this.m_coord = SECT163R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 7; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT163R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy64(((SecT163FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT163R1_FE_LONGS; + Nat192.Copy64(((SecT163FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT163R1_FE_LONGS; + } + } + + return new SecT163R1LookupTable(this, table, len); + } + + private class SecT163R1LookupTable + : ECLookupTable + { + private readonly SecT163R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT163R1LookupTable(SecT163R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat192.Create64(), y = Nat192.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT163R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT163R1_FE_LONGS + j] & MASK; + } + + pos += (SECT163R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs index 5a4fa5ad1..b0365388a 100644 --- a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT163R2Curve : AbstractF2mCurve { - private const int SecT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT163R2_FE_LONGS = 3; protected readonly SecT163R2Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("040000000000000000000292FE77E70C12A4234C33")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT163R2_DEFAULT_COORDS; + this.m_coord = SECT163R2_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 7; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT163R2_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.Copy64(((SecT163FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT163R2_FE_LONGS; + Nat192.Copy64(((SecT163FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT163R2_FE_LONGS; + } + } + + return new SecT163R2LookupTable(this, table, len); + } + + private class SecT163R2LookupTable + : ECLookupTable + { + private readonly SecT163R2Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT163R2LookupTable(SecT163R2Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat192.Create64(), y = Nat192.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT163R2_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT163R2_FE_LONGS + j] & MASK; + } + + pos += (SECT163R2_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs index a1150b3f9..9813bcb01 100644 --- a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT193FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT193FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT193FieldElement(z); } + public override int Trace() + { + return (int)SecT193Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat256.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs index a2cb5a8ac..e6cb3b4d8 100644 --- a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT193R1Curve : AbstractF2mCurve { - private const int SecT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT193R1_FE_LONGS = 4; protected readonly SecT193R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000C7F34A778F443ACC920EBA49")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT193R1_DEFAULT_COORDS; + this.m_coord = SECT193R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT193R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy64(((SecT193FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT193R1_FE_LONGS; + Nat256.Copy64(((SecT193FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT193R1_FE_LONGS; + } + } + + return new SecT193R1LookupTable(this, table, len); + } + + private class SecT193R1LookupTable + : ECLookupTable + { + private readonly SecT193R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT193R1LookupTable(SecT193R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat256.Create64(), y = Nat256.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT193R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT193R1_FE_LONGS + j] & MASK; + } + + pos += (SECT193R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs index 1c84a3eac..cfd690c65 100644 --- a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT193R2Curve : AbstractF2mCurve { - private const int SecT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT193R2_FE_LONGS = 4; protected readonly SecT193R2Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000015AAB561B005413CCD4EE99D5")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT193R2_DEFAULT_COORDS; + this.m_coord = SECT193R2_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT193R2_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy64(((SecT193FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT193R2_FE_LONGS; + Nat256.Copy64(((SecT193FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT193R2_FE_LONGS; + } + } + + return new SecT193R2LookupTable(this, table, len); + } + + private class SecT193R2LookupTable + : ECLookupTable + { + private readonly SecT193R2Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT193R2LookupTable(SecT193R2Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat256.Create64(), y = Nat256.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT193R2_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT193R2_FE_LONGS + j] & MASK; + } + + pos += (SECT193R2_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs index 91b8e2f1c..fbfe35e13 100644 --- a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT233FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT233FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT233FieldElement(z); } + public override int Trace() + { + return (int)SecT233Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat256.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs index 72935913d..07eae1564 100644 --- a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT233K1Curve : AbstractF2mCurve { - private const int SecT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT233K1_FE_LONGS = 4; protected readonly SecT233K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF")); this.m_cofactor = BigInteger.ValueOf(4); - this.m_coord = SecT233K1_DEFAULT_COORDS; + this.m_coord = SECT233K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT233K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy64(((SecT233FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT233K1_FE_LONGS; + Nat256.Copy64(((SecT233FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT233K1_FE_LONGS; + } + } + + return new SecT233K1LookupTable(this, table, len); + } + + private class SecT233K1LookupTable + : ECLookupTable + { + private readonly SecT233K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT233K1LookupTable(SecT233K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat256.Create64(), y = Nat256.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT233K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT233K1_FE_LONGS + j] & MASK; + } + + pos += (SECT233K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs index db6e6e1d4..5e8dee875 100644 --- a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT233R1Curve : AbstractF2mCurve { - private const int SecT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT233R1_FE_LONGS = 4; protected readonly SecT233R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT233R1_DEFAULT_COORDS; + this.m_coord = SECT233R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT233R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy64(((SecT233FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT233R1_FE_LONGS; + Nat256.Copy64(((SecT233FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT233R1_FE_LONGS; + } + } + + return new SecT233R1LookupTable(this, table, len); + } + + private class SecT233R1LookupTable + : ECLookupTable + { + private readonly SecT233R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT233R1LookupTable(SecT233R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat256.Create64(), y = Nat256.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT233R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT233R1_FE_LONGS + j] & MASK; + } + + pos += (SECT233R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs index a32ffc5d2..b1b58e89b 100644 --- a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT239FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected ulong[] x; + protected internal readonly ulong[] x; public SecT239FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT239FieldElement(z); } + public override int Trace() + { + return (int)SecT239Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat256.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs index a499d48b4..33792e631 100644 --- a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT239K1Curve : AbstractF2mCurve { - private const int SecT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT239K1_FE_LONGS = 4; protected readonly SecT239K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5")); this.m_cofactor = BigInteger.ValueOf(4); - this.m_coord = SecT239K1_DEFAULT_COORDS; + this.m_coord = SECT239K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT239K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.Copy64(((SecT239FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT239K1_FE_LONGS; + Nat256.Copy64(((SecT239FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT239K1_FE_LONGS; + } + } + + return new SecT239K1LookupTable(this, table, len); + } + + private class SecT239K1LookupTable + : ECLookupTable + { + private readonly SecT239K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT239K1LookupTable(SecT239K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat256.Create64(), y = Nat256.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT239K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT239K1_FE_LONGS + j] & MASK; + } + + pos += (SECT239K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT239FieldElement(x), new SecT239FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs index adfd4e0ed..c1bb2e30c 100644 --- a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT283FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT283FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT283FieldElement(z); } + public override int Trace() + { + return (int)SecT283Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat320.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs index 4053287ec..51725bc20 100644 --- a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT283K1Curve : AbstractF2mCurve { - private const int SecT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT283K1_FE_LONGS = 5; protected readonly SecT283K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61")); this.m_cofactor = BigInteger.ValueOf(4); - this.m_coord = SecT283K1_DEFAULT_COORDS; + this.m_coord = SECT283K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 12; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT283K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat320.Copy64(((SecT283FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT283K1_FE_LONGS; + Nat320.Copy64(((SecT283FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT283K1_FE_LONGS; + } + } + + return new SecT283K1LookupTable(this, table, len); + } + + private class SecT283K1LookupTable + : ECLookupTable + { + private readonly SecT283K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT283K1LookupTable(SecT283K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat320.Create64(), y = Nat320.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT283K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT283K1_FE_LONGS + j] & MASK; + } + + pos += (SECT283K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs index e659675ce..567df7686 100644 --- a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT283R1Curve : AbstractF2mCurve { - private const int SecT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT283R1_FE_LONGS = 5; protected readonly SecT283R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT283R1_DEFAULT_COORDS; + this.m_coord = SECT283R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 12; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT283R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat320.Copy64(((SecT283FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT283R1_FE_LONGS; + Nat320.Copy64(((SecT283FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT283R1_FE_LONGS; + } + } + + return new SecT283R1LookupTable(this, table, len); + } + + private class SecT283R1LookupTable + : ECLookupTable + { + private readonly SecT283R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT283R1LookupTable(SecT283R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat320.Create64(), y = Nat320.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT283R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT283R1_FE_LONGS + j] & MASK; + } + + pos += (SECT283R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs index f954f46e7..68a63312d 100644 --- a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT409FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected ulong[] x; + protected internal readonly ulong[] x; public SecT409FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT409FieldElement(z); } + public override int Trace() + { + return (int)SecT409Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat448.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs index 4f573553e..839ec8059 100644 --- a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT409K1Curve : AbstractF2mCurve { - private const int SecT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT409K1_FE_LONGS = 7; protected readonly SecT409K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF")); this.m_cofactor = BigInteger.ValueOf(4); - this.m_coord = SecT409K1_DEFAULT_COORDS; + this.m_coord = SECT409K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT409K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat448.Copy64(((SecT409FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT409K1_FE_LONGS; + Nat448.Copy64(((SecT409FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT409K1_FE_LONGS; + } + } + + return new SecT409K1LookupTable(this, table, len); + } + + private class SecT409K1LookupTable + : ECLookupTable + { + private readonly SecT409K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT409K1LookupTable(SecT409K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat448.Create64(), y = Nat448.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT409K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT409K1_FE_LONGS + j] & MASK; + } + + pos += (SECT409K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs index 9212fb5d2..f70dd5f8e 100644 --- a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT409R1Curve : AbstractF2mCurve { - private const int SecT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT409R1_FE_LONGS = 7; protected readonly SecT409R1Point m_infinity; @@ -21,7 +23,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT409R1_DEFAULT_COORDS; + this.m_coord = SECT409R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -94,5 +96,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 0; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT409R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat448.Copy64(((SecT409FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT409R1_FE_LONGS; + Nat448.Copy64(((SecT409FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT409R1_FE_LONGS; + } + } + + return new SecT409R1LookupTable(this, table, len); + } + + private class SecT409R1LookupTable + : ECLookupTable + { + private readonly SecT409R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT409R1LookupTable(SecT409R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat448.Create64(), y = Nat448.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT409R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT409R1_FE_LONGS + j] & MASK; + } + + pos += (SECT409R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs index c43b8dc3a..c9f3aa5c0 100644 --- a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs @@ -6,9 +6,9 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC.Custom.Sec { internal class SecT571FieldElement - : ECFieldElement + : AbstractF2mFieldElement { - protected readonly ulong[] x; + protected internal readonly ulong[] x; public SecT571FieldElement(BigInteger x) { @@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT571FieldElement(z); } + public override int Trace() + { + return (int)SecT571Field.Trace(x); + } + public override ECFieldElement Invert() { ulong[] z = Nat576.Create64(); diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs index f5806f09c..3d84797f7 100644 --- a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -8,7 +9,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT571K1Curve : AbstractF2mCurve { - private const int SecT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT571K1_FE_LONGS = 9; protected readonly SecT571K1Point m_infinity; @@ -22,7 +24,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001")); this.m_cofactor = BigInteger.ValueOf(4); - this.m_coord = SecT571K1_DEFAULT_COORDS; + this.m_coord = SECT571K1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -100,5 +102,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 10; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT571K1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat576.Copy64(((SecT571FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT571K1_FE_LONGS; + Nat576.Copy64(((SecT571FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT571K1_FE_LONGS; + } + } + + return new SecT571K1LookupTable(this, table, len); + } + + private class SecT571K1LookupTable + : ECLookupTable + { + private readonly SecT571K1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT571K1LookupTable(SecT571K1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat576.Create64(), y = Nat576.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT571K1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT571K1_FE_LONGS + j] & MASK; + } + + pos += (SECT571K1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs index 082afa5bd..7ebf90856 100644 --- a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Math.EC.Custom.Sec @@ -7,7 +8,8 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec internal class SecT571R1Curve : AbstractF2mCurve { - private const int SecT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private const int SECT571R1_FE_LONGS = 9; protected readonly SecT571R1Point m_infinity; @@ -25,7 +27,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47")); this.m_cofactor = BigInteger.Two; - this.m_coord = SecT571R1_DEFAULT_COORDS; + this.m_coord = SECT571R1_DEFAULT_COORDS; } protected override ECCurve CloneCurve() @@ -98,5 +100,62 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec { get { return 10; } } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + ulong[] table = new ulong[len * SECT571R1_FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat576.Copy64(((SecT571FieldElement)p.RawXCoord).x, 0, table, pos); pos += SECT571R1_FE_LONGS; + Nat576.Copy64(((SecT571FieldElement)p.RawYCoord).x, 0, table, pos); pos += SECT571R1_FE_LONGS; + } + } + + return new SecT571R1LookupTable(this, table, len); + } + + private class SecT571R1LookupTable + : ECLookupTable + { + private readonly SecT571R1Curve m_outer; + private readonly ulong[] m_table; + private readonly int m_size; + + internal SecT571R1LookupTable(SecT571R1Curve outer, ulong[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + ulong[] x = Nat576.Create64(), y = Nat576.Create64(); + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < SECT571R1_FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + SECT571R1_FE_LONGS + j] & MASK; + } + + pos += (SECT571R1_FE_LONGS * 2); + } + + return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false); + } + } } } diff --git a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs index 517881323..c2580c852 100644 --- a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs +++ b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs @@ -16,9 +16,14 @@ * Although the various multipliers ought not to produce invalid output under normal * circumstances, a final check here is advised to guard against fault attacks. */ - return ECAlgorithms.ValidatePoint(result); + return CheckResult(result); } protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k); + + protected virtual ECPoint CheckResult(ECPoint p) + { + return ECAlgorithms.ImplCheckResult(p); + } } } diff --git a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs index 05bb4000b..505832442 100644 --- a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs +++ b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs @@ -1,5 +1,7 @@ using System; +using Org.BouncyCastle.Math.Raw; + namespace Org.BouncyCastle.Math.EC.Multiplier { public class FixedPointCombMultiplier @@ -21,39 +23,34 @@ namespace Org.BouncyCastle.Math.EC.Multiplier throw new InvalidOperationException("fixed-point comb doesn't support scalars larger than the curve order"); } - int minWidth = GetWidthForCombSize(size); - - FixedPointPreCompInfo info = FixedPointUtilities.Precompute(p, minWidth); - ECPoint[] lookupTable = info.PreComp; + FixedPointPreCompInfo info = FixedPointUtilities.Precompute(p); + ECLookupTable lookupTable = info.LookupTable; int width = info.Width; int d = (size + width - 1) / width; ECPoint R = c.Infinity; - int top = d * width - 1; + int fullComb = d * width; + uint[] K = Nat.FromBigInteger(fullComb, k); + + int top = fullComb - 1; for (int i = 0; i < d; ++i) { - int index = 0; + int secretIndex = 0; for (int j = top - i; j >= 0; j -= d) { - index <<= 1; - if (k.TestBit(j)) - { - index |= 1; - } + secretIndex <<= 1; + secretIndex |= (int)Nat.GetBit(K, j); } - R = R.TwicePlus(lookupTable[index]); + ECPoint add = lookupTable.Lookup(secretIndex); + + R = R.TwicePlus(add); } return R.Add(info.Offset); } - - protected virtual int GetWidthForCombSize(int combSize) - { - return combSize > 257 ? 6 : 5; - } } } diff --git a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs index 11bdadc6f..5d6af9e5d 100644 --- a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs +++ b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs @@ -1,4 +1,6 @@ -namespace Org.BouncyCastle.Math.EC.Multiplier +using System; + +namespace Org.BouncyCastle.Math.EC.Multiplier { /** * Class holding precomputation data for fixed-point multiplications. @@ -9,10 +11,9 @@ protected ECPoint m_offset = null; /** - * Array holding the precomputed <code>ECPoint</code>s used for a fixed - * point multiplication. + * Lookup table for the precomputed <code>ECPoint</code>s used for a fixed point multiplication. */ - protected ECPoint[] m_preComp = null; + protected ECLookupTable m_lookupTable = null; /** * The width used for the precomputation. If a larger width precomputation @@ -21,18 +22,18 @@ */ protected int m_width = -1; + public virtual ECLookupTable LookupTable + { + get { return m_lookupTable; } + set { this.m_lookupTable = value; } + } + public virtual ECPoint Offset { get { return m_offset; } set { this.m_offset = value; } } - public virtual ECPoint[] PreComp - { - get { return m_preComp; } - set { this.m_preComp = value; } - } - public virtual int Width { get { return m_width; } diff --git a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs index 8e129a8f3..88f178e24 100644 --- a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs +++ b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs @@ -14,29 +14,40 @@ namespace Org.BouncyCastle.Math.EC.Multiplier public static FixedPointPreCompInfo GetFixedPointPreCompInfo(PreCompInfo preCompInfo) { - if ((preCompInfo != null) && (preCompInfo is FixedPointPreCompInfo)) - { - return (FixedPointPreCompInfo)preCompInfo; - } + return preCompInfo as FixedPointPreCompInfo; + } - return new FixedPointPreCompInfo(); + public static FixedPointPreCompInfo Precompute(ECPoint p) + { + return (FixedPointPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new FixedPointCallback(p)); } - public static FixedPointPreCompInfo Precompute(ECPoint p, int minWidth) + private class FixedPointCallback + : IPreCompCallback { - ECCurve c = p.Curve; + private readonly ECPoint m_p; - int n = 1 << minWidth; - FixedPointPreCompInfo info = GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME)); - ECPoint[] lookupTable = info.PreComp; + internal FixedPointCallback(ECPoint p) + { + this.m_p = p; + } - if (lookupTable == null || lookupTable.Length < n) + public PreCompInfo Precompute(PreCompInfo existing) { - int bits = GetCombSize(c); + FixedPointPreCompInfo existingFP = (existing is FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null; + + ECCurve c = m_p.Curve; + int bits = FixedPointUtilities.GetCombSize(c); + int minWidth = bits > 250 ? 6 : 5; + int n = 1 << minWidth; + + if (CheckExisting(existingFP, n)) + return existingFP; + int d = (bits + minWidth - 1) / minWidth; ECPoint[] pow2Table = new ECPoint[minWidth + 1]; - pow2Table[0] = p; + pow2Table[0] = m_p; for (int i = 1; i < minWidth; ++i) { pow2Table[i] = pow2Table[i - 1].TimesPow2(d); @@ -46,8 +57,8 @@ namespace Org.BouncyCastle.Math.EC.Multiplier pow2Table[minWidth] = pow2Table[0].Subtract(pow2Table[1]); c.NormalizeAll(pow2Table); - - lookupTable = new ECPoint[n]; + + ECPoint[] lookupTable = new ECPoint[n]; lookupTable[0] = pow2Table[0]; for (int bit = minWidth - 1; bit >= 0; --bit) @@ -63,14 +74,22 @@ namespace Org.BouncyCastle.Math.EC.Multiplier c.NormalizeAll(lookupTable); - info.Offset = pow2Table[minWidth]; - info.PreComp = lookupTable; - info.Width = minWidth; + FixedPointPreCompInfo result = new FixedPointPreCompInfo(); + result.LookupTable = c.CreateCacheSafeLookupTable(lookupTable, 0, lookupTable.Length); + result.Offset = pow2Table[minWidth]; + result.Width = minWidth; + return result; + } - c.SetPreCompInfo(p, PRECOMP_NAME, info); + private bool CheckExisting(FixedPointPreCompInfo existingFP, int n) + { + return existingFP != null && CheckTable(existingFP.LookupTable, n); } - return info; + private bool CheckTable(ECLookupTable table, int n) + { + return table != null && table.Size >= n; + } } } } diff --git a/crypto/src/math/ec/multiplier/IPreCompCallback.cs b/crypto/src/math/ec/multiplier/IPreCompCallback.cs new file mode 100644 index 000000000..e64ae834d --- /dev/null +++ b/crypto/src/math/ec/multiplier/IPreCompCallback.cs @@ -0,0 +1,9 @@ +using System; + +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + public interface IPreCompCallback + { + PreCompInfo Precompute(PreCompInfo existing); + } +} diff --git a/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs b/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs new file mode 100644 index 000000000..7ec2cbb95 --- /dev/null +++ b/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs @@ -0,0 +1,44 @@ +using System; + +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + internal class ValidityPreCompInfo + : PreCompInfo + { + internal static readonly string PRECOMP_NAME = "bc_validity"; + + private bool failed = false; + private bool curveEquationPassed = false; + private bool orderPassed = false; + + internal bool HasFailed() + { + return failed; + } + + internal void ReportFailed() + { + failed = true; + } + + internal bool HasCurveEquationPassed() + { + return curveEquationPassed; + } + + internal void ReportCurveEquationPassed() + { + curveEquationPassed = true; + } + + internal bool HasOrderPassed() + { + return orderPassed; + } + + internal void ReportOrderPassed() + { + orderPassed = true; + } + } +} diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs index 7d565dfbd..e893abd49 100644 --- a/crypto/src/math/ec/multiplier/WNafUtilities.cs +++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs @@ -287,12 +287,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo) { - if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo)) - { - return (WNafPreCompInfo)preCompInfo; - } - - return new WNafPreCompInfo(); + return preCompInfo as WNafPreCompInfo; } /** @@ -333,106 +328,178 @@ namespace Org.BouncyCastle.Math.EC.Multiplier WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated); ECPoint q = pointMap.Map(p); - WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME)); + c.Precompute(q, PRECOMP_NAME, new MapPointCallback(wnafPreCompP, includeNegated, pointMap)); + return q; + } - ECPoint twiceP = wnafPreCompP.Twice; - if (twiceP != null) - { - ECPoint twiceQ = pointMap.Map(twiceP); - wnafPreCompQ.Twice = twiceQ; - } + public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated) + { + return (WNafPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new WNafCallback(p, width, includeNegated)); + } + + private static byte[] Trim(byte[] a, int length) + { + byte[] result = new byte[length]; + Array.Copy(a, 0, result, 0, result.Length); + return result; + } + + private static int[] Trim(int[] a, int length) + { + int[] result = new int[length]; + Array.Copy(a, 0, result, 0, result.Length); + return result; + } + + private static ECPoint[] ResizeTable(ECPoint[] a, int length) + { + ECPoint[] result = new ECPoint[length]; + Array.Copy(a, 0, result, 0, a.Length); + return result; + } + + private class MapPointCallback + : IPreCompCallback + { + private readonly WNafPreCompInfo m_wnafPreCompP; + private readonly bool m_includeNegated; + private readonly ECPointMap m_pointMap; - ECPoint[] preCompP = wnafPreCompP.PreComp; - ECPoint[] preCompQ = new ECPoint[preCompP.Length]; - for (int i = 0; i < preCompP.Length; ++i) + internal MapPointCallback(WNafPreCompInfo wnafPreCompP, bool includeNegated, ECPointMap pointMap) { - preCompQ[i] = pointMap.Map(preCompP[i]); + this.m_wnafPreCompP = wnafPreCompP; + this.m_includeNegated = includeNegated; + this.m_pointMap = pointMap; } - wnafPreCompQ.PreComp = preCompQ; - if (includeNegated) + public PreCompInfo Precompute(PreCompInfo existing) { - ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length]; - for (int i = 0; i < preCompNegQ.Length; ++i) + WNafPreCompInfo result = new WNafPreCompInfo(); + + ECPoint twiceP = m_wnafPreCompP.Twice; + if (twiceP != null) { - preCompNegQ[i] = preCompQ[i].Negate(); + ECPoint twiceQ = m_pointMap.Map(twiceP); + result.Twice = twiceQ; } - wnafPreCompQ.PreCompNeg = preCompNegQ; - } - c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ); + ECPoint[] preCompP = m_wnafPreCompP.PreComp; + ECPoint[] preCompQ = new ECPoint[preCompP.Length]; + for (int i = 0; i < preCompP.Length; ++i) + { + preCompQ[i] = m_pointMap.Map(preCompP[i]); + } + result.PreComp = preCompQ; - return q; + if (m_includeNegated) + { + ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length]; + for (int i = 0; i < preCompNegQ.Length; ++i) + { + preCompNegQ[i] = preCompQ[i].Negate(); + } + result.PreCompNeg = preCompNegQ; + } + + return result; + } } - public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated) + private class WNafCallback + : IPreCompCallback { - ECCurve c = p.Curve; - WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME)); + private readonly ECPoint m_p; + private readonly int m_width; + private readonly bool m_includeNegated; - int iniPreCompLen = 0, reqPreCompLen = 1 << System.Math.Max(0, width - 2); - - ECPoint[] preComp = wnafPreCompInfo.PreComp; - if (preComp == null) + internal WNafCallback(ECPoint p, int width, bool includeNegated) { - preComp = EMPTY_POINTS; - } - else - { - iniPreCompLen = preComp.Length; + this.m_p = p; + this.m_width = width; + this.m_includeNegated = includeNegated; } - if (iniPreCompLen < reqPreCompLen) + public PreCompInfo Precompute(PreCompInfo existing) { - preComp = ResizeTable(preComp, reqPreCompLen); + WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo; + + int reqPreCompLen = 1 << System.Math.Max(0, m_width - 2); + + if (CheckExisting(existingWNaf, reqPreCompLen, m_includeNegated)) + return existingWNaf; - if (reqPreCompLen == 1) + ECCurve c = m_p.Curve; + ECPoint[] preComp = null, preCompNeg = null; + ECPoint twiceP = null; + + if (existingWNaf != null) + { + preComp = existingWNaf.PreComp; + preCompNeg = existingWNaf.PreCompNeg; + twiceP = existingWNaf.Twice; + } + + int iniPreCompLen = 0; + if (preComp == null) { - preComp[0] = p.Normalize(); + preComp = EMPTY_POINTS; } else { - int curPreCompLen = iniPreCompLen; - if (curPreCompLen == 0) - { - preComp[0] = p; - curPreCompLen = 1; - } + iniPreCompLen = preComp.Length; + } - ECFieldElement iso = null; + if (iniPreCompLen < reqPreCompLen) + { + preComp = WNafUtilities.ResizeTable(preComp, reqPreCompLen); - if (reqPreCompLen == 2) + if (reqPreCompLen == 1) { - preComp[1] = p.ThreeTimes(); + preComp[0] = m_p.Normalize(); } else { - ECPoint twiceP = wnafPreCompInfo.Twice, last = preComp[curPreCompLen - 1]; - if (twiceP == null) + int curPreCompLen = iniPreCompLen; + if (curPreCompLen == 0) + { + preComp[0] = m_p; + curPreCompLen = 1; + } + + ECFieldElement iso = null; + + if (reqPreCompLen == 2) + { + preComp[1] = m_p.ThreeTimes(); + } + else { - twiceP = preComp[0].Twice(); - wnafPreCompInfo.Twice = twiceP; - - /* - * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism - * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This - * also requires scaling the initial point's X, Y coordinates, and reversing the - * isomorphism as part of the subsequent normalization. - * - * NOTE: The correctness of this optimization depends on: - * 1) additions do not use the curve's A, B coefficients. - * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... - */ - if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64) + ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1]; + if (isoTwiceP == null) { - switch (c.CoordinateSystem) + isoTwiceP = preComp[0].Twice(); + twiceP = isoTwiceP; + + /* + * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism + * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This + * also requires scaling the initial point's X, Y coordinates, and reversing the + * isomorphism as part of the subsequent normalization. + * + * NOTE: The correctness of this optimization depends on: + * 1) additions do not use the curve's A, B coefficients. + * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... + */ + if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64) { + switch (c.CoordinateSystem) + { case ECCurve.COORD_JACOBIAN: case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: case ECCurve.COORD_JACOBIAN_MODIFIED: { iso = twiceP.GetZCoord(0); - twiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(), + isoTwiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(), twiceP.YCoord.ToBigInteger()); ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso); @@ -444,81 +511,69 @@ namespace Org.BouncyCastle.Math.EC.Multiplier } break; } + } } } - } - while (curPreCompLen < reqPreCompLen) - { - /* - * Compute the new ECPoints for the precomputation array. The values 1, 3, - * 5, ..., 2^(width-1)-1 times p are computed - */ - preComp[curPreCompLen++] = last = last.Add(twiceP); + while (curPreCompLen < reqPreCompLen) + { + /* + * Compute the new ECPoints for the precomputation array. The values 1, 3, + * 5, ..., 2^(width-1)-1 times p are computed + */ + preComp[curPreCompLen++] = last = last.Add(isoTwiceP); + } } - } - /* - * Having oft-used operands in affine form makes operations faster. - */ - c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); + /* + * Having oft-used operands in affine form makes operations faster. + */ + c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); + } } - } - - wnafPreCompInfo.PreComp = preComp; - - if (includeNegated) - { - ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg; - int pos; - if (preCompNeg == null) - { - pos = 0; - preCompNeg = new ECPoint[reqPreCompLen]; - } - else + if (m_includeNegated) { - pos = preCompNeg.Length; - if (pos < reqPreCompLen) + int pos; + if (preCompNeg == null) { - preCompNeg = ResizeTable(preCompNeg, reqPreCompLen); + pos = 0; + preCompNeg = new ECPoint[reqPreCompLen]; + } + else + { + pos = preCompNeg.Length; + if (pos < reqPreCompLen) + { + preCompNeg = WNafUtilities.ResizeTable(preCompNeg, reqPreCompLen); + } } - } - while (pos < reqPreCompLen) - { - preCompNeg[pos] = preComp[pos].Negate(); - ++pos; + while (pos < reqPreCompLen) + { + preCompNeg[pos] = preComp[pos].Negate(); + ++pos; + } } - wnafPreCompInfo.PreCompNeg = preCompNeg; + WNafPreCompInfo result = new WNafPreCompInfo(); + result.PreComp = preComp; + result.PreCompNeg = preCompNeg; + result.Twice = twiceP; + return result; } - c.SetPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo); - - return wnafPreCompInfo; - } - - private static byte[] Trim(byte[] a, int length) - { - byte[] result = new byte[length]; - Array.Copy(a, 0, result, 0, result.Length); - return result; - } - - private static int[] Trim(int[] a, int length) - { - int[] result = new int[length]; - Array.Copy(a, 0, result, 0, result.Length); - return result; - } + private bool CheckExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, bool includeNegated) + { + return existingWNaf != null + && CheckTable(existingWNaf.PreComp, reqPreCompLen) + && (!includeNegated || CheckTable(existingWNaf.PreCompNeg, reqPreCompLen)); + } - private static ECPoint[] ResizeTable(ECPoint[] a, int length) - { - ECPoint[] result = new ECPoint[length]; - Array.Copy(a, 0, result, 0, a.Length); - return result; + private bool CheckTable(ECPoint[] table, int reqLen) + { + return table != null && table.Length >= reqLen; + } } } } diff --git a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs index 1e7ddae91..4dce54440 100644 --- a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs +++ b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs @@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10); - return MultiplyWTnaf(p, rho, curve.GetPreCompInfo(p, PRECOMP_NAME), a, mu); + return MultiplyWTnaf(p, rho, a, mu); } /** @@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier * @return <code>p</code> multiplied by <code>λ</code>. */ private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda, - PreCompInfo preCompInfo, sbyte a, sbyte mu) + sbyte a, sbyte mu) { ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1; @@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width, BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha); - return MultiplyFromWTnaf(p, u, preCompInfo); + return MultiplyFromWTnaf(p, u); } /** @@ -71,24 +71,14 @@ namespace Org.BouncyCastle.Math.EC.Multiplier * @param u The the WTNAF of <code>λ</code>.. * @return <code>λ * p</code> */ - private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u, PreCompInfo preCompInfo) + private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u) { AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve; sbyte a = (sbyte)curve.A.ToBigInteger().IntValue; - AbstractF2mPoint[] pu; - if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo)) - { - pu = Tnaf.GetPreComp(p, a); - - WTauNafPreCompInfo pre = new WTauNafPreCompInfo(); - pre.PreComp = pu; - curve.SetPreCompInfo(p, PRECOMP_NAME, pre); - } - else - { - pu = ((WTauNafPreCompInfo)preCompInfo).PreComp; - } + WTauNafCallback callback = new WTauNafCallback(p, a); + WTauNafPreCompInfo preCompInfo = (WTauNafPreCompInfo)curve.Precompute(p, PRECOMP_NAME, callback); + AbstractF2mPoint[] pu = preCompInfo.PreComp; // TODO Include negations in precomp (optionally) and use from here AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length]; @@ -121,5 +111,28 @@ namespace Org.BouncyCastle.Math.EC.Multiplier } return q; } + + private class WTauNafCallback + : IPreCompCallback + { + private readonly AbstractF2mPoint m_p; + private readonly sbyte m_a; + + internal WTauNafCallback(AbstractF2mPoint p, sbyte a) + { + this.m_p = p; + this.m_a = a; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + if (existing is WTauNafPreCompInfo) + return existing; + + WTauNafPreCompInfo result = new WTauNafPreCompInfo(); + result.PreComp = Tnaf.GetPreComp(m_p, m_a); + return result; + } + } } } diff --git a/crypto/src/math/ec/rfc7748/X25519.cs b/crypto/src/math/ec/rfc7748/X25519.cs new file mode 100644 index 000000000..a10d53da5 --- /dev/null +++ b/crypto/src/math/ec/rfc7748/X25519.cs @@ -0,0 +1,237 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Org.BouncyCastle.Math.EC.Rfc7748 +{ + public abstract class X25519 + { + private const int C_A = 486662; + private const int C_A24 = (C_A + 2)/4; + + // 0x1 + //private static readonly int[] S_x = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + // 0x215132111D8354CB52385F46DCA2B71D440F6A51EB4D1207816B1E0137D48290 + private static readonly int[] PsubS_x = { 0x03D48290, 0x02C7804D, 0x01207816, 0x028F5A68, 0x00881ED4, 0x00A2B71D, + 0x0217D1B7, 0x014CB523, 0x0088EC1A, 0x0042A264 }; + + private static int[] precompBase = null; + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + private static void DecodeScalar(byte[] k, int kOff, uint[] n) + { + for (int i = 0; i < 8; ++i) + { + n[i] = Decode32(k, kOff + i * 4); + } + + n[0] &= 0xFFFFFFF8U; + n[7] &= 0x7FFFFFFFU; + n[7] |= 0x40000000U; + } + + private static void PointDouble(int[] x, int[] z) + { + int[] A = X25519Field.Create(); + int[] B = X25519Field.Create(); + + X25519Field.Apm(x, z, A, B); + X25519Field.Sqr(A, A); + X25519Field.Sqr(B, B); + X25519Field.Mul(A, B, x); + X25519Field.Sub(A, B, A); + X25519Field.Mul(A, C_A24, z); + X25519Field.Add(z, B, z); + X25519Field.Mul(z, A, z); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public static void Precompute() + { + if (precompBase != null) + return; + + precompBase = new int[X25519Field.Size * 252]; + + int[] xs = precompBase; + int[] zs = new int[X25519Field.Size * 251]; + + int[] x = X25519Field.Create(); x[0] = 9; + int[] z = X25519Field.Create(); z[0] = 1; + + int[] n = X25519Field.Create(); + int[] d = X25519Field.Create(); + + X25519Field.Apm(x, z, n, d); + + int[] c = X25519Field.Create(); X25519Field.Copy(d, 0, c, 0); + + int off = 0; + for (;;) + { + X25519Field.Copy(n, 0, xs, off); + + if (off == (X25519Field.Size * 251)) + break; + + PointDouble(x, z); + + X25519Field.Apm(x, z, n, d); + X25519Field.Mul(n, c, n); + X25519Field.Mul(c, d, c); + + X25519Field.Copy(d, 0, zs, off); + + off += X25519Field.Size; + } + + int[] u = X25519Field.Create(); + X25519Field.Inv(c, u); + + for (;;) + { + X25519Field.Copy(xs, off, x, 0); + + X25519Field.Mul(x, u, x); + //X25519Field.Normalize(x); + X25519Field.Copy(x, 0, precompBase, off); + + if (off == 0) + break; + + off -= X25519Field.Size; + X25519Field.Copy(zs, off, z, 0); + X25519Field.Mul(u, z, u); + } + } + + public static void ScalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) + { + uint[] n = new uint[8]; DecodeScalar(k, kOff, n); + + int[] x1 = X25519Field.Create(); X25519Field.Decode(u, uOff, x1); + int[] x2 = X25519Field.Create(); X25519Field.Copy(x1, 0, x2, 0); + int[] z2 = X25519Field.Create(); z2[0] = 1; + int[] x3 = X25519Field.Create(); x3[0] = 1; + int[] z3 = X25519Field.Create(); + + int[] t1 = X25519Field.Create(); + int[] t2 = X25519Field.Create(); + + Debug.Assert(n[7] >> 30 == 1U); + + int bit = 254, swap = 1; + do + { + X25519Field.Apm(x3, z3, t1, x3); + X25519Field.Apm(x2, z2, z3, x2); + X25519Field.Mul(t1, x2, t1); + X25519Field.Mul(x3, z3, x3); + X25519Field.Sqr(z3, z3); + X25519Field.Sqr(x2, x2); + + X25519Field.Sub(z3, x2, t2); + X25519Field.Mul(t2, C_A24, z2); + X25519Field.Add(z2, x2, z2); + X25519Field.Mul(z2, t2, z2); + X25519Field.Mul(x2, z3, x2); + + X25519Field.Apm(t1, x3, x3, z3); + X25519Field.Sqr(x3, x3); + X25519Field.Sqr(z3, z3); + X25519Field.Mul(z3, x1, z3); + + --bit; + + int word = bit >> 5, shift = bit & 0x1F; + int kt = (int)(n[word] >> shift) & 1; + swap ^= kt; + X25519Field.CSwap(swap, x2, x3); + X25519Field.CSwap(swap, z2, z3); + swap = kt; + } + while (bit >= 3); + + Debug.Assert(swap == 0); + + for (int i = 0; i < 3; ++i) + { + PointDouble(x2, z2); + } + + X25519Field.Inv(z2, z2); + X25519Field.Mul(x2, z2, x2); + + X25519Field.Normalize(x2); + X25519Field.Encode(x2, r, rOff); + } + + public static void ScalarMultBase(byte[] k, int kOff, byte[] r, int rOff) + { + Precompute(); + + uint[] n = new uint[8]; DecodeScalar(k, kOff, n); + + int[] x0 = X25519Field.Create(); + //int[] x1 = X25519Field.Create(); X25519Field.Copy(S_x, 0, x1, 0); + int[] x1 = X25519Field.Create(); x1[0] = 1; + int[] z1 = X25519Field.Create(); z1[0] = 1; + int[] x2 = X25519Field.Create(); X25519Field.Copy(PsubS_x, 0, x2, 0); + int[] z2 = X25519Field.Create(); z2[0] = 1; + + int[] A = x1; + int[] B = z1; + int[] C = x0; + int[] D = A; + int[] E = B; + + Debug.Assert(n[7] >> 30 == 1U); + + int off = 0, bit = 3, swap = 1; + do + { + X25519Field.Copy(precompBase, off, x0, 0); + off += X25519Field.Size; + + int word = bit >> 5, shift = bit & 0x1F; + int kt = (int)(n[word] >> shift) & 1; + swap ^= kt; + X25519Field.CSwap(swap, x1, x2); + X25519Field.CSwap(swap, z1, z2); + swap = kt; + + X25519Field.Apm(x1, z1, A, B); + X25519Field.Mul(x0, B, C); + X25519Field.Carry(A); + X25519Field.Apm(A, C, D, E); + X25519Field.Sqr(D, D); + X25519Field.Sqr(E, E); + X25519Field.Mul(z2, D, x1); + X25519Field.Mul(x2, E, z1); + } + while (++bit < 255); + + Debug.Assert(swap == 1); + + for (int i = 0; i < 3; ++i) + { + PointDouble(x1, z1); + } + + X25519Field.Inv(z1, z1); + X25519Field.Mul(x1, z1, x1); + + X25519Field.Normalize(x1); + X25519Field.Encode(x1, r, rOff); + } + } +} diff --git a/crypto/src/math/ec/rfc7748/X25519Field.cs b/crypto/src/math/ec/rfc7748/X25519Field.cs new file mode 100644 index 000000000..fd5599657 --- /dev/null +++ b/crypto/src/math/ec/rfc7748/X25519Field.cs @@ -0,0 +1,639 @@ +using System; +using System.Diagnostics; + +namespace Org.BouncyCastle.Math.EC.Rfc7748 +{ + public abstract class X25519Field + { + public const int Size = 10; + + private const int M24 = 0x00FFFFFF; + private const int M25 = 0x01FFFFFF; + private const int M26 = 0x03FFFFFF; + + private static readonly int[] RootNegOne = { 0x020EA0B0, 0x0386C9D2, 0x00478C4E, 0x0035697F, 0x005E8630, + 0x01FBD7A7, 0x0340264F, 0x01F0B2B4, 0x00027E0E, 0x00570649 }; + + private X25519Field() {} + + public static void Add(int[] x, int[] y, int[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = x[i] + y[i]; + } + } + + public static void AddOne(int[] z) + { + z[0] += 1; + } + + public static void AddOne(int[] z, int zOff) + { + z[zOff] += 1; + } + + public static void Apm(int[] x, int[] y, int[] zp, int[] zm) + { + for (int i = 0; i < Size; ++i) + { + int xi = x[i], yi = y[i]; + zp[i] = xi + yi; + zm[i] = xi - yi; + } + } + + public static void Carry(int[] z) + { + int z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4]; + int z5 = z[5], z6 = z[6], z7 = z[7], z8 = z[8], z9 = z[9]; + + z3 += (z2 >> 25); z2 &= M25; + z5 += (z4 >> 25); z4 &= M25; + z8 += (z7 >> 25); z7 &= M25; + //z0 += (z9 >> 24) * 19; z9 &= M24; + z0 += (z9 >> 25) * 38; z9 &= M25; + + z1 += (z0 >> 26); z0 &= M26; + z6 += (z5 >> 26); z5 &= M26; + + z2 += (z1 >> 26); z1 &= M26; + z4 += (z3 >> 26); z3 &= M26; + z7 += (z6 >> 26); z6 &= M26; + z9 += (z8 >> 26); z8 &= M26; + + z[0] = z0; z[1] = z1; z[2] = z2; z[3] = z3; z[4] = z4; + z[5] = z5; z[6] = z6; z[7] = z7; z[8] = z8; z[9] = z9; + } + + public static void CNegate(int negate, int[] z) + { + Debug.Assert(negate >> 1 == 0); + + int mask = 0 - negate; + for (int i = 0; i < Size; ++i) + { + z[i] = (z[i] ^ mask) - mask; + } + } + + public static void Copy(int[] x, int xOff, int[] z, int zOff) + { + for (int i = 0; i < Size; ++i) + { + z[zOff + i] = x[xOff + i]; + } + } + + public static int[] Create() + { + return new int[Size]; + } + + public static int[] CreateTable(int n) + { + return new int[Size * n]; + } + + public static void CSwap(int swap, int[] a, int[] b) + { + Debug.Assert(swap >> 1 == 0); + Debug.Assert(a != b); + + int mask = 0 - swap; + for (int i = 0; i < Size; ++i) + { + int ai = a[i], bi = b[i]; + int dummy = mask & (ai ^ bi); + a[i] = ai ^ dummy; + b[i] = bi ^ dummy; + } + } + + public static void Decode(byte[] x, int xOff, int[] z) + { + Decode128(x, xOff, z, 0); + Decode128(x, xOff + 16, z, 5); + z[9] &= M24; + } + + private static void Decode128(byte[] bs, int off, int[] z, int zOff) + { + uint t0 = Decode32(bs, off + 0); + uint t1 = Decode32(bs, off + 4); + uint t2 = Decode32(bs, off + 8); + uint t3 = Decode32(bs, off + 12); + + z[zOff + 0] = (int)t0 & M26; + z[zOff + 1] = (int)((t1 << 6) | (t0 >> 26)) & M26; + z[zOff + 2] = (int)((t2 << 12) | (t1 >> 20)) & M25; + z[zOff + 3] = (int)((t3 << 19) | (t2 >> 13)) & M26; + z[zOff + 4] = (int)(t3 >> 7); + } + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + public static void Encode(int[] x, byte[] z, int zOff) + { + Encode128(x, 0, z, zOff); + Encode128(x, 5, z, zOff + 16); + } + + private static void Encode128(int[] x, int xOff, byte[] bs, int off) + { + uint x0 = (uint)x[xOff + 0], x1 = (uint)x[xOff + 1], x2 = (uint)x[xOff + 2]; + uint x3 = (uint)x[xOff + 3], x4 = (uint)x[xOff + 4]; + + uint t0 = x0 | (x1 << 26); Encode32(t0, bs, off + 0); + uint t1 = (x1 >> 6) | (x2 << 20); Encode32(t1, bs, off + 4); + uint t2 = (x2 >> 12) | (x3 << 13); Encode32(t2, bs, off + 8); + uint t3 = (x3 >> 19) | (x4 << 7); Encode32(t3, bs, off + 12); + } + + private static void Encode32(uint n, byte[] bs, int off) + { + bs[ off] = (byte)(n ); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 24); + } + + public static void Inv(int[] x, int[] z) + { + // z = x^(p-2) = x^7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB + // (250 1s) (1 0s) (1 1s) (1 0s) (2 1s) + // Addition chain: [1] [2] 3 5 10 15 25 50 75 125 [250] + + int[] x2 = Create(); + int[] t = Create(); + PowPm5d8(x, x2, t); + Sqr(t, 3, t); + Mul(t, x2, z); + } + + public static bool IsZeroVar(int[] x) + { + int d = 0; + for (int i = 0; i < Size; ++i) + { + d |= x[i]; + } + return d == 0; + } + + public static void Mul(int[] x, int y, int[] z) + { + int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4]; + int x5 = x[5], x6 = x[6], x7 = x[7], x8 = x[8], x9 = x[9]; + long c0, c1, c2, c3; + + c0 = (long)x2 * y; x2 = (int)c0 & M25; c0 >>= 25; + c1 = (long)x4 * y; x4 = (int)c1 & M25; c1 >>= 25; + c2 = (long)x7 * y; x7 = (int)c2 & M25; c2 >>= 25; + //c3 = (long)x9 * y; x9 = (int)c3 & M24; c3 >>= 24; + //c3 *= 19; + c3 = (long)x9 * y; x9 = (int)c3 & M25; c3 >>= 25; + c3 *= 38; + + c3 += (long)x0 * y; z[0] = (int)c3 & M26; c3 >>= 26; + c1 += (long)x5 * y; z[5] = (int)c1 & M26; c1 >>= 26; + + c3 += (long)x1 * y; z[1] = (int)c3 & M26; c3 >>= 26; + c0 += (long)x3 * y; z[3] = (int)c0 & M26; c0 >>= 26; + c1 += (long)x6 * y; z[6] = (int)c1 & M26; c1 >>= 26; + c2 += (long)x8 * y; z[8] = (int)c2 & M26; c2 >>= 26; + + z[2] = x2 + (int)c3; + z[4] = x4 + (int)c0; + z[7] = x7 + (int)c1; + z[9] = x9 + (int)c2; + } + + public static void Mul(int[] x, int[] y, int[] z) + { + int x0 = x[0], y0 = y[0]; + int x1 = x[1], y1 = y[1]; + int x2 = x[2], y2 = y[2]; + int x3 = x[3], y3 = y[3]; + int x4 = x[4], y4 = y[4]; + + int u0 = x[5], v0 = y[5]; + int u1 = x[6], v1 = y[6]; + int u2 = x[7], v2 = y[7]; + int u3 = x[8], v3 = y[8]; + int u4 = x[9], v4 = y[9]; + + long a0 = (long)x0 * y0; + long a1 = (long)x0 * y1 + + (long)x1 * y0; + long a2 = (long)x0 * y2 + + (long)x1 * y1 + + (long)x2 * y0; + long a3 = (long)x1 * y2 + + (long)x2 * y1; + a3 <<= 1; + a3 += (long)x0 * y3 + + (long)x3 * y0; + long a4 = (long)x2 * y2; + a4 <<= 1; + a4 += (long)x0 * y4 + + (long)x1 * y3 + + (long)x3 * y1 + + (long)x4 * y0; + long a5 = (long)x1 * y4 + + (long)x2 * y3 + + (long)x3 * y2 + + (long)x4 * y1; + a5 <<= 1; + long a6 = (long)x2 * y4 + + (long)x4 * y2; + a6 <<= 1; + a6 += (long)x3 * y3; + long a7 = (long)x3 * y4 + + (long)x4 * y3; + long a8 = (long)x4 * y4; + a8 <<= 1; + + long b0 = (long)u0 * v0; + long b1 = (long)u0 * v1 + + (long)u1 * v0; + long b2 = (long)u0 * v2 + + (long)u1 * v1 + + (long)u2 * v0; + long b3 = (long)u1 * v2 + + (long)u2 * v1; + b3 <<= 1; + b3 += (long)u0 * v3 + + (long)u3 * v0; + long b4 = (long)u2 * v2; + b4 <<= 1; + b4 += (long)u0 * v4 + + (long)u1 * v3 + + (long)u3 * v1 + + (long)u4 * v0; + long b5 = (long)u1 * v4 + + (long)u2 * v3 + + (long)u3 * v2 + + (long)u4 * v1; + //b5 <<= 1; + long b6 = (long)u2 * v4 + + (long)u4 * v2; + b6 <<= 1; + b6 += (long)u3 * v3; + long b7 = (long)u3 * v4 + + (long)u4 * v3; + long b8 = (long)u4 * v4; + //b8 <<= 1; + + a0 -= b5 * 76; + a1 -= b6 * 38; + a2 -= b7 * 38; + a3 -= b8 * 76; + + a5 -= b0; + a6 -= b1; + a7 -= b2; + a8 -= b3; + //long a9 = -b4; + + x0 += u0; y0 += v0; + x1 += u1; y1 += v1; + x2 += u2; y2 += v2; + x3 += u3; y3 += v3; + x4 += u4; y4 += v4; + + long c0 = (long)x0 * y0; + long c1 = (long)x0 * y1 + + (long)x1 * y0; + long c2 = (long)x0 * y2 + + (long)x1 * y1 + + (long)x2 * y0; + long c3 = (long)x1 * y2 + + (long)x2 * y1; + c3 <<= 1; + c3 += (long)x0 * y3 + + (long)x3 * y0; + long c4 = (long)x2 * y2; + c4 <<= 1; + c4 += (long)x0 * y4 + + (long)x1 * y3 + + (long)x3 * y1 + + (long)x4 * y0; + long c5 = (long)x1 * y4 + + (long)x2 * y3 + + (long)x3 * y2 + + (long)x4 * y1; + c5 <<= 1; + long c6 = (long)x2 * y4 + + (long)x4 * y2; + c6 <<= 1; + c6 += (long)x3 * y3; + long c7 = (long)x3 * y4 + + (long)x4 * y3; + long c8 = (long)x4 * y4; + c8 <<= 1; + + int z8, z9; + long t; + + t = a8 + (c3 - a3); + z8 = (int)t & M26; t >>= 26; + //t += a9 + (c4 - a4); + t += (c4 - a4) - b4; + //z9 = (int)t & M24; t >>= 24; + //t = a0 + (t + ((c5 - a5) << 1)) * 19; + z9 = (int)t & M25; t >>= 25; + t = a0 + (t + c5 - a5) * 38; + z[0] = (int)t & M26; t >>= 26; + t += a1 + (c6 - a6) * 38; + z[1] = (int)t & M26; t >>= 26; + t += a2 + (c7 - a7) * 38; + z[2] = (int)t & M25; t >>= 25; + t += a3 + (c8 - a8) * 38; + z[3] = (int)t & M26; t >>= 26; + //t += a4 - a9 * 38; + t += a4 + b4 * 38; + z[4] = (int)t & M25; t >>= 25; + t += a5 + (c0 - a0); + z[5] = (int)t & M26; t >>= 26; + t += a6 + (c1 - a1); + z[6] = (int)t & M26; t >>= 26; + t += a7 + (c2 - a2); + z[7] = (int)t & M25; t >>= 25; + t += z8; + z[8] = (int)t & M26; t >>= 26; + z[9] = z9 + (int)t; + } + + public static void Negate(int[] x, int[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = -x[i]; + } + } + + public static void Normalize(int[] z) + { + int x = (z[9] >> 23) & 1; + Reduce(z, x); + Reduce(z, -x); + Debug.Assert(z[9] >> 24 == 0); + } + + public static void One(int[] z) + { + z[0] = 1; + for (int i = 1; i < Size; ++i) + { + z[i] = 0; + } + } + + private static void PowPm5d8(int[] x, int[] rx2, int[] rz) + { + // z = x^((p-5)/8) = x^FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD + // (250 1s) (1 0s) (1 1s) + // Addition chain: [1] 2 3 5 10 15 25 50 75 125 [250] + + int[] x2 = rx2; Sqr(x, x2); Mul(x, x2, x2); + int[] x3 = Create(); Sqr(x2, x3); Mul(x, x3, x3); + int[] x5 = x3; Sqr(x3, 2, x5); Mul(x2, x5, x5); + int[] x10 = Create(); Sqr(x5, 5, x10); Mul(x5, x10, x10); + int[] x15 = Create(); Sqr(x10, 5, x15); Mul(x5, x15, x15); + int[] x25 = x5; Sqr(x15, 10, x25); Mul(x10, x25, x25); + int[] x50 = x10; Sqr(x25, 25, x50); Mul(x25, x50, x50); + int[] x75 = x15; Sqr(x50, 25, x75); Mul(x25, x75, x75); + int[] x125 = x25; Sqr(x75, 50, x125); Mul(x50, x125, x125); + int[] x250 = x50; Sqr(x125, 125, x250); Mul(x125, x250, x250); + + int[] t = x125; + Sqr(x250, 2, t); + Mul(t, x, rz); + } + + private static void Reduce(int[] z, int c) + { + int z9 = z[9], t = z9; + z9 = t & M24; t >>= 24; + t += c; + t *= 19; + t += z[0]; z[0] = t & M26; t >>= 26; + t += z[1]; z[1] = t & M26; t >>= 26; + t += z[2]; z[2] = t & M25; t >>= 25; + t += z[3]; z[3] = t & M26; t >>= 26; + t += z[4]; z[4] = t & M25; t >>= 25; + t += z[5]; z[5] = t & M26; t >>= 26; + t += z[6]; z[6] = t & M26; t >>= 26; + t += z[7]; z[7] = t & M25; t >>= 25; + t += z[8]; z[8] = t & M26; t >>= 26; + t += z9; z[9] = t; + } + + public static void Sqr(int[] x, int[] z) + { + int x0 = x[0]; + int x1 = x[1]; + int x2 = x[2]; + int x3 = x[3]; + int x4 = x[4]; + + int u0 = x[5]; + int u1 = x[6]; + int u2 = x[7]; + int u3 = x[8]; + int u4 = x[9]; + + int x1_2 = x1 * 2; + int x2_2 = x2 * 2; + int x3_2 = x3 * 2; + int x4_2 = x4 * 2; + + long a0 = (long)x0 * x0; + long a1 = (long)x0 * x1_2; + long a2 = (long)x0 * x2_2 + + (long)x1 * x1; + long a3 = (long)x1_2 * x2_2 + + (long)x0 * x3_2; + long a4 = (long)x2 * x2_2 + + (long)x0 * x4_2 + + (long)x1 * x3_2; + long a5 = (long)x1_2 * x4_2 + + (long)x2_2 * x3_2; + long a6 = (long)x2_2 * x4_2 + + (long)x3 * x3; + long a7 = (long)x3 * x4_2; + long a8 = (long)x4 * x4_2; + + int u1_2 = u1 * 2; + int u2_2 = u2 * 2; + int u3_2 = u3 * 2; + int u4_2 = u4 * 2; + + long b0 = (long)u0 * u0; + long b1 = (long)u0 * u1_2; + long b2 = (long)u0 * u2_2 + + (long)u1 * u1; + long b3 = (long)u1_2 * u2_2 + + (long)u0 * u3_2; + long b4 = (long)u2 * u2_2 + + (long)u0 * u4_2 + + (long)u1 * u3_2; + long b5 = (long)u1_2 * u4_2 + + (long)u2_2 * u3_2; + long b6 = (long)u2_2 * u4_2 + + (long)u3 * u3; + long b7 = (long)u3 * u4_2; + long b8 = (long)u4 * u4_2; + + a0 -= b5 * 38; + a1 -= b6 * 38; + a2 -= b7 * 38; + a3 -= b8 * 38; + + a5 -= b0; + a6 -= b1; + a7 -= b2; + a8 -= b3; + //long a9 = -b4; + + x0 += u0; + x1 += u1; + x2 += u2; + x3 += u3; + x4 += u4; + + x1_2 = x1 * 2; + x2_2 = x2 * 2; + x3_2 = x3 * 2; + x4_2 = x4 * 2; + + long c0 = (long)x0 * x0; + long c1 = (long)x0 * x1_2; + long c2 = (long)x0 * x2_2 + + (long)x1 * x1; + long c3 = (long)x1_2 * x2_2 + + (long)x0 * x3_2; + long c4 = (long)x2 * x2_2 + + (long)x0 * x4_2 + + (long)x1 * x3_2; + long c5 = (long)x1_2 * x4_2 + + (long)x2_2 * x3_2; + long c6 = (long)x2_2 * x4_2 + + (long)x3 * x3; + long c7 = (long)x3 * x4_2; + long c8 = (long)x4 * x4_2; + + int z8, z9; + long t; + + t = a8 + (c3 - a3); + z8 = (int)t & M26; t >>= 26; + //t += a9 + (c4 - a4); + t += (c4 - a4) - b4; + //z9 = (int)t & M24; t >>= 24; + //t = a0 + (t + ((c5 - a5) << 1)) * 19; + z9 = (int)t & M25; t >>= 25; + t = a0 + (t + c5 - a5) * 38; + z[0] = (int)t & M26; t >>= 26; + t += a1 + (c6 - a6) * 38; + z[1] = (int)t & M26; t >>= 26; + t += a2 + (c7 - a7) * 38; + z[2] = (int)t & M25; t >>= 25; + t += a3 + (c8 - a8) * 38; + z[3] = (int)t & M26; t >>= 26; + //t += a4 - a9 * 38; + t += a4 + b4 * 38; + z[4] = (int)t & M25; t >>= 25; + t += a5 + (c0 - a0); + z[5] = (int)t & M26; t >>= 26; + t += a6 + (c1 - a1); + z[6] = (int)t & M26; t >>= 26; + t += a7 + (c2 - a2); + z[7] = (int)t & M25; t >>= 25; + t += z8; + z[8] = (int)t & M26; t >>= 26; + z[9] = z9 + (int)t; + } + + public static void Sqr(int[] x, int n, int[] z) + { + Debug.Assert(n > 0); + + Sqr(x, z); + + while (--n > 0) + { + Sqr(z, z); + } + } + + public static bool SqrtRatioVar(int[] u, int[] v, int[] z) + { + int[] uv3 = Create(); + int[] uv7 = Create(); + + Mul(u, v, uv3); + Sqr(v, uv7); + Mul(uv3, uv7, uv3); + Sqr(uv7, uv7); + Mul(uv7, uv3, uv7); + + int[] t = Create(); + int[] x = Create(); + PowPm5d8(uv7, t, x); + Mul(x, uv3, x); + + int[] vx2 = Create(); + Sqr(x, vx2); + Mul(vx2, v, vx2); + + Sub(vx2, u, t); + Normalize(t); + if (IsZeroVar(t)) + { + Copy(x, 0, z, 0); + return true; + } + + Add(vx2, u, t); + Normalize(t); + if (IsZeroVar(t)) + { + Mul(x, RootNegOne, z); + return true; + } + + return false; + } + + public static void Sub(int[] x, int[] y, int[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = x[i] - y[i]; + } + } + + public static void SubOne(int[] z) + { + z[0] -= 1; + } + + public static void Zero(int[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = 0; + } + } + } +} diff --git a/crypto/src/math/ec/rfc7748/X448.cs b/crypto/src/math/ec/rfc7748/X448.cs new file mode 100644 index 000000000..88e8a5d76 --- /dev/null +++ b/crypto/src/math/ec/rfc7748/X448.cs @@ -0,0 +1,255 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Org.BouncyCastle.Math.EC.Rfc7748 +{ + public abstract class X448 + { + private const uint C_A = 156326; + private const uint C_A24 = (C_A + 2)/4; + + // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE + private static readonly uint[] S_x = { 0x0FFFFFFEU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, + 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFEU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, 0x0FFFFFFFU, + 0x0FFFFFFFU }; + + // 0xF0FAB725013244423ACF03881AFFEB7BDACDD1031C81B9672954459D84C1F823F1BD65643ACE1B5123AC33FF1C69BAF8ACB1197DC99D2720 + private static readonly uint[] PsubS_x = { 0x099D2720U, 0x0B1197DCU, 0x09BAF8ACU, 0x033FF1C6U, 0x0B5123ACU, + 0x0643ACE1U, 0x03F1BD65U, 0x084C1F82U, 0x0954459DU, 0x081B9672U, 0x0DD1031CU, 0x0EB7BDACU, 0x03881AFFU, 0x0423ACF0U, + 0x05013244U, 0x0F0FAB72U }; + + private static uint[] precompBase = null; + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + private static void DecodeScalar(byte[] k, int kOff, uint[] n) + { + for (int i = 0; i < 14; ++i) + { + n[i] = Decode32(k, kOff + i * 4); + } + + n[ 0] &= 0xFFFFFFFCU; + n[13] |= 0x80000000U; + } + + private static void PointDouble(uint[] x, uint[] z) + { + uint[] A = X448Field.Create(); + uint[] B = X448Field.Create(); + + //X448Field.Apm(x, z, A, B); + X448Field.Add(x, z, A); + X448Field.Sub(x, z, B); + X448Field.Sqr(A, A); + X448Field.Sqr(B, B); + X448Field.Mul(A, B, x); + X448Field.Sub(A, B, A); + X448Field.Mul(A, C_A24, z); + X448Field.Add(z, B, z); + X448Field.Mul(z, A, z); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public static void Precompute() + { + if (precompBase != null) + return; + + precompBase = new uint[X448Field.Size * 446]; + + uint[] xs = precompBase; + uint[] zs = new uint[X448Field.Size * 445]; + + uint[] x = X448Field.Create(); x[0] = 5; + uint[] z = X448Field.Create(); z[0] = 1; + + uint[] n = X448Field.Create(); + uint[] d = X448Field.Create(); + + //X448Field.Apm(x, z, n, d); + X448Field.Add(x, z, n); + X448Field.Sub(x, z, d); + + uint[] c = X448Field.Create(); X448Field.Copy(d, 0, c, 0); + + int off = 0; + for (;;) + { + X448Field.Copy(n, 0, xs, off); + + if (off == (X448Field.Size * 445)) + break; + + PointDouble(x, z); + + //X448Field.Apm(x, z, n, d); + X448Field.Add(x, z, n); + X448Field.Sub(x, z, d); + X448Field.Mul(n, c, n); + X448Field.Mul(c, d, c); + + X448Field.Copy(d, 0, zs, off); + + off += X448Field.Size; + } + + uint[] u = X448Field.Create(); + X448Field.Inv(c, u); + + for (;;) + { + X448Field.Copy(xs, off, x, 0); + + X448Field.Mul(x, u, x); + //X448Field.Normalize(x); + X448Field.Copy(x, 0, precompBase, off); + + if (off == 0) + break; + + off -= X448Field.Size; + X448Field.Copy(zs, off, z, 0); + X448Field.Mul(u, z, u); + } + } + + public static void ScalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) + { + uint[] n = new uint[14]; DecodeScalar(k, kOff, n); + + uint[] x1 = X448Field.Create(); X448Field.Decode(u, uOff, x1); + uint[] x2 = X448Field.Create(); X448Field.Copy(x1, 0, x2, 0); + uint[] z2 = X448Field.Create(); z2[0] = 1; + uint[] x3 = X448Field.Create(); x3[0] = 1; + uint[] z3 = X448Field.Create(); + + uint[] t1 = X448Field.Create(); + uint[] t2 = X448Field.Create(); + + Debug.Assert(n[13] >> 31 == 1U); + + int bit = 447, swap = 1; + do + { + //X448Field.Apm(x3, z3, t1, x3); + X448Field.Add(x3, z3, t1); + X448Field.Sub(x3, z3, x3); + //X448Field.Apm(x2, z2, z3, x2); + X448Field.Add(x2, z2, z3); + X448Field.Sub(x2, z2, x2); + + X448Field.Mul(t1, x2, t1); + X448Field.Mul(x3, z3, x3); + X448Field.Sqr(z3, z3); + X448Field.Sqr(x2, x2); + + X448Field.Sub(z3, x2, t2); + X448Field.Mul(t2, C_A24, z2); + X448Field.Add(z2, x2, z2); + X448Field.Mul(z2, t2, z2); + X448Field.Mul(x2, z3, x2); + + //X448Field.Apm(t1, x3, x3, z3); + X448Field.Sub(t1, x3, z3); + X448Field.Add(t1, x3, x3); + X448Field.Sqr(x3, x3); + X448Field.Sqr(z3, z3); + X448Field.Mul(z3, x1, z3); + + --bit; + + int word = bit >> 5, shift = bit & 0x1F; + int kt = (int)(n[word] >> shift) & 1; + swap ^= kt; + X448Field.CSwap(swap, x2, x3); + X448Field.CSwap(swap, z2, z3); + swap = kt; + } + while (bit >= 2); + + Debug.Assert(swap == 0); + + for (int i = 0; i < 2; ++i) + { + PointDouble(x2, z2); + } + + X448Field.Inv(z2, z2); + X448Field.Mul(x2, z2, x2); + + X448Field.Normalize(x2); + X448Field.Encode(x2, r, rOff); + } + + public static void ScalarMultBase(byte[] k, int kOff, byte[] r, int rOff) + { + Precompute(); + + uint[] n = new uint[14]; DecodeScalar(k, kOff, n); + + uint[] x0 = X448Field.Create(); + uint[] x1 = X448Field.Create(); X448Field.Copy(S_x, 0, x1, 0); + uint[] z1 = X448Field.Create(); z1[0] = 1; + uint[] x2 = X448Field.Create(); X448Field.Copy(PsubS_x, 0, x2, 0); + uint[] z2 = X448Field.Create(); z2[0] = 1; + + uint[] A = X448Field.Create(); + uint[] B = z1; + uint[] C = x0; + uint[] D = x1; + uint[] E = B; + + Debug.Assert(n[13] >> 31 == 1U); + + int off = 0, bit = 2, swap = 1; + do + { + X448Field.Copy(precompBase, off, x0, 0); + off += X448Field.Size; + + int word = bit >> 5, shift = bit & 0x1F; + int kt = (int)(n[word] >> shift) & 1; + swap ^= kt; + X448Field.CSwap(swap, x1, x2); + X448Field.CSwap(swap, z1, z2); + swap = kt; + + //X448Field.Apm(x1, z1, A, B); + X448Field.Add(x1, z1, A); + X448Field.Sub(x1, z1, B); + X448Field.Mul(x0, B, C); + X448Field.Carry(A); + //X448Field.Apm(A, C, D, E); + X448Field.Add(A, C, D); + X448Field.Sub(A, C, E); + X448Field.Sqr(D, D); + X448Field.Sqr(E, E); + X448Field.Mul(z2, D, x1); + X448Field.Mul(x2, E, z1); + } + while (++bit < 448); + + Debug.Assert(swap == 1); + + for (int i = 0; i < 2; ++i) + { + PointDouble(x1, z1); + } + + X448Field.Inv(z1, z1); + X448Field.Mul(x1, z1, x1); + + X448Field.Normalize(x1); + X448Field.Encode(x1, r, rOff); + } + } +} diff --git a/crypto/src/math/ec/rfc7748/X448Field.cs b/crypto/src/math/ec/rfc7748/X448Field.cs new file mode 100644 index 000000000..5a682714d --- /dev/null +++ b/crypto/src/math/ec/rfc7748/X448Field.cs @@ -0,0 +1,1001 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Math.Raw; + +namespace Org.BouncyCastle.Math.EC.Rfc7748 +{ + [CLSCompliantAttribute(false)] + public abstract class X448Field + { + public const int Size = 16; + + private const uint M28 = 0x0FFFFFFFU; + + private X448Field() {} + + public static void Add(uint[] x, uint[] y, uint[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = x[i] + y[i]; + } + } + + public static void AddOne(uint[] z) + { + z[0] += 1; + } + + public static void AddOne(uint[] z, int zOff) + { + z[zOff] += 1; + } + + //public static void Apm(int[] x, int[] y, int[] zp, int[] zm) + //{ + // for (int i = 0; i < Size; ++i) + // { + // int xi = x[i], yi = y[i]; + // zp[i] = xi + yi; + // zm[i] = xi - yi; + // } + //} + + public static void Carry(uint[] z) + { + uint z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4], z5 = z[5], z6 = z[6], z7 = z[7]; + uint z8 = z[8], z9 = z[9], z10 = z[10], z11 = z[11], z12 = z[12], z13 = z[13], z14 = z[14], z15 = z[15]; + + z2 += (z1 >> 28); z1 &= M28; + z6 += (z5 >> 28); z5 &= M28; + z10 += (z9 >> 28); z9 &= M28; + z14 += (z13 >> 28); z13 &= M28; + + z3 += (z2 >> 28); z2 &= M28; + z7 += (z6 >> 28); z6 &= M28; + z11 += (z10 >> 28); z10 &= M28; + z15 += (z14 >> 28); z14 &= M28; + + uint t = z15 >> 28; z15 &= M28; + z0 += t; + z8 += t; + + z4 += (z3 >> 28); z3 &= M28; + z8 += (z7 >> 28); z7 &= M28; + z12 += (z11 >> 28); z11 &= M28; + + z1 += (z0 >> 28); z0 &= M28; + z5 += (z4 >> 28); z4 &= M28; + z9 += (z8 >> 28); z8 &= M28; + z13 += (z12 >> 28); z12 &= M28; + + z[0] = z0; z[1] = z1; z[2] = z2; z[3] = z3; z[4] = z4; z[5] = z5; z[6] = z6; z[7] = z7; + z[8] = z8; z[9] = z9; z[10] = z10; z[11] = z11; z[12] = z12; z[13] = z13; z[14] = z14; z[15] = z15; + } + + public static void CNegate(int negate, uint[] z) + { + Debug.Assert(negate >> 1 == 0); + + uint[] t = Create(); + Sub(t, z, t); + + Nat.CMov(Size, negate, t, 0, z, 0); + } + + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + for (int i = 0; i < Size; ++i) + { + z[zOff + i] = x[xOff + i]; + } + } + + public static uint[] Create() + { + return new uint[Size]; + } + + public static void CSwap(int swap, uint[] a, uint[] b) + { + Debug.Assert(swap >> 1 == 0); + Debug.Assert(a != b); + + uint mask = (uint)(0 - swap); + for (int i = 0; i < Size; ++i) + { + uint ai = a[i], bi = b[i]; + uint dummy = mask & (ai ^ bi); + a[i] = ai ^ dummy; + b[i] = bi ^ dummy; + } + } + + public static void Decode(byte[] x, int xOff, uint[] z) + { + Decode56(x, xOff, z, 0); + Decode56(x, xOff + 7, z, 2); + Decode56(x, xOff + 14, z, 4); + Decode56(x, xOff + 21, z, 6); + Decode56(x, xOff + 28, z, 8); + Decode56(x, xOff + 35, z, 10); + Decode56(x, xOff + 42, z, 12); + Decode56(x, xOff + 49, z, 14); + } + + private static uint Decode24(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + return n; + } + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + private static void Decode56(byte[] bs, int off, uint[] z, int zOff) + { + uint lo = Decode32(bs, off); + uint hi = Decode24(bs, off + 4); + z[zOff] = lo & M28; + z[zOff + 1] = (lo >> 28) | (hi << 4); + } + + public static void Encode(uint[] x, byte[] z, int zOff) + { + Encode56(x, 0, z, zOff); + Encode56(x, 2, z, zOff + 7); + Encode56(x, 4, z, zOff + 14); + Encode56(x, 6, z, zOff + 21); + Encode56(x, 8, z, zOff + 28); + Encode56(x, 10, z, zOff + 35); + Encode56(x, 12, z, zOff + 42); + Encode56(x, 14, z, zOff + 49); + } + + private static void Encode24(uint n, byte[] bs, int off) + { + bs[ off] = (byte)(n ); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + } + + private static void Encode32(uint n, byte[] bs, int off) + { + bs[ off] = (byte)(n ); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 24); + } + + private static void Encode56(uint[] x, int xOff, byte[] bs, int off) + { + uint lo = x[xOff], hi = x[xOff + 1]; + Encode32(lo | (hi << 28), bs, off); + Encode24(hi >> 4, bs, off + 4); + } + + public static void Inv(uint[] x, uint[] z) + { + // z = x^(p-2) = x^(2^448 - 2^224 - 3) + // (223 1s) (1 0s) (222 1s) (1 0s) (1 1s) + // Addition chain: [1] 2 3 6 9 18 19 37 74 111 [222] [223] + + uint[] t = Create(); + PowPm3d4(x, t); + Sqr(t, 2, t); + Mul(t, x, z); + } + + public static bool IsZeroVar(uint[] x) + { + uint d = 0; + for (int i = 0; i < Size; ++i) + { + d |= x[i]; + } + return d == 0U; + } + + public static void Mul(uint[] x, uint y, uint[] z) + { + uint x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7]; + uint x8 = x[8], x9 = x[9], x10 = x[10], x11 = x[11], x12 = x[12], x13 = x[13], x14 = x[14], x15 = x[15]; + + uint z1, z5, z9, z13; + ulong c, d, e, f; + + c = (ulong)x1 * y; + z1 = (uint)c & M28; c >>= 28; + d = (ulong)x5 * y; + z5 = (uint)d & M28; d >>= 28; + e = (ulong)x9 * y; + z9 = (uint)e & M28; e >>= 28; + f = (ulong)x13 * y; + z13 = (uint)f & M28; f >>= 28; + + c += (ulong)x2 * y; + z[2] = (uint)c & M28; c >>= 28; + d += (ulong)x6 * y; + z[6] = (uint)d & M28; d >>= 28; + e += (ulong)x10 * y; + z[10] = (uint)e & M28; e >>= 28; + f += (ulong)x14 * y; + z[14] = (uint)f & M28; f >>= 28; + + c += (ulong)x3 * y; + z[3] = (uint)c & M28; c >>= 28; + d += (ulong)x7 * y; + z[7] = (uint)d & M28; d >>= 28; + e += (ulong)x11 * y; + z[11] = (uint)e & M28; e >>= 28; + f += (ulong)x15 * y; + z[15] = (uint)f & M28; f >>= 28; + + d += f; + + c += (ulong)x4 * y; + z[4] = (uint)c & M28; c >>= 28; + d += (ulong)x8 * y; + z[8] = (uint)d & M28; d >>= 28; + e += (ulong)x12 * y; + z[12] = (uint)e & M28; e >>= 28; + f += (ulong)x0 * y; + z[0] = (uint)f & M28; f >>= 28; + + z[1] = z1 + (uint)f; + z[5] = z5 + (uint)c; + z[9] = z9 + (uint)d; + z[13] = z13 + (uint)e; + } + + public static void Mul(uint[] x, uint[] y, uint[] z) + { + uint x0 = x[0]; + uint x1 = x[1]; + uint x2 = x[2]; + uint x3 = x[3]; + uint x4 = x[4]; + uint x5 = x[5]; + uint x6 = x[6]; + uint x7 = x[7]; + + uint u0 = x[8]; + uint u1 = x[9]; + uint u2 = x[10]; + uint u3 = x[11]; + uint u4 = x[12]; + uint u5 = x[13]; + uint u6 = x[14]; + uint u7 = x[15]; + + uint y0 = y[0]; + uint y1 = y[1]; + uint y2 = y[2]; + uint y3 = y[3]; + uint y4 = y[4]; + uint y5 = y[5]; + uint y6 = y[6]; + uint y7 = y[7]; + + uint v0 = y[8]; + uint v1 = y[9]; + uint v2 = y[10]; + uint v3 = y[11]; + uint v4 = y[12]; + uint v5 = y[13]; + uint v6 = y[14]; + uint v7 = y[15]; + + uint s0 = x0 + u0; + uint s1 = x1 + u1; + uint s2 = x2 + u2; + uint s3 = x3 + u3; + uint s4 = x4 + u4; + uint s5 = x5 + u5; + uint s6 = x6 + u6; + uint s7 = x7 + u7; + + uint t0 = y0 + v0; + uint t1 = y1 + v1; + uint t2 = y2 + v2; + uint t3 = y3 + v3; + uint t4 = y4 + v4; + uint t5 = y5 + v5; + uint t6 = y6 + v6; + uint t7 = y7 + v7; + + uint z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15; + ulong c, d; + + ulong f0 = (ulong)x0 * y0; + ulong f8 = (ulong)x7 * y1 + + (ulong)x6 * y2 + + (ulong)x5 * y3 + + (ulong)x4 * y4 + + (ulong)x3 * y5 + + (ulong)x2 * y6 + + (ulong)x1 * y7; + ulong g0 = (ulong)u0 * v0; + ulong g8 = (ulong)u7 * v1 + + (ulong)u6 * v2 + + (ulong)u5 * v3 + + (ulong)u4 * v4 + + (ulong)u3 * v5 + + (ulong)u2 * v6 + + (ulong)u1 * v7; + ulong h0 = (ulong)s0 * t0; + ulong h8 = (ulong)s7 * t1 + + (ulong)s6 * t2 + + (ulong)s5 * t3 + + (ulong)s4 * t4 + + (ulong)s3 * t5 + + (ulong)s2 * t6 + + (ulong)s1 * t7; + + c = f0 + g0 + h8 - f8; + z0 = (uint)c & M28; c >>= 28; + d = g8 + h0 - f0 + h8; + z8 = (uint)d & M28; d >>= 28; + + ulong f1 = (ulong)x1 * y0 + + (ulong)x0 * y1; + ulong f9 = (ulong)x7 * y2 + + (ulong)x6 * y3 + + (ulong)x5 * y4 + + (ulong)x4 * y5 + + (ulong)x3 * y6 + + (ulong)x2 * y7; + ulong g1 = (ulong)u1 * v0 + + (ulong)u0 * v1; + ulong g9 = (ulong)u7 * v2 + + (ulong)u6 * v3 + + (ulong)u5 * v4 + + (ulong)u4 * v5 + + (ulong)u3 * v6 + + (ulong)u2 * v7; + ulong h1 = (ulong)s1 * t0 + + (ulong)s0 * t1; + ulong h9 = (ulong)s7 * t2 + + (ulong)s6 * t3 + + (ulong)s5 * t4 + + (ulong)s4 * t5 + + (ulong)s3 * t6 + + (ulong)s2 * t7; + + c += f1 + g1 + h9 - f9; + z1 = (uint)c & M28; c >>= 28; + d += g9 + h1 - f1 + h9; + z9 = (uint)d & M28; d >>= 28; + + ulong f2 = (ulong)x2 * y0 + + (ulong)x1 * y1 + + (ulong)x0 * y2; + ulong f10 = (ulong)x7 * y3 + + (ulong)x6 * y4 + + (ulong)x5 * y5 + + (ulong)x4 * y6 + + (ulong)x3 * y7; + ulong g2 = (ulong)u2 * v0 + + (ulong)u1 * v1 + + (ulong)u0 * v2; + ulong g10 = (ulong)u7 * v3 + + (ulong)u6 * v4 + + (ulong)u5 * v5 + + (ulong)u4 * v6 + + (ulong)u3 * v7; + ulong h2 = (ulong)s2 * t0 + + (ulong)s1 * t1 + + (ulong)s0 * t2; + ulong h10 = (ulong)s7 * t3 + + (ulong)s6 * t4 + + (ulong)s5 * t5 + + (ulong)s4 * t6 + + (ulong)s3 * t7; + + c += f2 + g2 + h10 - f10; + z2 = (uint)c & M28; c >>= 28; + d += g10 + h2 - f2 + h10; + z10 = (uint)d & M28; d >>= 28; + + ulong f3 = (ulong)x3 * y0 + + (ulong)x2 * y1 + + (ulong)x1 * y2 + + (ulong)x0 * y3; + ulong f11 = (ulong)x7 * y4 + + (ulong)x6 * y5 + + (ulong)x5 * y6 + + (ulong)x4 * y7; + ulong g3 = (ulong)u3 * v0 + + (ulong)u2 * v1 + + (ulong)u1 * v2 + + (ulong)u0 * v3; + ulong g11 = (ulong)u7 * v4 + + (ulong)u6 * v5 + + (ulong)u5 * v6 + + (ulong)u4 * v7; + ulong h3 = (ulong)s3 * t0 + + (ulong)s2 * t1 + + (ulong)s1 * t2 + + (ulong)s0 * t3; + ulong h11 = (ulong)s7 * t4 + + (ulong)s6 * t5 + + (ulong)s5 * t6 + + (ulong)s4 * t7; + + c += f3 + g3 + h11 - f11; + z3 = (uint)c & M28; c >>= 28; + d += g11 + h3 - f3 + h11; + z11 = (uint)d & M28; d >>= 28; + + ulong f4 = (ulong)x4 * y0 + + (ulong)x3 * y1 + + (ulong)x2 * y2 + + (ulong)x1 * y3 + + (ulong)x0 * y4; + ulong f12 = (ulong)x7 * y5 + + (ulong)x6 * y6 + + (ulong)x5 * y7; + ulong g4 = (ulong)u4 * v0 + + (ulong)u3 * v1 + + (ulong)u2 * v2 + + (ulong)u1 * v3 + + (ulong)u0 * v4; + ulong g12 = (ulong)u7 * v5 + + (ulong)u6 * v6 + + (ulong)u5 * v7; + ulong h4 = (ulong)s4 * t0 + + (ulong)s3 * t1 + + (ulong)s2 * t2 + + (ulong)s1 * t3 + + (ulong)s0 * t4; + ulong h12 = (ulong)s7 * t5 + + (ulong)s6 * t6 + + (ulong)s5 * t7; + + c += f4 + g4 + h12 - f12; + z4 = (uint)c & M28; c >>= 28; + d += g12 + h4 - f4 + h12; + z12 = (uint)d & M28; d >>= 28; + + ulong f5 = (ulong)x5 * y0 + + (ulong)x4 * y1 + + (ulong)x3 * y2 + + (ulong)x2 * y3 + + (ulong)x1 * y4 + + (ulong)x0 * y5; + ulong f13 = (ulong)x7 * y6 + + (ulong)x6 * y7; + ulong g5 = (ulong)u5 * v0 + + (ulong)u4 * v1 + + (ulong)u3 * v2 + + (ulong)u2 * v3 + + (ulong)u1 * v4 + + (ulong)u0 * v5; + ulong g13 = (ulong)u7 * v6 + + (ulong)u6 * v7; + ulong h5 = (ulong)s5 * t0 + + (ulong)s4 * t1 + + (ulong)s3 * t2 + + (ulong)s2 * t3 + + (ulong)s1 * t4 + + (ulong)s0 * t5; + ulong h13 = (ulong)s7 * t6 + + (ulong)s6 * t7; + + c += f5 + g5 + h13 - f13; + z5 = (uint)c & M28; c >>= 28; + d += g13 + h5 - f5 + h13; + z13 = (uint)d & M28; d >>= 28; + + ulong f6 = (ulong)x6 * y0 + + (ulong)x5 * y1 + + (ulong)x4 * y2 + + (ulong)x3 * y3 + + (ulong)x2 * y4 + + (ulong)x1 * y5 + + (ulong)x0 * y6; + ulong f14 = (ulong)x7 * y7; + ulong g6 = (ulong)u6 * v0 + + (ulong)u5 * v1 + + (ulong)u4 * v2 + + (ulong)u3 * v3 + + (ulong)u2 * v4 + + (ulong)u1 * v5 + + (ulong)u0 * v6; + ulong g14 = (ulong)u7 * v7; + ulong h6 = (ulong)s6 * t0 + + (ulong)s5 * t1 + + (ulong)s4 * t2 + + (ulong)s3 * t3 + + (ulong)s2 * t4 + + (ulong)s1 * t5 + + (ulong)s0 * t6; + ulong h14 = (ulong)s7 * t7; + + c += f6 + g6 + h14 - f14; + z6 = (uint)c & M28; c >>= 28; + d += g14 + h6 - f6 + h14; + z14 = (uint)d & M28; d >>= 28; + + ulong f7 = (ulong)x7 * y0 + + (ulong)x6 * y1 + + (ulong)x5 * y2 + + (ulong)x4 * y3 + + (ulong)x3 * y4 + + (ulong)x2 * y5 + + (ulong)x1 * y6 + + (ulong)x0 * y7; + ulong g7 = (ulong)u7 * v0 + + (ulong)u6 * v1 + + (ulong)u5 * v2 + + (ulong)u4 * v3 + + (ulong)u3 * v4 + + (ulong)u2 * v5 + + (ulong)u1 * v6 + + (ulong)u0 * v7; + ulong h7 = (ulong)s7 * t0 + + (ulong)s6 * t1 + + (ulong)s5 * t2 + + (ulong)s4 * t3 + + (ulong)s3 * t4 + + (ulong)s2 * t5 + + (ulong)s1 * t6 + + (ulong)s0 * t7; + + c += f7 + g7; + z7 = (uint)c & M28; c >>= 28; + d += h7 - f7; + z15 = (uint)d & M28; d >>= 28; + + c += d; + + c += z8; + z8 = (uint)c & M28; c >>= 28; + d += z0; + z0 = (uint)d & M28; d >>= 28; + z9 += (uint)c; + z1 += (uint)d; + + z[0] = z0; + z[1] = z1; + z[2] = z2; + z[3] = z3; + z[4] = z4; + z[5] = z5; + z[6] = z6; + z[7] = z7; + z[8] = z8; + z[9] = z9; + z[10] = z10; + z[11] = z11; + z[12] = z12; + z[13] = z13; + z[14] = z14; + z[15] = z15; + } + + public static void Negate(uint[] x, uint[] z) + { + uint[] zero = Create(); + Sub(zero, x, z); + } + + public static void Normalize(uint[] z) + { + //int x = (z[15] >> (28 - 1)) & 1; + Reduce(z, 1); + Reduce(z, -1); + Debug.Assert(z[15] >> 28 == 0U); + } + + public static void One(uint[] z) + { + z[0] = 1U; + for (int i = 1; i < Size; ++i) + { + z[i] = 0; + } + } + + private static void PowPm3d4(uint[] x, uint[] z) + { + // z = x^((p-3)/4) = x^(2^446 - 2^222 - 1) + // (223 1s) (1 0s) (222 1s) + // Addition chain: 1 2 3 6 9 18 19 37 74 111 [222] [223] + uint[] x2 = Create(); Sqr(x, x2); Mul(x, x2, x2); + uint[] x3 = Create(); Sqr(x2, x3); Mul(x, x3, x3); + uint[] x6 = Create(); Sqr(x3, 3, x6); Mul(x3, x6, x6); + uint[] x9 = Create(); Sqr(x6, 3, x9); Mul(x3, x9, x9); + uint[] x18 = Create(); Sqr(x9, 9, x18); Mul(x9, x18, x18); + uint[] x19 = Create(); Sqr(x18, x19); Mul(x, x19, x19); + uint[] x37 = Create(); Sqr(x19, 18, x37); Mul(x18, x37, x37); + uint[] x74 = Create(); Sqr(x37, 37, x74); Mul(x37, x74, x74); + uint[] x111 = Create(); Sqr(x74, 37, x111); Mul(x37, x111, x111); + uint[] x222 = Create(); Sqr(x111, 111, x222); Mul(x111, x222, x222); + uint[] x223 = Create(); Sqr(x222, x223); Mul(x, x223, x223); + + uint[] t = Create(); + Sqr(x223, 223, t); + Mul(t, x222, z); + } + + private static void Reduce(uint[] z, int c) + { + uint z15 = z[15]; + long t = z15; + z15 &= M28; + t = (t >> 28) + c; + z[8] += (uint)t; + for (int i = 0; i < 15; ++i) + { + t += z[i]; z[i] = (uint)t & M28; t >>= 28; + } + z[15] = z15 + (uint)t; + } + + public static void Sqr(uint[] x, uint[] z) + { + uint x0 = x[0]; + uint x1 = x[1]; + uint x2 = x[2]; + uint x3 = x[3]; + uint x4 = x[4]; + uint x5 = x[5]; + uint x6 = x[6]; + uint x7 = x[7]; + + uint u0 = x[8]; + uint u1 = x[9]; + uint u2 = x[10]; + uint u3 = x[11]; + uint u4 = x[12]; + uint u5 = x[13]; + uint u6 = x[14]; + uint u7 = x[15]; + + uint x0_2 = x0 * 2; + uint x1_2 = x1 * 2; + uint x2_2 = x2 * 2; + uint x3_2 = x3 * 2; + uint x4_2 = x4 * 2; + uint x5_2 = x5 * 2; + uint x6_2 = x6 * 2; + + uint u0_2 = u0 * 2; + uint u1_2 = u1 * 2; + uint u2_2 = u2 * 2; + uint u3_2 = u3 * 2; + uint u4_2 = u4 * 2; + uint u5_2 = u5 * 2; + uint u6_2 = u6 * 2; + + uint s0 = x0 + u0; + uint s1 = x1 + u1; + uint s2 = x2 + u2; + uint s3 = x3 + u3; + uint s4 = x4 + u4; + uint s5 = x5 + u5; + uint s6 = x6 + u6; + uint s7 = x7 + u7; + + uint s0_2 = s0 * 2; + uint s1_2 = s1 * 2; + uint s2_2 = s2 * 2; + uint s3_2 = s3 * 2; + uint s4_2 = s4 * 2; + uint s5_2 = s5 * 2; + uint s6_2 = s6 * 2; + + uint z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15; + ulong c, d; + + ulong f0 = (ulong)x0 * x0; + ulong f8 = (ulong)x7 * x1_2 + + (ulong)x6 * x2_2 + + (ulong)x5 * x3_2 + + (ulong)x4 * x4; + ulong g0 = (ulong)u0 * u0; + ulong g8 = (ulong)u7 * u1_2 + + (ulong)u6 * u2_2 + + (ulong)u5 * u3_2 + + (ulong)u4 * u4; + ulong h0 = (ulong)s0 * s0; + ulong h8 = (ulong)s7 * s1_2 + + (ulong)s6 * s2_2 + + (ulong)s5 * s3_2 + + (ulong)s4 * s4; + + c = f0 + g0 + h8 - f8; + z0 = (uint)c & M28; c >>= 28; + d = g8 + h0 - f0 + h8; + z8 = (uint)d & M28; d >>= 28; + + ulong f1 = (ulong)x1 * x0_2; + ulong f9 = (ulong)x7 * x2_2 + + (ulong)x6 * x3_2 + + (ulong)x5 * x4_2; + ulong g1 = (ulong)u1 * u0_2; + ulong g9 = (ulong)u7 * u2_2 + + (ulong)u6 * u3_2 + + (ulong)u5 * u4_2; + ulong h1 = (ulong)s1 * s0_2; + ulong h9 = (ulong)s7 * s2_2 + + (ulong)s6 * s3_2 + + (ulong)s5 * s4_2; + + c += f1 + g1 + h9 - f9; + z1 = (uint)c & M28; c >>= 28; + d += g9 + h1 - f1 + h9; + z9 = (uint)d & M28; d >>= 28; + + ulong f2 = (ulong)x2 * x0_2 + + (ulong)x1 * x1; + ulong f10 = (ulong)x7 * x3_2 + + (ulong)x6 * x4_2 + + (ulong)x5 * x5; + ulong g2 = (ulong)u2 * u0_2 + + (ulong)u1 * u1; + ulong g10 = (ulong)u7 * u3_2 + + (ulong)u6 * u4_2 + + (ulong)u5 * u5; + ulong h2 = (ulong)s2 * s0_2 + + (ulong)s1 * s1; + ulong h10 = (ulong)s7 * s3_2 + + (ulong)s6 * s4_2 + + (ulong)s5 * s5; + + c += f2 + g2 + h10 - f10; + z2 = (uint)c & M28; c >>= 28; + d += g10 + h2 - f2 + h10; + z10 = (uint)d & M28; d >>= 28; + + ulong f3 = (ulong)x3 * x0_2 + + (ulong)x2 * x1_2; + ulong f11 = (ulong)x7 * x4_2 + + (ulong)x6 * x5_2; + ulong g3 = (ulong)u3 * u0_2 + + (ulong)u2 * u1_2; + ulong g11 = (ulong)u7 * u4_2 + + (ulong)u6 * u5_2; + ulong h3 = (ulong)s3 * s0_2 + + (ulong)s2 * s1_2; + ulong h11 = (ulong)s7 * s4_2 + + (ulong)s6 * s5_2; + + c += f3 + g3 + h11 - f11; + z3 = (uint)c & M28; c >>= 28; + d += g11 + h3 - f3 + h11; + z11 = (uint)d & M28; d >>= 28; + + ulong f4 = (ulong)x4 * x0_2 + + (ulong)x3 * x1_2 + + (ulong)x2 * x2; + ulong f12 = (ulong)x7 * x5_2 + + (ulong)x6 * x6; + ulong g4 = (ulong)u4 * u0_2 + + (ulong)u3 * u1_2 + + (ulong)u2 * u2; + ulong g12 = (ulong)u7 * u5_2 + + (ulong)u6 * u6; + ulong h4 = (ulong)s4 * s0_2 + + (ulong)s3 * s1_2 + + (ulong)s2 * s2; + ulong h12 = (ulong)s7 * s5_2 + + (ulong)s6 * s6; + + c += f4 + g4 + h12 - f12; + z4 = (uint)c & M28; c >>= 28; + d += g12 + h4 - f4 + h12; + z12 = (uint)d & M28; d >>= 28; + + ulong f5 = (ulong)x5 * x0_2 + + (ulong)x4 * x1_2 + + (ulong)x3 * x2_2; + ulong f13 = (ulong)x7 * x6_2; + ulong g5 = (ulong)u5 * u0_2 + + (ulong)u4 * u1_2 + + (ulong)u3 * u2_2; + ulong g13 = (ulong)u7 * u6_2; + ulong h5 = (ulong)s5 * s0_2 + + (ulong)s4 * s1_2 + + (ulong)s3 * s2_2; + ulong h13 = (ulong)s7 * s6_2; + + c += f5 + g5 + h13 - f13; + z5 = (uint)c & M28; c >>= 28; + d += g13 + h5 - f5 + h13; + z13 = (uint)d & M28; d >>= 28; + + ulong f6 = (ulong)x6 * x0_2 + + (ulong)x5 * x1_2 + + (ulong)x4 * x2_2 + + (ulong)x3 * x3; + ulong f14 = (ulong)x7 * x7; + ulong g6 = (ulong)u6 * u0_2 + + (ulong)u5 * u1_2 + + (ulong)u4 * u2_2 + + (ulong)u3 * u3; + ulong g14 = (ulong)u7 * u7; + ulong h6 = (ulong)s6 * s0_2 + + (ulong)s5 * s1_2 + + (ulong)s4 * s2_2 + + (ulong)s3 * s3; + ulong h14 = (ulong)s7 * s7; + + c += f6 + g6 + h14 - f14; + z6 = (uint)c & M28; c >>= 28; + d += g14 + h6 - f6 + h14; + z14 = (uint)d & M28; d >>= 28; + + ulong f7 = (ulong)x7 * x0_2 + + (ulong)x6 * x1_2 + + (ulong)x5 * x2_2 + + (ulong)x4 * x3_2; + ulong g7 = (ulong)u7 * u0_2 + + (ulong)u6 * u1_2 + + (ulong)u5 * u2_2 + + (ulong)u4 * u3_2; + ulong h7 = (ulong)s7 * s0_2 + + (ulong)s6 * s1_2 + + (ulong)s5 * s2_2 + + (ulong)s4 * s3_2; + + c += f7 + g7; + z7 = (uint)c & M28; c >>= 28; + d += h7 - f7; + z15 = (uint)d & M28; d >>= 28; + + c += d; + + c += z8; + z8 = (uint)c & M28; c >>= 28; + d += z0; + z0 = (uint)d & M28; d >>= 28; + z9 += (uint)c; + z1 += (uint)d; + + z[0] = z0; + z[1] = z1; + z[2] = z2; + z[3] = z3; + z[4] = z4; + z[5] = z5; + z[6] = z6; + z[7] = z7; + z[8] = z8; + z[9] = z9; + z[10] = z10; + z[11] = z11; + z[12] = z12; + z[13] = z13; + z[14] = z14; + z[15] = z15; + } + + public static void Sqr(uint[] x, int n, uint[] z) + { + Debug.Assert(n > 0); + + Sqr(x, z); + + while (--n > 0) + { + Sqr(z, z); + } + } + + public static bool SqrtRatioVar(uint[] u, uint[] v, uint[] z) + { + uint[] u3v = Create(); + uint[] u5v3 = Create(); + + Sqr(u, u3v); + Mul(u3v, v, u3v); + Sqr(u3v, u5v3); + Mul(u3v, u, u3v); + Mul(u5v3, u, u5v3); + Mul(u5v3, v, u5v3); + + uint[] x = Create(); + PowPm3d4(u5v3, x); + Mul(x, u3v, x); + + uint[] t = Create(); + Sqr(x, t); + Mul(t, v, t); + + Sub(u, t, t); + Normalize(t); + + if (IsZeroVar(t)) + { + Copy(x, 0, z, 0); + return true; + } + + return false; + } + + public static void Sub(uint[] x, uint[] y, uint[] z) + { + uint x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7]; + uint x8 = x[8], x9 = x[9], x10 = x[10], x11 = x[11], x12 = x[12], x13 = x[13], x14 = x[14], x15 = x[15]; + uint y0 = y[0], y1 = y[1], y2 = y[2], y3 = y[3], y4 = y[4], y5 = y[5], y6 = y[6], y7 = y[7]; + uint y8 = y[8], y9 = y[9], y10 = y[10], y11 = y[11], y12 = y[12], y13 = y[13], y14 = y[14], y15 = y[15]; + + uint z0 = x0 + 0x1FFFFFFEU - y0; + uint z1 = x1 + 0x1FFFFFFEU - y1; + uint z2 = x2 + 0x1FFFFFFEU - y2; + uint z3 = x3 + 0x1FFFFFFEU - y3; + uint z4 = x4 + 0x1FFFFFFEU - y4; + uint z5 = x5 + 0x1FFFFFFEU - y5; + uint z6 = x6 + 0x1FFFFFFEU - y6; + uint z7 = x7 + 0x1FFFFFFEU - y7; + uint z8 = x8 + 0x1FFFFFFCU - y8; + uint z9 = x9 + 0x1FFFFFFEU - y9; + uint z10 = x10 + 0x1FFFFFFEU - y10; + uint z11 = x11 + 0x1FFFFFFEU - y11; + uint z12 = x12 + 0x1FFFFFFEU - y12; + uint z13 = x13 + 0x1FFFFFFEU - y13; + uint z14 = x14 + 0x1FFFFFFEU - y14; + uint z15 = x15 + 0x1FFFFFFEU - y15; + + z2 += z1 >> 28; z1 &= M28; + z6 += z5 >> 28; z5 &= M28; + z10 += z9 >> 28; z9 &= M28; + z14 += z13 >> 28; z13 &= M28; + + z3 += z2 >> 28; z2 &= M28; + z7 += z6 >> 28; z6 &= M28; + z11 += z10 >> 28; z10 &= M28; + z15 += z14 >> 28; z14 &= M28; + + uint t = z15 >> 28; z15 &= M28; + z0 += t; + z8 += t; + + z4 += z3 >> 28; z3 &= M28; + z8 += z7 >> 28; z7 &= M28; + z12 += z11 >> 28; z11 &= M28; + + z1 += z0 >> 28; z0 &= M28; + z5 += z4 >> 28; z4 &= M28; + z9 += z8 >> 28; z8 &= M28; + z13 += z12 >> 28; z12 &= M28; + + z[0] = z0; + z[1] = z1; + z[2] = z2; + z[3] = z3; + z[4] = z4; + z[5] = z5; + z[6] = z6; + z[7] = z7; + z[8] = z8; + z[9] = z9; + z[10] = z10; + z[11] = z11; + z[12] = z12; + z[13] = z13; + z[14] = z14; + z[15] = z15; + } + + public static void Zero(uint[] z) + { + for (int i = 0; i < Size; ++i) + { + z[i] = 0; + } + } + } +} diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs new file mode 100644 index 000000000..ff4587cb2 --- /dev/null +++ b/crypto/src/math/ec/rfc8032/Ed25519.cs @@ -0,0 +1,937 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Math.EC.Rfc7748; +using Org.BouncyCastle.Math.Raw; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Math.EC.Rfc8032 +{ + public abstract class Ed25519 + { + private const long M28L = 0x0FFFFFFFL; + private const long M32L = 0xFFFFFFFFL; + + private const int PointBytes = 32; + private const int ScalarUints = 8; + private const int ScalarBytes = ScalarUints * 4; + + public static readonly int PublicKeySize = PointBytes; + public static readonly int SecretKeySize = 32; + public static readonly int SignatureSize = PointBytes + ScalarBytes; + + //private static readonly byte[] Dom2Prefix = Strings.ToByteArray("SigEd25519 no Ed25519 collisions"); + + private static readonly uint[] P = { 0xFFFFFFEDU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU }; + private static readonly uint[] L = { 0x5CF5D3EDU, 0x5812631AU, 0xA2F79CD6U, 0x14DEF9DEU, 0x00000000U, 0x00000000U, 0x00000000U, 0x10000000U }; + + private const int L0 = unchecked((int)0xFCF5D3ED); // L0:26/-- + private const int L1 = 0x012631A6; // L1:24/22 + private const int L2 = 0x079CD658; // L2:27/-- + private const int L3 = unchecked((int)0xFF9DEA2F); // L3:23/-- + private const int L4 = 0x000014DF; // L4:12/11 + + private static readonly int[] B_x = { 0x0325D51A, 0x018B5823, 0x007B2C95, 0x0304A92D, 0x00D2598E, 0x01D6DC5C, + 0x01388C7F, 0x013FEC0A, 0x029E6B72, 0x0042D26D }; + private static readonly int[] B_y = { 0x02666658, 0x01999999, 0x00666666, 0x03333333, 0x00CCCCCC, 0x02666666, + 0x01999999, 0x00666666, 0x03333333, 0x00CCCCCC, }; + private static readonly int[] C_d = { 0x035978A3, 0x02D37284, 0x018AB75E, 0x026A0A0E, 0x0000E014, 0x0379E898, + 0x01D01E5D, 0x01E738CC, 0x03715B7F, 0x00A406D9 }; + private static readonly int[] C_d2 = { 0x02B2F159, 0x01A6E509, 0x01156EBD, 0x00D4141D, 0x0001C029, 0x02F3D130, + 0x03A03CBB, 0x01CE7198, 0x02E2B6FF, 0x00480DB3 }; + private static readonly int[] C_d4 = { 0x0165E2B2, 0x034DCA13, 0x002ADD7A, 0x01A8283B, 0x00038052, 0x01E7A260, + 0x03407977, 0x019CE331, 0x01C56DFF, 0x00901B67 }; + + private const int WnafWidthBase = 7; + + private const int PrecompBlocks = 8; + private const int PrecompTeeth = 4; + private const int PrecompSpacing = 8; + private const int PrecompPoints = 1 << (PrecompTeeth - 1); + private const int PrecompMask = PrecompPoints - 1; + + // TODO[ed25519] Convert to PointPrecomp + private static PointExt[] precompBaseTable = null; + private static int[] precompBase = null; + + private class PointAccum + { + internal int[] x = X25519Field.Create(); + internal int[] y = X25519Field.Create(); + internal int[] z = X25519Field.Create(); + internal int[] u = X25519Field.Create(); + internal int[] v = X25519Field.Create(); + } + + private class PointExt + { + internal int[] x = X25519Field.Create(); + internal int[] y = X25519Field.Create(); + internal int[] z = X25519Field.Create(); + internal int[] t = X25519Field.Create(); + } + + private class PointPrecomp + { + internal int[] ypx_h = X25519Field.Create(); + internal int[] ymx_h = X25519Field.Create(); + internal int[] xyd = X25519Field.Create(); + } + + private static byte[] CalculateS(byte[] r, byte[] k, byte[] s) + { + uint[] t = new uint[ScalarUints * 2]; DecodeScalar(r, 0, t); + uint[] u = new uint[ScalarUints]; DecodeScalar(k, 0, u); + uint[] v = new uint[ScalarUints]; DecodeScalar(s, 0, v); + + Nat256.MulAddTo(u, v, t); + + byte[] result = new byte[ScalarBytes * 2]; + for (int i = 0; i < t.Length; ++i) + { + Encode32(t[i], result, i * 4); + } + return ReduceScalar(result); + } + + private static bool CheckPointVar(byte[] p) + { + uint[] t = new uint[8]; + Decode32(p, 0, t, 0, 8); + t[7] &= 0x7FFFFFFFU; + return !Nat256.Gte(t, P); + } + + private static bool CheckScalarVar(byte[] s) + { + uint[] n = new uint[ScalarUints]; + DecodeScalar(s, 0, n); + return !Nat256.Gte(n, L); + } + + private static uint Decode24(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + return n; + } + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + private static void Decode32(byte[] bs, int bsOff, uint[] n, int nOff, int nLen) + { + for (int i = 0; i < nLen; ++i) + { + n[nOff + i] = Decode32(bs, bsOff + i * 4); + } + } + + private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointExt r) + { + byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); + if (!CheckPointVar(py)) + { + return false; + } + + int x_0 = (py[PointBytes - 1] & 0x80) >> 7; + py[PointBytes - 1] &= 0x7F; + + X25519Field.Decode(py, 0, r.y); + + int[] u = X25519Field.Create(); + int[] v = X25519Field.Create(); + + X25519Field.Sqr(r.y, u); + X25519Field.Mul(C_d, u, v); + X25519Field.SubOne(u); + X25519Field.AddOne(v); + + if (!X25519Field.SqrtRatioVar(u, v, r.x)) + { + return false; + } + + X25519Field.Normalize(r.x); + if (x_0 == 1 && X25519Field.IsZeroVar(r.x)) + { + return false; + } + + if (negate ^ (x_0 != (r.x[0] & 1))) + { + X25519Field.Negate(r.x, r.x); + } + + PointExtendXY(r); + return true; + } + + private static void DecodeScalar(byte[] k, int kOff, uint[] n) + { + Decode32(k, kOff, n, 0, ScalarUints); + } + + private static void Encode24(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + } + + private static void Encode32(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 24); + } + + private static void Encode56(ulong n, byte[] bs, int off) + { + Encode32((uint)n, bs, off); + Encode24((uint)(n >> 32), bs, off + 4); + } + + private static void EncodePoint(PointAccum p, byte[] r, int rOff) + { + int[] x = X25519Field.Create(); + int[] y = X25519Field.Create(); + + X25519Field.Inv(p.z, y); + X25519Field.Mul(p.x, y, x); + X25519Field.Mul(p.y, y, y); + X25519Field.Normalize(x); + X25519Field.Normalize(y); + + X25519Field.Encode(y, r, rOff); + r[rOff + PointBytes - 1] |= (byte)((x[0] & 1) << 7); + } + + public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) + { + Sha512Digest d = new Sha512Digest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ScalarMultBaseEncoded(s, pk, pkOff); + } + + private static sbyte[] GetWnaf(uint[] n, int width) + { + Debug.Assert(n[ScalarUints - 1] >> 31 == 0); + + uint[] t = new uint[ScalarUints * 2]; + { + uint c = 0; + int tPos = t.Length, i = ScalarUints; + while (--i >= 0) + { + uint next = n[i]; + t[--tPos] = (next >> 16) | (c << 16); + t[--tPos] = c = next; + } + } + + sbyte[] ws = new sbyte[256]; + + uint pow2 = 1U << width; + uint mask = pow2 - 1U; + uint sign = pow2 >> 1; + + uint carry = 0U; + int j = 0; + for (int i = 0; i < t.Length; ++i, j -= 16) + { + uint word = t[i]; + while (j < 16) + { + uint word16 = word >> j; + uint bit = word16 & 1U; + + if (bit == carry) + { + ++j; + continue; + } + + uint digit = (word16 & mask) + carry; + carry = digit & sign; + digit -= (carry << 1); + carry >>= (width - 1); + + ws[(i << 4) + j] = (sbyte)digit; + + j += width; + } + } + + Debug.Assert(carry == 0); + + return ws; + } + + private static void ImplSign(Sha512Digest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + d.BlockUpdate(h, ScalarBytes, ScalarBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0); + + byte[] r = ReduceScalar(h); + byte[] R = new byte[PointBytes]; + ScalarMultBaseEncoded(r, R, 0); + + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, 0, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0); + + byte[] k = ReduceScalar(h); + byte[] S = CalculateS(r, k, s); + + Array.Copy(R, 0, sig, sigOff, PointBytes); + Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes); + } + + private static void PointAddVar(bool negate, PointExt p, PointAccum r) + { + int[] A = X25519Field.Create(); + int[] B = X25519Field.Create(); + int[] C = X25519Field.Create(); + int[] D = X25519Field.Create(); + int[] E = r.u; + int[] F = X25519Field.Create(); + int[] G = X25519Field.Create(); + int[] H = r.v; + + int[] c, d, f, g; + if (negate) + { + c = D; d = C; f = G; g = F; + } + else + { + c = C; d = D; f = F; g = G; + } + + X25519Field.Apm(r.y, r.x, B, A); + X25519Field.Apm(p.y, p.x, d, c); + X25519Field.Mul(A, C, A); + X25519Field.Mul(B, D, B); + X25519Field.Mul(r.u, r.v, C); + X25519Field.Mul(C, p.t, C); + X25519Field.Mul(C, C_d2, C); + X25519Field.Mul(r.z, p.z, D); + X25519Field.Add(D, D, D); + X25519Field.Apm(B, A, H, E); + X25519Field.Apm(D, C, g, f); + X25519Field.Carry(g); + X25519Field.Mul(E, F, r.x); + X25519Field.Mul(G, H, r.y); + X25519Field.Mul(F, G, r.z); + } + + private static void PointAddVar(bool negate, PointExt p, PointExt q, PointExt r) + { + int[] A = X25519Field.Create(); + int[] B = X25519Field.Create(); + int[] C = X25519Field.Create(); + int[] D = X25519Field.Create(); + int[] E = X25519Field.Create(); + int[] F = X25519Field.Create(); + int[] G = X25519Field.Create(); + int[] H = X25519Field.Create(); + + int[] c, d, f, g; + if (negate) + { + c = D; d = C; f = G; g = F; + } + else + { + c = C; d = D; f = F; g = G; + } + + X25519Field.Apm(p.y, p.x, B, A); + X25519Field.Apm(q.y, q.x, d, c); + X25519Field.Mul(A, C, A); + X25519Field.Mul(B, D, B); + X25519Field.Mul(p.t, q.t, C); + X25519Field.Mul(C, C_d2, C); + X25519Field.Mul(p.z, q.z, D); + X25519Field.Add(D, D, D); + X25519Field.Apm(B, A, H, E); + X25519Field.Apm(D, C, g, f); + X25519Field.Carry(g); + X25519Field.Mul(E, F, r.x); + X25519Field.Mul(G, H, r.y); + X25519Field.Mul(F, G, r.z); + X25519Field.Mul(E, H, r.t); + } + + private static void PointAddPrecomp(PointPrecomp p, PointAccum r) + { + int[] A = X25519Field.Create(); + int[] B = X25519Field.Create(); + int[] C = X25519Field.Create(); + int[] E = r.u; + int[] F = X25519Field.Create(); + int[] G = X25519Field.Create(); + int[] H = r.v; + + X25519Field.Apm(r.y, r.x, B, A); + X25519Field.Mul(A, p.ymx_h, A); + X25519Field.Mul(B, p.ypx_h, B); + X25519Field.Mul(r.u, r.v, C); + X25519Field.Mul(C, p.xyd, C); + X25519Field.Apm(B, A, H, E); + X25519Field.Apm(r.z, C, G, F); + X25519Field.Carry(G); + X25519Field.Mul(E, F, r.x); + X25519Field.Mul(G, H, r.y); + X25519Field.Mul(F, G, r.z); + } + + private static PointExt PointCopy(PointAccum p) + { + PointExt r = new PointExt(); + X25519Field.Copy(p.x, 0, r.x, 0); + X25519Field.Copy(p.y, 0, r.y, 0); + X25519Field.Copy(p.z, 0, r.z, 0); + X25519Field.Mul(p.u, p.v, r.t); + return r; + } + + private static PointExt PointCopy(PointExt p) + { + PointExt r = new PointExt(); + X25519Field.Copy(p.x, 0, r.x, 0); + X25519Field.Copy(p.y, 0, r.y, 0); + X25519Field.Copy(p.z, 0, r.z, 0); + X25519Field.Copy(p.t, 0, r.t, 0); + return r; + } + + private static void PointDouble(PointAccum r) + { + int[] A = X25519Field.Create(); + int[] B = X25519Field.Create(); + int[] C = X25519Field.Create(); + int[] E = r.u; + int[] F = X25519Field.Create(); + int[] G = X25519Field.Create(); + int[] H = r.v; + + X25519Field.Sqr(r.x, A); + X25519Field.Sqr(r.y, B); + X25519Field.Sqr(r.z, C); + X25519Field.Add(C, C, C); + X25519Field.Apm(A, B, H, G); + X25519Field.Add(r.x, r.y, E); + X25519Field.Sqr(E, E); + X25519Field.Sub(H, E, E); + X25519Field.Add(C, G, F); + X25519Field.Carry(F); + X25519Field.Mul(E, F, r.x); + X25519Field.Mul(G, H, r.y); + X25519Field.Mul(F, G, r.z); + } + + private static void PointExtendXY(PointAccum p) + { + X25519Field.One(p.z); + X25519Field.Copy(p.x, 0, p.u, 0); + X25519Field.Copy(p.y, 0, p.v, 0); + } + + private static void PointExtendXY(PointExt p) + { + X25519Field.One(p.z); + X25519Field.Mul(p.x, p.y, p.t); + } + + private static void PointLookup(int block, int index, PointPrecomp p) + { + Debug.Assert(0 <= block && block < PrecompBlocks); + Debug.Assert(0 <= index && index < PrecompPoints); + + int off = block * PrecompPoints * 3 * X25519Field.Size; + + for (int i = 0; i < PrecompPoints; ++i) + { + int mask = ((i ^ index) - 1) >> 31; + Nat.CMov(X25519Field.Size, mask, precompBase, off, p.ypx_h, 0); off += X25519Field.Size; + Nat.CMov(X25519Field.Size, mask, precompBase, off, p.ymx_h, 0); off += X25519Field.Size; + Nat.CMov(X25519Field.Size, mask, precompBase, off, p.xyd, 0); off += X25519Field.Size; + } + } + + private static PointExt[] PointPrecompVar(PointExt p, int count) + { + Debug.Assert(count > 0); + + PointExt d = new PointExt(); + PointAddVar(false, p, p, d); + + PointExt[] table = new PointExt[count]; + table[0] = PointCopy(p); + for (int i = 1; i < count; ++i) + { + PointAddVar(false, table[i - 1], d, table[i] = new PointExt()); + } + return table; + } + + private static void PointSetNeutral(PointAccum p) + { + X25519Field.Zero(p.x); + X25519Field.One(p.y); + X25519Field.One(p.z); + X25519Field.Zero(p.u); + X25519Field.One(p.v); + } + + private static void PointSetNeutral(PointExt p) + { + X25519Field.Zero(p.x); + X25519Field.One(p.y); + X25519Field.One(p.z); + X25519Field.Zero(p.t); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public static void Precompute() + { + if (precompBase != null) + { + return; + } + + // Precomputed table for the base point in verification ladder + { + PointExt b = new PointExt(); + X25519Field.Copy(B_x, 0, b.x, 0); + X25519Field.Copy(B_y, 0, b.y, 0); + PointExtendXY(b); + + precompBaseTable = PointPrecompVar(b, 1 << (WnafWidthBase - 2)); + } + + PointAccum p = new PointAccum(); + X25519Field.Copy(B_x, 0, p.x, 0); + X25519Field.Copy(B_y, 0, p.y, 0); + PointExtendXY(p); + + precompBase = new int[PrecompBlocks * PrecompPoints * 3 * X25519Field.Size]; + + int off = 0; + for (int b = 0; b < PrecompBlocks; ++b) + { + PointExt[] ds = new PointExt[PrecompTeeth]; + + PointExt sum = new PointExt(); + PointSetNeutral(sum); + + for (int t = 0; t < PrecompTeeth; ++t) + { + PointExt q = PointCopy(p); + PointAddVar(true, sum, q, sum); + PointDouble(p); + + ds[t] = PointCopy(p); + + for (int s = 1; s < PrecompSpacing; ++s) + { + PointDouble(p); + } + } + + PointExt[] points = new PointExt[PrecompPoints]; + int k = 0; + points[k++] = sum; + + for (int t = 0; t < (PrecompTeeth - 1); ++t) + { + int size = 1 << t; + for (int j = 0; j < size; ++j, ++k) + { + PointAddVar(false, points[k - size], ds[t], points[k] = new PointExt()); + } + } + + Debug.Assert(k == PrecompPoints); + + for (int i = 0; i < PrecompPoints; ++i) + { + PointExt q = points[i]; + + int[] x = X25519Field.Create(); + int[] y = X25519Field.Create(); + + X25519Field.Add(q.z, q.z, x); + // TODO[ed25519] Batch inversion + X25519Field.Inv(x, y); + X25519Field.Mul(q.x, y, x); + X25519Field.Mul(q.y, y, y); + + PointPrecomp r = new PointPrecomp(); + X25519Field.Apm(y, x, r.ypx_h, r.ymx_h); + X25519Field.Mul(x, y, r.xyd); + X25519Field.Mul(r.xyd, C_d4, r.xyd); + + X25519Field.Normalize(r.ypx_h); + X25519Field.Normalize(r.ymx_h); + //X25519Field.Normalize(r.xyd); + + X25519Field.Copy(r.ypx_h, 0, precompBase, off); off += X25519Field.Size; + X25519Field.Copy(r.ymx_h, 0, precompBase, off); off += X25519Field.Size; + X25519Field.Copy(r.xyd, 0, precompBase, off); off += X25519Field.Size; + } + } + + Debug.Assert(off == precompBase.Length); + } + + private static void PruneScalar(byte[] n, int nOff, byte[] r) + { + Array.Copy(n, nOff, r, 0, ScalarBytes); + + r[0] &= 0xF8; + r[ScalarBytes - 1] &= 0x7F; + r[ScalarBytes - 1] |= 0x40; + } + + private static byte[] ReduceScalar(byte[] n) + { + long x00 = Decode32(n, 0) & M32L; // x00:32/-- + long x01 = (Decode24(n, 4) << 4) & M32L; // x01:28/-- + long x02 = Decode32(n, 7) & M32L; // x02:32/-- + long x03 = (Decode24(n, 11) << 4) & M32L; // x03:28/-- + long x04 = Decode32(n, 14) & M32L; // x04:32/-- + long x05 = (Decode24(n, 18) << 4) & M32L; // x05:28/-- + long x06 = Decode32(n, 21) & M32L; // x06:32/-- + long x07 = (Decode24(n, 25) << 4) & M32L; // x07:28/-- + long x08 = Decode32(n, 28) & M32L; // x08:32/-- + long x09 = (Decode24(n, 32) << 4) & M32L; // x09:28/-- + long x10 = Decode32(n, 35) & M32L; // x10:32/-- + long x11 = (Decode24(n, 39) << 4) & M32L; // x11:28/-- + long x12 = Decode32(n, 42) & M32L; // x12:32/-- + long x13 = (Decode24(n, 46) << 4) & M32L; // x13:28/-- + long x14 = Decode32(n, 49) & M32L; // x14:32/-- + long x15 = (Decode24(n, 53) << 4) & M32L; // x15:28/-- + long x16 = Decode32(n, 56) & M32L; // x16:32/-- + long x17 = (Decode24(n, 60) << 4) & M32L; // x17:28/-- + long x18 = n[63] & 0xFFL; // x18:08/-- + long t; + + //x18 += (x17 >> 28); x17 &= M28L; + x09 -= x18 * L0; // x09:34/28 + x10 -= x18 * L1; // x10:33/30 + x11 -= x18 * L2; // x11:35/28 + x12 -= x18 * L3; // x12:32/31 + x13 -= x18 * L4; // x13:28/21 + + x17 += (x16 >> 28); x16 &= M28L; // x17:28/--, x16:28/-- + x08 -= x17 * L0; // x08:54/32 + x09 -= x17 * L1; // x09:52/51 + x10 -= x17 * L2; // x10:55/34 + x11 -= x17 * L3; // x11:51/36 + x12 -= x17 * L4; // x12:41/-- + + //x16 += (x15 >> 28); x15 &= M28L; + x07 -= x16 * L0; // x07:54/28 + x08 -= x16 * L1; // x08:54/53 + x09 -= x16 * L2; // x09:55/53 + x10 -= x16 * L3; // x10:55/52 + x11 -= x16 * L4; // x11:51/41 + + x15 += (x14 >> 28); x14 &= M28L; // x15:28/--, x14:28/-- + x06 -= x15 * L0; // x06:54/32 + x07 -= x15 * L1; // x07:54/53 + x08 -= x15 * L2; // x08:56/-- + x09 -= x15 * L3; // x09:55/54 + x10 -= x15 * L4; // x10:55/53 + + //x14 += (x13 >> 28); x13 &= M28L; + x05 -= x14 * L0; // x05:54/28 + x06 -= x14 * L1; // x06:54/53 + x07 -= x14 * L2; // x07:56/-- + x08 -= x14 * L3; // x08:56/51 + x09 -= x14 * L4; // x09:56/-- + + x13 += (x12 >> 28); x12 &= M28L; // x13:28/22, x12:28/-- + x04 -= x13 * L0; // x04:54/49 + x05 -= x13 * L1; // x05:54/53 + x06 -= x13 * L2; // x06:56/-- + x07 -= x13 * L3; // x07:56/52 + x08 -= x13 * L4; // x08:56/52 + + x12 += (x11 >> 28); x11 &= M28L; // x12:28/24, x11:28/-- + x03 -= x12 * L0; // x03:54/49 + x04 -= x12 * L1; // x04:54/51 + x05 -= x12 * L2; // x05:56/-- + x06 -= x12 * L3; // x06:56/52 + x07 -= x12 * L4; // x07:56/53 + + x11 += (x10 >> 28); x10 &= M28L; // x11:29/--, x10:28/-- + x02 -= x11 * L0; // x02:55/32 + x03 -= x11 * L1; // x03:55/-- + x04 -= x11 * L2; // x04:56/55 + x05 -= x11 * L3; // x05:56/52 + x06 -= x11 * L4; // x06:56/53 + + x10 += (x09 >> 28); x09 &= M28L; // x10:29/--, x09:28/-- + x01 -= x10 * L0; // x01:55/28 + x02 -= x10 * L1; // x02:55/54 + x03 -= x10 * L2; // x03:56/55 + x04 -= x10 * L3; // x04:57/-- + x05 -= x10 * L4; // x05:56/53 + + x08 += (x07 >> 28); x07 &= M28L; // x08:56/53, x07:28/-- + x09 += (x08 >> 28); x08 &= M28L; // x09:29/25, x08:28/-- + + t = (x08 >> 27) & 1L; + x09 += t; // x09:29/26 + + x00 -= x09 * L0; // x00:55/53 + x01 -= x09 * L1; // x01:55/54 + x02 -= x09 * L2; // x02:57/-- + x03 -= x09 * L3; // x03:57/-- + x04 -= x09 * L4; // x04:57/42 + + x01 += (x00 >> 28); x00 &= M28L; + x02 += (x01 >> 28); x01 &= M28L; + x03 += (x02 >> 28); x02 &= M28L; + x04 += (x03 >> 28); x03 &= M28L; + x05 += (x04 >> 28); x04 &= M28L; + x06 += (x05 >> 28); x05 &= M28L; + x07 += (x06 >> 28); x06 &= M28L; + x08 += (x07 >> 28); x07 &= M28L; + x09 = (x08 >> 28); x08 &= M28L; + + x09 -= t; + + Debug.Assert(x09 == 0L || x09 == -1L); + + x00 += x09 & L0; + x01 += x09 & L1; + x02 += x09 & L2; + x03 += x09 & L3; + x04 += x09 & L4; + + x01 += (x00 >> 28); x00 &= M28L; + x02 += (x01 >> 28); x01 &= M28L; + x03 += (x02 >> 28); x02 &= M28L; + x04 += (x03 >> 28); x03 &= M28L; + x05 += (x04 >> 28); x04 &= M28L; + x06 += (x05 >> 28); x05 &= M28L; + x07 += (x06 >> 28); x06 &= M28L; + x08 += (x07 >> 28); x07 &= M28L; + + byte[] r = new byte[ScalarBytes]; + Encode56((ulong)(x00 | (x01 << 28)), r, 0); + Encode56((ulong)(x02 | (x03 << 28)), r, 7); + Encode56((ulong)(x04 | (x05 << 28)), r, 14); + Encode56((ulong)(x06 | (x07 << 28)), r, 21); + Encode32((uint)x08, r, 28); + return r; + } + + private static void ScalarMultBase(byte[] k, PointAccum r) + { + Precompute(); + + PointSetNeutral(r); + + uint[] n = new uint[ScalarUints]; + DecodeScalar(k, 0, n); + + // Recode the scalar into signed-digit form, then group comb bits in each block + { + uint c1 = Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); Debug.Assert(c1 == 0); + uint c2 = Nat.ShiftDownBit(ScalarUints, n, 1U); Debug.Assert(c2 == (1U << 31)); + + for (int i = 0; i < ScalarUints; ++i) + { + n[i] = Interleave.Shuffle2(n[i]); + } + } + + PointPrecomp p = new PointPrecomp(); + + int cOff = (PrecompSpacing - 1) * PrecompTeeth; + for (; ; ) + { + for (int b = 0; b < PrecompBlocks; ++b) + { + uint w = n[b] >> cOff; + int sign = (int)(w >> (PrecompTeeth - 1)) & 1; + int abs = ((int)w ^ -sign) & PrecompMask; + + Debug.Assert(sign == 0 || sign == 1); + Debug.Assert(0 <= abs && abs < PrecompPoints); + + PointLookup(b, abs, p); + + X25519Field.CSwap(sign, p.ypx_h, p.ymx_h); + X25519Field.CNegate(sign, p.xyd); + + PointAddPrecomp(p, r); + } + + if ((cOff -= PrecompTeeth) < 0) + { + break; + } + + PointDouble(r); + } + } + + private static void ScalarMultBaseEncoded(byte[] k, byte[] r, int rOff) + { + PointAccum p = new PointAccum(); + ScalarMultBase(k, p); + EncodePoint(p, r, rOff); + } + + private static void ScalarMultStraussVar(uint[] nb, uint[] np, PointExt p, PointAccum r) + { + Precompute(); + + int width = 5; + + sbyte[] ws_b = GetWnaf(nb, WnafWidthBase); + sbyte[] ws_p = GetWnaf(np, width); + + PointExt[] tp = PointPrecompVar(p, 1 << (width - 2)); + + PointSetNeutral(r); + + int bit = 255; + while (bit > 0 && (ws_b[bit] | ws_p[bit]) == 0) + { + --bit; + } + + for (; ; ) + { + int wb = ws_b[bit]; + if (wb != 0) + { + int sign = wb >> 31; + int index = (wb ^ sign) >> 1; + + PointAddVar((sign != 0), precompBaseTable[index], r); + } + + int wp = ws_p[bit]; + if (wp != 0) + { + int sign = wp >> 31; + int index = (wp ^ sign) >> 1; + + PointAddVar((sign != 0), tp[index], r); + } + + if (--bit < 0) + { + break; + } + + PointDouble(r); + } + } + + public static void Sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + Sha512Digest d = new Sha512Digest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + byte[] pk = new byte[PointBytes]; + ScalarMultBaseEncoded(s, pk, 0); + + ImplSign(d, h, s, pk, 0, m, mOff, mLen, sig, sigOff); + } + + public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + Sha512Digest d = new Sha512Digest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ImplSign(d, h, s, pk, pkOff, m, mOff, mLen, sig, sigOff); + } + + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) + { + byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); + byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + + if (!CheckPointVar(R)) + { + return false; + } + if (!CheckScalarVar(S)) + { + return false; + } + + PointExt pA = new PointExt(); + if (!DecodePointVar(pk, pkOff, true, pA)) + { + return false; + } + + Sha512Digest d = new Sha512Digest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, pkOff, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0); + + byte[] k = ReduceScalar(h); + + uint[] nS = new uint[ScalarUints]; + DecodeScalar(S, 0, nS); + + uint[] nA = new uint[ScalarUints]; + DecodeScalar(k, 0, nA); + + PointAccum pR = new PointAccum(); + ScalarMultStraussVar(nS, nA, pA, pR); + + byte[] check = new byte[PointBytes]; + EncodePoint(pR, check, 0); + + return Arrays.AreEqual(check, R); + } + } +} diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs new file mode 100644 index 000000000..52c215160 --- /dev/null +++ b/crypto/src/math/ec/rfc8032/Ed448.cs @@ -0,0 +1,1067 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Math.EC.Rfc7748; +using Org.BouncyCastle.Math.Raw; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Math.EC.Rfc8032 +{ + public abstract class Ed448 + { + private const ulong M26UL = 0x03FFFFFFUL; + private const ulong M28UL = 0x0FFFFFFFUL; + + private const int PointBytes = 57; + private const int ScalarUints = 14; + private const int ScalarBytes = ScalarUints * 4 + 1; + + public static readonly int PublicKeySize = PointBytes; + public static readonly int SecretKeySize = 57; + public static readonly int SignatureSize = PointBytes + ScalarBytes; + + private static readonly byte[] Dom4Prefix = Strings.ToByteArray("SigEd448"); + + private static readonly uint[] P = { 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, + 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU }; + private static readonly uint[] L = { 0xAB5844F3U, 0x2378C292U, 0x8DC58F55U, 0x216CC272U, 0xAED63690U, 0xC44EDB49U, 0x7CCA23E9U, + 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU }; + private static readonly BigInteger N = Nat.ToBigInteger(L.Length, L); + + private const int L_0 = 0x04A7BB0D; // L_0:26/24 + private const int L_1 = 0x0873D6D5; // L_1:27/23 + private const int L_2 = 0x0A70AADC; // L_2:27/26 + private const int L_3 = 0x03D8D723; // L_3:26/-- + private const int L_4 = 0x096FDE93; // L_4:27/25 + private const int L_5 = 0x0B65129C; // L_5:27/26 + private const int L_6 = 0x063BB124; // L_6:27/-- + private const int L_7 = 0x08335DC1; // L_7:27/22 + + private const int L4_0 = 0x029EEC34; // L4_0:25/24 + private const int L4_1 = 0x01CF5B55; // L4_1:25/-- + private const int L4_2 = 0x09C2AB72; // L4_2:27/25 + private const int L4_3 = 0x0F635C8E; // L4_3:28/-- + private const int L4_4 = 0x05BF7A4C; // L4_4:26/25 + private const int L4_5 = 0x0D944A72; // L4_5:28/-- + private const int L4_6 = 0x08EEC492; // L4_6:27/24 + private const int L4_7 = 0x20CD7705; // L4_7:29/24 + + private static readonly uint[] B_x = { 0x070CC05EU, 0x026A82BCU, 0x00938E26U, 0x080E18B0U, 0x0511433BU, 0x0F72AB66U, 0x0412AE1AU, + 0x0A3D3A46U, 0x0A6DE324U, 0x00F1767EU, 0x04657047U, 0x036DA9E1U, 0x05A622BFU, 0x0ED221D1U, 0x066BED0DU, 0x04F1970CU }; + private static readonly uint[] B_y = { 0x0230FA14U, 0x008795BFU, 0x07C8AD98U, 0x0132C4EDU, 0x09C4FDBDU, 0x01CE67C3U, 0x073AD3FFU, + 0x005A0C2DU, 0x07789C1EU, 0x0A398408U, 0x0A73736CU, 0x0C7624BEU, 0x003756C9U, 0x02488762U, 0x016EB6BCU, 0x0693F467U }; + private const int C_d = -39081; + + private const int WnafWidthBase = 7; + + private const int PrecompBlocks = 5; + private const int PrecompTeeth = 5; + private const int PrecompSpacing = 18; + private const int PrecompPoints = 1 << (PrecompTeeth - 1); + private const int PrecompMask = PrecompPoints - 1; + + // TODO[ed448] Convert to PointPrecomp + private static PointExt[] precompBaseTable = null; + private static uint[] precompBase = null; + + private class PointExt + { + internal uint[] x = X448Field.Create(); + internal uint[] y = X448Field.Create(); + internal uint[] z = X448Field.Create(); + } + + private class PointPrecomp + { + internal uint[] x = X448Field.Create(); + internal uint[] y = X448Field.Create(); + } + + private static byte[] CalculateS(byte[] r, byte[] k, byte[] s) + { + uint[] t = new uint[ScalarUints * 2]; DecodeScalar(r, 0, t); + uint[] u = new uint[ScalarUints]; DecodeScalar(k, 0, u); + uint[] v = new uint[ScalarUints]; DecodeScalar(s, 0, v); + + Nat.MulAddTo(14, u, v, t); + + byte[] result = new byte[ScalarBytes * 2]; + for (int i = 0; i < t.Length; ++i) + { + Encode32(t[i], result, i * 4); + } + return ReduceScalar(result); + } + + private static bool CheckContextVar(byte[] ctx) + { + return ctx != null && ctx.Length < 256; + } + + private static bool CheckPointVar(byte[] p) + { + if ((p[PointBytes - 1] & 0x7F) != 0x00) + { + return false; + } + + uint[] t = new uint[14]; + Decode32(p, 0, t, 0, 14); + return !Nat.Gte(14, t, P); + } + + private static bool CheckScalarVar(byte[] s) + { + if (s[ScalarBytes - 1] != 0x00) + { + return false; + } + + uint[] n = new uint[ScalarUints]; + DecodeScalar(s, 0, n); + return !Nat.Gte(ScalarUints, n, L); + } + + private static uint Decode16(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + return n; + } + + private static uint Decode24(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + return n; + } + + private static uint Decode32(byte[] bs, int off) + { + uint n = bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + private static void Decode32(byte[] bs, int bsOff, uint[] n, int nOff, int nLen) + { + for (int i = 0; i < nLen; ++i) + { + n[nOff + i] = Decode32(bs, bsOff + i * 4); + } + } + + private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointExt r) + { + byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); + if (!CheckPointVar(py)) + { + return false; + } + + int x_0 = (py[PointBytes - 1] & 0x80) >> 7; + py[PointBytes - 1] &= 0x7F; + + X448Field.Decode(py, 0, r.y); + + uint[] u = X448Field.Create(); + uint[] v = X448Field.Create(); + + X448Field.Sqr(r.y, u); + X448Field.Mul(u, (uint)-C_d, v); + X448Field.Negate(u, u); + X448Field.AddOne(u); + X448Field.AddOne(v); + + if (!X448Field.SqrtRatioVar(u, v, r.x)) + { + return false; + } + + X448Field.Normalize(r.x); + if (x_0 == 1 && X448Field.IsZeroVar(r.x)) + { + return false; + } + + if (negate ^ (x_0 != (r.x[0] & 1))) + { + X448Field.Negate(r.x, r.x); + } + + PointExtendXY(r); + return true; + } + + private static void DecodeScalar(byte[] k, int kOff, uint[] n) + { + Debug.Assert(k[kOff + ScalarBytes - 1] == 0x00); + + Decode32(k, kOff, n, 0, ScalarUints); + } + + private static void Dom4(ShakeDigest d, byte x, byte[] y) + { + d.BlockUpdate(Dom4Prefix, 0, Dom4Prefix.Length); + d.Update(x); + d.Update((byte)y.Length); + d.BlockUpdate(y, 0, y.Length); + } + + private static void Encode24(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + } + + private static void Encode32(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 24); + } + + private static void Encode56(ulong n, byte[] bs, int off) + { + Encode32((uint)n, bs, off); + Encode24((uint)(n >> 32), bs, off + 4); + } + + private static void EncodePoint(PointExt p, byte[] r, int rOff) + { + uint[] x = X448Field.Create(); + uint[] y = X448Field.Create(); + + X448Field.Inv(p.z, y); + X448Field.Mul(p.x, y, x); + X448Field.Mul(p.y, y, y); + X448Field.Normalize(x); + X448Field.Normalize(y); + + X448Field.Encode(y, r, rOff); + r[rOff + PointBytes - 1] = (byte)((x[0] & 1) << 7); + } + + public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) + { + ShakeDigest d = new ShakeDigest(256); + byte[] h = new byte[ScalarBytes * 2]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0, h.Length); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ScalarMultBaseEncoded(s, pk, pkOff); + } + + private static sbyte[] GetWnaf(uint[] n, int width) + { + Debug.Assert(n[ScalarUints - 1] >> 31 == 0U); + + uint[] t = new uint[ScalarUints * 2]; + { + uint c = 0; + int tPos = t.Length, i = ScalarUints; + while (--i >= 0) + { + uint next = n[i]; + t[--tPos] = (next >> 16) | (c << 16); + t[--tPos] = c = next; + } + } + + sbyte[] ws = new sbyte[448]; + + uint pow2 = 1U << width; + uint mask = pow2 - 1U; + uint sign = pow2 >> 1; + + uint carry = 0U; + int j = 0; + for (int i = 0; i < t.Length; ++i, j -= 16) + { + uint word = t[i]; + while (j < 16) + { + uint word16 = word >> j; + uint bit = word16 & 1U; + + if (bit == carry) + { + ++j; + continue; + } + + uint digit = (word16 & mask) + carry; + carry = digit & sign; + digit -= (carry << 1); + carry >>= (width - 1); + + ws[(i << 4) + j] = (sbyte)digit; + + j += width; + } + } + + Debug.Assert(carry == 0); + + return ws; + } + + private static void ImplSign(ShakeDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte phflag = 0x00; + + Dom4(d, phflag, ctx); + d.BlockUpdate(h, ScalarBytes, ScalarBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0, h.Length); + + byte[] r = ReduceScalar(h); + byte[] R = new byte[PointBytes]; + ScalarMultBaseEncoded(r, R, 0); + + Dom4(d, phflag, ctx); + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, pkOff, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0, h.Length); + + byte[] k = ReduceScalar(h); + byte[] S = CalculateS(r, k, s); + + Array.Copy(R, 0, sig, sigOff, PointBytes); + Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes); + } + + private static void PointAddVar(bool negate, PointExt p, PointExt r) + { + uint[] A = X448Field.Create(); + uint[] B = X448Field.Create(); + uint[] C = X448Field.Create(); + uint[] D = X448Field.Create(); + uint[] E = X448Field.Create(); + uint[] F = X448Field.Create(); + uint[] G = X448Field.Create(); + uint[] H = X448Field.Create(); + + uint[] b, e, f, g; + if (negate) + { + b = E; e = B; f = G; g = F; + X448Field.Sub(p.y, p.x, H); + } + else + { + b = B; e = E; f = F; g = G; + X448Field.Add(p.y, p.x, H); + } + + X448Field.Mul(p.z, r.z, A); + X448Field.Sqr(A, B); + X448Field.Mul(p.x, r.x, C); + X448Field.Mul(p.y, r.y, D); + X448Field.Mul(C, D, E); + X448Field.Mul(E, -C_d, E); + // X448Field.Apm(B, E, F, G); + X448Field.Add(B, E, f); + X448Field.Sub(B, E, g); + X448Field.Add(r.x, r.y, E); + X448Field.Mul(H, E, H); + // X448Field.Apm(D, C, B, E); + X448Field.Add(D, C, b); + X448Field.Sub(D, C, e); + X448Field.Carry(b); + X448Field.Sub(H, B, H); + X448Field.Mul(H, A, H); + X448Field.Mul(E, A, E); + X448Field.Mul(F, H, r.x); + X448Field.Mul(E, G, r.y); + X448Field.Mul(F, G, r.z); + } + + private static void PointAddPrecomp(PointPrecomp p, PointExt r) + { + uint[] B = X448Field.Create(); + uint[] C = X448Field.Create(); + uint[] D = X448Field.Create(); + uint[] E = X448Field.Create(); + uint[] F = X448Field.Create(); + uint[] G = X448Field.Create(); + uint[] H = X448Field.Create(); + + X448Field.Sqr(r.z, B); + X448Field.Mul(p.x, r.x, C); + X448Field.Mul(p.y, r.y, D); + X448Field.Mul(C, D, E); + X448Field.Mul(E, -C_d, E); + // X448Field.Apm(B, E, F, G); + X448Field.Add(B, E, F); + X448Field.Sub(B, E, G); + X448Field.Add(p.x, p.y, B); + X448Field.Add(r.x, r.y, E); + X448Field.Mul(B, E, H); + // X448Field.Apm(D, C, B, E); + X448Field.Add(D, C, B); + X448Field.Sub(D, C, E); + X448Field.Carry(B); + X448Field.Sub(H, B, H); + X448Field.Mul(H, r.z, H); + X448Field.Mul(E, r.z, E); + X448Field.Mul(F, H, r.x); + X448Field.Mul(E, G, r.y); + X448Field.Mul(F, G, r.z); + } + + private static PointExt PointCopy(PointExt p) + { + PointExt r = new PointExt(); + X448Field.Copy(p.x, 0, r.x, 0); + X448Field.Copy(p.y, 0, r.y, 0); + X448Field.Copy(p.z, 0, r.z, 0); + return r; + } + + private static void PointDouble(PointExt r) + { + uint[] B = X448Field.Create(); + uint[] C = X448Field.Create(); + uint[] D = X448Field.Create(); + uint[] E = X448Field.Create(); + uint[] H = X448Field.Create(); + uint[] J = X448Field.Create(); + + X448Field.Add(r.x, r.y, B); + X448Field.Sqr(B, B); + X448Field.Sqr(r.x, C); + X448Field.Sqr(r.y, D); + X448Field.Add(C, D, E); + X448Field.Carry(E); + X448Field.Sqr(r.z, H); + X448Field.Add(H, H, H); + X448Field.Carry(H); + X448Field.Sub(E, H, J); + X448Field.Sub(B, E, B); + X448Field.Sub(C, D, C); + X448Field.Mul(B, J, r.x); + X448Field.Mul(E, C, r.y); + X448Field.Mul(E, J, r.z); + } + + private static void PointExtendXY(PointExt p) + { + X448Field.One(p.z); + } + + private static void PointLookup(int block, int index, PointPrecomp p) + { + Debug.Assert(0 <= block && block < PrecompBlocks); + Debug.Assert(0 <= index && index < PrecompPoints); + + int off = block * PrecompPoints * 2 * X448Field.Size; + + for (int i = 0; i < PrecompPoints; ++i) + { + int mask = ((i ^ index) - 1) >> 31; + Nat.CMov(X448Field.Size, mask, precompBase, off, p.x, 0); off += X448Field.Size; + Nat.CMov(X448Field.Size, mask, precompBase, off, p.y, 0); off += X448Field.Size; + } + } + + private static PointExt[] PointPrecompVar(PointExt p, int count) + { + Debug.Assert(count > 0); + + PointExt d = PointCopy(p); + PointDouble(d); + + PointExt[] table = new PointExt[count]; + table[0] = PointCopy(p); + for (int i = 1; i < count; ++i) + { + table[i] = PointCopy(table[i - 1]); + PointAddVar(false, d, table[i]); + } + return table; + } + + private static void PointSetNeutral(PointExt p) + { + X448Field.Zero(p.x); + X448Field.One(p.y); + X448Field.One(p.z); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public static void Precompute() + { + if (precompBase != null) + { + return; + } + + PointExt p = new PointExt(); + X448Field.Copy(B_x, 0, p.x, 0); + X448Field.Copy(B_y, 0, p.y, 0); + PointExtendXY(p); + + precompBaseTable = PointPrecompVar(p, 1 << (WnafWidthBase - 2)); + + precompBase = new uint[PrecompBlocks * PrecompPoints * 2 * X448Field.Size]; + + int off = 0; + for (int b = 0; b < PrecompBlocks; ++b) + { + PointExt[] ds = new PointExt[PrecompTeeth]; + + PointExt sum = new PointExt(); + PointSetNeutral(sum); + + for (int t = 0; t < PrecompTeeth; ++t) + { + PointAddVar(true, p, sum); + PointDouble(p); + + ds[t] = PointCopy(p); + + for (int s = 1; s < PrecompSpacing; ++s) + { + PointDouble(p); + } + } + + PointExt[] points = new PointExt[PrecompPoints]; + int k = 0; + points[k++] = sum; + + for (int t = 0; t < (PrecompTeeth - 1); ++t) + { + int size = 1 << t; + for (int j = 0; j < size; ++j, ++k) + { + points[k] = PointCopy(points[k - size]); + PointAddVar(false, ds[t], points[k]); + } + } + + Debug.Assert(k == PrecompPoints); + + for (int i = 0; i < PrecompPoints; ++i) + { + PointExt q = points[i]; + // TODO[ed448] Batch inversion + X448Field.Inv(q.z, q.z); + X448Field.Mul(q.x, q.z, q.x); + X448Field.Mul(q.y, q.z, q.y); + + // X448Field.Normalize(q.x); + // X448Field.Normalize(q.y); + + X448Field.Copy(q.x, 0, precompBase, off); off += X448Field.Size; + X448Field.Copy(q.y, 0, precompBase, off); off += X448Field.Size; + } + } + + Debug.Assert(off == precompBase.Length); + } + + private static void PruneScalar(byte[] n, int nOff, byte[] r) + { + Array.Copy(n, nOff, r, 0, ScalarBytes); + + r[0] &= 0xFC; + r[ScalarBytes - 2] |= 0x80; + r[ScalarBytes - 1] &= 0x00; + } + + private static byte[] ReduceScalar(byte[] n) + { + ulong x00 = Decode32(n, 0); // x00:32/-- + ulong x01 = (Decode24(n, 4) << 4); // x01:28/-- + ulong x02 = Decode32(n, 7); // x02:32/-- + ulong x03 = (Decode24(n, 11) << 4); // x03:28/-- + ulong x04 = Decode32(n, 14); // x04:32/-- + ulong x05 = (Decode24(n, 18) << 4); // x05:28/-- + ulong x06 = Decode32(n, 21); // x06:32/-- + ulong x07 = (Decode24(n, 25) << 4); // x07:28/-- + ulong x08 = Decode32(n, 28); // x08:32/-- + ulong x09 = (Decode24(n, 32) << 4); // x09:28/-- + ulong x10 = Decode32(n, 35); // x10:32/-- + ulong x11 = (Decode24(n, 39) << 4); // x11:28/-- + ulong x12 = Decode32(n, 42); // x12:32/-- + ulong x13 = (Decode24(n, 46) << 4); // x13:28/-- + ulong x14 = Decode32(n, 49); // x14:32/-- + ulong x15 = (Decode24(n, 53) << 4); // x15:28/-- + ulong x16 = Decode32(n, 56); // x16:32/-- + ulong x17 = (Decode24(n, 60) << 4); // x17:28/-- + ulong x18 = Decode32(n, 63); // x18:32/-- + ulong x19 = (Decode24(n, 67) << 4); // x19:28/-- + ulong x20 = Decode32(n, 70); // x20:32/-- + ulong x21 = (Decode24(n, 74) << 4); // x21:28/-- + ulong x22 = Decode32(n, 77); // x22:32/-- + ulong x23 = (Decode24(n, 81) << 4); // x23:28/-- + ulong x24 = Decode32(n, 84); // x24:32/-- + ulong x25 = (Decode24(n, 88) << 4); // x25:28/-- + ulong x26 = Decode32(n, 91); // x26:32/-- + ulong x27 = (Decode24(n, 95) << 4); // x27:28/-- + ulong x28 = Decode32(n, 98); // x28:32/-- + ulong x29 = (Decode24(n, 102) << 4); // x29:28/-- + ulong x30 = Decode32(n, 105); // x30:32/-- + ulong x31 = (Decode24(n, 109) << 4); // x31:28/-- + ulong x32 = Decode16(n, 112); // x32:16/-- + + // x32 += (x31 >> 28); x31 &= M28UL; + x16 += x32 * L4_0; // x16:42/-- + x17 += x32 * L4_1; // x17:41/28 + x18 += x32 * L4_2; // x18:43/42 + x19 += x32 * L4_3; // x19:44/28 + x20 += x32 * L4_4; // x20:43/-- + x21 += x32 * L4_5; // x21:44/28 + x22 += x32 * L4_6; // x22:43/41 + x23 += x32 * L4_7; // x23:45/41 + + x31 += (x30 >> 28); x30 &= M28UL; // x31:28/--, x30:28/-- + x15 += x31 * L4_0; // x15:54/-- + x16 += x31 * L4_1; // x16:53/42 + x17 += x31 * L4_2; // x17:55/54 + x18 += x31 * L4_3; // x18:56/44 + x19 += x31 * L4_4; // x19:55/-- + x20 += x31 * L4_5; // x20:56/43 + x21 += x31 * L4_6; // x21:55/53 + x22 += x31 * L4_7; // x22:57/53 + + // x30 += (x29 >> 28); x29 &= M28UL; + x14 += x30 * L4_0; // x14:54/-- + x15 += x30 * L4_1; // x15:54/53 + x16 += x30 * L4_2; // x16:56/-- + x17 += x30 * L4_3; // x17:57/-- + x18 += x30 * L4_4; // x18:56/55 + x19 += x30 * L4_5; // x19:56/55 + x20 += x30 * L4_6; // x20:57/-- + x21 += x30 * L4_7; // x21:57/56 + + x29 += (x28 >> 28); x28 &= M28UL; // x29:28/--, x28:28/-- + x13 += x29 * L4_0; // x13:54/-- + x14 += x29 * L4_1; // x14:54/53 + x15 += x29 * L4_2; // x15:56/-- + x16 += x29 * L4_3; // x16:57/-- + x17 += x29 * L4_4; // x17:57/55 + x18 += x29 * L4_5; // x18:57/55 + x19 += x29 * L4_6; // x19:57/52 + x20 += x29 * L4_7; // x20:58/52 + + // x28 += (x27 >> 28); x27 &= M28UL; + x12 += x28 * L4_0; // x12:54/-- + x13 += x28 * L4_1; // x13:54/53 + x14 += x28 * L4_2; // x14:56/-- + x15 += x28 * L4_3; // x15:57/-- + x16 += x28 * L4_4; // x16:57/55 + x17 += x28 * L4_5; // x17:58/-- + x18 += x28 * L4_6; // x18:58/-- + x19 += x28 * L4_7; // x19:58/53 + + x27 += (x26 >> 28); x26 &= M28UL; // x27:28/--, x26:28/-- + x11 += x27 * L4_0; // x11:54/-- + x12 += x27 * L4_1; // x12:54/53 + x13 += x27 * L4_2; // x13:56/-- + x14 += x27 * L4_3; // x14:57/-- + x15 += x27 * L4_4; // x15:57/55 + x16 += x27 * L4_5; // x16:58/-- + x17 += x27 * L4_6; // x17:58/56 + x18 += x27 * L4_7; // x18:59/-- + + // x26 += (x25 >> 28); x25 &= M28UL; + x10 += x26 * L4_0; // x10:54/-- + x11 += x26 * L4_1; // x11:54/53 + x12 += x26 * L4_2; // x12:56/-- + x13 += x26 * L4_3; // x13:57/-- + x14 += x26 * L4_4; // x14:57/55 + x15 += x26 * L4_5; // x15:58/-- + x16 += x26 * L4_6; // x16:58/56 + x17 += x26 * L4_7; // x17:59/-- + + x25 += (x24 >> 28); x24 &= M28UL; // x25:28/--, x24:28/-- + x09 += x25 * L4_0; // x09:54/-- + x10 += x25 * L4_1; // x10:54/53 + x11 += x25 * L4_2; // x11:56/-- + x12 += x25 * L4_3; // x12:57/-- + x13 += x25 * L4_4; // x13:57/55 + x14 += x25 * L4_5; // x14:58/-- + x15 += x25 * L4_6; // x15:58/56 + x16 += x25 * L4_7; // x16:59/-- + + x21 += (x20 >> 28); x20 &= M28UL; // x21:58/--, x20:28/-- + x22 += (x21 >> 28); x21 &= M28UL; // x22:57/54, x21:28/-- + x23 += (x22 >> 28); x22 &= M28UL; // x23:45/42, x22:28/-- + x24 += (x23 >> 28); x23 &= M28UL; // x24:28/18, x23:28/-- + + x08 += x24 * L4_0; // x08:54/-- + x09 += x24 * L4_1; // x09:55/-- + x10 += x24 * L4_2; // x10:56/46 + x11 += x24 * L4_3; // x11:57/46 + x12 += x24 * L4_4; // x12:57/55 + x13 += x24 * L4_5; // x13:58/-- + x14 += x24 * L4_6; // x14:58/56 + x15 += x24 * L4_7; // x15:59/-- + + x07 += x23 * L4_0; // x07:54/-- + x08 += x23 * L4_1; // x08:54/53 + x09 += x23 * L4_2; // x09:56/53 + x10 += x23 * L4_3; // x10:57/46 + x11 += x23 * L4_4; // x11:57/55 + x12 += x23 * L4_5; // x12:58/-- + x13 += x23 * L4_6; // x13:58/56 + x14 += x23 * L4_7; // x14:59/-- + + x06 += x22 * L4_0; // x06:54/-- + x07 += x22 * L4_1; // x07:54/53 + x08 += x22 * L4_2; // x08:56/-- + x09 += x22 * L4_3; // x09:57/53 + x10 += x22 * L4_4; // x10:57/55 + x11 += x22 * L4_5; // x11:58/-- + x12 += x22 * L4_6; // x12:58/56 + x13 += x22 * L4_7; // x13:59/-- + + x18 += (x17 >> 28); x17 &= M28UL; // x18:59/31, x17:28/-- + x19 += (x18 >> 28); x18 &= M28UL; // x19:58/54, x18:28/-- + x20 += (x19 >> 28); x19 &= M28UL; // x20:30/29, x19:28/-- + x21 += (x20 >> 28); x20 &= M28UL; // x21:28/03, x20:28/-- + + x05 += x21 * L4_0; // x05:54/-- + x06 += x21 * L4_1; // x06:55/-- + x07 += x21 * L4_2; // x07:56/31 + x08 += x21 * L4_3; // x08:57/31 + x09 += x21 * L4_4; // x09:57/56 + x10 += x21 * L4_5; // x10:58/-- + x11 += x21 * L4_6; // x11:58/56 + x12 += x21 * L4_7; // x12:59/-- + + x04 += x20 * L4_0; // x04:54/-- + x05 += x20 * L4_1; // x05:54/53 + x06 += x20 * L4_2; // x06:56/53 + x07 += x20 * L4_3; // x07:57/31 + x08 += x20 * L4_4; // x08:57/55 + x09 += x20 * L4_5; // x09:58/-- + x10 += x20 * L4_6; // x10:58/56 + x11 += x20 * L4_7; // x11:59/-- + + x03 += x19 * L4_0; // x03:54/-- + x04 += x19 * L4_1; // x04:54/53 + x05 += x19 * L4_2; // x05:56/-- + x06 += x19 * L4_3; // x06:57/53 + x07 += x19 * L4_4; // x07:57/55 + x08 += x19 * L4_5; // x08:58/-- + x09 += x19 * L4_6; // x09:58/56 + x10 += x19 * L4_7; // x10:59/-- + + x15 += (x14 >> 28); x14 &= M28UL; // x15:59/31, x14:28/-- + x16 += (x15 >> 28); x15 &= M28UL; // x16:59/32, x15:28/-- + x17 += (x16 >> 28); x16 &= M28UL; // x17:31/29, x16:28/-- + x18 += (x17 >> 28); x17 &= M28UL; // x18:28/04, x17:28/-- + + x02 += x18 * L4_0; // x02:54/-- + x03 += x18 * L4_1; // x03:55/-- + x04 += x18 * L4_2; // x04:56/32 + x05 += x18 * L4_3; // x05:57/32 + x06 += x18 * L4_4; // x06:57/56 + x07 += x18 * L4_5; // x07:58/-- + x08 += x18 * L4_6; // x08:58/56 + x09 += x18 * L4_7; // x09:59/-- + + x01 += x17 * L4_0; // x01:54/-- + x02 += x17 * L4_1; // x02:54/53 + x03 += x17 * L4_2; // x03:56/53 + x04 += x17 * L4_3; // x04:57/32 + x05 += x17 * L4_4; // x05:57/55 + x06 += x17 * L4_5; // x06:58/-- + x07 += x17 * L4_6; // x07:58/56 + x08 += x17 * L4_7; // x08:59/-- + + x16 *= 4; + x16 += (x15 >> 26); x15 &= M26UL; + x16 += 1; // x16:30/01 + + x00 += x16 * L_0; + x01 += x16 * L_1; + x02 += x16 * L_2; + x03 += x16 * L_3; + x04 += x16 * L_4; + x05 += x16 * L_5; + x06 += x16 * L_6; + x07 += x16 * L_7; + + x01 += (x00 >> 28); x00 &= M28UL; + x02 += (x01 >> 28); x01 &= M28UL; + x03 += (x02 >> 28); x02 &= M28UL; + x04 += (x03 >> 28); x03 &= M28UL; + x05 += (x04 >> 28); x04 &= M28UL; + x06 += (x05 >> 28); x05 &= M28UL; + x07 += (x06 >> 28); x06 &= M28UL; + x08 += (x07 >> 28); x07 &= M28UL; + x09 += (x08 >> 28); x08 &= M28UL; + x10 += (x09 >> 28); x09 &= M28UL; + x11 += (x10 >> 28); x10 &= M28UL; + x12 += (x11 >> 28); x11 &= M28UL; + x13 += (x12 >> 28); x12 &= M28UL; + x14 += (x13 >> 28); x13 &= M28UL; + x15 += (x14 >> 28); x14 &= M28UL; + x16 = (x15 >> 26); x15 &= M26UL; + + x16 -= 1; + + Debug.Assert(x16 == 0UL || x16 == ulong.MaxValue); + + x00 -= x16 & L_0; + x01 -= x16 & L_1; + x02 -= x16 & L_2; + x03 -= x16 & L_3; + x04 -= x16 & L_4; + x05 -= x16 & L_5; + x06 -= x16 & L_6; + x07 -= x16 & L_7; + + x01 += (ulong)((long)x00 >> 28); x00 &= M28UL; + x02 += (ulong)((long)x01 >> 28); x01 &= M28UL; + x03 += (ulong)((long)x02 >> 28); x02 &= M28UL; + x04 += (ulong)((long)x03 >> 28); x03 &= M28UL; + x05 += (ulong)((long)x04 >> 28); x04 &= M28UL; + x06 += (ulong)((long)x05 >> 28); x05 &= M28UL; + x07 += (ulong)((long)x06 >> 28); x06 &= M28UL; + x08 += (ulong)((long)x07 >> 28); x07 &= M28UL; + x09 += (ulong)((long)x08 >> 28); x08 &= M28UL; + x10 += (ulong)((long)x09 >> 28); x09 &= M28UL; + x11 += (ulong)((long)x10 >> 28); x10 &= M28UL; + x12 += (ulong)((long)x11 >> 28); x11 &= M28UL; + x13 += (ulong)((long)x12 >> 28); x12 &= M28UL; + x14 += (ulong)((long)x13 >> 28); x13 &= M28UL; + x15 += (ulong)((long)x14 >> 28); x14 &= M28UL; + + Debug.Assert(x15 >> 26 == 0UL); + + byte[] r = new byte[ScalarBytes]; + Encode56(x00 | (x01 << 28), r, 0); + Encode56(x02 | (x03 << 28), r, 7); + Encode56(x04 | (x05 << 28), r, 14); + Encode56(x06 | (x07 << 28), r, 21); + Encode56(x08 | (x09 << 28), r, 28); + Encode56(x10 | (x11 << 28), r, 35); + Encode56(x12 | (x13 << 28), r, 42); + Encode56(x14 | (x15 << 28), r, 49); + // r[ScalarBytes - 1] = 0; + return r; + } + + private static void ScalarMultBase(byte[] k, PointExt r) + { + Precompute(); + + PointSetNeutral(r); + + uint[] n = new uint[ScalarUints + 1]; + DecodeScalar(k, 0, n); + + // Recode the scalar into signed-digit form + { + n[ScalarUints] = 4U + Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); + uint c = Nat.ShiftDownBit(n.Length, n, 0); + Debug.Assert(c == (1U << 31)); + } + + PointPrecomp p = new PointPrecomp(); + + int cOff = PrecompSpacing - 1; + for (;;) + { + int tPos = cOff; + + for (int b = 0; b < PrecompBlocks; ++b) + { + uint w = 0; + for (int t = 0; t < PrecompTeeth; ++t) + { + uint tBit = (n[tPos >> 5] >> (tPos & 0x1F)) & 1U; + w |= tBit << t; + tPos += PrecompSpacing; + } + + int sign = (int)(w >> (PrecompTeeth - 1)) & 1; + int abs = ((int)w ^ -sign) & PrecompMask; + + Debug.Assert(sign == 0 || sign == 1); + Debug.Assert(0 <= abs && abs < PrecompPoints); + + PointLookup(b, abs, p); + + X448Field.CNegate(sign, p.x); + + PointAddPrecomp(p, r); + } + + if (--cOff < 0) + { + break; + } + + PointDouble(r); + } + } + + private static void ScalarMultBaseEncoded(byte[] k, byte[] r, int rOff) + { + PointExt p = new PointExt(); + ScalarMultBase(k, p); + EncodePoint(p, r, rOff); + } + + private static void ScalarMultStraussVar(uint[] nb, uint[] np, PointExt p, PointExt r) + { + Precompute(); + + int width = 5; + + sbyte[] ws_b = GetWnaf(nb, WnafWidthBase); + sbyte[] ws_p = GetWnaf(np, width); + + PointExt[] tp = PointPrecompVar(p, 1 << (width - 2)); + + PointSetNeutral(r); + + int bit = 447; + while (bit > 0 && (ws_b[bit] | ws_p[bit]) == 0) + { + --bit; + } + + for (;;) + { + int wb = ws_b[bit]; + if (wb != 0) + { + int sign = wb >> 31; + int index = (wb ^ sign) >> 1; + + PointAddVar((sign != 0), precompBaseTable[index], r); + } + + int wp = ws_p[bit]; + if (wp != 0) + { + int sign = wp >> 31; + int index = (wp ^ sign) >> 1; + + PointAddVar((sign != 0), tp[index], r); + } + + if (--bit < 0) + { + break; + } + + PointDouble(r); + } + } + + public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx)) + { + throw new ArgumentException("ctx"); + } + + ShakeDigest d = new ShakeDigest(256); + byte[] h = new byte[ScalarBytes * 2]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0, h.Length); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + byte[] pk = new byte[PointBytes]; + ScalarMultBaseEncoded(s, pk, 0); + + ImplSign(d, h, s, pk, 0, ctx, m, mOff, mLen, sig, sigOff); + } + + public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx)) + { + throw new ArgumentException("ctx"); + } + + ShakeDigest d = new ShakeDigest(256); + byte[] h = new byte[ScalarBytes * 2]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0, h.Length); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ImplSign(d, h, s, pk, pkOff, ctx, m, mOff, mLen, sig, sigOff); + } + + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + { + if (!CheckContextVar(ctx)) + { + throw new ArgumentException("ctx"); + } + + byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); + byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + + if (!CheckPointVar(R)) + { + return false; + } + if (!CheckScalarVar(S)) + { + return false; + } + + PointExt pA = new PointExt(); + if (!DecodePointVar(pk, pkOff, true, pA)) + { + return false; + } + + byte phflag = 0x00; + + ShakeDigest d = new ShakeDigest(256); + byte[] h = new byte[ScalarBytes * 2]; + + Dom4(d, phflag, ctx); + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, pkOff, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0, h.Length); + + byte[] k = ReduceScalar(h); + + uint[] nS = new uint[ScalarUints]; + DecodeScalar(S, 0, nS); + + uint[] nA = new uint[ScalarUints]; + DecodeScalar(k, 0, nA); + + PointExt pR = new PointExt(); + ScalarMultStraussVar(nS, nA, pA, pR); + + byte[] check = new byte[PointBytes]; + EncodePoint(pR, check, 0); + + return Arrays.AreEqual(check, R); + } + } +} diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs index d21840644..591ba3f15 100644 --- a/crypto/src/math/raw/Interleave.cs +++ b/crypto/src/math/raw/Interleave.cs @@ -6,6 +6,7 @@ namespace Org.BouncyCastle.Math.Raw { private const ulong M32 = 0x55555555UL; private const ulong M64 = 0x5555555555555555UL; + private const ulong M64R = 0xAAAAAAAAAAAAAAAAUL; /* * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. @@ -92,6 +93,65 @@ namespace Org.BouncyCastle.Math.Raw z[zOff + 1] = (x >> 1) & M64; } + internal static void Expand64To128Rev(ulong x, ulong[] z, int zOff) + { + // "shuffle" low half to even bits and high half to odd bits + ulong t; + t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16)); + t = (x ^ (x >> 8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t << 8)); + t = (x ^ (x >> 4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t << 2)); + t = (x ^ (x >> 1)) & 0x2222222222222222UL; x ^= (t ^ (t << 1)); + + z[zOff] = (x ) & M64R; + z[zOff + 1] = (x << 1) & M64R; + } + + internal static uint Shuffle(uint x) + { + // "shuffle" low half to even bits and high half to odd bits + uint t; + t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8)); + t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 2)) & 0x0C0C0C0CU; x ^= (t ^ (t << 2)); + t = (x ^ (x >> 1)) & 0x22222222U; x ^= (t ^ (t << 1)); + return x; + } + + internal static ulong Shuffle(ulong x) + { + // "shuffle" low half to even bits and high half to odd bits + ulong t; + t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16)); + t = (x ^ (x >> 8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t << 8)); + t = (x ^ (x >> 4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t << 2)); + t = (x ^ (x >> 1)) & 0x2222222222222222UL; x ^= (t ^ (t << 1)); + return x; + } + + internal static uint Shuffle2(uint x) + { + // "shuffle" (twice) low half to even bits and high half to odd bits + uint t; + t = (x ^ (x >> 7)) & 0x00AA00AAU; x ^= (t ^ (t << 7)); + t = (x ^ (x >> 14)) & 0x0000CCCCU; x ^= (t ^ (t << 14)); + t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8)); + return x; + } + + internal static uint Unshuffle(uint x) + { + // "unshuffle" even bits to low half and odd bits to high half + uint t; + t = (x ^ (x >> 1)) & 0x22222222U; x ^= (t ^ (t << 1)); + t = (x ^ (x >> 2)) & 0x0C0C0C0CU; x ^= (t ^ (t << 2)); + t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8)); + return x; + } + internal static ulong Unshuffle(ulong x) { // "unshuffle" even bits to low half and odd bits to high half @@ -103,5 +163,16 @@ namespace Org.BouncyCastle.Math.Raw t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16)); return x; } + + internal static uint Unshuffle2(uint x) + { + // "unshuffle" (twice) even bits to low half and odd bits to high half + uint t; + t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8)); + t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4)); + t = (x ^ (x >> 14)) & 0x0000CCCCU; x ^= (t ^ (t << 14)); + t = (x ^ (x >> 7)) & 0x00AA00AAU; x ^= (t ^ (t << 7)); + return x; + } } } diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs index 1f9ab00ec..7ca60278a 100644 --- a/crypto/src/math/raw/Nat.cs +++ b/crypto/src/math/raw/Nat.cs @@ -195,6 +195,64 @@ namespace Org.BouncyCastle.Math.Raw return c == 0 ? 0 : IncAt(len, z, zOff, 1); } + public static uint CAdd(int len, int mask, uint[] x, uint[] y, uint[] z) + { + uint MASK = (uint)-(mask & 1); + + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[i] + (y[i] & MASK); + z[i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static void CMov(int len, int mask, uint[] x, int xOff, uint[] z, int zOff) + { + uint MASK = (uint)-(mask & 1); + + for (int i = 0; i < len; ++i) + { + uint z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & MASK); + z[zOff + i] = z_i; + } + + //uint half = 0x55555555U, rest = half << (-(int)MASK); + + //for (int i = 0; i < len; ++i) + //{ + // uint z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + // z_i ^= (diff & half); + // z_i ^= (diff & rest); + // z[zOff + i] = z_i; + //} + } + + public static void CMov(int len, int mask, int[] x, int xOff, int[] z, int zOff) + { + mask = -(mask & 1); + + for (int i = 0; i < len; ++i) + { + int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & mask); + z[zOff + i] = z_i; + } + + //int half = 0x55555555, rest = half << (-mask); + + //for (int i = 0; i < len; ++i) + //{ + // int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + // z_i ^= (diff & half); + // z_i ^= (diff & rest); + // z[zOff + i] = z_i; + //} + } + public static void Copy(int len, uint[] x, uint[] z) { Array.Copy(x, 0, z, 0, len); @@ -207,6 +265,11 @@ namespace Org.BouncyCastle.Math.Raw return z; } + public static void Copy(int len, uint[] x, int xOff, uint[] z, int zOff) + { + Array.Copy(x, xOff, z, zOff, len); + } + public static uint[] Create(int len) { return new uint[len]; @@ -443,6 +506,33 @@ namespace Org.BouncyCastle.Math.Raw } } + public static uint MulAddTo(int len, uint[] x, uint[] y, uint[] zz) + { + ulong zc = 0; + for (int i = 0; i < len; ++i) + { + ulong c = MulWordAddTo(len, x[i], y, 0, zz, i) & M; + c += zc + (zz[i + len] & M); + zz[i + len] = (uint)c; + zc = c >> 32; + } + return (uint)zc; + } + + public static uint MulAddTo(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff) + { + ulong zc = 0; + for (int i = 0; i < len; ++i) + { + ulong c = MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; + c += zc + (zz[zzOff + len] & M); + zz[zzOff + len] = (uint)c; + zc = c >> 32; + ++zzOff; + } + return (uint)zc; + } + public static uint Mul31BothAdd(int len, uint a, uint[] x, uint b, uint[] y, uint[] z, int zOff) { ulong c = 0, aVal = (ulong)a, bVal = (ulong)b; diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs index 1d3b64d32..27ed5abe4 100644 --- a/crypto/src/math/raw/Nat128.cs +++ b/crypto/src/math/raw/Nat128.cs @@ -111,12 +111,26 @@ namespace Org.BouncyCastle.Math.Raw z[3] = x[3]; } + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + } + public static void Copy64(ulong[] x, ulong[] z) { z[0] = x[0]; z[1] = x[1]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + } + public static uint[] Create() { return new uint[4]; diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs index 1fd00e576..57212cae0 100644 --- a/crypto/src/math/raw/Nat160.cs +++ b/crypto/src/math/raw/Nat160.cs @@ -129,6 +129,15 @@ namespace Org.BouncyCastle.Math.Raw z[4] = x[4]; } + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + } + public static uint[] Create() { return new uint[5]; diff --git a/crypto/src/math/raw/Nat192.cs b/crypto/src/math/raw/Nat192.cs index 3099bafab..06c75aa54 100644 --- a/crypto/src/math/raw/Nat192.cs +++ b/crypto/src/math/raw/Nat192.cs @@ -145,6 +145,16 @@ namespace Org.BouncyCastle.Math.Raw z[5] = x[5]; } + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + } + public static void Copy64(ulong[] x, ulong[] z) { z[0] = x[0]; @@ -152,6 +162,13 @@ namespace Org.BouncyCastle.Math.Raw z[2] = x[2]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + } + public static uint[] Create() { return new uint[6]; diff --git a/crypto/src/math/raw/Nat224.cs b/crypto/src/math/raw/Nat224.cs index 978caf265..ff1eb6306 100644 --- a/crypto/src/math/raw/Nat224.cs +++ b/crypto/src/math/raw/Nat224.cs @@ -216,6 +216,17 @@ namespace Org.BouncyCastle.Math.Raw z[6] = x[6]; } + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + } + public static uint[] Create() { return new uint[7]; diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs index 09c751a5a..2be03d642 100644 --- a/crypto/src/math/raw/Nat256.cs +++ b/crypto/src/math/raw/Nat256.cs @@ -239,6 +239,18 @@ namespace Org.BouncyCastle.Math.Raw z[7] = x[7]; } + public static void Copy(uint[] x, int xOff, uint[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + z[zOff + 7] = x[xOff + 7]; + } + public static void Copy64(ulong[] x, ulong[] z) { z[0] = x[0]; @@ -247,6 +259,14 @@ namespace Org.BouncyCastle.Math.Raw z[3] = x[3]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + } + public static uint[] Create() { return new uint[8]; diff --git a/crypto/src/math/raw/Nat320.cs b/crypto/src/math/raw/Nat320.cs index c7daa71e2..0ad677db4 100644 --- a/crypto/src/math/raw/Nat320.cs +++ b/crypto/src/math/raw/Nat320.cs @@ -16,6 +16,15 @@ namespace Org.BouncyCastle.Math.Raw z[4] = x[4]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + } + public static ulong[] Create64() { return new ulong[5]; diff --git a/crypto/src/math/raw/Nat448.cs b/crypto/src/math/raw/Nat448.cs index 52a253f1b..b0774b37a 100644 --- a/crypto/src/math/raw/Nat448.cs +++ b/crypto/src/math/raw/Nat448.cs @@ -18,6 +18,17 @@ namespace Org.BouncyCastle.Math.Raw z[6] = x[6]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + } + public static ulong[] Create64() { return new ulong[7]; diff --git a/crypto/src/math/raw/Nat576.cs b/crypto/src/math/raw/Nat576.cs index 813fb86be..14279b61a 100644 --- a/crypto/src/math/raw/Nat576.cs +++ b/crypto/src/math/raw/Nat576.cs @@ -20,6 +20,19 @@ namespace Org.BouncyCastle.Math.Raw z[8] = x[8]; } + public static void Copy64(ulong[] x, int xOff, ulong[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + z[zOff + 7] = x[xOff + 7]; + z[zOff + 8] = x[xOff + 8]; + } + public static ulong[] Create64() { return new ulong[9]; diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs index 7d96dee8d..a3efd591f 100644 --- a/crypto/src/openpgp/PgpUtilities.cs +++ b/crypto/src/openpgp/PgpUtilities.cs @@ -356,7 +356,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); Stream pOut = lData.Open(output, fileType, file.Name, file.Length, file.LastWriteTime); - PipeFileContents(file, pOut, 4096); + PipeFileContents(file, pOut, 32768); } /// <summary>Write out the passed in file as a literal data packet in partial packet format.</summary> @@ -376,15 +376,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp FileStream inputStream = file.OpenRead(); byte[] buf = new byte[bufSize]; - int len; - while ((len = inputStream.Read(buf, 0, buf.Length)) > 0) + try { - pOut.Write(buf, 0, len); + int len; + while ((len = inputStream.Read(buf, 0, buf.Length)) > 0) + { + pOut.Write(buf, 0, len); + } } + finally + { + Array.Clear(buf, 0, buf.Length); - Platform.Dispose(pOut); - Platform.Dispose(inputStream); - } + Platform.Dispose(pOut); + Platform.Dispose(inputStream); + } + } #endif private const int ReadAhead = 60; diff --git a/crypto/src/pkix/PkixAttrCertPathBuilder.cs b/crypto/src/pkix/PkixAttrCertPathBuilder.cs index 646cc5db5..3d5fa18e3 100644 --- a/crypto/src/pkix/PkixAttrCertPathBuilder.cs +++ b/crypto/src/pkix/PkixAttrCertPathBuilder.cs @@ -143,7 +143,7 @@ namespace Org.BouncyCastle.Pkix try { // check whether the issuer of <tbvCert> is a TrustAnchor - if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null) + if (PkixCertPathValidatorUtilities.IsIssuerTrustAnchor(tbvCert, pkixParams.GetTrustAnchors())) { PkixCertPath certPath = new PkixCertPath(tbvPath); PkixCertPathValidatorResult result; diff --git a/crypto/src/pkix/PkixCertPathBuilder.cs b/crypto/src/pkix/PkixCertPathBuilder.cs index fa38a5ec0..37a1c8c9c 100644 --- a/crypto/src/pkix/PkixCertPathBuilder.cs +++ b/crypto/src/pkix/PkixCertPathBuilder.cs @@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Pkix try { // check whether the issuer of <tbvCert> is a TrustAnchor - if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null) + if (PkixCertPathValidatorUtilities.IsIssuerTrustAnchor(tbvCert, pkixParams.GetTrustAnchors())) { // exception message from possibly later tried certification // chains diff --git a/crypto/src/pkix/PkixCertPathValidator.cs b/crypto/src/pkix/PkixCertPathValidator.cs index fcfa63837..64039f9f1 100644 --- a/crypto/src/pkix/PkixCertPathValidator.cs +++ b/crypto/src/pkix/PkixCertPathValidator.cs @@ -3,6 +3,7 @@ using System.Collections; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; @@ -81,16 +82,18 @@ namespace Org.BouncyCastle.Pkix trust = PkixCertPathValidatorUtilities.FindTrustAnchor( (X509Certificate)certs[certs.Count - 1], paramsPkix.GetTrustAnchors()); + + if (trust == null) + throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); + + CheckCertificate(trust.TrustedCert); } catch (Exception e) { - throw new PkixCertPathValidatorException(e.Message, e, certPath, certs.Count - 1); + throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, certs.Count - 1); } - if (trust == null) - throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); - - // + // // (e), (f), (g) are part of the paramsPkix object. // IEnumerator certIter; @@ -253,6 +256,15 @@ namespace Org.BouncyCastle.Pkix // cert = (X509Certificate)certs[index]; + try + { + CheckCertificate(cert); + } + catch (Exception e) + { + throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, index); + } + // // 6.1.3 // @@ -277,6 +289,10 @@ namespace Org.BouncyCastle.Pkix { if (cert != null && cert.Version == 1) { + // we've found the trust anchor at the top of the path, ignore and keep going + if ((i == 1) && cert.Equals(trust.TrustedCert)) + continue; + throw new PkixCertPathValidatorException( "Version 1 certificates can't be used as CA ones.", null, certPath, index); } @@ -416,5 +432,17 @@ namespace Org.BouncyCastle.Pkix throw new PkixCertPathValidatorException("Path processing failed on policy.", null, certPath, index); } + + internal static void CheckCertificate(X509Certificate cert) + { + try + { + TbsCertificateStructure.GetInstance(cert.CertificateStructure.TbsCertificate); + } + catch (CertificateEncodingException e) + { + throw new Exception("unable to process TBSCertificate", e); + } + } } } diff --git a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs index a2704a746..2ccaa32ce 100644 --- a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs +++ b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs @@ -143,6 +143,20 @@ namespace Org.BouncyCastle.Pkix return trust; } + internal static bool IsIssuerTrustAnchor( + X509Certificate cert, + ISet trustAnchors) + { + try + { + return FindTrustAnchor(cert, trustAnchors) != null; + } + catch (Exception e) + { + return false; + } + } + internal static void AddAdditionalStoresFromAltNames( X509Certificate cert, PkixParameters pkixParams) diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs index 7ddf6c8e4..445304196 100644 --- a/crypto/src/security/DigestUtilities.cs +++ b/crypto/src/security/DigestUtilities.cs @@ -3,10 +3,14 @@ using System.Collections; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.GM; +using Org.BouncyCastle.Asn1.Misc; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.UA; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto; @@ -20,7 +24,11 @@ namespace Org.BouncyCastle.Security public sealed class DigestUtilities { private enum DigestAlgorithm { + BLAKE2B_160, BLAKE2B_256, BLAKE2B_384, BLAKE2B_512, + BLAKE2S_128, BLAKE2S_160, BLAKE2S_224, BLAKE2S_256, + DSTU7564_256, DSTU7564_384, DSTU7564_512, GOST3411, + GOST3411_2012_256, GOST3411_2012_512, KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512, MD2, MD4, MD5, RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320, @@ -28,6 +36,7 @@ namespace Org.BouncyCastle.Security SHA_512_224, SHA_512_256, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256, + SM3, TIGER, WHIRLPOOL, }; @@ -74,6 +83,12 @@ namespace Org.BouncyCastle.Security algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411"; + algorithms["KECCAK224"] = "KECCAK-224"; + algorithms["KECCAK256"] = "KECCAK-256"; + algorithms["KECCAK288"] = "KECCAK-288"; + algorithms["KECCAK384"] = "KECCAK-384"; + algorithms["KECCAK512"] = "KECCAK-512"; + algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224"; algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256"; algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384"; @@ -81,6 +96,24 @@ namespace Org.BouncyCastle.Security algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128"; algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256"; + algorithms[GMObjectIdentifiers.sm3.Id] = "SM3"; + + algorithms[MiscObjectIdentifiers.id_blake2b160.Id] = "BLAKE2B-160"; + algorithms[MiscObjectIdentifiers.id_blake2b256.Id] = "BLAKE2B-256"; + algorithms[MiscObjectIdentifiers.id_blake2b384.Id] = "BLAKE2B-384"; + algorithms[MiscObjectIdentifiers.id_blake2b512.Id] = "BLAKE2B-512"; + algorithms[MiscObjectIdentifiers.id_blake2s128.Id] = "BLAKE2S-128"; + algorithms[MiscObjectIdentifiers.id_blake2s160.Id] = "BLAKE2S-160"; + algorithms[MiscObjectIdentifiers.id_blake2s224.Id] = "BLAKE2S-224"; + algorithms[MiscObjectIdentifiers.id_blake2s256.Id] = "BLAKE2S-256"; + + algorithms[RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id] = "GOST3411-2012-256"; + algorithms[RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id] = "GOST3411-2012-512"; + + algorithms[UAObjectIdentifiers.dstu7564digest_256.Id] = "DSTU7564-256"; + algorithms[UAObjectIdentifiers.dstu7564digest_384.Id] = "DSTU7564-384"; + algorithms[UAObjectIdentifiers.dstu7564digest_512.Id] = "DSTU7564-512"; + oids["MD2"] = PkcsObjectIdentifiers.MD2; oids["MD4"] = PkcsObjectIdentifiers.MD4; oids["MD5"] = PkcsObjectIdentifiers.MD5; @@ -101,6 +134,20 @@ namespace Org.BouncyCastle.Security oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160; oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256; oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411; + oids["SM3"] = GMObjectIdentifiers.sm3; + oids["BLAKE2B-160"] = MiscObjectIdentifiers.id_blake2b160; + oids["BLAKE2B-256"] = MiscObjectIdentifiers.id_blake2b256; + oids["BLAKE2B-384"] = MiscObjectIdentifiers.id_blake2b384; + oids["BLAKE2B-512"] = MiscObjectIdentifiers.id_blake2b512; + oids["BLAKE2S-128"] = MiscObjectIdentifiers.id_blake2s128; + oids["BLAKE2S-160"] = MiscObjectIdentifiers.id_blake2s160; + oids["BLAKE2S-224"] = MiscObjectIdentifiers.id_blake2s224; + oids["BLAKE2S-256"] = MiscObjectIdentifiers.id_blake2s256; + oids["GOST3411-2012-256"] = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256; + oids["GOST3411-2012-512"] = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512; + oids["DSTU7564-256"] = UAObjectIdentifiers.dstu7564digest_256; + oids["DSTU7564-384"] = UAObjectIdentifiers.dstu7564digest_384; + oids["DSTU7564-512"] = UAObjectIdentifiers.dstu7564digest_512; } /// <summary> @@ -153,34 +200,48 @@ namespace Org.BouncyCastle.Security switch (digestAlgorithm) { - case DigestAlgorithm.GOST3411: return new Gost3411Digest(); - case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224); - case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256); - case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288); - case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384); - case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512); - case DigestAlgorithm.MD2: return new MD2Digest(); - case DigestAlgorithm.MD4: return new MD4Digest(); - case DigestAlgorithm.MD5: return new MD5Digest(); - case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest(); - case DigestAlgorithm.RIPEMD160: return new RipeMD160Digest(); - case DigestAlgorithm.RIPEMD256: return new RipeMD256Digest(); - case DigestAlgorithm.RIPEMD320: return new RipeMD320Digest(); - case DigestAlgorithm.SHA_1: return new Sha1Digest(); - case DigestAlgorithm.SHA_224: return new Sha224Digest(); - case DigestAlgorithm.SHA_256: return new Sha256Digest(); - case DigestAlgorithm.SHA_384: return new Sha384Digest(); - case DigestAlgorithm.SHA_512: return new Sha512Digest(); - case DigestAlgorithm.SHA_512_224: return new Sha512tDigest(224); - case DigestAlgorithm.SHA_512_256: return new Sha512tDigest(256); - case DigestAlgorithm.SHA3_224: return new Sha3Digest(224); - case DigestAlgorithm.SHA3_256: return new Sha3Digest(256); - case DigestAlgorithm.SHA3_384: return new Sha3Digest(384); - case DigestAlgorithm.SHA3_512: return new Sha3Digest(512); - case DigestAlgorithm.SHAKE128: return new ShakeDigest(128); - case DigestAlgorithm.SHAKE256: return new ShakeDigest(256); - case DigestAlgorithm.TIGER: return new TigerDigest(); - case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest(); + case DigestAlgorithm.BLAKE2B_160: return new Blake2bDigest(160); + case DigestAlgorithm.BLAKE2B_256: return new Blake2bDigest(256); + case DigestAlgorithm.BLAKE2B_384: return new Blake2bDigest(384); + case DigestAlgorithm.BLAKE2B_512: return new Blake2bDigest(512); + case DigestAlgorithm.BLAKE2S_128: return new Blake2sDigest(128); + case DigestAlgorithm.BLAKE2S_160: return new Blake2sDigest(160); + case DigestAlgorithm.BLAKE2S_224: return new Blake2sDigest(224); + case DigestAlgorithm.BLAKE2S_256: return new Blake2sDigest(256); + case DigestAlgorithm.DSTU7564_256: return new Dstu7564Digest(256); + case DigestAlgorithm.DSTU7564_384: return new Dstu7564Digest(384); + case DigestAlgorithm.DSTU7564_512: return new Dstu7564Digest(512); + case DigestAlgorithm.GOST3411: return new Gost3411Digest(); + case DigestAlgorithm.GOST3411_2012_256: return new GOST3411_2012_256Digest(); + case DigestAlgorithm.GOST3411_2012_512: return new GOST3411_2012_512Digest(); + case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224); + case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256); + case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288); + case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384); + case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512); + case DigestAlgorithm.MD2: return new MD2Digest(); + case DigestAlgorithm.MD4: return new MD4Digest(); + case DigestAlgorithm.MD5: return new MD5Digest(); + case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest(); + case DigestAlgorithm.RIPEMD160: return new RipeMD160Digest(); + case DigestAlgorithm.RIPEMD256: return new RipeMD256Digest(); + case DigestAlgorithm.RIPEMD320: return new RipeMD320Digest(); + case DigestAlgorithm.SHA_1: return new Sha1Digest(); + case DigestAlgorithm.SHA_224: return new Sha224Digest(); + case DigestAlgorithm.SHA_256: return new Sha256Digest(); + case DigestAlgorithm.SHA_384: return new Sha384Digest(); + case DigestAlgorithm.SHA_512: return new Sha512Digest(); + case DigestAlgorithm.SHA_512_224: return new Sha512tDigest(224); + case DigestAlgorithm.SHA_512_256: return new Sha512tDigest(256); + case DigestAlgorithm.SHA3_224: return new Sha3Digest(224); + case DigestAlgorithm.SHA3_256: return new Sha3Digest(256); + case DigestAlgorithm.SHA3_384: return new Sha3Digest(384); + case DigestAlgorithm.SHA3_512: return new Sha3Digest(512); + case DigestAlgorithm.SHAKE128: return new ShakeDigest(128); + case DigestAlgorithm.SHAKE256: return new ShakeDigest(256); + case DigestAlgorithm.SM3: return new SM3Digest(); + case DigestAlgorithm.TIGER: return new TigerDigest(); + case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest(); } } catch (ArgumentException) diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs index 69322b549..df9d327de 100644 --- a/crypto/src/security/DotNetUtilities.cs +++ b/crypto/src/security/DotNetUtilities.cs @@ -9,197 +9,205 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; -using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509; namespace Org.BouncyCastle.Security { - /// <summary> - /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world. - /// </summary> - public sealed class DotNetUtilities - { - private DotNetUtilities() - { - } - - /// <summary> - /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure. - /// </summary> - /// <param name="x509Struct"></param> - /// <returns>A System.Security.Cryptography.X509Certificate.</returns> - 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( - DSA dsa) - { - return GetDsaKeyPair(dsa.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( - DSA dsa) - { - return GetDsaPublicKey(dsa.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( - RSA rsa) - { - return GetRsaKeyPair(rsa.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( - RSA rsa) - { - return GetRsaPublicKey(rsa.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 DSA) - { - return GetDsaKeyPair((DSA)privateKey); - } - - if (privateKey is RSA) - { - return GetRsaKeyPair((RSA)privateKey); - } - - throw new ArgumentException("Unsupported algorithm specified", "privateKey"); - } - - public static RSA ToRSA(RsaKeyParameters rsaKey) - { + /// <summary> + /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world. + /// </summary> + public sealed class DotNetUtilities + { + private DotNetUtilities() + { + } + + /// <summary> + /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure. + /// </summary> + /// <param name="x509Struct"></param> + /// <returns>A System.Security.Cryptography.X509Certificate.</returns> + 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(DSA dsa) + { + return GetDsaKeyPair(dsa.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(DSA dsa) + { + return GetDsaPublicKey(dsa.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(RSA rsa) + { + return GetRsaKeyPair(rsa.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(RSA rsa) + { + return GetRsaPublicKey(rsa.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 DSA) + { + return GetDsaKeyPair((DSA)privateKey); + } + + if (privateKey is RSA) + { + return GetRsaKeyPair((RSA)privateKey); + } + + throw new ArgumentException("Unsupported algorithm specified", "privateKey"); + } + + public static RSA ToRSA(RsaKeyParameters rsaKey) + { // TODO This appears to not work for private keys (when no CRT info) return CreateRSAProvider(ToRSAParameters(rsaKey)); } - public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey) - { + public static RSA ToRSA(RsaKeyParameters rsaKey, CspParameters csp) + { + // TODO This appears to not work for private keys (when no CRT info) + return CreateRSAProvider(ToRSAParameters(rsaKey), csp); + } + + public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey) + { return CreateRSAProvider(ToRSAParameters(privKey)); } + public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey, CspParameters csp) + { + return CreateRSAProvider(ToRSAParameters(privKey), csp); + } + public static RSA ToRSA(RsaPrivateKeyStructure privKey) { return CreateRSAProvider(ToRSAParameters(privKey)); } + public static RSA ToRSA(RsaPrivateKeyStructure privKey, CspParameters csp) + { + return CreateRSAProvider(ToRSAParameters(privKey), csp); + } + public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey) - { - RSAParameters rp = new RSAParameters(); - rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned(); - if (rsaKey.IsPrivate) - rp.D = ConvertRSAParametersField(rsaKey.Exponent, rp.Modulus.Length); - else - rp.Exponent = rsaKey.Exponent.ToByteArrayUnsigned(); - return rp; - } - - public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey) - { - RSAParameters rp = new RSAParameters(); - rp.Modulus = privKey.Modulus.ToByteArrayUnsigned(); - rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned(); - rp.P = privKey.P.ToByteArrayUnsigned(); - rp.Q = privKey.Q.ToByteArrayUnsigned(); - rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length); - rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length); - rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length); - rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length); - return rp; - } + { + RSAParameters rp = new RSAParameters(); + rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned(); + if (rsaKey.IsPrivate) + rp.D = ConvertRSAParametersField(rsaKey.Exponent, rp.Modulus.Length); + else + rp.Exponent = rsaKey.Exponent.ToByteArrayUnsigned(); + return rp; + } + + public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey) + { + RSAParameters rp = new RSAParameters(); + rp.Modulus = privKey.Modulus.ToByteArrayUnsigned(); + rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned(); + rp.P = privKey.P.ToByteArrayUnsigned(); + rp.Q = privKey.Q.ToByteArrayUnsigned(); + rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length); + rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length); + rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length); + rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length); + return rp; + } public static RSAParameters ToRSAParameters(RsaPrivateKeyStructure privKey) { @@ -216,20 +224,20 @@ namespace Org.BouncyCastle.Security } // TODO Move functionality to more general class - private static byte[] ConvertRSAParametersField(BigInteger n, int size) - { - byte[] bs = n.ToByteArrayUnsigned(); + private static byte[] ConvertRSAParametersField(BigInteger n, int size) + { + byte[] bs = n.ToByteArrayUnsigned(); - if (bs.Length == size) - return bs; + if (bs.Length == size) + return bs; - if (bs.Length > size) - throw new ArgumentException("Specified size too small", "size"); + if (bs.Length > size) + throw new ArgumentException("Specified size too small", "size"); - byte[] padded = new byte[size]; - Array.Copy(bs, 0, padded, size - bs.Length, bs.Length); - return padded; - } + byte[] padded = new byte[size]; + Array.Copy(bs, 0, padded, size - bs.Length, bs.Length); + return padded; + } private static RSA CreateRSAProvider(RSAParameters rp) { @@ -239,7 +247,14 @@ namespace Org.BouncyCastle.Security rsaCsp.ImportParameters(rp); return rsaCsp; } - } + + private static RSA CreateRSAProvider(RSAParameters rp, CspParameters csp) + { + RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp); + rsaCsp.ImportParameters(rp); + return rsaCsp; + } + } } #endif diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs index 3beebd05b..db1929c16 100644 --- a/crypto/src/security/GeneratorUtilities.cs +++ b/crypto/src/security/GeneratorUtilities.cs @@ -8,6 +8,7 @@ using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Ntt; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; @@ -138,17 +139,28 @@ namespace Org.BouncyCastle.Security PkcsObjectIdentifiers.IdHmacWithSha512); AddHMacKeyGenerator("SHA512/224"); AddHMacKeyGenerator("SHA512/256"); - AddHMacKeyGenerator("SHA3-224"); - AddHMacKeyGenerator("SHA3-256"); - AddHMacKeyGenerator("SHA3-384"); - AddHMacKeyGenerator("SHA3-512"); + AddHMacKeyGenerator("KECCAK224"); + AddHMacKeyGenerator("KECCAK256"); + AddHMacKeyGenerator("KECCAK288"); + AddHMacKeyGenerator("KECCAK384"); + AddHMacKeyGenerator("KECCAK512"); + AddHMacKeyGenerator("SHA3-224", + NistObjectIdentifiers.IdHMacWithSha3_224); + AddHMacKeyGenerator("SHA3-256", + NistObjectIdentifiers.IdHMacWithSha3_256); + AddHMacKeyGenerator("SHA3-384", + NistObjectIdentifiers.IdHMacWithSha3_384); + AddHMacKeyGenerator("SHA3-512", + NistObjectIdentifiers.IdHMacWithSha3_512); AddHMacKeyGenerator("RIPEMD128"); AddHMacKeyGenerator("RIPEMD160", IanaObjectIdentifiers.HmacRipeMD160); AddHMacKeyGenerator("TIGER", IanaObjectIdentifiers.HmacTiger); - - + AddHMacKeyGenerator("GOST3411-2012-256", + RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256); + AddHMacKeyGenerator("GOST3411-2012-512", + RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512); // // key pair generators. @@ -183,11 +195,12 @@ namespace Org.BouncyCastle.Security AddDefaultKeySizeEntries(160, "HMACRIPEMD160", "HMACSHA1"); AddDefaultKeySizeEntries(192, "AES", "AES192", "CAMELLIA192", "DESEDE3", "HMACTIGER", "RIJNDAEL", "SERPENT", "TNEPRES"); - AddDefaultKeySizeEntries(224, "HMACSHA224", "HMACSHA512/224"); + AddDefaultKeySizeEntries(224, "HMACSHA3-224", "HMACKECCAK224", "HMACSHA224", "HMACSHA512/224"); AddDefaultKeySizeEntries(256, "AES256", "CAMELLIA", "CAMELLIA256", "CAST6", "GOST28147", - "HC256", "HMACSHA256", "HMACSHA512/256", "RC5-64", "RC6", "THREEFISH-256", "TWOFISH"); - AddDefaultKeySizeEntries(384, "HMACSHA384"); - AddDefaultKeySizeEntries(512, "HMACSHA512", "THREEFISH-512"); + "HC256", "HMACGOST3411-2012-256", "HMACSHA3-256", "HMACKECCAK256", "HMACSHA256", "HMACSHA512/256", "RC5-64", "RC6", "THREEFISH-256", "TWOFISH"); + AddDefaultKeySizeEntries(288, "HMACKECCAK288"); + AddDefaultKeySizeEntries(384, "HMACSHA3-384", "HMACKECCAK384", "HMACSHA384"); + AddDefaultKeySizeEntries(512, "HMACGOST3411-2012-512", "HMACSHA3-512", "HMACKECCAK512", "HMACSHA512", "THREEFISH-512"); AddDefaultKeySizeEntries(1024, "THREEFISH-1024"); } diff --git a/crypto/src/security/MacUtilities.cs b/crypto/src/security/MacUtilities.cs index 278f3bec1..a3bf8809f 100644 --- a/crypto/src/security/MacUtilities.cs +++ b/crypto/src/security/MacUtilities.cs @@ -4,7 +4,9 @@ using System.Globalization; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Macs; @@ -38,6 +40,14 @@ namespace Org.BouncyCastle.Security algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384"; algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512"; + algorithms[NistObjectIdentifiers.IdHMacWithSha3_224.Id] = "HMAC-SHA3-224"; + algorithms[NistObjectIdentifiers.IdHMacWithSha3_256.Id] = "HMAC-SHA3-256"; + algorithms[NistObjectIdentifiers.IdHMacWithSha3_384.Id] = "HMAC-SHA3-384"; + algorithms[NistObjectIdentifiers.IdHMacWithSha3_512.Id] = "HMAC-SHA3-512"; + + algorithms[RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256.Id] = "HMAC-GOST3411-2012-256"; + algorithms[RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512.Id] = "HMAC-GOST3411-2012-512"; + // TODO AESMAC? algorithms["DES"] = "DESMAC"; diff --git a/crypto/src/tsp/TSPAlgorithms.cs b/crypto/src/tsp/TSPAlgorithms.cs index e3dfc7916..928468ed7 100644 --- a/crypto/src/tsp/TSPAlgorithms.cs +++ b/crypto/src/tsp/TSPAlgorithms.cs @@ -1,9 +1,11 @@ using System.Collections; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Asn1.TeleTrust; using Org.BouncyCastle.Utilities; @@ -28,14 +30,18 @@ namespace Org.BouncyCastle.Tsp public static readonly string RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id; public static readonly string Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id; + public static readonly string Gost3411_2012_256 = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id; + public static readonly string Gost3411_2012_512 = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id; - public static readonly IList Allowed; + public static readonly string SM3 = GMObjectIdentifiers.sm3.Id; + + public static readonly IList Allowed; static TspAlgorithms() { string[] algs = new string[] { - Gost3411, MD5, Sha1, Sha224, Sha256, Sha384, Sha512, RipeMD128, RipeMD160, RipeMD256 + Gost3411, Gost3411_2012_256, Gost3411_2012_512, MD5, RipeMD128, RipeMD160, RipeMD256, Sha1, Sha224, Sha256, Sha384, Sha512, SM3 }; Allowed = Platform.CreateArrayList(); diff --git a/crypto/src/tsp/TSPUtil.cs b/crypto/src/tsp/TSPUtil.cs index dc8ed3c21..a17657472 100644 --- a/crypto/src/tsp/TSPUtil.cs +++ b/crypto/src/tsp/TSPUtil.cs @@ -4,9 +4,11 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Asn1.TeleTrust; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Cms; @@ -38,6 +40,9 @@ namespace Org.BouncyCastle.Tsp digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, 20); digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, 32); digestLengths.Add(CryptoProObjectIdentifiers.GostR3411.Id, 32); + digestLengths.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, 32); + digestLengths.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, 64); + digestLengths.Add(GMObjectIdentifiers.sm3.Id, 32); digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5"); digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1"); @@ -45,7 +50,7 @@ namespace Org.BouncyCastle.Tsp digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256"); digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384"); digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512"); - digestNames.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5"); + digestNames.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption.Id, "MD5"); digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1"); digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224"); digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256"); @@ -57,8 +62,11 @@ namespace Org.BouncyCastle.Tsp digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411"); digestNames.Add(OiwObjectIdentifiers.DsaWithSha1.Id, "SHA1"); digestNames.Add(OiwObjectIdentifiers.Sha1WithRsa.Id, "SHA1"); - digestNames.Add(OiwObjectIdentifiers.MD5WithRsa, "MD5"); - } + digestNames.Add(OiwObjectIdentifiers.MD5WithRsa.Id, "MD5"); + digestNames.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "GOST3411-2012-256"); + digestNames.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "GOST3411-2012-512"); + digestNames.Add(GMObjectIdentifiers.sm3.Id, "SM3"); + } /** diff --git a/crypto/src/x509/store/X509CertStoreSelector.cs b/crypto/src/x509/store/X509CertStoreSelector.cs index 3874edf1d..f92a4ac03 100644 --- a/crypto/src/x509/store/X509CertStoreSelector.cs +++ b/crypto/src/x509/store/X509CertStoreSelector.cs @@ -21,6 +21,7 @@ namespace Org.BouncyCastle.X509.Store private X509Certificate certificate; private DateTimeObject certificateValid; private ISet extendedKeyUsage; + private bool ignoreX509NameOrdering; private X509Name issuer; private bool[] keyUsage; private ISet policy; @@ -43,6 +44,7 @@ namespace Org.BouncyCastle.X509.Store this.certificate = o.Certificate; this.certificateValid = o.CertificateValid; this.extendedKeyUsage = o.ExtendedKeyUsage; + this.ignoreX509NameOrdering = o.IgnoreX509NameOrdering; this.issuer = o.Issuer; this.keyUsage = o.KeyUsage; this.policy = o.Policy; @@ -95,6 +97,12 @@ namespace Org.BouncyCastle.X509.Store set { extendedKeyUsage = CopySet(value); } } + public bool IgnoreX509NameOrdering + { + get { return ignoreX509NameOrdering; } + set { this.ignoreX509NameOrdering = value; } + } + public X509Name Issuer { get { return issuer; } @@ -140,7 +148,8 @@ namespace Org.BouncyCastle.X509.Store set { subject = value; } } - public string SubjectAsString + [Obsolete("Avoid working with X509Name objects in string form")] + public string SubjectAsString { get { return subject != null ? subject.ToString() : null; } } @@ -212,7 +221,7 @@ namespace Org.BouncyCastle.X509.Store } } - if (issuer != null && !issuer.Equivalent(c.IssuerDN, true)) + if (issuer != null && !issuer.Equivalent(c.IssuerDN, !ignoreX509NameOrdering)) return false; if (keyUsage != null) @@ -277,7 +286,7 @@ namespace Org.BouncyCastle.X509.Store if (serialNumber != null && !serialNumber.Equals(c.SerialNumber)) return false; - if (subject != null && !subject.Equivalent(c.SubjectDN, true)) + if (subject != null && !subject.Equivalent(c.SubjectDN, !ignoreX509NameOrdering)) return false; if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier)) diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index 67d3e1b91..5f0e7af57 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -156,6 +156,8 @@ <Compile Include="src\crypto\test\AESWrapTest.cs" /> <Compile Include="src\crypto\test\AllTests.cs" /> <Compile Include="src\crypto\test\BCryptTest.cs" /> + <Compile Include="src\crypto\test\Blake2bDigestTest.cs" /> + <Compile Include="src\crypto\test\Blake2sDigestTest.cs" /> <Compile Include="src\crypto\test\BlockCipherMonteCarloTest.cs" /> <Compile Include="src\crypto\test\BlockCipherVectorTest.cs" /> <Compile Include="src\crypto\test\BlowfishTest.cs" /> @@ -321,11 +323,16 @@ <Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" /> <Compile Include="src\math\ec\custom\sec\test\SecP256R1FieldTest.cs" /> <Compile Include="src\math\ec\custom\sec\test\SecP384R1FieldTest.cs" /> + <Compile Include="src\math\ec\rfc7748\test\X25519Test.cs" /> + <Compile Include="src\math\ec\rfc7748\test\X448Test.cs" /> + <Compile Include="src\math\ec\rfc8032\test\Ed25519Test.cs" /> + <Compile Include="src\math\ec\rfc8032\test\Ed448Test.cs" /> <Compile Include="src\math\ec\test\AllTests.cs" /> <Compile Include="src\math\ec\test\ECAlgorithmsTest.cs" /> <Compile Include="src\math\ec\test\ECPointPerformanceTest.cs" /> <Compile Include="src\math\ec\test\ECPointTest.cs" /> <Compile Include="src\math\ec\test\F2mProofer.cs" /> + <Compile Include="src\math\ec\test\FixedPointTest.cs" /> <Compile Include="src\math\ec\test\TnafTest.cs" /> <Compile Include="src\math\test\AllTests.cs" /> <Compile Include="src\math\test\BigIntegerTest.cs" /> diff --git a/crypto/test/src/crypto/test/BCryptTest.cs b/crypto/test/src/crypto/test/BCryptTest.cs index 2d9771d17..42d925f80 100644 --- a/crypto/test/src/crypto/test/BCryptTest.cs +++ b/crypto/test/src/crypto/test/BCryptTest.cs @@ -134,6 +134,8 @@ namespace Org.BouncyCastle.Crypto.Tests DoTest(password, salt, cost, expected); } + IsTrue(AreEqual(BCrypt.Generate(BCrypt.PasswordToByteArray("12341234".ToCharArray()), Hex.Decode("01020304050607080102030405060708"), 5), Hex.Decode("cdd19088721c50e5cb49a7b743d93b5a6e67bef0f700cd78"))); + IsTrue(AreEqual(BCrypt.Generate(BCrypt.PasswordToByteArray("1234".ToCharArray()), Hex.Decode("01020304050607080102030405060708"), 5), Hex.Decode("02a3269aca2732484057b40c614204814cbfc2becd8e093e"))); } private void DoTest(byte[] password, byte[] salt, int cost, byte[] expected) diff --git a/crypto/test/src/crypto/test/Blake2bDigestTest.cs b/crypto/test/src/crypto/test/Blake2bDigestTest.cs new file mode 100644 index 000000000..0d0853977 --- /dev/null +++ b/crypto/test/src/crypto/test/Blake2bDigestTest.cs @@ -0,0 +1,251 @@ +using System; +using System.Text; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class Blake2bDigestTest + : SimpleTest + { + private static readonly string[][] keyedTestVectors = + { // input/message, key, hash + + // Vectors from BLAKE2 web site: https://blake2.net/blake2b-test.txt + new string[]{ + "", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568" }, + + new string[]{ + "00", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd" }, + + new string[]{ + "0001", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965" }, + + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd" }, + + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f" }, + + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461" } + }; + + private static readonly string[][] unkeyedTestVectors = + { // from: http://fossies.org/linux/john/src/rawBLAKE2_512_fmt_plug.c + // hash, input/message + // digests without leading $BLAKE2$ + new string[]{ + "4245af08b46fbb290222ab8a68613621d92ce78577152d712467742417ebc1153668f1c9e1ec1e152a32a9c242dc686d175e087906377f0c483c5be2cb68953e", + "blake2" }, + new string[]{ + "021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0", + "hello world" }, + new string[]{ + "1f7d9b7c9a90f7bfc66e52b69f3b6c3befbd6aee11aac860e99347a495526f30c9e51f6b0db01c24825092a09dd1a15740f0ade8def87e60c15da487571bcef7", + "verystrongandlongpassword" }, + new string[]{ + "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", + "The quick brown fox jumps over the lazy dog" }, + new string[]{ + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", + "" }, + new string[]{ + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "abc" }, + }; + + public override string Name + { + get { return "BLAKE2b"; } + } + + private void offsetTest( + IDigest digest, + byte[] input, + byte[] expected) + { + byte[] resBuf = new byte[expected.Length + 11]; + + digest.BlockUpdate(input, 0, input.Length); + + digest.DoFinal(resBuf, 11); + + if (!AreEqual(Arrays.CopyOfRange(resBuf, 11, resBuf.Length), expected)) + { + Fail("Offset failed got " + Hex.ToHexString(resBuf)); + } + } + + public override void PerformTest() + { + // test keyed test vectors: + + Blake2bDigest blake2bkeyed = new Blake2bDigest(Hex.Decode(keyedTestVectors[0][1])); + for (int tv = 0; tv < keyedTestVectors.Length; tv++) + { + + byte[] input = Hex.Decode(keyedTestVectors[tv][0]); + blake2bkeyed.Reset(); + + blake2bkeyed.BlockUpdate(input, 0, input.Length); + byte[] keyedHash = new byte[64]; + blake2bkeyed.DoFinal(keyedHash, 0); + + if (!Arrays.AreEqual(Hex.Decode(keyedTestVectors[tv][2]), keyedHash)) + { + Fail("BLAKE2b mismatch on test vector ", + keyedTestVectors[tv][2], + Hex.ToHexString(keyedHash)); + } + + offsetTest(blake2bkeyed, input, keyedHash); + } + + Blake2bDigest blake2bunkeyed = new Blake2bDigest(); + // test unkeyed test vectors: + for (int i = 0; i < unkeyedTestVectors.Length; i++) + { + // blake2bunkeyed.update( + // unkeyedTestVectors[i][1].getBytes("UTF-8")); + // test update(byte b) + byte[] unkeyedInput = Encoding.UTF8.GetBytes(unkeyedTestVectors[i][1]); + for (int j = 0; j < unkeyedInput.Length; j++) + { + blake2bunkeyed.Update(unkeyedInput[j]); + } + + byte[] unkeyedHash = new byte[64]; + blake2bunkeyed.DoFinal(unkeyedHash, 0); + blake2bunkeyed.Reset(); + + if (!Arrays.AreEqual(Hex.Decode(unkeyedTestVectors[i][0]), + unkeyedHash)) + { + Fail("BLAKE2b mismatch on test vector ", + unkeyedTestVectors[i][0], + Hex.ToHexString(unkeyedHash)); + } + } + + cloneTest(); + resetTest(); + } + + private void cloneTest() + { + Blake2bDigest blake2bCloneSource = new Blake2bDigest(Hex.Decode(keyedTestVectors[3][1]), 16, Hex.Decode("000102030405060708090a0b0c0d0e0f"), Hex.Decode("101112131415161718191a1b1c1d1e1f")); + byte[] expected = Hex.Decode("b6d48ed5771b17414c4e08bd8d8a3bc4"); + + checkClone(blake2bCloneSource, expected); + + // just digest size + blake2bCloneSource = new Blake2bDigest(160); + expected = Hex.Decode("64202454e538279b21cea0f5a7688be656f8f484"); + checkClone(blake2bCloneSource, expected); + + // null salt and personalisation + blake2bCloneSource = new Blake2bDigest(Hex.Decode(keyedTestVectors[3][1]), 16, null, null); + expected = Hex.Decode("2b4a081fae2d7b488f5eed7e83e42a20"); + checkClone(blake2bCloneSource, expected); + + // null personalisation + blake2bCloneSource = new Blake2bDigest(Hex.Decode(keyedTestVectors[3][1]), 16, Hex.Decode("000102030405060708090a0b0c0d0e0f"), null); + expected = Hex.Decode("00c3a2a02fcb9f389857626e19d706f6"); + checkClone(blake2bCloneSource, expected); + + // null salt + blake2bCloneSource = new Blake2bDigest(Hex.Decode(keyedTestVectors[3][1]), 16, null, Hex.Decode("101112131415161718191a1b1c1d1e1f")); + expected = Hex.Decode("f445ec9c062a3c724f8fdef824417abb"); + checkClone(blake2bCloneSource, expected); + } + + private void checkClone(Blake2bDigest blake2bCloneSource, byte[] expected) + { + byte[] message = Hex.Decode(keyedTestVectors[3][0]); + + blake2bCloneSource.BlockUpdate(message, 0, message.Length); + + byte[] hash = new byte[blake2bCloneSource.GetDigestSize()]; + + Blake2bDigest digClone = new Blake2bDigest(blake2bCloneSource); + + blake2bCloneSource.DoFinal(hash, 0); + if (!AreEqual(expected, hash)) + { + Fail("clone source not correct"); + } + + digClone.DoFinal(hash, 0); + if (!AreEqual(expected, hash)) + { + Fail("clone not correct"); + } + } + + private void resetTest() + { + // Generate a non-zero key + byte[] key = new byte[32]; + for (byte i = 0; i < key.Length; i++) + { + key[i] = i; + } + // Generate some non-zero input longer than the key + byte[] input = new byte[key.Length + 1]; + for (byte i = 0; i < input.Length; i++) + { + input[i] = i; + } + // Hash the input + Blake2bDigest digest = new Blake2bDigest(key); + digest.BlockUpdate(input, 0, input.Length); + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + // Using a second instance, hash the input without calling doFinal() + Blake2bDigest digest1 = new Blake2bDigest(key); + digest1.BlockUpdate(input, 0, input.Length); + // Reset the second instance and hash the input again + digest1.Reset(); + digest1.BlockUpdate(input, 0, input.Length); + byte[] hash1 = new byte[digest.GetDigestSize()]; + digest1.DoFinal(hash1, 0); + // The hashes should be identical + if (!Arrays.AreEqual(hash, hash1)) + { + Fail("state was not reset"); + } + } + + public static void Main(string[] args) + { + RunTest(new Blake2bDigestTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/crypto/test/Blake2sDigestTest.cs b/crypto/test/src/crypto/test/Blake2sDigestTest.cs new file mode 100644 index 000000000..2365071dd --- /dev/null +++ b/crypto/test/src/crypto/test/Blake2sDigestTest.cs @@ -0,0 +1,243 @@ +using System; +using System.Text; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class Blake2sDigestTest + : SimpleTest + { + // Vectors from BLAKE2 web site: https://blake2.net/blake2s-test.txt + private static readonly string[][] keyedTestVectors = { + // input/message, key, hash + new string[]{ + "", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49", + }, + new string[]{ + "00", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1", + }, + new string[]{ + "0001", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803", + }, + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "172ffc67153d12e0ca76a8b6cd5d4731885b39ce0cac93a8972a18006c8b8baf", + }, + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4f8ce1e51d2fe7f24043a904d898ebfc91975418753413aa099b795ecb35cedb", + }, + new string[]{ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd", + }, + }; + + public override string Name + { + get { return "BLAKE2s"; } + } + + public void DoTestDigestWithKeyedTestVectors() + { + Blake2sDigest digest = new Blake2sDigest(Hex.Decode( + keyedTestVectors[0][1])); + for (int i = 0; i != keyedTestVectors.Length; i++) + { + String[] keyedTestVector = keyedTestVectors[i]; + byte[] input = Hex.Decode(keyedTestVector[0]); + digest.Reset(); + + digest.BlockUpdate(input, 0, input.Length); + byte[] hash = new byte[32]; + digest.DoFinal(hash, 0); + + if (!AreEqual(Hex.Decode(keyedTestVector[2]), hash)) + { + Fail("BLAKE2s mismatch on test vector ", + keyedTestVector[2], + Hex.ToHexString(hash)); + } + } + } + + public void DoTestDigestWithKeyedTestVectorsAndRandomUpdate() + { + Blake2sDigest digest = new Blake2sDigest(Hex.Decode( + keyedTestVectors[0][1])); + Random random = new Random(); + for (int i = 0; i < 100; i++) + { + for (int j = 0; j != keyedTestVectors.Length; j++) + { + String[] keyedTestVector = keyedTestVectors[j]; + byte[] input = Hex.Decode(keyedTestVector[0]); + if (input.Length < 3) + { + continue; + } + digest.Reset(); + + int pos = (random.Next() & 0xffff) % input.Length; + if (pos > 0) + { + digest.BlockUpdate(input, 0, pos); + } + digest.Update(input[pos]); + if (pos < (input.Length - 1)) + { + digest.BlockUpdate(input, pos + 1, input.Length - (pos + 1)); + } + + byte[] hash = new byte[32]; + digest.DoFinal(hash, 0); + + if (!AreEqual(Hex.Decode(keyedTestVector[2]), hash)) + { + Fail("BLAKE2s mismatch on test vector ", + keyedTestVector[2], + Hex.ToHexString(hash)); + } + } + } + } + + public void DoTestReset() + { + // Generate a non-zero key + byte[] key = new byte[32]; + for (byte i = 0; i < key.Length; i++) + { + key[i] = i; + } + // Generate some non-zero input longer than the key + byte[] input = new byte[key.Length + 1]; + for (byte i = 0; i < input.Length; i++) + { + input[i] = i; + } + // Hash the input + Blake2sDigest digest = new Blake2sDigest(key); + digest.BlockUpdate(input, 0, input.Length); + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + // Create a second instance, hash the input without calling doFinal() + Blake2sDigest digest1 = new Blake2sDigest(key); + digest1.BlockUpdate(input, 0, input.Length); + // Reset the second instance and hash the input again + digest1.Reset(); + digest1.BlockUpdate(input, 0, input.Length); + byte[] hash1 = new byte[digest.GetDigestSize()]; + digest1.DoFinal(hash1, 0); + // The hashes should be identical + if (!AreEqual(hash, hash1)) + { + Fail("BLAKE2s mismatch on test vector ", + Hex.ToHexString(hash), + Hex.ToHexString(hash1)); + } + } + + // Self-test routine from https://tools.ietf.org/html/rfc7693#appendix-E + private static readonly string SELF_TEST_RESULT = + "6A411F08CE25ADCDFB02ABA641451CEC53C598B24F4FC787FBDC88797F4C1DFE"; + private static readonly int[] SELF_TEST_DIGEST_LEN = {16, 20, 28, 32}; + private static readonly int[] SELF_TEST_INPUT_LEN = {0, 3, 64, 65, 255, 1024}; + + private static byte[] selfTestSequence(int len, int seed) + { + int a = (int)(0xDEAD4BAD * seed); + int b = 1; + int t; + byte[] output = new byte[len]; + + for (int i = 0; i < len; i++) + { + t = a + b; + a = b; + b = t; + output[i] = (byte)(t >> 24); + } + + return output; + } + + public void RunSelfTest() + { + Blake2sDigest testDigest = new Blake2sDigest(); + byte[] md = new byte[32]; + + for (int i = 0; i < 4; i++) + { + int outlen = SELF_TEST_DIGEST_LEN[i]; + for (int j = 0; j < 6; j++) + { + int inlen = SELF_TEST_INPUT_LEN[j]; + + // unkeyed hash + byte[] input = selfTestSequence(inlen, inlen); + Blake2sDigest unkeyedDigest = new Blake2sDigest(outlen * 8); + unkeyedDigest.BlockUpdate(input, 0, inlen); + unkeyedDigest.DoFinal(md, 0); + // hash the hash + testDigest.BlockUpdate(md, 0, outlen); + + // keyed hash + byte[] key = selfTestSequence(outlen, outlen); + Blake2sDigest keyedDigest = new Blake2sDigest(key, outlen, null, + null); + keyedDigest.BlockUpdate(input, 0, inlen); + keyedDigest.DoFinal(md, 0); + // hash the hash + testDigest.BlockUpdate(md, 0, outlen); + } + } + + byte[] hash = new byte[32]; + testDigest.DoFinal(hash, 0); + if (!AreEqual(Hex.Decode(SELF_TEST_RESULT), hash)) + { + Fail("BLAKE2s mismatch on test vector ", + SELF_TEST_RESULT, + Hex.ToHexString(hash)); + } + } + + public override void PerformTest() + { + DoTestDigestWithKeyedTestVectors(); + DoTestDigestWithKeyedTestVectorsAndRandomUpdate(); + DoTestReset(); + RunSelfTest(); + } + + public static void Main(string[] args) + { + RunTest(new Blake2sDigestTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/crypto/test/ECGOST3410Test.cs b/crypto/test/src/crypto/test/ECGOST3410Test.cs index 37cb23ecf..4c938378a 100644 --- a/crypto/test/src/crypto/test/ECGOST3410Test.cs +++ b/crypto/test/src/crypto/test/ECGOST3410Test.cs @@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tests curve.CreatePoint( new BigInteger("2"), // x new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y - mod_q); + mod_q, BigInteger.One); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( "ECGOST3410", @@ -127,7 +127,7 @@ namespace Org.BouncyCastle.Crypto.Tests curve.CreatePoint( new BigInteger("2"), // x new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y - mod_q); + mod_q, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator(); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( @@ -184,7 +184,7 @@ namespace Org.BouncyCastle.Crypto.Tests curve.CreatePoint( new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); + mod_q, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410"); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( @@ -234,7 +234,7 @@ namespace Org.BouncyCastle.Crypto.Tests curve.CreatePoint( new BigInteger("1"), // x new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y - mod_q); + mod_q, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410"); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( @@ -284,7 +284,7 @@ namespace Org.BouncyCastle.Crypto.Tests curve.CreatePoint( new BigInteger("0"), // x new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y - mod_q); + mod_q, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410"); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( diff --git a/crypto/test/src/crypto/test/ECIESTest.cs b/crypto/test/src/crypto/test/ECIESTest.cs index e8cfd6df4..1e2e8f711 100644 --- a/crypto/test/src/crypto/test/ECIESTest.cs +++ b/crypto/test/src/crypto/test/ECIESTest.cs @@ -46,9 +46,9 @@ namespace Org.BouncyCastle.Crypto.Tests n, BigInteger.One); ECDomainParameters parameters = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G - n); + curve, + curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n, BigInteger.One); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( "ECDH", @@ -220,9 +220,9 @@ namespace Org.BouncyCastle.Crypto.Tests n, BigInteger.One); ECDomainParameters parameters = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G - n); + curve, + curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n, BigInteger.One); ECKeyPairGenerator eGen = new ECKeyPairGenerator(); KeyGenerationParameters gParam = new ECKeyGenerationParameters(parameters, new SecureRandom()); diff --git a/crypto/test/src/crypto/test/ECNRTest.cs b/crypto/test/src/crypto/test/ECNRTest.cs index 5eae9f097..1ab67546c 100644 --- a/crypto/test/src/crypto/test/ECNRTest.cs +++ b/crypto/test/src/crypto/test/ECNRTest.cs @@ -49,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - n); + n, BigInteger.One); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d diff --git a/crypto/test/src/crypto/test/ECTest.cs b/crypto/test/src/crypto/test/ECTest.cs index 5697f41eb..7dc847ebe 100644 --- a/crypto/test/src/crypto/test/ECTest.cs +++ b/crypto/test/src/crypto/test/ECTest.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.EC; using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; @@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G - n); + n, BigInteger.One); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( "ECDSA", @@ -98,12 +99,8 @@ namespace Org.BouncyCastle.Crypto.Tests [Test] public void TestDecode() { - FpCurve curve = new FpCurve( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q - new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a - new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b - - ECPoint p = curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")).Normalize(); + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime192v1"); + ECPoint p = x9.G; if (!p.AffineXCoord.ToBigInteger().Equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16))) { @@ -115,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Tests Fail("y uncompressed incorrectly"); } - byte[] encoding = p.GetEncoded(); + byte[] encoding = p.GetEncoded(true); if (!AreEqual(encoding, Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"))) { @@ -149,7 +146,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - n); + n, BigInteger.One); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( "ECDSA", @@ -651,7 +648,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - n); + n, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator(); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( @@ -683,7 +680,7 @@ namespace Org.BouncyCastle.Crypto.Tests * Basic Key Agreement Test */ [Test] - public void TestECBasicAgreementTest() + public void TestECDHBasicAgreement() { SecureRandom random = new SecureRandom(); @@ -698,7 +695,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - n); + n, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator(); ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(parameters, random); @@ -744,6 +741,35 @@ namespace Org.BouncyCastle.Crypto.Tests } [Test] + public void TestECDHBasicAgreementCofactor() + { + SecureRandom random = new SecureRandom(); + + X9ECParameters x9 = CustomNamedCurves.GetByName("curve25519"); + ECDomainParameters ec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed()); + + ECKeyPairGenerator kpg = new ECKeyPairGenerator(); + kpg.Init(new ECKeyGenerationParameters(ec, random)); + + AsymmetricCipherKeyPair p1 = kpg.GenerateKeyPair(); + AsymmetricCipherKeyPair p2 = kpg.GenerateKeyPair(); + + IBasicAgreement e1 = new ECDHBasicAgreement(); + IBasicAgreement e2 = new ECDHBasicAgreement(); + + e1.Init(p1.Private); + e2.Init(p2.Private); + + BigInteger k1 = e1.CalculateAgreement(p2.Public); + BigInteger k2 = e2.CalculateAgreement(p1.Public); + + if (!k1.Equals(k2)) + { + Fail("calculated agreement test failed"); + } + } + + [Test] public void TestECMqvTestVector1() { // Test Vector from GEC-2 @@ -843,7 +869,7 @@ namespace Org.BouncyCastle.Crypto.Tests ECDomainParameters parameters = new ECDomainParameters( curve, curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - n); + n, BigInteger.One); ECKeyPairGenerator pGen = new ECKeyPairGenerator(); @@ -909,7 +935,8 @@ namespace Org.BouncyCastle.Crypto.Tests TestECDsa191bitBinary(); TestECDsa239bitBinary(); TestECDsaKeyGenTest(); - TestECBasicAgreementTest(); + TestECDHBasicAgreement(); + TestECDHBasicAgreementCofactor(); TestECDsaP224Sha224(); TestECDsaP224OneByteOver(); diff --git a/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs b/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs index 8501588ee..fabe84d6b 100644 --- a/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs +++ b/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs @@ -74,6 +74,28 @@ namespace Org.BouncyCastle.Crypto.Tests new string[]{"8nv;PAN~-FQ]Emh@.TKG=^.t8R0EQC0T?x9|9g4xzxYmSbBO1qDx8kv-ehh0IBv>3KWhz.Z~jUF0tt8[5U@8;5:=[v6pf.IEJ", "$2a$08$eXo9KDc1BZyybBgMurpcD.GA1/ch3XhgBnIH10Xvjc2ogZaGg3t/m"}, }; + + // 2y vectors generated from htpasswd -nB -C 12, nb leading username was removed. + private static readonly string[,] twoYVec = new string[,]{ + {"a", "$2y$12$DB3BUbYa/SsEL7kCOVji0OauTkPkB5Y1OeyfxJHM7jvMrbml5sgD2"}, + {"abc", "$2y$12$p.xODEbFcXUlHGbNxWZqAe6AA5FWupqXmN9tZea2ACDhwIx4EA2a6"}, + {"hello world", "$2y$12$wfkxITYXjNLVpEi9nOjz7uXMhCXKSTY7O2y7X4bwY89aGSvRziguq"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXY", "$2y$12$QwAt5kuG68nW7v.87q0QPuwdki3romFc/RU/RV3Qqk4FPw6WdbQzu"} + }; + + // Same as 2y vectors only version changed to 2b to verify handling of that version. + private static readonly string[,] twoBVec = new string[,]{ + {"a", "$2b$12$DB3BUbYa/SsEL7kCOVji0OauTkPkB5Y1OeyfxJHM7jvMrbml5sgD2"}, + {"abc", "$2b$12$p.xODEbFcXUlHGbNxWZqAe6AA5FWupqXmN9tZea2ACDhwIx4EA2a6"}, + {"hello world", "$2b$12$wfkxITYXjNLVpEi9nOjz7uXMhCXKSTY7O2y7X4bwY89aGSvRziguq"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXY", "$2b$12$QwAt5kuG68nW7v.87q0QPuwdki3romFc/RU/RV3Qqk4FPw6WdbQzu"} + }; + + public static void Main(string[] args) + { + RunTest(new OpenBsdBCryptTest()); + } + public override string Name { get { return "OpenBsdBCrypt"; } @@ -129,11 +151,36 @@ namespace Org.BouncyCastle.Crypto.Tests Fail("test4 mismatch: " + "[" + i + "] " + password); } } - } - public static void Main(string[] args) - { - RunTest(new OpenBsdBCryptTest()); + { + int lower = twoYVec.GetLowerBound(0); + int upper = twoYVec.GetUpperBound(0); + for (int i = lower; i <= upper; i++) + { + password = twoYVec[i, 0]; + encoded = twoYVec[i, 1]; + + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("twoYVec mismatch: " + "[" + i + "] " + password); + } + } + } + + { + int lower = twoBVec.GetLowerBound(0); + int upper = twoBVec.GetUpperBound(0); + for (int i = lower; i <= upper; i++) + { + password = twoBVec[i, 0]; + encoded = twoBVec[i, 1]; + + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("twoBVec mismatch: " + "[" + i + "] " + password); + } + } + } } [Test] diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index c065a1320..13fe23ecc 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -126,6 +126,8 @@ namespace Org.BouncyCastle.Crypto.Tests new BCryptTest(), new OpenBsdBCryptTest(), new X931SignerTest(), + new Blake2bDigestTest(), + new Blake2sDigestTest(), new KeccakDigestTest(), new ShakeDigestTest(), new SM2EngineTest(), diff --git a/crypto/test/src/crypto/test/SCryptTest.cs b/crypto/test/src/crypto/test/SCryptTest.cs index c055ab718..82bc60880 100644 --- a/crypto/test/src/crypto/test/SCryptTest.cs +++ b/crypto/test/src/crypto/test/SCryptTest.cs @@ -26,6 +26,54 @@ namespace Org.BouncyCastle.Crypto.Tests public override void PerformTest() { + TestParameters(); + TestVectors(); + } + + [Test] + public void TestParameters() + { + CheckOK("Minimal values", new byte[0], new byte[0], 2, 1, 1, 1); + CheckIllegal("Cost parameter must be > 1", new byte[0], new byte[0], 1, 1, 1, 1); + CheckOK("Cost parameter 32768 OK for r == 1", new byte[0], new byte[0], 32768, 1, 1, 1); + CheckIllegal("Cost parameter must < 65536 for r == 1", new byte[0], new byte[0], 65536, 1, 1, 1); + CheckIllegal("Block size must be >= 1", new byte[0], new byte[0], 2, 0, 2, 1); + CheckIllegal("Parallelisation parameter must be >= 1", new byte[0], new byte[0], 2, 1, 0, 1); + // CheckOK("Parallelisation parameter 65535 OK for r = 4", new byte[0], new byte[0], 2, 32, 65535, 1); + CheckIllegal("Parallelisation parameter must be < 65535 for r = 4", new byte[0], new byte[0], 2, 32, 65536, 1); + + CheckIllegal("Len parameter must be > 1", new byte[0], new byte[0], 2, 1, 1, 0); + } + + private void CheckOK(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.Generate(pass, salt, N, r, p, len); + } + catch (ArgumentException e) + { + Console.Error.WriteLine(e.StackTrace); + Fail(msg); + } + } + + private void CheckIllegal(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.Generate(pass, salt, N, r, p, len); + Fail(msg); + } + catch (ArgumentException e) + { + //Console.Error.WriteLine(e.StackTrace); + } + } + + [Test] + public void TestVectors() + { using (StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("scrypt.TestVectors.txt"))) { int count = 0; @@ -91,13 +139,5 @@ namespace Org.BouncyCastle.Crypto.Tests { RunTest(new SCryptTest()); } - - [Test] - public void TestFunction() - { - string resultText = Perform().ToString(); - - Assert.AreEqual(Name + ": Okay", resultText); - } } } diff --git a/crypto/test/src/crypto/test/SM2EngineTest.cs b/crypto/test/src/crypto/test/SM2EngineTest.cs index 8a1987d52..1a2d1d13e 100644 --- a/crypto/test/src/crypto/test/SM2EngineTest.cs +++ b/crypto/test/src/crypto/test/SM2EngineTest.cs @@ -28,10 +28,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = BigInteger.One; BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); - ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); @@ -104,11 +105,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("00", 16); BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); - BigInteger SM2_ECC_H = BigInteger.ValueOf(4); - ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); diff --git a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs index d7a2650eb..39131f163 100644 --- a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs +++ b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs @@ -30,10 +30,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = BigInteger.One; BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); - ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); @@ -119,11 +120,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("00", 16); BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); - BigInteger SM2_ECC_H = BigInteger.ValueOf(4); - ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); diff --git a/crypto/test/src/crypto/test/SM2SignerTest.cs b/crypto/test/src/crypto/test/SM2SignerTest.cs index 5904c95a7..e3c9c21ae 100644 --- a/crypto/test/src/crypto/test/SM2SignerTest.cs +++ b/crypto/test/src/crypto/test/SM2SignerTest.cs @@ -29,10 +29,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); - ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); @@ -76,10 +77,11 @@ namespace Org.BouncyCastle.Crypto.Tests BigInteger SM2_ECC_A = new BigInteger("00", 16); BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); - ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); diff --git a/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs b/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs new file mode 100644 index 000000000..89c325fd5 --- /dev/null +++ b/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs @@ -0,0 +1,184 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.EC.Rfc7748.Tests +{ + [TestFixture] + public class X25519Test + { + private static readonly SecureRandom Random = new SecureRandom(); + + [SetUp] + public void SetUp() + { + X25519.Precompute(); + } + + [Test] + public void TestConsistency() + { + byte[] u = new byte[32]; u[0] = 9; + byte[] k = new byte[32]; + byte[] rF = new byte[32]; + byte[] rV = new byte[32]; + + for (int i = 1; i <= 100; ++i) + { + Random.NextBytes(k); + X25519.ScalarMultBase(k, 0, rF, 0); + X25519.ScalarMult(k, 0, u, 0, rV, 0); + Assert.IsTrue(Arrays.AreEqual(rF, rV), "Consistency #" + i); + } + } + + [Test] + public void TestECDH() + { + byte[] kA = new byte[32]; + byte[] kB = new byte[32]; + byte[] qA = new byte[32]; + byte[] qB = new byte[32]; + byte[] sA = new byte[32]; + byte[] sB = new byte[32]; + + for (int i = 1; i <= 100; ++i) + { + // Each party generates an ephemeral private key, ... + Random.NextBytes(kA); + Random.NextBytes(kB); + + // ... publishes their public key, ... + X25519.ScalarMultBase(kA, 0, qA, 0); + X25519.ScalarMultBase(kB, 0, qB, 0); + + // ... computes the shared secret, ... + X25519.ScalarMult(kA, 0, qB, 0, sA, 0); + X25519.ScalarMult(kB, 0, qA, 0, sB, 0); + + // ... which is the same for both parties. + //Assert.IsTrue(Arrays.AreEqual(sA, sB), "ECDH #" + i); + if (!Arrays.AreEqual(sA, sB)) + { + Console.WriteLine(" " + i); + } + } + } + + [Test] + public void TestECDHVector1() + { + CheckECDHVector( + "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", + "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a", + "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", + "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", + "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742", + "ECDH Vector #1"); + } + + [Test] + public void TestX25519Iterated() + { + CheckIterated(1000); + } + + //[Test, Explicit] + //public void TestX25519IteratedFull() + //{ + // CheckIterated(1000000); + //} + + [Test] + public void TestX25519Vector1() + { + CheckX25519Vector( + "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", + "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", + "Vector #1"); + } + + [Test] + public void TestX25519Vector2() + { + CheckX25519Vector( + "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", + "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", + "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", + "Vector #2"); + } + + private static void CheckECDHVector(string sA, string sAPub, string sB, string sBPub, string sK, string text) + { + byte[] a = Hex.Decode(sA); + byte[] b = Hex.Decode(sB); + + byte[] aPub = new byte[32]; + X25519.ScalarMultBase(a, 0, aPub, 0); + CheckValue(aPub, text, sAPub); + + byte[] bPub = new byte[32]; + X25519.ScalarMultBase(b, 0, bPub, 0); + CheckValue(bPub, text, sBPub); + + byte[] aK = new byte[32]; + X25519.ScalarMult(a, 0, bPub, 0, aK, 0); + CheckValue(aK, text, sK); + + byte[] bK = new byte[32]; + X25519.ScalarMult(b, 0, aPub, 0, bK, 0); + CheckValue(bK, text, sK); + } + + private static void CheckIterated(int count) + { + byte[] k = new byte[32]; k[0] = 9; + byte[] u = new byte[32]; u[0] = 9; + byte[] r = new byte[32]; + + int iterations = 0; + while (iterations < count) + { + X25519.ScalarMult(k, 0, u, 0, r, 0); + + Array.Copy(k, 0, u, 0, 32); + Array.Copy(r, 0, k, 0, 32); + + switch (++iterations) + { + case 1: + CheckValue(k, "Iterated @1", "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079"); + break; + case 1000: + CheckValue(k, "Iterated @1000", "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51"); + break; + case 1000000: + CheckValue(k, "Iterated @1000000", "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424"); + break; + default: + break; + } + } + } + + private static void CheckValue(byte[] n, string text, string se) + { + byte[] e = Hex.Decode(se); + Assert.IsTrue(Arrays.AreEqual(e, n), text); + } + + private static void CheckX25519Vector(string sk, string su, string se, string text) + { + byte[] k = Hex.Decode(sk); + byte[] u = Hex.Decode(su); + byte[] r = new byte[32]; + X25519.ScalarMult(k, 0, u, 0, r, 0); + CheckValue(r, text, se); + } + } +} diff --git a/crypto/test/src/math/ec/rfc7748/test/X448Test.cs b/crypto/test/src/math/ec/rfc7748/test/X448Test.cs new file mode 100644 index 000000000..b095eade0 --- /dev/null +++ b/crypto/test/src/math/ec/rfc7748/test/X448Test.cs @@ -0,0 +1,183 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.EC.Rfc7748.Tests +{ + [TestFixture] + public class X448Test + { + private static readonly SecureRandom Random = new SecureRandom(); + + [SetUp] + public void SetUp() + { + X448.Precompute(); + } + + [Test] + public void TestConsistency() + { + byte[] u = new byte[56]; u[0] = 5; + byte[] k = new byte[56]; + byte[] rF = new byte[56]; + byte[] rV = new byte[56]; + + for (int i = 1; i <= 100; ++i) + { + Random.NextBytes(k); + X448.ScalarMultBase(k, 0, rF, 0); + X448.ScalarMult(k, 0, u, 0, rV, 0); + Assert.IsTrue(Arrays.AreEqual(rF, rV), "Consistency #" + i); + } + } + + [Test] + public void TestECDH() + { + byte[] kA = new byte[56]; + byte[] kB = new byte[56]; + byte[] qA = new byte[56]; + byte[] qB = new byte[56]; + byte[] sA = new byte[56]; + byte[] sB = new byte[56]; + + for (int i = 1; i <= 100; ++i) + { + // Each party generates an ephemeral private key, ... + Random.NextBytes(kA); + Random.NextBytes(kB); + + // ... publishes their public key, ... + X448.ScalarMultBase(kA, 0, qA, 0); + X448.ScalarMultBase(kB, 0, qB, 0); + + // ... computes the shared secret, ... + X448.ScalarMult(kA, 0, qB, 0, sA, 0); + X448.ScalarMult(kB, 0, qA, 0, sB, 0); + + // ... which is the same for both parties. + Assert.IsTrue(Arrays.AreEqual(sA, sB), "ECDH #" + i); + } + } + + [Test] + public void TestECDHVector1() + { + CheckECDHVector( + "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b", + "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0", + "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d", + "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609", + "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d", + "ECDH Vector #1"); + } + + [Test] + public void TestX448Iterated() + { + CheckIterated(1000); + } + + //[Test, Explicit] + //public void TestX448IteratedFull() + //{ + // CheckIterated(1000000); + //} + + [Test] + public void TestX448Vector1() + { + CheckX448Vector( + "3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", + "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", + "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f", + "Vector #1"); + } + + [Test] + public void TestX448Vector2() + { + CheckX448Vector( + "203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", + "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", + "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d", + "Vector #2"); + } + + private static void CheckECDHVector(string sA, string sAPub, string sB, string sBPub, string sK, string text) + { + byte[] a = Hex.Decode(sA); + byte[] b = Hex.Decode(sB); + + byte[] aPub = new byte[56]; + X448.ScalarMultBase(a, 0, aPub, 0); + CheckValue(aPub, text, sAPub); + + byte[] bPub = new byte[56]; + X448.ScalarMultBase(b, 0, bPub, 0); + CheckValue(bPub, text, sBPub); + + byte[] aK = new byte[56]; + X448.ScalarMult(a, 0, bPub, 0, aK, 0); + CheckValue(aK, text, sK); + + byte[] bK = new byte[56]; + X448.ScalarMult(b, 0, aPub, 0, bK, 0); + CheckValue(bK, text, sK); + } + + private static void CheckIterated(int count) + { + byte[] k = new byte[56]; k[0] = 5; + byte[] u = new byte[56]; u[0] = 5; + byte[] r = new byte[56]; + + int iterations = 0; + while (iterations < count) + { + X448.ScalarMult(k, 0, u, 0, r, 0); + + Array.Copy(k, 0, u, 0, 56); + Array.Copy(r, 0, k, 0, 56); + + switch (++iterations) + { + case 1: + CheckValue(k, "Iterated @1", + "3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113"); + break; + case 1000: + CheckValue(k, "Iterated @1000", + "aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38"); + break; + case 1000000: + CheckValue(k, "Iterated @1000000", + "077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37"); + break; + default: + break; + } + } + } + + private static void CheckValue(byte[] n, String text, String se) + { + byte[] e = Hex.Decode(se); + Assert.IsTrue(Arrays.AreEqual(e, n), text); + } + + private static void CheckX448Vector(String sk, String su, String se, String text) + { + byte[] k = Hex.Decode(sk); + byte[] u = Hex.Decode(su); + byte[] r = new byte[56]; + X448.ScalarMult(k, 0, u, 0, r, 0); + CheckValue(r, text, se); + } + } +} diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs new file mode 100644 index 000000000..43ea23988 --- /dev/null +++ b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs @@ -0,0 +1,231 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests +{ + [TestFixture] + public class Ed25519Test + { + private static readonly SecureRandom Random = new SecureRandom(); + + [SetUp] + public void SetUp() + { + Ed25519.Precompute(); + } + + [Test] + public void TestEd25519Consistency() + { + byte[] sk = new byte[Ed25519.SecretKeySize]; + byte[] pk = new byte[Ed25519.PublicKeySize]; + byte[] m = new byte[255]; + byte[] sig1 = new byte[Ed25519.SignatureSize]; + byte[] sig2 = new byte[Ed25519.SignatureSize]; + + Random.NextBytes(m); + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed25519.GeneratePublicKey(sk, 0, pk, 0); + + int mLen = Random.Next() & 255; + + Ed25519.Sign(sk, 0, m, 0, mLen, sig1, 0); + Ed25519.Sign(sk, 0, pk, 0, m, 0, mLen, sig2, 0); + + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Consistent signatures #" + i); + + bool shouldVerify = Ed25519.Verify(sig1, 0, pk, 0, m, 0, mLen); + + Assert.IsTrue(shouldVerify, "Consistent sign/verify #" + i); + + sig1[Ed25519.PublicKeySize - 1] ^= 0x80; + bool shouldNotVerify = Ed25519.Verify(sig1, 0, pk, 0, m, 0, mLen); + + Assert.IsFalse(shouldNotVerify, "Consistent verification failure #" + i); + } + } + + [Test] + public void TestEd25519Vector1() + { + CheckEd25519Vector( + ("9d61b19deffd5a60ba844af492ec2cc4" + + "4449c5697b326919703bac031cae7f60"), + ("d75a980182b10ab7d54bfed3c964073a" + + "0ee172f3daa62325af021a68f707511a"), + "", + ("e5564300c360ac729086e2cc806e828a" + + "84877f1eb8e5d974d873e06522490155" + + "5fb8821590a33bacc61e39701cf9b46b" + + "d25bf5f0595bbe24655141438e7a100b"), + "Ed25519 Vector #1"); + } + + [Test] + public void TestEd25519Vector2() + { + CheckEd25519Vector( + ("4ccd089b28ff96da9db6c346ec114e0f" + + "5b8a319f35aba624da8cf6ed4fb8a6fb"), + ("3d4017c3e843895a92b70aa74d1b7ebc" + + "9c982ccf2ec4968cc0cd55f12af4660c"), + "72", + ("92a009a9f0d4cab8720e820b5f642540" + + "a2b27b5416503f8fb3762223ebdb69da" + + "085ac1e43e15996e458f3613d0f11d8c" + + "387b2eaeb4302aeeb00d291612bb0c00"), + "Ed25519 Vector #2"); + } + + [Test] + public void TestEd25519Vector3() + { + CheckEd25519Vector( + ("c5aa8df43f9f837bedb7442f31dcb7b1" + + "66d38535076f094b85ce3a2e0b4458f7"), + ("fc51cd8e6218a1a38da47ed00230f058" + + "0816ed13ba3303ac5deb911548908025"), + "af82", + ("6291d657deec24024827e69c3abe01a3" + + "0ce548a284743a445e3680d7db5ac3ac" + + "18ff9b538d16f290ae67f760984dc659" + + "4a7c15e9716ed28dc027beceea1ec40a"), + "Ed25519 Vector #3"); + } + + [Test] + public void TestEd25519Vector1023() + { + string m = + "08b8b2b733424243760fe426a4b54908" + + "632110a66c2f6591eabd3345e3e4eb98" + + "fa6e264bf09efe12ee50f8f54e9f77b1" + + "e355f6c50544e23fb1433ddf73be84d8" + + "79de7c0046dc4996d9e773f4bc9efe57" + + "38829adb26c81b37c93a1b270b20329d" + + "658675fc6ea534e0810a4432826bf58c" + + "941efb65d57a338bbd2e26640f89ffbc" + + "1a858efcb8550ee3a5e1998bd177e93a" + + "7363c344fe6b199ee5d02e82d522c4fe" + + "ba15452f80288a821a579116ec6dad2b" + + "3b310da903401aa62100ab5d1a36553e" + + "06203b33890cc9b832f79ef80560ccb9" + + "a39ce767967ed628c6ad573cb116dbef" + + "efd75499da96bd68a8a97b928a8bbc10" + + "3b6621fcde2beca1231d206be6cd9ec7" + + "aff6f6c94fcd7204ed3455c68c83f4a4" + + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" + + "85ce81bd84359d44254d95629e9855a9" + + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" + + "d17ba70eb6248e594e1a2297acbbb39d" + + "502f1a8c6eb6f1ce22b3de1a1f40cc24" + + "554119a831a9aad6079cad88425de6bd" + + "e1a9187ebb6092cf67bf2b13fd65f270" + + "88d78b7e883c8759d2c4f5c65adb7553" + + "878ad575f9fad878e80a0c9ba63bcbcc" + + "2732e69485bbc9c90bfbd62481d9089b" + + "eccf80cfe2df16a2cf65bd92dd597b07" + + "07e0917af48bbb75fed413d238f5555a" + + "7a569d80c3414a8d0859dc65a46128ba" + + "b27af87a71314f318c782b23ebfe808b" + + "82b0ce26401d2e22f04d83d1255dc51a" + + "ddd3b75a2b1ae0784504df543af8969b" + + "e3ea7082ff7fc9888c144da2af58429e" + + "c96031dbcad3dad9af0dcbaaaf268cb8" + + "fcffead94f3c7ca495e056a9b47acdb7" + + "51fb73e666c6c655ade8297297d07ad1" + + "ba5e43f1bca32301651339e22904cc8c" + + "42f58c30c04aafdb038dda0847dd988d" + + "cda6f3bfd15c4b4c4525004aa06eeff8" + + "ca61783aacec57fb3d1f92b0fe2fd1a8" + + "5f6724517b65e614ad6808d6f6ee34df" + + "f7310fdc82aebfd904b01e1dc54b2927" + + "094b2db68d6f903b68401adebf5a7e08" + + "d78ff4ef5d63653a65040cf9bfd4aca7" + + "984a74d37145986780fc0b16ac451649" + + "de6188a7dbdf191f64b5fc5e2ab47b57" + + "f7f7276cd419c17a3ca8e1b939ae49e4" + + "88acba6b965610b5480109c8b17b80e1" + + "b7b750dfc7598d5d5011fd2dcc5600a3" + + "2ef5b52a1ecc820e308aa342721aac09" + + "43bf6686b64b2579376504ccc493d97e" + + "6aed3fb0f9cd71a43dd497f01f17c0e2" + + "cb3797aa2a2f256656168e6c496afc5f" + + "b93246f6b1116398a346f1a641f3b041" + + "e989f7914f90cc2c7fff357876e506b5" + + "0d334ba77c225bc307ba537152f3f161" + + "0e4eafe595f6d9d90d11faa933a15ef1" + + "369546868a7f3a45a96768d40fd9d034" + + "12c091c6315cf4fde7cb68606937380d" + + "b2eaaa707b4c4185c32eddcdd306705e" + + "4dc1ffc872eeee475a64dfac86aba41c" + + "0618983f8741c5ef68d3a101e8a3b8ca" + + "c60c905c15fc910840b94c00a0b9d0"; + + CheckEd25519Vector( + ("f5e5767cf153319517630f226876b86c" + + "8160cc583bc013744c6bf255f5cc0ee5"), + ("278117fc144c72340f67d0f2316e8386" + + "ceffbf2b2428c9c51fef7c597f1d426e"), + m, + ("0aab4c900501b3e24d7cdf4663326a3a" + + "87df5e4843b2cbdb67cbf6e460fec350" + + "aa5371b1508f9f4528ecea23c436d94b" + + "5e8fcd4f681e30a6ac00a9704a188a03"), + "Ed25519 Vector #1023"); + } + + [Test] + public void TestEd25519VectorSHAabc() + { + CheckEd25519Vector( + ("833fe62409237b9d62ec77587520911e" + + "9a759cec1d19755b7da901b96dca3d42"), + ("ec172b93ad5e563bf4932c70e1245034" + + "c35467ef2efd4d64ebf819683467e2bf"), + ("ddaf35a193617abacc417349ae204131" + + "12e6fa4e89a97ea20a9eeee64b55d39a" + + "2192992a274fc1a836ba3c23a3feebbd" + + "454d4423643ce80e2a9ac94fa54ca49f"), + ("dc2a4459e7369633a52b1bf277839a00" + + "201009a3efbf3ecb69bea2186c26b589" + + "09351fc9ac90b3ecfdfbc7c66431e030" + + "3dca179c138ac17ad9bef1177331a704"), + "Ed25519 Vector SHA(abc)"); + } + + private static void CheckEd25519Vector(string sSK, string sPK, string sM, string sSig, string text) + { + byte[] sk = Hex.Decode(sSK); + + byte[] pk = Hex.Decode(sPK); + byte[] pkGen = new byte[Ed25519.PublicKeySize]; + Ed25519.GeneratePublicKey(sk, 0, pkGen, 0); + Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); + + byte[] m = Hex.Decode(sM); + byte[] sig = Hex.Decode(sSig); + byte[] sigGen = new byte[Ed25519.SignatureSize]; + Ed25519.Sign(sk, 0, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + Ed25519.Sign(sk, 0, pk, 0, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + bool shouldVerify = Ed25519.Verify(sig, 0, pk, 0, m, 0, m.Length); + Assert.IsTrue(shouldVerify, text); + + sig[Ed25519.SignatureSize - 1] ^= 0x80; + bool shouldNotVerify = Ed25519.Verify(sig, 0, pk, 0, m, 0, m.Length); + Assert.IsFalse(shouldNotVerify, text); + } + } +} diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs new file mode 100644 index 000000000..98c487c09 --- /dev/null +++ b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs @@ -0,0 +1,400 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests +{ + [TestFixture] + public class Ed448Test + { + private static readonly SecureRandom Random = new SecureRandom(); + + [SetUp] + public void SetUp() + { + Ed448.Precompute(); + } + + [Test] + public void TestEd448Consistency() + { + byte[] sk = new byte[Ed448.SecretKeySize]; + byte[] pk = new byte[Ed448.PublicKeySize]; + byte[] ctx = new byte[Random.Next() & 7]; + byte[] m = new byte[255]; + byte[] sig1 = new byte[Ed448.SignatureSize]; + byte[] sig2 = new byte[Ed448.SignatureSize]; + + Random.NextBytes(ctx); + Random.NextBytes(m); + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed448.GeneratePublicKey(sk, 0, pk, 0); + + int mLen = Random.Next() & 255; + + Ed448.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0); + Ed448.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0); + + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Consistent signatures #" + i); + + bool shouldVerify = Ed448.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); + + Assert.IsTrue(shouldVerify, "Consistent sign/verify #" + i); + + sig1[Ed448.PublicKeySize - 1] ^= 0x80; + bool shouldNotVerify = Ed448.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); + + Assert.IsFalse(shouldNotVerify, "Consistent verification failure #" + i); + } + } + + [Test] + public void TestEd448Vector1() + { + CheckEd448Vector( + ( "6c82a562cb808d10d632be89c8513ebf" + + "6c929f34ddfa8c9f63c9960ef6e348a3" + + "528c8a3fcc2f044e39a3fc5b94492f8f" + + "032e7549a20098f95b"), + ( "5fd7449b59b461fd2ce787ec616ad46a" + + "1da1342485a70e1f8a0ea75d80e96778" + + "edf124769b46c7061bd6783df1e50f6c" + + "d1fa1abeafe8256180"), + "", + "", + ( "533a37f6bbe457251f023c0d88f976ae" + + "2dfb504a843e34d2074fd823d41a591f" + + "2b233f034f628281f2fd7a22ddd47d78" + + "28c59bd0a21bfd3980ff0d2028d4b18a" + + "9df63e006c5d1c2d345b925d8dc00b41" + + "04852db99ac5c7cdda8530a113a0f4db" + + "b61149f05a7363268c71d95808ff2e65" + + "2600"), + "Ed448 Vector #1"); + } + + [Test] + public void TestEd448Vector2() + { + CheckEd448Vector( + ( "c4eab05d357007c632f3dbb48489924d" + + "552b08fe0c353a0d4a1f00acda2c463a" + + "fbea67c5e8d2877c5e3bc397a659949e" + + "f8021e954e0a12274e"), + ( "43ba28f430cdff456ae531545f7ecd0a" + + "c834a55d9358c0372bfa0c6c6798c086" + + "6aea01eb00742802b8438ea4cb82169c" + + "235160627b4c3a9480"), + "03", + "", + ( "26b8f91727bd62897af15e41eb43c377" + + "efb9c610d48f2335cb0bd0087810f435" + + "2541b143c4b981b7e18f62de8ccdf633" + + "fc1bf037ab7cd779805e0dbcc0aae1cb" + + "cee1afb2e027df36bc04dcecbf154336" + + "c19f0af7e0a6472905e799f1953d2a0f" + + "f3348ab21aa4adafd1d234441cf807c0" + + "3a00"), + "Ed448 Vector #2"); + } + + [Test] + public void TestEd448Vector3() + { + CheckEd448Vector( + ( "c4eab05d357007c632f3dbb48489924d" + + "552b08fe0c353a0d4a1f00acda2c463a" + + "fbea67c5e8d2877c5e3bc397a659949e" + + "f8021e954e0a12274e"), + ( "43ba28f430cdff456ae531545f7ecd0a" + + "c834a55d9358c0372bfa0c6c6798c086" + + "6aea01eb00742802b8438ea4cb82169c" + + "235160627b4c3a9480"), + "03", + "666f6f", + ( "d4f8f6131770dd46f40867d6fd5d5055" + + "de43541f8c5e35abbcd001b32a89f7d2" + + "151f7647f11d8ca2ae279fb842d60721" + + "7fce6e042f6815ea000c85741de5c8da" + + "1144a6a1aba7f96de42505d7a7298524" + + "fda538fccbbb754f578c1cad10d54d0d" + + "5428407e85dcbc98a49155c13764e66c" + + "3c00"), + "Ed448 Vector #3"); + } + + [Test] + public void TestEd448Vector4() + { + CheckEd448Vector( + ( "cd23d24f714274e744343237b93290f5" + + "11f6425f98e64459ff203e8985083ffd" + + "f60500553abc0e05cd02184bdb89c4cc" + + "d67e187951267eb328"), + ( "dcea9e78f35a1bf3499a831b10b86c90" + + "aac01cd84b67a0109b55a36e9328b1e3" + + "65fce161d71ce7131a543ea4cb5f7e9f" + + "1d8b00696447001400"), + "0c3e544074ec63b0265e0c", + "", + ( "1f0a8888ce25e8d458a21130879b840a" + + "9089d999aaba039eaf3e3afa090a09d3" + + "89dba82c4ff2ae8ac5cdfb7c55e94d5d" + + "961a29fe0109941e00b8dbdeea6d3b05" + + "1068df7254c0cdc129cbe62db2dc957d" + + "bb47b51fd3f213fb8698f064774250a5" + + "028961c9bf8ffd973fe5d5c206492b14" + + "0e00"), + "Ed448 Vector #4"); + } + + [Test] + public void TestEd448Vector5() + { + CheckEd448Vector( + ( "258cdd4ada32ed9c9ff54e63756ae582" + + "fb8fab2ac721f2c8e676a72768513d93" + + "9f63dddb55609133f29adf86ec9929dc" + + "cb52c1c5fd2ff7e21b"), + ( "3ba16da0c6f2cc1f30187740756f5e79" + + "8d6bc5fc015d7c63cc9510ee3fd44adc" + + "24d8e968b6e46e6f94d19b945361726b" + + "d75e149ef09817f580"), + "64a65f3cdedcdd66811e2915", + "", + ( "7eeeab7c4e50fb799b418ee5e3197ff6" + + "bf15d43a14c34389b59dd1a7b1b85b4a" + + "e90438aca634bea45e3a2695f1270f07" + + "fdcdf7c62b8efeaf00b45c2c96ba457e" + + "b1a8bf075a3db28e5c24f6b923ed4ad7" + + "47c3c9e03c7079efb87cb110d3a99861" + + "e72003cbae6d6b8b827e4e6c143064ff" + + "3c00"), + "Ed448 Vector #5"); + } + + [Test] + public void TestEd448Vector6() + { + CheckEd448Vector( + ( "7ef4e84544236752fbb56b8f31a23a10" + + "e42814f5f55ca037cdcc11c64c9a3b29" + + "49c1bb60700314611732a6c2fea98eeb" + + "c0266a11a93970100e"), + ( "b3da079b0aa493a5772029f0467baebe" + + "e5a8112d9d3a22532361da294f7bb381" + + "5c5dc59e176b4d9f381ca0938e13c6c0" + + "7b174be65dfa578e80"), + "64a65f3cdedcdd66811e2915e7", + "", + ( "6a12066f55331b6c22acd5d5bfc5d712" + + "28fbda80ae8dec26bdd306743c5027cb" + + "4890810c162c027468675ecf645a8317" + + "6c0d7323a2ccde2d80efe5a1268e8aca" + + "1d6fbc194d3f77c44986eb4ab4177919" + + "ad8bec33eb47bbb5fc6e28196fd1caf5" + + "6b4e7e0ba5519234d047155ac727a105" + + "3100"), + "Ed448 Vector #6"); + } + + [Test] + public void TestEd448Vector64() + { + string m = + "bd0f6a3747cd561bdddf4640a332461a" + + "4a30a12a434cd0bf40d766d9c6d458e5" + + "512204a30c17d1f50b5079631f64eb31" + + "12182da3005835461113718d1a5ef944"; + + CheckEd448Vector( + ( "d65df341ad13e008567688baedda8e9d" + + "cdc17dc024974ea5b4227b6530e339bf" + + "f21f99e68ca6968f3cca6dfe0fb9f4fa" + + "b4fa135d5542ea3f01"), + ( "df9705f58edbab802c7f8363cfe5560a" + + "b1c6132c20a9f1dd163483a26f8ac53a" + + "39d6808bf4a1dfbd261b099bb03b3fb5" + + "0906cb28bd8a081f00"), + m, + "", + ( "554bc2480860b49eab8532d2a533b7d5" + + "78ef473eeb58c98bb2d0e1ce488a98b1" + + "8dfde9b9b90775e67f47d4a1c3482058" + + "efc9f40d2ca033a0801b63d45b3b722e" + + "f552bad3b4ccb667da350192b61c508c" + + "f7b6b5adadc2c8d9a446ef003fb05cba" + + "5f30e88e36ec2703b349ca229c267083" + + "3900"), + "Ed448 Vector #64"); + } + + [Test] + public void TestEd448Vector256() + { + string m = + "15777532b0bdd0d1389f636c5f6b9ba7" + + "34c90af572877e2d272dd078aa1e567c" + + "fa80e12928bb542330e8409f31745041" + + "07ecd5efac61ae7504dabe2a602ede89" + + "e5cca6257a7c77e27a702b3ae39fc769" + + "fc54f2395ae6a1178cab4738e543072f" + + "c1c177fe71e92e25bf03e4ecb72f47b6" + + "4d0465aaea4c7fad372536c8ba516a60" + + "39c3c2a39f0e4d832be432dfa9a706a6" + + "e5c7e19f397964ca4258002f7c0541b5" + + "90316dbc5622b6b2a6fe7a4abffd9610" + + "5eca76ea7b98816af0748c10df048ce0" + + "12d901015a51f189f3888145c03650aa" + + "23ce894c3bd889e030d565071c59f409" + + "a9981b51878fd6fc110624dcbcde0bf7" + + "a69ccce38fabdf86f3bef6044819de11"; + + CheckEd448Vector( + ( "2ec5fe3c17045abdb136a5e6a913e32a" + + "b75ae68b53d2fc149b77e504132d3756" + + "9b7e766ba74a19bd6162343a21c8590a" + + "a9cebca9014c636df5"), + ( "79756f014dcfe2079f5dd9e718be4171" + + "e2ef2486a08f25186f6bff43a9936b9b" + + "fe12402b08ae65798a3d81e22e9ec80e" + + "7690862ef3d4ed3a00"), + m, + "", + ( "c650ddbb0601c19ca11439e1640dd931" + + "f43c518ea5bea70d3dcde5f4191fe53f" + + "00cf966546b72bcc7d58be2b9badef28" + + "743954e3a44a23f880e8d4f1cfce2d7a" + + "61452d26da05896f0a50da66a239a8a1" + + "88b6d825b3305ad77b73fbac0836ecc6" + + "0987fd08527c1a8e80d5823e65cafe2a" + + "3d00"), + "Ed448 Vector #256"); + } + + [Test] + public void TestEd448Vector1023() + { + string m = + "6ddf802e1aae4986935f7f981ba3f035" + + "1d6273c0a0c22c9c0e8339168e675412" + + "a3debfaf435ed651558007db4384b650" + + "fcc07e3b586a27a4f7a00ac8a6fec2cd" + + "86ae4bf1570c41e6a40c931db27b2faa" + + "15a8cedd52cff7362c4e6e23daec0fbc" + + "3a79b6806e316efcc7b68119bf46bc76" + + "a26067a53f296dafdbdc11c77f7777e9" + + "72660cf4b6a9b369a6665f02e0cc9b6e" + + "dfad136b4fabe723d2813db3136cfde9" + + "b6d044322fee2947952e031b73ab5c60" + + "3349b307bdc27bc6cb8b8bbd7bd32321" + + "9b8033a581b59eadebb09b3c4f3d2277" + + "d4f0343624acc817804728b25ab79717" + + "2b4c5c21a22f9c7839d64300232eb66e" + + "53f31c723fa37fe387c7d3e50bdf9813" + + "a30e5bb12cf4cd930c40cfb4e1fc6225" + + "92a49588794494d56d24ea4b40c89fc0" + + "596cc9ebb961c8cb10adde976a5d602b" + + "1c3f85b9b9a001ed3c6a4d3b1437f520" + + "96cd1956d042a597d561a596ecd3d173" + + "5a8d570ea0ec27225a2c4aaff26306d1" + + "526c1af3ca6d9cf5a2c98f47e1c46db9" + + "a33234cfd4d81f2c98538a09ebe76998" + + "d0d8fd25997c7d255c6d66ece6fa56f1" + + "1144950f027795e653008f4bd7ca2dee" + + "85d8e90f3dc315130ce2a00375a318c7" + + "c3d97be2c8ce5b6db41a6254ff264fa6" + + "155baee3b0773c0f497c573f19bb4f42" + + "40281f0b1f4f7be857a4e59d416c06b4" + + "c50fa09e1810ddc6b1467baeac5a3668" + + "d11b6ecaa901440016f389f80acc4db9" + + "77025e7f5924388c7e340a732e554440" + + "e76570f8dd71b7d640b3450d1fd5f041" + + "0a18f9a3494f707c717b79b4bf75c984" + + "00b096b21653b5d217cf3565c9597456" + + "f70703497a078763829bc01bb1cbc8fa" + + "04eadc9a6e3f6699587a9e75c94e5bab" + + "0036e0b2e711392cff0047d0d6b05bd2" + + "a588bc109718954259f1d86678a579a3" + + "120f19cfb2963f177aeb70f2d4844826" + + "262e51b80271272068ef5b3856fa8535" + + "aa2a88b2d41f2a0e2fda7624c2850272" + + "ac4a2f561f8f2f7a318bfd5caf969614" + + "9e4ac824ad3460538fdc25421beec2cc" + + "6818162d06bbed0c40a387192349db67" + + "a118bada6cd5ab0140ee273204f628aa" + + "d1c135f770279a651e24d8c14d75a605" + + "9d76b96a6fd857def5e0b354b27ab937" + + "a5815d16b5fae407ff18222c6d1ed263" + + "be68c95f32d908bd895cd76207ae7264" + + "87567f9a67dad79abec316f683b17f2d" + + "02bf07e0ac8b5bc6162cf94697b3c27c" + + "d1fea49b27f23ba2901871962506520c" + + "392da8b6ad0d99f7013fbc06c2c17a56" + + "9500c8a7696481c1cd33e9b14e40b82e" + + "79a5f5db82571ba97bae3ad3e0479515" + + "bb0e2b0f3bfcd1fd33034efc6245eddd" + + "7ee2086ddae2600d8ca73e214e8c2b0b" + + "db2b047c6a464a562ed77b73d2d841c4" + + "b34973551257713b753632efba348169" + + "abc90a68f42611a40126d7cb21b58695" + + "568186f7e569d2ff0f9e745d0487dd2e" + + "b997cafc5abf9dd102e62ff66cba87"; + + CheckEd448Vector( + ( "872d093780f5d3730df7c212664b37b8" + + "a0f24f56810daa8382cd4fa3f77634ec" + + "44dc54f1c2ed9bea86fafb7632d8be19" + + "9ea165f5ad55dd9ce8"), + ( "a81b2e8a70a5ac94ffdbcc9badfc3feb" + + "0801f258578bb114ad44ece1ec0e799d" + + "a08effb81c5d685c0c56f64eecaef8cd" + + "f11cc38737838cf400"), + m, + "", + ( "e301345a41a39a4d72fff8df69c98075" + + "a0cc082b802fc9b2b6bc503f926b65bd" + + "df7f4c8f1cb49f6396afc8a70abe6d8a" + + "ef0db478d4c6b2970076c6a0484fe76d" + + "76b3a97625d79f1ce240e7c576750d29" + + "5528286f719b413de9ada3e8eb78ed57" + + "3603ce30d8bb761785dc30dbc320869e" + + "1a00"), + "Ed448 Vector #1023"); + } + + private static void CheckEd448Vector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) + { + byte[] sk = Hex.Decode(sSK); + + byte[] pk = Hex.Decode(sPK); + byte[] pkGen = new byte[Ed448.PublicKeySize]; + Ed448.GeneratePublicKey(sk, 0, pkGen, 0); + Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); + + byte[] m = Hex.Decode(sM); + byte[] ctx = Hex.Decode(sCTX); + byte[] sig = Hex.Decode(sSig); + byte[] sigGen = new byte[Ed448.SignatureSize]; + Ed448.Sign(sk, 0, ctx, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + Ed448.Sign(sk, 0, pk, 0, ctx, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + bool shouldVerify = Ed448.Verify(sig, 0, pk, 0, ctx, m, 0, m.Length); + Assert.IsTrue(shouldVerify, text); + + sig[Ed448.SignatureSize - 1] ^= 0x80; + bool shouldNotVerify = Ed448.Verify(sig, 0, pk, 0, ctx, m, 0, m.Length); + Assert.IsFalse(shouldNotVerify, text); + } + } +} diff --git a/crypto/test/src/math/ec/test/AllTests.cs b/crypto/test/src/math/ec/test/AllTests.cs index 0517ac713..3d3f3939b 100644 --- a/crypto/test/src/math/ec/test/AllTests.cs +++ b/crypto/test/src/math/ec/test/AllTests.cs @@ -21,6 +21,7 @@ namespace Org.BouncyCastle.Math.EC.Tests TestSuite suite = new TestSuite("EC Math tests"); suite.Add(new ECAlgorithmsTest()); suite.Add(new ECPointTest()); + suite.Add(new FixedPointTest()); return suite; } } diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs index 089fb88b3..a5ca083e2 100644 --- a/crypto/test/src/math/ec/test/ECPointTest.cs +++ b/crypto/test/src/math/ec/test/ECPointTest.cs @@ -442,6 +442,22 @@ namespace Org.BouncyCastle.Math.EC.Tests } } + private void ImplValidityTest(ECCurve c, ECPoint g) + { + Assert.IsTrue(g.IsValid()); + + BigInteger h = c.Cofactor; + if (h != null && h.CompareTo(BigInteger.One) > 0) + { + if (ECAlgorithms.IsF2mCurve(c)) + { + ECPoint order2 = c.CreatePoint(BigInteger.Zero, c.B.Sqrt().ToBigInteger()); + ECPoint bad = g.Add(order2); + Assert.IsFalse(bad.IsValid()); + } + } + } + private void ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(X9ECParameters x9ECParameters) { BigInteger n = x9ECParameters.N; @@ -470,6 +486,8 @@ namespace Org.BouncyCastle.Math.EC.Tests ImplAddSubtractMultiplyTwiceEncodingTest(c, q, n); ImplSqrtTest(c); + + ImplValidityTest(c, g); } } } diff --git a/crypto/test/src/math/ec/test/FixedPointTest.cs b/crypto/test/src/math/ec/test/FixedPointTest.cs new file mode 100644 index 000000000..83e5fab8f --- /dev/null +++ b/crypto/test/src/math/ec/test/FixedPointTest.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.EC; +using Org.BouncyCastle.Math.EC.Multiplier; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Math.EC.Tests +{ + [TestFixture] + public class FixedPointTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + private const int TestsPerCurve = 5; + + [Test] + public void TestFixedPointMultiplier() + { + FixedPointCombMultiplier M = new FixedPointCombMultiplier(); + + ArrayList names = new ArrayList(); + CollectionUtilities.AddRange(names, ECNamedCurveTable.Names); + CollectionUtilities.AddRange(names, CustomNamedCurves.Names); + + ISet uniqNames = new HashSet(names); + + foreach (string name in uniqNames) + { + X9ECParameters x9A = ECNamedCurveTable.GetByName(name); + X9ECParameters x9B = CustomNamedCurves.GetByName(name); + + X9ECParameters x9 = x9B != null ? x9B : x9A; + + for (int i = 0; i < TestsPerCurve; ++i) + { + BigInteger k = new BigInteger(x9.N.BitLength, Random); + ECPoint pRef = ECAlgorithms.ReferenceMultiply(x9.G, k); + + if (x9A != null) + { + ECPoint pA = M.Multiply(x9A.G, k); + AssertPointsEqual("Standard curve fixed-point failure", pRef, pA); + } + + if (x9B != null) + { + ECPoint pB = M.Multiply(x9B.G, k); + AssertPointsEqual("Custom curve fixed-point failure", pRef, pB); + } + } + } + } + + private void AssertPointsEqual(string message, ECPoint a, ECPoint b) + { + // NOTE: We intentionally test points for equality in both directions + Assert.AreEqual(a, b, message); + Assert.AreEqual(b, a, message); + } + } +} diff --git a/crypto/test/src/security/test/TestEncodings.cs b/crypto/test/src/security/test/TestEncodings.cs index 557d2dc51..a70d5b5b7 100644 --- a/crypto/test/src/security/test/TestEncodings.cs +++ b/crypto/test/src/security/test/TestEncodings.cs @@ -32,24 +32,19 @@ namespace Org.BouncyCastle.Security.Tests BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx")); BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo")); - FpCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters ecDomain = - new ECDomainParameters( - curve, - new FpPoint(curve, - curve.FromBigInteger(ECParraGX), - curve.FromBigInteger(ECParraGY)), - ECParraN); - - ECPublicKeyParameters ecPub = new ECPublicKeyParameters( - new FpPoint( - curve, - curve.FromBigInteger(ECPubQX), - curve.FromBigInteger(ECPubQY)), + FpCurve curve = new FpCurve( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + ECParraN, ECParraH); + + ECDomainParameters ecDomain = new ECDomainParameters( + curve, + curve.ValidatePoint(ECParraGX, ECParraGY), + ECParraN, ECParraH); + + ECPublicKeyParameters ecPub = new ECPublicKeyParameters( + curve.ValidatePoint(ECPubQX, ECPubQY), ecDomain); ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain); diff --git a/crypto/test/src/security/test/TestSignerUtil.cs b/crypto/test/src/security/test/TestSignerUtil.cs index 18b856e3f..f2ee4b048 100644 --- a/crypto/test/src/security/test/TestSignerUtil.cs +++ b/crypto/test/src/security/test/TestSignerUtil.cs @@ -56,18 +56,16 @@ namespace Org.BouncyCastle.Security.Tests FpCurve curve = new FpCurve( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + ECParraN, ECParraH); - ECDomainParameters ecDomain = new ECDomainParameters(curve, - new FpPoint(curve, - curve.FromBigInteger(ECParraGX), - curve.FromBigInteger(ECParraGY)), - ECParraN); + ECDomainParameters ecDomain = new ECDomainParameters( + curve, + curve.ValidatePoint(ECParraGX, ECParraGY), + ECParraN, ECParraH); ECPublicKeyParameters ecPub = new ECPublicKeyParameters( - new FpPoint(curve, - curve.FromBigInteger(ECPubQX), - curve.FromBigInteger(ECPubQY)), + curve.ValidatePoint(ECPubQX, ECPubQY), ecDomain); ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain); diff --git a/crypto/test/src/test/BlockCipherTest.cs b/crypto/test/src/test/BlockCipherTest.cs index e6f92b84e..18753eb1a 100644 --- a/crypto/test/src/test/BlockCipherTest.cs +++ b/crypto/test/src/test/BlockCipherTest.cs @@ -313,7 +313,7 @@ namespace Org.BouncyCastle.Tests "SEED/OCB/NoPadding", "eb04b3612769e1ad681f975af1a6f401d94dc88276dd50fc3ebce791c28825c652b7351acbad8c63d4d66191de94c970", "SEED/CCM/NoPadding", - "8bb16b37e7f1d4eb97bb1fa3b9bfd411aca64a3581bb3c5b2a91346983aa334984d73ad629a847f7", + "da684e8cab782d4ebae835726f43c3aeea97ee270897255714d464e981ac39af06c9483153f8a05a", "SEED/GCM/NoPadding", "ed5f6293c9a4f280af6695750bfb3bb3b60c214565a049494df955152757812ebfb93705895606c4378498a93f2541b5", //"SM4/GCM/NoPadding", @@ -440,7 +440,7 @@ namespace Org.BouncyCastle.Tests throw new Exception("Unhandled mode: " + mode); if (baseMode == "CCM") - return 13; + return 12; if (baseMode == "ECB") return 0; if (baseMode == "OCB") diff --git a/crypto/test/src/test/CertPathValidatorTest.cs b/crypto/test/src/test/CertPathValidatorTest.cs index f83ac850a..3f9ff57fa 100644 --- a/crypto/test/src/test/CertPathValidatorTest.cs +++ b/crypto/test/src/test/CertPathValidatorTest.cs @@ -165,6 +165,7 @@ namespace Org.BouncyCastle.Tests IList certchain = new ArrayList(); certchain.Add(finalCert); certchain.Add(interCert); + // CertPath cp = CertificateFactory.GetInstance("X.509").GenerateCertPath(certchain); PkixCertPath cp = new PkixCertPath(certchain); ISet trust = new HashSet(); @@ -179,7 +180,7 @@ namespace Org.BouncyCastle.Tests MyChecker checker = new MyChecker(); param.AddCertPathChecker(checker); - PkixCertPathValidatorResult result = (PkixCertPathValidatorResult) cpv.Validate(cp, param); + PkixCertPathValidatorResult result = (PkixCertPathValidatorResult)cpv.Validate(cp, param); PkixPolicyNode policyTree = result.PolicyTree; AsymmetricKeyParameter subjectPublicKey = result.SubjectPublicKey; @@ -193,6 +194,28 @@ namespace Org.BouncyCastle.Tests Fail("wrong public key returned"); } + IsTrue(result.TrustAnchor.TrustedCert.Equals(rootCert)); + + // try a path with trust anchor included. + certchain.Clear(); + certchain.Add(finalCert); + certchain.Add(interCert); + certchain.Add(rootCert); + + cp = new PkixCertPath(certchain); + + cpv = new PkixCertPathValidator(); + param = new PkixParameters(trust); + param.AddStore(x509CertStore); + param.AddStore(x509CrlStore); + param.Date = new DateTimeObject(validDate); + checker = new MyChecker(); + param.AddCertPathChecker(checker); + + result = (PkixCertPathValidatorResult)cpv.Validate(cp, param); + + IsTrue(result.TrustAnchor.TrustedCert.Equals(rootCert)); + // // invalid path containing a valid one test // @@ -223,6 +246,7 @@ namespace Org.BouncyCastle.Tests certchain = new ArrayList(); certchain.Add(finalCert); certchain.Add(interCert); + // cp = CertificateFactory.GetInstance("X.509").GenerateCertPath(certchain); cp = new PkixCertPath(certchain); trust = new HashSet(); diff --git a/crypto/test/src/test/CertTest.cs b/crypto/test/src/test/CertTest.cs index d9af06c82..46276a75b 100644 --- a/crypto/test/src/test/CertTest.cs +++ b/crypto/test/src/test/CertTest.cs @@ -1391,15 +1391,9 @@ namespace Org.BouncyCastle.Tests */ internal void checkCreation3() { - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters spec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( "ECDSA", @@ -1533,16 +1527,9 @@ namespace Org.BouncyCastle.Tests string algorithm, DerObjectIdentifier algOid) { - FpCurve curve = new FpCurve( - new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p) - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a - new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b - - ECDomainParameters spec = new ECDomainParameters( - curve, -// curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G - curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("secp521r1"); + ECCurve curve = x9.Curve; + ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( "ECDSA", diff --git a/crypto/test/src/test/DHTest.cs b/crypto/test/src/test/DHTest.cs index 1acc0d603..3ed79ca84 100644 --- a/crypto/test/src/test/DHTest.cs +++ b/crypto/test/src/test/DHTest.cs @@ -2,6 +2,7 @@ using System; using NUnit.Framework; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; @@ -375,37 +376,22 @@ namespace Org.BouncyCastle.Tests [Test] public void TestECDH() { - doTestECDH("ECDH"); + DoTestECDH("ECDH"); } [Test] public void TestECDHC() { - doTestECDH("ECDHC"); + DoTestECDH("ECDHC"); } - private void doTestECDH( - string algorithm) + private void DoTestECDH(string algorithm) { IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator(algorithm); -// EllipticCurve curve = new EllipticCurve( -// new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q -// new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a -// new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters ecSpec = new ECDomainParameters( - curve, -// ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n - BigInteger.One); //1); // h - -// g.initialize(ecSpec, new SecureRandom()); + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H); + g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); // @@ -429,11 +415,6 @@ namespace Org.BouncyCastle.Tests // // agreement // -// aKeyAgreeBasic.doPhase(bKeyPair.Public, true); -// bKeyAgreeBasic.doPhase(aKeyPair.Public, true); -// -// BigInteger k1 = new BigInteger(aKeyAgreeBasic.generateSecret()); -// BigInteger k2 = new BigInteger(bKeyAgreeBasic.generateSecret()); BigInteger k1 = aKeyAgreeBasic.CalculateAgreement(bKeyPair.Public); BigInteger k2 = bKeyAgreeBasic.CalculateAgreement(aKeyPair.Public); diff --git a/crypto/test/src/test/DSATest.cs b/crypto/test/src/test/DSATest.cs index a8b8bec3b..9ed1109e2 100644 --- a/crypto/test/src/test/DSATest.cs +++ b/crypto/test/src/test/DSATest.cs @@ -252,15 +252,9 @@ namespace Org.BouncyCastle.Tests SecureRandom k = FixedSecureRandom.From(kData); - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters spec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( "ECDSA", @@ -330,17 +324,9 @@ namespace Org.BouncyCastle.Tests SecureRandom k = FixedSecureRandom.From(kData); - ECCurve curve = new F2mCurve( - 239, // m - 36, // k - new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a - new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b - - ECDomainParameters parameters = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G - new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n - BigInteger.ValueOf(4)); // h + X9ECParameters x9 = ECNamedCurveTable.GetByName("c2tnb239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters parameters = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters sKey = new ECPrivateKeyParameters( "ECDSA", @@ -435,17 +421,9 @@ namespace Org.BouncyCastle.Tests SecureRandom k = FixedSecureRandom.From(kData); - ECCurve curve = new F2mCurve( - 239, // m - 36, // k - new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a - new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b - - ECDomainParameters parameters = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G - new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n - BigInteger.ValueOf(4)); // h + X9ECParameters x9 = ECNamedCurveTable.GetByName("c2tnb239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters parameters = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters sKey = new ECPrivateKeyParameters( new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d @@ -554,15 +532,9 @@ namespace Org.BouncyCastle.Tests // s = SignerUtilities.GetSigner("ECDSA"); - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters ecSpec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); g = GeneratorUtilities.GetKeyPairGenerator("ECDSA"); g.Init(new ECKeyGenerationParameters(ecSpec, rand)); @@ -594,17 +566,9 @@ namespace Org.BouncyCastle.Tests // s = SignerUtilities.GetSigner("ECDSA"); - curve = new F2mCurve( - 239, // m - 36, // k - new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a - new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b - - ecSpec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G - new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n - BigInteger.ValueOf(4)); // h + x9 = ECNamedCurveTable.GetByName("c2tnb239v1"); + curve = x9.Curve; + ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); g = GeneratorUtilities.GetKeyPairGenerator("ECDSA"); g.Init(new ECKeyGenerationParameters(ecSpec, rand)); diff --git a/crypto/test/src/test/DigestTest.cs b/crypto/test/src/test/DigestTest.cs index 5d840ee66..9f68a8361 100644 --- a/crypto/test/src/test/DigestTest.cs +++ b/crypto/test/src/test/DigestTest.cs @@ -3,6 +3,9 @@ using System.Text; using NUnit.Framework; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Rosstandart; +using Org.BouncyCastle.Asn1.UA; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Encoders; @@ -32,7 +35,43 @@ namespace Org.BouncyCastle.Tests { "RIPEMD320", "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d" }, { "Tiger", "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93" }, { "GOST3411", "b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c" }, - { "WHIRLPOOL", "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5" } + { "WHIRLPOOL", "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5" }, + { "SM3", "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0" }, + { "SHA3-224", "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf" }, + { "SHA3-256", "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" }, + { "SHA3-384", "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25" }, + { "SHA3-512", "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0" }, + { "KECCAK-224", "c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8" }, + { "KECCAK-256", "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45" }, + { "KECCAK-288", "20ff13d217d5789fa7fc9e0e9a2ee627363ec28171d0b6c52bbd2f240554dbc94289f4d6" }, + { "KECCAK-384", "f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e" }, + { "KECCAK-512", "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96" }, + { "BLAKE2B-160", "384264f676f39536840523f284921cdc68b6846b" }, + { "BLAKE2B-256", "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" }, + { "BLAKE2B-384", "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4" }, + { "BLAKE2B-512", "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" }, + { MiscObjectIdentifiers.id_blake2b160.Id, "384264f676f39536840523f284921cdc68b6846b" }, + { MiscObjectIdentifiers.id_blake2b256.Id, "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" }, + { MiscObjectIdentifiers.id_blake2b384.Id, "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4" }, + { MiscObjectIdentifiers.id_blake2b512.Id, "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" }, + { "BLAKE2S-128", "aa4938119b1dc7b87cbad0ffd200d0ae" }, + { "BLAKE2S-160", "5ae3b99be29b01834c3b508521ede60438f8de17" }, + { "BLAKE2S-224", "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55" }, + { "BLAKE2S-256", "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" }, + { MiscObjectIdentifiers.id_blake2s128.Id, "aa4938119b1dc7b87cbad0ffd200d0ae" }, + { MiscObjectIdentifiers.id_blake2s160.Id, "5ae3b99be29b01834c3b508521ede60438f8de17" }, + { MiscObjectIdentifiers.id_blake2s224.Id, "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55" }, + { MiscObjectIdentifiers.id_blake2s256.Id, "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" }, + { "GOST3411-2012-256", "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" }, + { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" }, + { "GOST3411-2012-512", "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" }, + { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" }, + { "DSTU7564-256", "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04" }, + { UAObjectIdentifiers.dstu7564digest_256.Id, "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04" }, + { "DSTU7564-384", "72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { UAObjectIdentifiers.dstu7564digest_384.Id, "72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { "DSTU7564-512", "9e5be7daf7b68b49d2ecbd04c7a5b3af72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { UAObjectIdentifiers.dstu7564digest_512.Id, "9e5be7daf7b68b49d2ecbd04c7a5b3af72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, }; public override string Name diff --git a/crypto/test/src/test/GOST3410Test.cs b/crypto/test/src/test/GOST3410Test.cs index db232c5a1..03dcf3144 100644 --- a/crypto/test/src/test/GOST3410Test.cs +++ b/crypto/test/src/test/GOST3410Test.cs @@ -29,19 +29,21 @@ namespace Org.BouncyCastle.Tests SecureRandom k = FixedSecureRandom.From(kData); - BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); ECCurve curve = new FpCurve( - mod_p, // p + mod_p, new BigInteger("7"), // a - new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, BigInteger.One); ECDomainParameters spec = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("2"), new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), - new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q + mod_q, BigInteger.One); ECPrivateKeyParameters sKey = new ECPrivateKeyParameters( "ECGOST3410", @@ -193,19 +195,21 @@ namespace Org.BouncyCastle.Tests s = SignerUtilities.GetSigner("ECGOST3410"); g = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410"); - BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); ECCurve curve = new FpCurve( - mod_p, // p + mod_p, new BigInteger("7"), // a - new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, BigInteger.One); ECDomainParameters ecSpec = new ECDomainParameters( curve, curve.CreatePoint( new BigInteger("2"), new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), - new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q + mod_q, BigInteger.One); g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); diff --git a/crypto/test/src/test/HMacTest.cs b/crypto/test/src/test/HMacTest.cs index e4f5cb9c1..4a018ac50 100644 --- a/crypto/test/src/test/HMacTest.cs +++ b/crypto/test/src/test/HMacTest.cs @@ -4,7 +4,10 @@ using System.Text; using NUnit.Framework; using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; +using Org.BouncyCastle.Asn1.UA; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; @@ -36,23 +39,33 @@ namespace Org.BouncyCastle.Tests private static byte[] outputOld384 = Hex.Decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40"); private static byte[] outputOld512 = Hex.Decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a"); - public void doTestHMac( - string hmacName, - byte[] output) + private static byte[] outputKck224 = Hex.Decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc"); + private static byte[] outputKck256 = Hex.Decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821"); + private static byte[] outputKck288 = Hex.Decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441"); + private static byte[] outputKck384 = Hex.Decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048"); + private static byte[] outputKck512 = Hex.Decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755"); + + private static byte[] outputSha3_224 = Hex.Decode("3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7"); + private static byte[] outputSha3_256 = Hex.Decode("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb"); + private static byte[] outputSha3_384 = Hex.Decode("68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd"); + private static byte[] outputSha3_512 = Hex.Decode("eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e"); + + private static byte[] outputGost2012_256 = Hex.Decode("f03422dfa37a507ca126ce01b8eba6b7fdda8f8a60dd8f2703e3a372120b8294"); + private static byte[] outputGost2012_512 = Hex.Decode("86b6a06bfa9f1974aff6ccd7fa3f835f0bd850395d6084efc47b9dda861a2cdf0dcaf959160733d5269f6567966dd7a9f932a77cd6f080012cd476f1c2cc31bb"); + + private static byte[] outputDSTU7564_256 = Hex.Decode("98ac67aa21eaf6e8666fb748d66cfc15d5d66f5194c87fffa647e406d3375cdb"); + private static byte[] outputDSTU7564_384 = Hex.Decode("4e46a87e70fcd2ccfb4433a8eaec68991a96b11085c5d5484db71af51bac469c03f76e1f721843c8e8667708fe41a48d"); + private static byte[] outputDSTU7564_512 = Hex.Decode("5b7acf633a7551b8410fa66a60c74a494e46a87e70fcd2ccfb4433a8eaec68991a96b11085c5d5484db71af51bac469c03f76e1f721843c8e8667708fe41a48d"); + + private void DoTestHMac(string hmacName, byte[] output) { KeyParameter key = new KeyParameter(keyBytes); //, hmacName); IMac mac = MacUtilities.GetMac(hmacName); - mac.Init(key); - mac.Reset(); - mac.BlockUpdate(message, 0, message.Length); - -// byte[] outBytes = mac.DoFinal(); - byte[] outBytes = new byte[mac.GetMacSize()]; - mac.DoFinal(outBytes, 0); + byte[] outBytes = MacUtilities.DoFinal(mac); if (!AreEqual(outBytes, output)) { @@ -63,22 +76,42 @@ namespace Org.BouncyCastle.Tests // no key generator for the old algorithms if (hmacName.StartsWith("Old")) - { return; - } CipherKeyGenerator kGen = GeneratorUtilities.GetKeyGenerator(hmacName); + key = new KeyParameter(kGen.GenerateKey()); + mac.Init(key); // hmacName + mac.BlockUpdate(message, 0, message.Length); + outBytes = MacUtilities.DoFinal(mac); + } + + private void DoTestHMac(string hmacName, int defKeySize, byte[] output) + { + KeyParameter key = new KeyParameter(keyBytes); //, hmacName); + + IMac mac = MacUtilities.GetMac(hmacName); + mac.Init(key); + mac.Reset(); + mac.BlockUpdate(message, 0, message.Length); + byte[] outBytes = MacUtilities.DoFinal(mac); - mac.Init(new KeyParameter(kGen.GenerateKey())); // hmacName + if (!AreEqual(outBytes, output)) + { + Fail("Failed - expected " + + Hex.ToHexString(output) + " got " + + Hex.ToHexString(outBytes)); + } + CipherKeyGenerator kGen = GeneratorUtilities.GetKeyGenerator(hmacName); + key = new KeyParameter(kGen.GenerateKey()); + mac.Init(key); // hmacName mac.BlockUpdate(message, 0, message.Length); + outBytes = MacUtilities.DoFinal(mac); -// outBytes = mac.DoFinal(); - outBytes = new byte[mac.GetMacSize()]; - mac.DoFinal(outBytes, 0); + IsTrue("default key wrong length", key.GetKey().Length == (defKeySize / 8)); } - private void doTestExceptions() + private void DoTestExceptions() { IMac mac = MacUtilities.GetMac("HmacSHA1"); @@ -124,47 +157,86 @@ namespace Org.BouncyCastle.Tests public override void PerformTest() { - doTestHMac("HMac-SHA1", output1); - doTestHMac("HMac-MD5", outputMD5); - doTestHMac("HMac-MD4", outputMD4); - doTestHMac("HMac-MD2", outputMD2); - doTestHMac("HMac-SHA224", output224); - doTestHMac("HMac-SHA256", output256); - doTestHMac("HMac-SHA384", output384); - doTestHMac("HMac-SHA512", output512); - doTestHMac("HMac-SHA512/224", output512_224); - doTestHMac("HMac-SHA512/256", output512_256); - doTestHMac("HMac-RIPEMD128", outputRipeMD128); - doTestHMac("HMac-RIPEMD160", outputRipeMD160); - doTestHMac("HMac-TIGER", outputTiger); - - doTestHMac("HMac/SHA1", output1); - doTestHMac("HMac/MD5", outputMD5); - doTestHMac("HMac/MD4", outputMD4); - doTestHMac("HMac/MD2", outputMD2); - doTestHMac("HMac/SHA224", output224); - doTestHMac("HMac/SHA256", output256); - doTestHMac("HMac/SHA384", output384); - doTestHMac("HMac/SHA512", output512); - doTestHMac("HMac/RIPEMD128", outputRipeMD128); - doTestHMac("HMac/RIPEMD160", outputRipeMD160); - doTestHMac("HMac/TIGER", outputTiger); - - doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha1.Id, output1); - doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha224.Id, output224); - doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha256.Id, output256); - doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha384.Id, output384); - doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha512.Id, output512); - doTestHMac(IanaObjectIdentifiers.HmacSha1.Id, output1); - doTestHMac(IanaObjectIdentifiers.HmacMD5.Id, outputMD5); - doTestHMac(IanaObjectIdentifiers.HmacRipeMD160.Id, outputRipeMD160); - doTestHMac(IanaObjectIdentifiers.HmacTiger.Id, outputTiger); + DoTestHMac("HMac-SHA1", output1); + DoTestHMac("HMac-MD5", outputMD5); + DoTestHMac("HMac-MD4", outputMD4); + DoTestHMac("HMac-MD2", outputMD2); + DoTestHMac("HMac-SHA224", output224); + DoTestHMac("HMac-SHA256", output256); + DoTestHMac("HMac-SHA384", output384); + DoTestHMac("HMac-SHA512", output512); + DoTestHMac("HMac-SHA512/224", output512_224); + DoTestHMac("HMac-SHA512/256", output512_256); + DoTestHMac("HMac-RIPEMD128", outputRipeMD128); + DoTestHMac("HMac-RIPEMD160", outputRipeMD160); + DoTestHMac("HMac-TIGER", outputTiger); + DoTestHMac("HMac-KECCAK224", 224, outputKck224); + DoTestHMac("HMac-KECCAK256", 256, outputKck256); + DoTestHMac("HMac-KECCAK288", 288, outputKck288); + DoTestHMac("HMac-KECCAK384", 384, outputKck384); + DoTestHMac("HMac-KECCAK512", 512, outputKck512); + DoTestHMac("HMac-SHA3-224", 224, outputSha3_224); + DoTestHMac("HMac-SHA3-256", 256, outputSha3_256); + DoTestHMac("HMac-SHA3-384", 384, outputSha3_384); + DoTestHMac("HMac-SHA3-512", 512, outputSha3_512); + + DoTestHMac("HMac-GOST3411-2012-256", 256, outputGost2012_256); + DoTestHMac("HMac-GOST3411-2012-512", 512, outputGost2012_512); + + //DoTestHMac("HMac-DSTU7564-256", 256, outputDSTU7564_256); + //DoTestHMac("HMac-DSTU7564-384", 384, outputDSTU7564_384); + //DoTestHMac("HMac-DSTU7564-512", 512, outputDSTU7564_512); + + DoTestHMac("HMac/SHA1", output1); + DoTestHMac("HMac/MD5", outputMD5); + DoTestHMac("HMac/MD4", outputMD4); + DoTestHMac("HMac/MD2", outputMD2); + DoTestHMac("HMac/SHA224", output224); + DoTestHMac("HMac/SHA256", output256); + DoTestHMac("HMac/SHA384", output384); + DoTestHMac("HMac/SHA512", output512); + DoTestHMac("HMac/RIPEMD128", outputRipeMD128); + DoTestHMac("HMac/RIPEMD160", outputRipeMD160); + DoTestHMac("HMac/TIGER", outputTiger); + DoTestHMac("HMac/KECCAK224", 224, outputKck224); + DoTestHMac("HMac/KECCAK256", 256, outputKck256); + DoTestHMac("HMac/KECCAK288", 288, outputKck288); + DoTestHMac("HMac/KECCAK384", 384, outputKck384); + DoTestHMac("HMac/KECCAK512", 512, outputKck512); + DoTestHMac("HMac/SHA3-224", 224, outputSha3_224); + DoTestHMac("HMac/SHA3-256", 256, outputSha3_256); + DoTestHMac("HMac/SHA3-384", 384, outputSha3_384); + DoTestHMac("HMac/SHA3-512", 512, outputSha3_512); + DoTestHMac("HMac/GOST3411-2012-256", 256, outputGost2012_256); + DoTestHMac("HMac/GOST3411-2012-512", 512, outputGost2012_512); + + DoTestHMac(PkcsObjectIdentifiers.IdHmacWithSha1.Id, output1); + DoTestHMac(PkcsObjectIdentifiers.IdHmacWithSha224.Id, output224); + DoTestHMac(PkcsObjectIdentifiers.IdHmacWithSha256.Id, output256); + DoTestHMac(PkcsObjectIdentifiers.IdHmacWithSha384.Id, output384); + DoTestHMac(PkcsObjectIdentifiers.IdHmacWithSha512.Id, output512); + DoTestHMac(IanaObjectIdentifiers.HmacSha1.Id, output1); + DoTestHMac(IanaObjectIdentifiers.HmacMD5.Id, outputMD5); + DoTestHMac(IanaObjectIdentifiers.HmacRipeMD160.Id, outputRipeMD160); + DoTestHMac(IanaObjectIdentifiers.HmacTiger.Id, outputTiger); + + DoTestHMac(NistObjectIdentifiers.IdHMacWithSha3_224.Id, 224, outputSha3_224); + DoTestHMac(NistObjectIdentifiers.IdHMacWithSha3_256.Id, 256, outputSha3_256); + DoTestHMac(NistObjectIdentifiers.IdHMacWithSha3_384.Id, 384, outputSha3_384); + DoTestHMac(NistObjectIdentifiers.IdHMacWithSha3_512.Id, 512, outputSha3_512); + + DoTestHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256.Id, 256, outputGost2012_256); + DoTestHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512.Id, 512, outputGost2012_512); + + //DoTestHMac(UAObjectIdentifiers.dstu7564mac_256.Id, 256, outputDSTU7564_256); + //DoTestHMac(UAObjectIdentifiers.dstu7564mac_384.Id, 384, outputDSTU7564_384); + //DoTestHMac(UAObjectIdentifiers.dstu7564mac_512.Id, 512, outputDSTU7564_512); // // test for compatibility with broken HMac. -// doTestHMac("OldHMacSHA384", outputOld384); -// doTestHMac("OldHMacSHA512", outputOld512); +// DoTestHMac("OldHMacSHA384", outputOld384); +// DoTestHMac("OldHMacSHA512", outputOld512); - doTestExceptions(); + DoTestExceptions(); } public override string Name diff --git a/crypto/test/src/test/IESTest.cs b/crypto/test/src/test/IESTest.cs index 193fe1ae9..99aacc66d 100644 --- a/crypto/test/src/test/IESTest.cs +++ b/crypto/test/src/test/IESTest.cs @@ -32,15 +32,8 @@ namespace Org.BouncyCastle.Tests { IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECIES"); - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters ecSpec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H); g.Init( new ECKeyGenerationParameters( diff --git a/crypto/test/src/test/MqvTest.cs b/crypto/test/src/test/MqvTest.cs index ef36e1a23..b26d5619b 100644 --- a/crypto/test/src/test/MqvTest.cs +++ b/crypto/test/src/test/MqvTest.cs @@ -2,6 +2,7 @@ using System; using NUnit.Framework; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; @@ -31,24 +32,10 @@ namespace Org.BouncyCastle.Tests { IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECMQV"); -// EllipticCurve curve = new EllipticCurve( -// new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q -// new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a -// new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H); - ECDomainParameters ecSpec = new ECDomainParameters( - curve, -// ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n - BigInteger.One); //1); // h - -// g.initialize(ecSpec, new SecureRandom()); - g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); + g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); // // U side diff --git a/crypto/test/src/test/PKCS10CertRequestTest.cs b/crypto/test/src/test/PKCS10CertRequestTest.cs index 9bad0a678..ea27d5111 100644 --- a/crypto/test/src/test/PKCS10CertRequestTest.cs +++ b/crypto/test/src/test/PKCS10CertRequestTest.cs @@ -126,16 +126,9 @@ namespace Org.BouncyCastle.Tests string algorithm, DerObjectIdentifier algOid) { - FpCurve curve = new FpCurve( - new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p) - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a - new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b - - ECDomainParameters spec = new ECDomainParameters( - curve, -// curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G - curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("secp521r1"); + ECCurve curve = x9.Curve; + ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d @@ -413,15 +406,9 @@ namespace Org.BouncyCastle.Tests // elliptic curve openSSL IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDSA"); - ECCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - - ECDomainParameters ecSpec = new ECDomainParameters( - curve, - curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H); // g.initialize(ecSpec, new SecureRandom()); g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); diff --git a/crypto/test/src/x509/test/TestCertificateGen.cs b/crypto/test/src/x509/test/TestCertificateGen.cs index e91a102f1..24dbdf08f 100644 --- a/crypto/test/src/x509/test/TestCertificateGen.cs +++ b/crypto/test/src/x509/test/TestCertificateGen.cs @@ -5,6 +5,7 @@ using System.Text; using NUnit.Framework; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; @@ -222,20 +223,14 @@ namespace Org.BouncyCastle.X509.Tests BigInteger ECPubQX = new BigInteger(Base64.Decode("HWWi17Yb+Bm3PYr/DMjLOYNFhyOwX1QY7ZvqqM+l")); BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx")); BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo")); - FpCurve curve = new FpCurve( - new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b - ECDomainParameters ecDomain = - new ECDomainParameters(curve, new FpPoint(curve, curve.FromBigInteger(ECParraGX), curve.FromBigInteger(ECParraGY)), ECParraN); - ECPublicKeyParameters ecPub = new ECPublicKeyParameters( - "ECDSA", - new FpPoint(curve, - curve.FromBigInteger(ECPubQX), - curve.FromBigInteger(ECPubQY)), - ecDomain); - ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters("ECDSA", ECPrivD, ecDomain); + X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1"); + ECCurve curve = x9.Curve; + ECDomainParameters ecDomain = new ECDomainParameters(curve, curve.ValidatePoint(ECParraGX, ECParraGY), ECParraN, ECParraH); + + ECPublicKeyParameters ecPub = new ECPublicKeyParameters("ECDSA", + curve.ValidatePoint(ECPubQX, ECPubQY), ecDomain); + ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters("ECDSA", ECPrivD, ecDomain); IDictionary attrs = new Hashtable(); attrs[X509Name.C] = "AU"; |