diff options
author | Oren Novotny <oren@novotny.org> | 2015-10-16 20:23:05 -0400 |
---|---|---|
committer | Oren Novotny <oren@novotny.org> | 2015-10-16 20:23:05 -0400 |
commit | de17e96f2d52a25a33e742d0f81e9052da77f49b (patch) | |
tree | 03ccef76aacc1bac6340df9faedf1d64dda76077 /crypto/src | |
parent | prep release for 1.8.0-rc2 (diff) | |
parent | Merge branch 'master' into master-vs12 (diff) | |
download | BouncyCastle.NET-ed25519-de17e96f2d52a25a33e742d0f81e9052da77f49b.tar.xz |
Merge branch 'master-vs12' into pcl
Diffstat (limited to 'crypto/src')
135 files changed, 4999 insertions, 3491 deletions
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs index 18d13c32d..501e788a0 100644 --- a/crypto/src/asn1/Asn1InputStream.cs +++ b/crypto/src/asn1/Asn1InputStream.cs @@ -2,7 +2,6 @@ using System; using System.Diagnostics; using System.IO; -using Org.BouncyCastle.Asn1.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Asn1 diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs index f95d123f9..c03d9dc11 100644 --- a/crypto/src/asn1/DerOutputStream.cs +++ b/crypto/src/asn1/DerOutputStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Asn1 { diff --git a/crypto/src/asn1/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs index 04e30bb07..c7f9545f2 100644 --- a/crypto/src/asn1/anssi/ANSSINamedCurves.cs +++ b/crypto/src/asn1/anssi/ANSSINamedCurves.cs @@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.Anssi BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF" + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB")); diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs index 45adce4f7..8128b6952 100644 --- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs +++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs @@ -41,13 +41,39 @@ namespace Org.BouncyCastle.Asn1.Misc // iso/itu(2) country(16) us(840) organization(1) novell(113719) // public static readonly string Novell = "2.16.840.1.113719"; - public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1"); + public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1"); // // Entrust // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) // public static readonly string Entrust = "1.2.840.113533.7"; - public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0"); + public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0"); + + // + // Ascom + // + public static readonly DerObjectIdentifier as_sys_sec_alg_ideaCBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2"); + + // + // Peter Gutmann's Cryptlib + // + public static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029"); + + public static readonly DerObjectIdentifier cryptlib_algorithm = cryptlib.Branch("1"); + public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.Branch("1.1"); + public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.Branch("1.2"); + public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.Branch("1.3"); + public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.Branch("1.4"); + + // + // Blake2b + // + public static readonly DerObjectIdentifier blake2 = new DerObjectIdentifier("1.3.6.1.4.1.1722.12.2"); + + public static readonly DerObjectIdentifier id_blake2b160 = blake2.Branch("1.5"); + 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"); } } diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs index 8eb5ed437..55b9d8e68 100644 --- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs +++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs @@ -25,6 +25,12 @@ namespace Org.BouncyCastle.Asn1.Nist public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4"); public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5"); public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6"); + public static readonly DerObjectIdentifier IdSha3_224 = HashAlgs.Branch("7"); + public static readonly DerObjectIdentifier IdSha3_256 = HashAlgs.Branch("8"); + public static readonly DerObjectIdentifier IdSha3_384 = HashAlgs.Branch("9"); + 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 Aes = new DerObjectIdentifier(NistAlgorithm + ".1"); diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs index 0bd60b0b8..ca71a4e66 100644 --- a/crypto/src/asn1/sec/SECNamedCurves.cs +++ b/crypto/src/asn1/sec/SECNamedCurves.cs @@ -54,9 +54,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "09487239995A5EE76B55F9C2F098")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "09487239995A5EE76B55F9C2F098" + "A89CE5AF8724C0A23E0E0FF77500")); @@ -85,9 +83,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "4BA30AB5E892B4E1649DD0928643")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "4BA30AB5E892B4E1649DD0928643" + "ADCD46F5882E3747DEF36E956E97")); @@ -116,9 +112,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "161FF7528B899B2D0C28607CA52C5B86")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "161FF7528B899B2D0C28607CA52C5B86" + "CF5AC8395BAFEB13C02DA292DDED7A83")); @@ -147,9 +141,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "7B6AA5D85E572983E6FB32A7CDEBC140" + "27B6916A894D3AEE7106FE805FC34B44")); @@ -191,9 +183,7 @@ namespace Org.BouncyCastle.Asn1.Sec 176); ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + "938CF935318FDCED6BC28286531733C3F03C4FEE")); @@ -222,9 +212,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "4A96B5688EF573284664698968C38BB913CBFC82")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "4A96B5688EF573284664698968C38BB913CBFC82" + "23A628553168947D59DCC912042351377AC5FB32")); @@ -253,9 +241,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); @@ -297,9 +283,7 @@ namespace Org.BouncyCastle.Asn1.Sec 208); ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); @@ -328,9 +312,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); @@ -372,9 +354,7 @@ namespace Org.BouncyCastle.Asn1.Sec 240); ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); @@ -403,9 +383,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); @@ -447,9 +425,7 @@ namespace Org.BouncyCastle.Asn1.Sec 272); ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); @@ -478,9 +454,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); @@ -509,9 +483,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); @@ -540,9 +512,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.One; ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); @@ -572,9 +542,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "009D73616F35F4AB1407D73562C10F")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "009D73616F35F4AB1407D73562C10F" + "00A52830277958EE84D1315ED31886")); @@ -604,9 +572,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "01A57A6A7B26CA5EF52FCDB8164797")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "01A57A6A7B26CA5EF52FCDB8164797" + "00B3ADC94ED1FE674C06E695BABA1D")); @@ -638,9 +604,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "0081BAF91FDF9833C40F9C181343638399")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0081BAF91FDF9833C40F9C181343638399" + "078C6E7EA38C001F73C8134B1B4EF9E150")); @@ -672,9 +636,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "0356DCD8F2F95031AD652D23951BB366A8")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0356DCD8F2F95031AD652D23951BB366A8" + "0648F06D867940A5366D9E265DE9EB240F")); @@ -706,9 +668,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); @@ -740,9 +700,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "0369979697AB43897789566789567F787A7876A654")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0369979697AB43897789566789567F787A7876A654" + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); @@ -774,9 +732,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); @@ -806,9 +762,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); @@ -838,9 +792,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); @@ -870,9 +822,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); @@ -902,9 +852,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); @@ -934,9 +882,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); @@ -968,9 +914,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); @@ -1002,9 +946,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); @@ -1034,9 +976,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); @@ -1066,9 +1006,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); @@ -1100,9 +1038,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(4); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("02" - //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); @@ -1134,9 +1070,7 @@ namespace Org.BouncyCastle.Asn1.Sec BigInteger h = BigInteger.ValueOf(2); ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); - //ECPoint G = curve.DecodePoint(Hex.Decode("03" - //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs index f476619a7..ba3eda620 100644 --- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs +++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs @@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G + new X9ECPoint(curve, Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G n, h); } } @@ -66,7 +66,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G + new X9ECPoint(curve, Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G n, h); } } @@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G + new X9ECPoint(curve, Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G n, h); } } @@ -117,7 +117,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' + new X9ECPoint(curve, Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' n, h); } } @@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G + new X9ECPoint(curve, Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G n, h); } } @@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' + new X9ECPoint(curve, Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' n, h); } } @@ -193,7 +193,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G + new X9ECPoint(curve, Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G n, h); } } @@ -219,7 +219,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' + new X9ECPoint(curve, Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' n, h); } } @@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G + new X9ECPoint(curve, Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G n, h); } } @@ -270,7 +270,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' + new X9ECPoint(curve, Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' n, h); } } @@ -295,7 +295,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G + new X9ECPoint(curve, Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G n, h); } } @@ -321,7 +321,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' + new X9ECPoint(curve, Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' n, h); } } @@ -346,7 +346,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G + new X9ECPoint(curve, Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G n, h); } } @@ -372,7 +372,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust return new X9ECParameters( curve, - curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' + new X9ECPoint(curve, Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' n, h); } } diff --git a/crypto/src/asn1/util/FilterStream.cs b/crypto/src/asn1/util/FilterStream.cs index 2b22856a6..3d08446cd 100644 --- a/crypto/src/asn1/util/FilterStream.cs +++ b/crypto/src/asn1/util/FilterStream.cs @@ -3,8 +3,10 @@ using System.IO; namespace Org.BouncyCastle.Asn1.Utilities { + [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")] public class FilterStream : Stream { + [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")] public FilterStream(Stream s) { this.s = s; diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs index 4ed3a400d..c6f4af5bf 100644 --- a/crypto/src/asn1/x509/AlgorithmIdentifier.cs +++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs @@ -69,11 +69,22 @@ namespace Org.BouncyCastle.Asn1.X509 } } + /// <summary> + /// Return the OID in the Algorithm entry of this identifier. + /// </summary> + public virtual DerObjectIdentifier Algorithm + { + get { return objectID; } + } + public virtual DerObjectIdentifier ObjectID { get { return objectID; } } + /// <summary> + /// Return the parameters structure in the Parameters entry of this identifier. + /// </summary> public Asn1Encodable Parameters { get { return parameters; } diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs index d8315c16f..92d4393a8 100644 --- a/crypto/src/asn1/x9/ECNamedCurveTable.cs +++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs @@ -49,6 +49,28 @@ namespace Org.BouncyCastle.Asn1.X9 return ecP; } + public static string GetName(DerObjectIdentifier oid) + { + string name = X962NamedCurves.GetName(oid); + if (name == null) + { + name = SecNamedCurves.GetName(oid); + } + if (name == null) + { + name = NistNamedCurves.GetName(oid); + } + if (name == null) + { + name = TeleTrusTNamedCurves.GetName(oid); + } + if (name == null) + { + name = AnssiNamedCurves.GetName(oid); + } + return name; + } + /** * return the object identifier signified by the passed in name. Null * if there is no object identifier associated with name. diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs index a9ea0240c..6fa4e7c4b 100644 --- a/crypto/src/asn1/x9/X962NamedCurves.cs +++ b/crypto/src/asn1/x9/X962NamedCurves.cs @@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp192v1, - cFp192v1.DecodePoint( + new X9ECPoint(cFp192v1, Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), n, h, Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); @@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp192v2, - cFp192v2.DecodePoint( + new X9ECPoint(cFp192v2, Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), n, h, Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); @@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp192v3, - cFp192v3.DecodePoint( + new X9ECPoint(cFp192v3, Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), n, h, Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e")); @@ -119,7 +119,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp239v1, - cFp239v1.DecodePoint( + new X9ECPoint(cFp239v1, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), n, h, Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); @@ -146,7 +146,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp239v2, - cFp239v2.DecodePoint( + new X9ECPoint(cFp239v2, Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), n, h, Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616")); @@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp239v3, - cFp239v3.DecodePoint( + new X9ECPoint(cFp239v3, Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), n, h, Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); @@ -200,7 +200,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( cFp256v1, - cFp256v1.DecodePoint( + new X9ECPoint(cFp256v1, Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), n, h, Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90")); @@ -231,7 +231,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m163v1, - c2m163v1.DecodePoint( + new X9ECPoint(c2m163v1, Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), n, h, Hex.Decode("D2C0FB15760860DEF1EEF4D696E6768756151754")); @@ -259,7 +259,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m163v2, - c2m163v2.DecodePoint( + new X9ECPoint(c2m163v2, Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), n, h, null); @@ -287,7 +287,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m163v3, - c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), + new X9ECPoint(c2m163v3, Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), n, h, null); } @@ -314,7 +314,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m176w1, - c2m176w1.DecodePoint( + new X9ECPoint(c2m176w1, Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), n, h, null); @@ -342,7 +342,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m191v1, - c2m191v1.DecodePoint( + new X9ECPoint(c2m191v1, Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), n, h, Hex.Decode("4E13CA542744D696E67687561517552F279A8C84")); @@ -370,7 +370,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m191v2, - c2m191v2.DecodePoint( + new X9ECPoint(c2m191v2, Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), n, h, null); @@ -398,7 +398,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m191v3, - c2m191v3.DecodePoint( + new X9ECPoint(c2m191v3, Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), n, h, null); @@ -426,7 +426,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m208w1, - c2m208w1.DecodePoint( + new X9ECPoint(c2m208w1, Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), n, h, null); @@ -454,7 +454,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m239v1, - c2m239v1.DecodePoint( + new X9ECPoint(c2m239v1, Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), n, h, null); @@ -482,7 +482,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m239v2, - c2m239v2.DecodePoint( + new X9ECPoint(c2m239v2, Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), n, h, null); @@ -510,7 +510,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m239v3, - c2m239v3.DecodePoint( + new X9ECPoint(c2m239v3, Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), n, h, null); @@ -538,7 +538,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m272w1, - c2m272w1.DecodePoint( + new X9ECPoint(c2m272w1, Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), n, h, null); @@ -566,7 +566,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m304w1, - c2m304w1.DecodePoint( + new X9ECPoint(c2m304w1, Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), n, h, null); @@ -594,7 +594,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m359v1, - c2m359v1.DecodePoint( + new X9ECPoint(c2m359v1, Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), n, h, null); @@ -622,7 +622,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m368w1, - c2m368w1.DecodePoint( + new X9ECPoint(c2m368w1, Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), n, h, null); @@ -650,7 +650,7 @@ namespace Org.BouncyCastle.Asn1.X9 return new X9ECParameters( c2m431r1, - c2m431r1.DecodePoint( + new X9ECPoint(c2m431r1, Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), n, h, null); diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs index a192e4c52..2b6b14bcb 100644 --- a/crypto/src/asn1/x9/X9ECParameters.cs +++ b/crypto/src/asn1/x9/X9ECParameters.cs @@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Asn1.X9 { private X9FieldID fieldID; private ECCurve curve; - private ECPoint g; + private X9ECPoint g; private BigInteger n; private BigInteger h; private byte[] seed; @@ -29,36 +29,28 @@ namespace Org.BouncyCastle.Asn1.X9 throw new ArgumentException("bad version in X9ECParameters"); } - X9Curve x9c = null; - if (seq[2] is X9Curve) - { - x9c = (X9Curve) seq[2]; - } - else - { - x9c = new X9Curve( - new X9FieldID( - (Asn1Sequence) seq[1]), - (Asn1Sequence) seq[2]); - } + X9Curve x9c = new X9Curve( + X9FieldID.GetInstance(seq[1]), + Asn1Sequence.GetInstance(seq[2])); this.curve = x9c.Curve; + object p = seq[3]; - if (seq[3] is X9ECPoint) + if (p is X9ECPoint) { - this.g = ((X9ECPoint) seq[3]).Point; + this.g = ((X9ECPoint)p); } else { - this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point; + this.g = new X9ECPoint(curve, (Asn1OctetString)p); } - this.n = ((DerInteger) seq[4]).Value; + this.n = ((DerInteger)seq[4]).Value; this.seed = x9c.GetSeed(); if (seq.Count == 6) { - this.h = ((DerInteger) seq[5]).Value; + this.h = ((DerInteger)seq[5]).Value; } } @@ -66,7 +58,16 @@ namespace Org.BouncyCastle.Asn1.X9 ECCurve curve, ECPoint g, BigInteger n) - : this(curve, g, n, BigInteger.One, null) + : this(curve, g, n, null, null) + { + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h) + : this(curve, g, n, h, null) { } @@ -85,9 +86,19 @@ namespace Org.BouncyCastle.Asn1.X9 BigInteger n, BigInteger h, byte[] seed) + : this(curve, new X9ECPoint(g), n, h, seed) + { + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) { this.curve = curve; - this.g = g.Normalize(); + this.g = g; this.n = n; this.h = h; this.seed = seed; @@ -126,7 +137,7 @@ namespace Org.BouncyCastle.Asn1.X9 public ECPoint G { - get { return g; } + get { return g.Point; } } public BigInteger N @@ -136,16 +147,7 @@ namespace Org.BouncyCastle.Asn1.X9 public BigInteger H { - get - { - if (h == null) - { - // TODO - this should be calculated, it will cause issues with custom curves. - return BigInteger.One; - } - - return h; - } + get { return h; } } public byte[] GetSeed() @@ -154,6 +156,36 @@ namespace Org.BouncyCastle.Asn1.X9 } /** + * Return the ASN.1 entry representing the Curve. + * + * @return the X9Curve for the curve in these parameters. + */ + public X9Curve CurveEntry + { + get { return new X9Curve(curve, seed); } + } + + /** + * Return the ASN.1 entry representing the FieldID. + * + * @return the X9FieldID for the FieldID in these parameters. + */ + public X9FieldID FieldIDEntry + { + get { return fieldID; } + } + + /** + * Return the ASN.1 entry representing the base point G. + * + * @return the X9ECPoint for the base point in these parameters. + */ + public X9ECPoint BaseEntry + { + get { return g; } + } + + /** * Produce an object suitable for an Asn1OutputStream. * <pre> * ECParameters ::= Sequence { @@ -169,10 +201,10 @@ namespace Org.BouncyCastle.Asn1.X9 public override Asn1Object ToAsn1Object() { Asn1EncodableVector v = new Asn1EncodableVector( - new DerInteger(1), + new DerInteger(BigInteger.One), fieldID, new X9Curve(curve, seed), - new X9ECPoint(g), + g, new DerInteger(n)); if (h != null) diff --git a/crypto/src/asn1/x9/X9ECParametersHolder.cs b/crypto/src/asn1/x9/X9ECParametersHolder.cs index dd59e9f56..e802b738c 100644 --- a/crypto/src/asn1/x9/X9ECParametersHolder.cs +++ b/crypto/src/asn1/x9/X9ECParametersHolder.cs @@ -1,13 +1,13 @@ namespace Org.BouncyCastle.Asn1.X9 { - public abstract class X9ECParametersHolder - { - private X9ECParameters parameters; + public abstract class X9ECParametersHolder + { + private X9ECParameters parameters; - public X9ECParameters Parameters - { - get - { + public X9ECParameters Parameters + { + get + { lock (this) { if (parameters == null) @@ -20,6 +20,6 @@ namespace Org.BouncyCastle.Asn1.X9 } } - protected abstract X9ECParameters CreateParameters(); - } + protected abstract X9ECParameters CreateParameters(); + } } diff --git a/crypto/src/asn1/x9/X9ECPoint.cs b/crypto/src/asn1/x9/X9ECPoint.cs index 75d58cd38..7ef4f13bc 100644 --- a/crypto/src/asn1/x9/X9ECPoint.cs +++ b/crypto/src/asn1/x9/X9ECPoint.cs @@ -1,5 +1,7 @@ using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; + namespace Org.BouncyCastle.Asn1.X9 { /** @@ -8,24 +10,58 @@ namespace Org.BouncyCastle.Asn1.X9 public class X9ECPoint : Asn1Encodable { - private readonly ECPoint p; + private readonly Asn1OctetString encoding; + + private ECCurve c; + private ECPoint p; + + public X9ECPoint(ECPoint p) + : this(p, false) + { + } - public X9ECPoint( - ECPoint p) + public X9ECPoint(ECPoint p, bool compressed) { this.p = p.Normalize(); + this.encoding = new DerOctetString(p.GetEncoded(compressed)); + } + + public X9ECPoint(ECCurve c, byte[] encoding) + { + this.c = c; + this.encoding = new DerOctetString(Arrays.Clone(encoding)); } - public X9ECPoint( - ECCurve c, - Asn1OctetString s) + public X9ECPoint(ECCurve c, Asn1OctetString s) + : this(c, s.GetOctets()) { - this.p = c.DecodePoint(s.GetOctets()); + } + + public byte[] GetPointEncoding() + { + return Arrays.Clone(encoding.GetOctets()); } public ECPoint Point { - get { return p; } + get + { + if (p == null) + { + p = c.DecodePoint(encoding.GetOctets()).Normalize(); + } + + return p; + } + } + + public bool IsPointCompressed + { + get + { + byte[] octets = encoding.GetOctets(); + return octets != null && octets.Length > 0 && (octets[0] == 2 || octets[0] == 3); + } } /** @@ -38,7 +74,7 @@ namespace Org.BouncyCastle.Asn1.X9 */ public override Asn1Object ToAsn1Object() { - return new DerOctetString(p.GetEncoded()); + return encoding; } } } diff --git a/crypto/src/asn1/x9/X9FieldID.cs b/crypto/src/asn1/x9/X9FieldID.cs index 58823a285..08d7d71b4 100644 --- a/crypto/src/asn1/x9/X9FieldID.cs +++ b/crypto/src/asn1/x9/X9FieldID.cs @@ -90,11 +90,19 @@ namespace Org.BouncyCastle.Asn1.X9 this.parameters = new DerSequence(fieldIdParams); } - internal X9FieldID( - Asn1Sequence seq) + private X9FieldID(Asn1Sequence seq) { - this.id = (DerObjectIdentifier) seq[0]; - this.parameters = (Asn1Object) seq[1]; + this.id = DerObjectIdentifier.GetInstance(seq[0]); + this.parameters = seq[1].ToAsn1Object(); + } + + public static X9FieldID GetInstance(object obj) + { + if (obj is X9FieldID) + return (X9FieldID)obj; + if (obj == null) + return null; + return new X9FieldID(Asn1Sequence.GetInstance(obj)); } public DerObjectIdentifier Identifier diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs index e8a4f048d..9835891b1 100644 --- a/crypto/src/bcpg/BcpgInputStream.cs +++ b/crypto/src/bcpg/BcpgInputStream.cs @@ -105,19 +105,15 @@ namespace Org.BouncyCastle.Bcpg next = true; } - if (nextB >= 0) + if (nextB < 0) + return (PacketTag)nextB; + + int maskB = nextB & 0x3f; + if ((nextB & 0x40) == 0) // old { - if ((nextB & 0x40) != 0) // new - { - return (PacketTag)(nextB & 0x3f); - } - else // old - { - return (PacketTag)((nextB & 0x3f) >> 2); - } + maskB >>= 2; } - - return (PacketTag) nextB; + return (PacketTag)maskB; } public Packet ReadPacket() diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs index b85379586..dc225e31e 100644 --- a/crypto/src/bcpg/ECDHPublicBCPGKey.cs +++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs @@ -10,8 +10,8 @@ namespace Org.BouncyCastle.Bcpg : ECPublicBcpgKey { private byte reserved; - private byte hashFunctionId; - private byte symAlgorithmId; + private HashAlgorithmTag hashFunctionId; + private SymmetricKeyAlgorithmTag symAlgorithmId; /// <param name="bcpgIn">The stream to read the packet from.</param> public ECDHPublicBcpgKey( @@ -26,8 +26,8 @@ namespace Org.BouncyCastle.Bcpg bcpgIn.ReadFully(kdfParameters); reserved = kdfParameters[0]; - hashFunctionId = kdfParameters[1]; - symAlgorithmId = kdfParameters[2]; + hashFunctionId = (HashAlgorithmTag)kdfParameters[1]; + symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2]; VerifyHashAlgorithm(); VerifySymmetricKeyAlgorithm(); @@ -36,13 +36,13 @@ namespace Org.BouncyCastle.Bcpg public ECDHPublicBcpgKey( DerObjectIdentifier oid, ECPoint point, - int hashAlgorithm, - int symmetricKeyAlgorithm) + HashAlgorithmTag hashAlgorithm, + SymmetricKeyAlgorithmTag symmetricKeyAlgorithm) : base(oid, point) { reserved = 1; - hashFunctionId = (byte)hashAlgorithm; - symAlgorithmId = (byte)symmetricKeyAlgorithm; + hashFunctionId = hashAlgorithm; + symAlgorithmId = symmetricKeyAlgorithm; VerifyHashAlgorithm(); VerifySymmetricKeyAlgorithm(); @@ -53,12 +53,12 @@ namespace Org.BouncyCastle.Bcpg get { return reserved; } } - public virtual byte HashAlgorithm + public virtual HashAlgorithmTag HashAlgorithm { get { return hashFunctionId; } } - public virtual byte SymmetricKeyAlgorithm + public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm { get { return symAlgorithmId; } } @@ -69,8 +69,8 @@ namespace Org.BouncyCastle.Bcpg base.Encode(bcpgOut); bcpgOut.WriteByte(0x3); bcpgOut.WriteByte(reserved); - bcpgOut.WriteByte(hashFunctionId); - bcpgOut.WriteByte(symAlgorithmId); + bcpgOut.WriteByte((byte)hashFunctionId); + bcpgOut.WriteByte((byte)symAlgorithmId); } private void VerifyHashAlgorithm() diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs index 4a6704c14..9e30b54f7 100644 --- a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs +++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs @@ -1,3 +1,5 @@ +using System; + namespace Org.BouncyCastle.Bcpg { /// <remarks>Public Key Algorithm tag numbers.</remarks> @@ -8,6 +10,7 @@ namespace Org.BouncyCastle.Bcpg RsaSign = 3, // RSA Sign-Only ElGamalEncrypt = 16, // Elgamal (Encrypt-Only), see [ELGAMAL] Dsa = 17, // DSA (Digital Signature Standard) + [Obsolete("Use 'ECDH' instead")] EC = 18, // Reserved for Elliptic Curve ECDH = 18, // Reserved for Elliptic Curve (actual algorithm name) ECDsa = 19, // Reserved for ECDSA diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs index d10605f1d..eefe4495b 100644 --- a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs +++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs @@ -2,6 +2,8 @@ using System; using System.IO; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Bcpg { @@ -12,7 +14,7 @@ namespace Org.BouncyCastle.Bcpg private int version; private long keyId; private PublicKeyAlgorithmTag algorithm; - private BigInteger[] data; + private byte[][] data; internal PublicKeyEncSessionPacket( BcpgInputStream bcpgIn) @@ -34,33 +36,41 @@ namespace Org.BouncyCastle.Bcpg { case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaGeneral: - data = new BigInteger[]{ new MPInteger(bcpgIn).Value }; + data = new byte[][]{ new MPInteger(bcpgIn).GetEncoded() }; break; case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: - data = new BigInteger[] - { - new MPInteger(bcpgIn).Value, - new MPInteger(bcpgIn).Value - }; + MPInteger p = new MPInteger(bcpgIn); + MPInteger g = new MPInteger(bcpgIn); + data = new byte[][]{ + p.GetEncoded(), + g.GetEncoded(), + }; break; + case PublicKeyAlgorithmTag.ECDH: + data = new byte[][]{ Streams.ReadAll(bcpgIn) }; + break; default: throw new IOException("unknown PGP public key algorithm encountered"); } } - public PublicKeyEncSessionPacket( - long keyId, - PublicKeyAlgorithmTag algorithm, - BigInteger[] data) + public PublicKeyEncSessionPacket( + long keyId, + PublicKeyAlgorithmTag algorithm, + byte[][] data) { this.version = 3; this.keyId = keyId; this.algorithm = algorithm; - this.data = (BigInteger[]) data.Clone(); + this.data = new byte[data.Length][]; + for (int i = 0; i < data.Length; ++i) + { + this.data[i] = Arrays.Clone(data[i]); + } } - public int Version + public int Version { get { return version; } } @@ -75,12 +85,12 @@ namespace Org.BouncyCastle.Bcpg get { return algorithm; } } - public BigInteger[] GetEncSessionKey() + public byte[][] GetEncSessionKey() { - return (BigInteger[]) data.Clone(); + return data; } - public override void Encode( + public override void Encode( BcpgOutputStream bcpgOut) { MemoryStream bOut = new MemoryStream(); @@ -92,12 +102,14 @@ namespace Org.BouncyCastle.Bcpg pOut.WriteByte((byte)algorithm); - for (int i = 0; i != data.Length; i++) - { - MPInteger.Encode(pOut, data[i]); - } + for (int i = 0; i < data.Length; ++i) + { + pOut.Write(data[i]); + } + + pOut.Dispose(); - bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true); + bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true); } } } diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs index cea5c8ed2..bbed941dc 100644 --- a/crypto/src/bcpg/PublicKeyPacket.cs +++ b/crypto/src/bcpg/PublicKeyPacket.cs @@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Bcpg case PublicKeyAlgorithmTag.ElGamalGeneral: key = new ElGamalPublicBcpgKey(bcpgIn); break; - case PublicKeyAlgorithmTag.EC: + case PublicKeyAlgorithmTag.ECDH: key = new ECDHPublicBcpgKey(bcpgIn); break; case PublicKeyAlgorithmTag.ECDsa: diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs index f6d306890..33fd792fe 100644 --- a/crypto/src/bcpg/S2k.cs +++ b/crypto/src/bcpg/S2k.cs @@ -84,19 +84,19 @@ namespace Org.BouncyCastle.Bcpg this.itCount = itCount; } - public int Type + public virtual int Type { get { return type; } } /// <summary>The hash algorithm.</summary> - public HashAlgorithmTag HashAlgorithm + public virtual HashAlgorithmTag HashAlgorithm { get { return algorithm; } } /// <summary>The IV for the key generation algorithm.</summary> - public byte[] GetIV() + public virtual byte[] GetIV() { return Arrays.Clone(iv); } @@ -108,13 +108,13 @@ namespace Org.BouncyCastle.Bcpg } /// <summary>The iteration count</summary> - public long IterationCount + public virtual long IterationCount { get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); } } /// <summary>The protection mode - only if GnuDummyS2K</summary> - public int ProtectionMode + public virtual int ProtectionMode { get { return protectionMode; } } diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs index ac26f8a3c..d99315599 100644 --- a/crypto/src/bcpg/SignatureSubpacket.cs +++ b/crypto/src/bcpg/SignatureSubpacket.cs @@ -7,20 +7,22 @@ namespace Org.BouncyCastle.Bcpg { private readonly SignatureSubpacketTag type; private readonly bool critical; - - internal readonly byte[] data; + private readonly bool isLongLength; + internal byte[] data; protected internal SignatureSubpacket( SignatureSubpacketTag type, bool critical, + bool isLongLength, byte[] data) { this.type = type; this.critical = critical; + this.isLongLength = isLongLength; this.data = data; } - public SignatureSubpacketTag SubpacketType + public SignatureSubpacketTag SubpacketType { get { return type; } } @@ -30,7 +32,12 @@ namespace Org.BouncyCastle.Bcpg return critical; } - /// <summary>Return the generic data making up the packet.</summary> + public bool IsLongLength() + { + return isLongLength; + } + + /// <summary>Return the generic data making up the packet.</summary> public byte[] GetData() { return (byte[]) data.Clone(); @@ -41,18 +48,7 @@ namespace Org.BouncyCastle.Bcpg { int bodyLen = data.Length + 1; - if (bodyLen < 192) - { - os.WriteByte((byte)bodyLen); - } - else if (bodyLen <= 8383) - { - bodyLen -= 192; - - os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192)); - os.WriteByte((byte)bodyLen); - } - else + if (isLongLength) { os.WriteByte(0xff); os.WriteByte((byte)(bodyLen >> 24)); @@ -60,6 +56,28 @@ namespace Org.BouncyCastle.Bcpg os.WriteByte((byte)(bodyLen >> 8)); os.WriteByte((byte)bodyLen); } + else + { + if (bodyLen < 192) + { + os.WriteByte((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192)); + os.WriteByte((byte)bodyLen); + } + else + { + os.WriteByte(0xff); + os.WriteByte((byte)(bodyLen >> 24)); + os.WriteByte((byte)(bodyLen >> 16)); + os.WriteByte((byte)(bodyLen >> 8)); + os.WriteByte((byte)bodyLen); + } + } if (critical) { diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs index 8dd1af332..80bedb07c 100644 --- a/crypto/src/bcpg/SignatureSubpacketsReader.cs +++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs @@ -1,6 +1,8 @@ using System; using System.IO; + using Org.BouncyCastle.Bcpg.Sig; +using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Bcpg @@ -25,7 +27,9 @@ namespace Org.BouncyCastle.Bcpg return null; int bodyLen = 0; - if (l < 192) + bool isLongLength = false; + + if (l < 192) { bodyLen = l; } @@ -35,54 +39,90 @@ namespace Org.BouncyCastle.Bcpg } else if (l == 255) { + isLongLength = true; bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16) | (input.ReadByte() << 8) | input.ReadByte(); } else { - // TODO Error? + throw new IOException("unexpected length header"); } - int tag = input.ReadByte(); + int tag = input.ReadByte(); if (tag < 0) throw new EndOfStreamException("unexpected EOF reading signature sub packet"); - byte[] data = new byte[bodyLen - 1]; - if (Streams.ReadFully(input, data) < data.Length) - throw new EndOfStreamException(); + byte[] data = new byte[bodyLen - 1]; + + // + // this may seem a bit strange but it turns out some applications miscode the length + // in fixed length fields, so we check the length we do get, only throwing an exception if + // we really cannot continue + // + int bytesRead = Streams.ReadFully(input, data); + + bool isCritical = ((tag & 0x80) != 0); + SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f); - bool isCritical = ((tag & 0x80) != 0); - SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f); - switch (type) + if (bytesRead != data.Length) + { + switch (type) + { + case SignatureSubpacketTag.CreationTime: + data = CheckData(data, 4, bytesRead, "Signature Creation Time"); + break; + case SignatureSubpacketTag.IssuerKeyId: + data = CheckData(data, 8, bytesRead, "Issuer"); + break; + case SignatureSubpacketTag.KeyExpireTime: + data = CheckData(data, 4, bytesRead, "Signature Key Expiration Time"); + break; + case SignatureSubpacketTag.ExpireTime: + data = CheckData(data, 4, bytesRead, "Signature Expiration Time"); + break; + default: + throw new EndOfStreamException("truncated subpacket data."); + } + } + + switch (type) { case SignatureSubpacketTag.CreationTime: - return new SignatureCreationTime(isCritical, data); + return new SignatureCreationTime(isCritical, isLongLength, data); case SignatureSubpacketTag.KeyExpireTime: - return new KeyExpirationTime(isCritical, data); + return new KeyExpirationTime(isCritical, isLongLength, data); case SignatureSubpacketTag.ExpireTime: - return new SignatureExpirationTime(isCritical, data); + return new SignatureExpirationTime(isCritical, isLongLength, data); case SignatureSubpacketTag.Revocable: - return new Revocable(isCritical, data); + return new Revocable(isCritical, isLongLength, data); case SignatureSubpacketTag.Exportable: - return new Exportable(isCritical, data); + return new Exportable(isCritical, isLongLength, data); case SignatureSubpacketTag.IssuerKeyId: - return new IssuerKeyId(isCritical, data); + return new IssuerKeyId(isCritical, isLongLength, data); case SignatureSubpacketTag.TrustSig: - return new TrustSignature(isCritical, data); + return new TrustSignature(isCritical, isLongLength, data); case SignatureSubpacketTag.PreferredCompressionAlgorithms: case SignatureSubpacketTag.PreferredHashAlgorithms: case SignatureSubpacketTag.PreferredSymmetricAlgorithms: - return new PreferredAlgorithms(type, isCritical, data); + return new PreferredAlgorithms(type, isCritical, isLongLength, data); case SignatureSubpacketTag.KeyFlags: - return new KeyFlags(isCritical, data); + return new KeyFlags(isCritical, isLongLength, data); case SignatureSubpacketTag.PrimaryUserId: - return new PrimaryUserId(isCritical, data); + return new PrimaryUserId(isCritical, isLongLength, data); case SignatureSubpacketTag.SignerUserId: - return new SignerUserId(isCritical, data); + return new SignerUserId(isCritical, isLongLength, data); case SignatureSubpacketTag.NotationData: - return new NotationData(isCritical, data); + return new NotationData(isCritical, isLongLength, data); } - return new SignatureSubpacket(type, isCritical, data); + return new SignatureSubpacket(type, isCritical, isLongLength, data); } + + private byte[] CheckData(byte[] data, int expected, int bytesRead, string name) + { + if (bytesRead != expected) + throw new EndOfStreamException("truncated " + name + " subpacket data."); + + return Arrays.CopyOfRange(data, 0, expected); + } } } diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs index e47604ac8..fffdaef73 100644 --- a/crypto/src/bcpg/sig/EmbeddedSignature.cs +++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs @@ -10,8 +10,9 @@ namespace Org.BouncyCastle.Bcpg.Sig { public EmbeddedSignature( bool critical, + bool isLongLength, byte[] data) - : base(SignatureSubpacketTag.EmbeddedSignature, critical, data) + : base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data) { } } diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs index 4455c3814..4d030346f 100644 --- a/crypto/src/bcpg/sig/Exportable.cs +++ b/crypto/src/bcpg/sig/Exportable.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -27,15 +25,16 @@ namespace Org.BouncyCastle.Bcpg.Sig public Exportable( bool critical, - byte[] data) - : base(SignatureSubpacketTag.Exportable, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.Exportable, critical, isLongLength, data) { } public Exportable( bool critical, bool isExportable) - : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable)) + : base(SignatureSubpacketTag.Exportable, critical, false, BooleanToByteArray(isExportable)) { } diff --git a/crypto/src/bcpg/sig/Features.cs b/crypto/src/bcpg/sig/Features.cs new file mode 100644 index 000000000..29584239a --- /dev/null +++ b/crypto/src/bcpg/sig/Features.cs @@ -0,0 +1,75 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature expiration time. + */ + public class Features + : SignatureSubpacket + { + /** Identifier for the modification detection feature */ + public static readonly byte FEATURE_MODIFICATION_DETECTION = 1; + + private static byte[] FeatureToByteArray(byte feature) + { + return new byte[]{ feature }; + } + + public Features( + bool critical, + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.Features, critical, isLongLength, data) + { + } + + public Features(bool critical, byte feature) + : base(SignatureSubpacketTag.Features, critical, false, FeatureToByteArray(feature)) + { + } + + /** + * Returns if modification detection is supported. + */ + public bool SupportsModificationDetection + { + get { return SupportsFeature(FEATURE_MODIFICATION_DETECTION); } + } + + /** + * Returns if a particular feature is supported. + */ + public bool SupportsFeature(byte feature) + { + return Array.IndexOf(data, feature) >= 0; + } + + /** + * Sets support for a particular feature. + */ + private void SetSupportsFeature(byte feature, bool support) + { + if (feature == 0) + throw new ArgumentException("cannot be 0", "feature"); + + int i = Array.IndexOf(data, feature); + if ((i >= 0) == support) + return; + + if (support) + { + data = Arrays.Append(data, feature); + } + else + { + byte[] temp = new byte[data.Length - 1]; + Array.Copy(data, 0, temp, 0, i); + Array.Copy(data, i + 1, temp, i, temp.Length - i); + data = temp; + } + } + } +} diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs index 91490d33b..627ea3ecf 100644 --- a/crypto/src/bcpg/sig/IssuerKeyId.cs +++ b/crypto/src/bcpg/sig/IssuerKeyId.cs @@ -29,15 +29,16 @@ namespace Org.BouncyCastle.Bcpg.Sig public IssuerKeyId( bool critical, - byte[] data) - : base(SignatureSubpacketTag.IssuerKeyId, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data) { } public IssuerKeyId( bool critical, - long keyId) - : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId)) + long keyId) + : base(SignatureSubpacketTag.IssuerKeyId, critical, false, KeyIdToBytes(keyId)) { } diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs index 23b4cac29..dfd3e76fd 100644 --- a/crypto/src/bcpg/sig/KeyExpirationTime.cs +++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -25,15 +23,16 @@ namespace Org.BouncyCastle.Bcpg.Sig public KeyExpirationTime( bool critical, - byte[] data) - : base(SignatureSubpacketTag.KeyExpireTime, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data) { } public KeyExpirationTime( bool critical, - long seconds) - : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds)) + long seconds) + : base(SignatureSubpacketTag.KeyExpireTime, critical, false, TimeToBytes(seconds)) { } diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs index 0592301b3..5b5d85a72 100644 --- a/crypto/src/bcpg/sig/KeyFlags.cs +++ b/crypto/src/bcpg/sig/KeyFlags.cs @@ -40,15 +40,16 @@ namespace Org.BouncyCastle.Bcpg.Sig public KeyFlags( bool critical, - byte[] data) - : base(SignatureSubpacketTag.KeyFlags, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data) { } public KeyFlags( - bool critical, - int flags) - : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags)) + bool critical, + int flags) + : base(SignatureSubpacketTag.KeyFlags, critical, false, IntToByteArray(flags)) { } diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs index ccc9aa745..9ac6f89cf 100644 --- a/crypto/src/bcpg/sig/NotationData.cs +++ b/crypto/src/bcpg/sig/NotationData.cs @@ -17,8 +17,9 @@ namespace Org.BouncyCastle.Bcpg.Sig public NotationData( bool critical, - byte[] data) - : base(SignatureSubpacketTag.NotationData, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.NotationData, critical, isLongLength, data) { } @@ -27,12 +28,12 @@ namespace Org.BouncyCastle.Bcpg.Sig bool humanReadable, string notationName, string notationValue) - : base(SignatureSubpacketTag.NotationData, critical, - createData(humanReadable, notationName, notationValue)) + : base(SignatureSubpacketTag.NotationData, critical, false, + CreateData(humanReadable, notationName, notationValue)) { } - private static byte[] createData( + private static byte[] CreateData( bool humanReadable, string notationName, string notationValue) diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs index 0f282a38c..9514bed2b 100644 --- a/crypto/src/bcpg/sig/PreferredAlgorithms.cs +++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -24,24 +22,25 @@ namespace Org.BouncyCastle.Bcpg.Sig } public PreferredAlgorithms( - SignatureSubpacketTag type, - bool critical, - byte[] data) - : base(type, critical, data) + SignatureSubpacketTag type, + bool critical, + bool isLongLength, + byte[] data) + : base(type, critical, isLongLength, data) { } public PreferredAlgorithms( - SignatureSubpacketTag type, - bool critical, - int[] preferences) - : base(type, critical, IntToByteArray(preferences)) + SignatureSubpacketTag type, + bool critical, + int[] preferences) + : base(type, critical, false, IntToByteArray(preferences)) { } public int[] GetPreferences() { - int[] v = new int[data.Length]; + int[] v = new int[data.Length]; for (int i = 0; i != v.Length; i++) { diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs index fc0353afd..1f16f40eb 100644 --- a/crypto/src/bcpg/sig/PrimaryUserId.cs +++ b/crypto/src/bcpg/sig/PrimaryUserId.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -28,15 +26,16 @@ namespace Org.BouncyCastle.Bcpg.Sig public PrimaryUserId( bool critical, - byte[] data) - : base(SignatureSubpacketTag.PrimaryUserId, critical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data) { } public PrimaryUserId( bool critical, bool isPrimaryUserId) - : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId)) + : base(SignatureSubpacketTag.PrimaryUserId, critical, false, BooleanToByteArray(isPrimaryUserId)) { } diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs index b5e94feec..7aa91391f 100644 --- a/crypto/src/bcpg/sig/Revocable.cs +++ b/crypto/src/bcpg/sig/Revocable.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -28,16 +26,17 @@ namespace Org.BouncyCastle.Bcpg.Sig public Revocable( bool critical, - byte[] data) - : base(SignatureSubpacketTag.Revocable, critical, data) - { + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.Revocable, critical, isLongLength, data) + { } public Revocable( bool critical, bool isRevocable) - : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable)) - { + : base(SignatureSubpacketTag.Revocable, critical, false, BooleanToByteArray(isRevocable)) + { } public bool IsRevocable() diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs index 66982cb5a..11467d2af 100644 --- a/crypto/src/bcpg/sig/RevocationKey.cs +++ b/crypto/src/bcpg/sig/RevocationKey.cs @@ -14,17 +14,18 @@ namespace Org.BouncyCastle.Bcpg // 20 octets of fingerprint public RevocationKey( bool isCritical, - byte[] data) - : base(SignatureSubpacketTag.RevocationKey, isCritical, data) + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data) { } - public RevocationKey( + public RevocationKey( bool isCritical, RevocationKeyTag signatureClass, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint) - : base(SignatureSubpacketTag.RevocationKey, isCritical, + : base(SignatureSubpacketTag.RevocationKey, isCritical, false, CreateData(signatureClass, keyAlgorithm, fingerprint)) { } diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs index 98e9b0a3d..42afd5f5b 100644 --- a/crypto/src/bcpg/sig/RevocationReason.cs +++ b/crypto/src/bcpg/sig/RevocationReason.cs @@ -11,16 +11,16 @@ namespace Org.BouncyCastle.Bcpg public class RevocationReason : SignatureSubpacket { - public RevocationReason(bool isCritical, byte[] data) - : base(SignatureSubpacketTag.RevocationReason, isCritical, data) + public RevocationReason(bool isCritical, bool isLongLength, byte[] data) + : base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data) { } - public RevocationReason( - bool isCritical, - RevocationReasonTag reason, - string description) - : base(SignatureSubpacketTag.RevocationReason, isCritical, CreateData(reason, description)) + public RevocationReason( + bool isCritical, + RevocationReasonTag reason, + string description) + : base(SignatureSubpacketTag.RevocationReason, isCritical, false, CreateData(reason, description)) { } diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs index e6f241f11..d172e5d52 100644 --- a/crypto/src/bcpg/sig/SignatureCreationTime.cs +++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs @@ -21,18 +21,22 @@ namespace Org.BouncyCastle.Bcpg.Sig data[3] = (byte)t; return data; } + public SignatureCreationTime( - bool critical, - byte[] data) - : base(SignatureSubpacketTag.CreationTime, critical, data) + bool critical, + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data) { } + public SignatureCreationTime( - bool critical, - DateTime date) - : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date)) + bool critical, + DateTime date) + : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date)) { } + public DateTime GetTime() { long time = (long)( diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs index 7fddf5743..24f0a9f8a 100644 --- a/crypto/src/bcpg/sig/SignatureExpirationTime.cs +++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs @@ -1,7 +1,5 @@ using System; - - namespace Org.BouncyCastle.Bcpg.Sig { /** @@ -11,29 +9,28 @@ namespace Org.BouncyCastle.Bcpg.Sig : SignatureSubpacket { protected static byte[] TimeToBytes( - long t) + long t) { - byte[] data = new byte[4]; - + byte[] data = new byte[4]; data[0] = (byte)(t >> 24); data[1] = (byte)(t >> 16); data[2] = (byte)(t >> 8); data[3] = (byte)t; - return data; } public SignatureExpirationTime( bool critical, - byte[] data) - : base(SignatureSubpacketTag.ExpireTime, critical, data) - { + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data) + { } public SignatureExpirationTime( bool critical, - long seconds) - : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds)) + long seconds) + : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds)) { } diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs index 98cc808e7..8ab62ed2e 100644 --- a/crypto/src/bcpg/sig/SignerUserId.cs +++ b/crypto/src/bcpg/sig/SignerUserId.cs @@ -24,20 +24,21 @@ namespace Org.BouncyCastle.Bcpg.Sig } public SignerUserId( - bool critical, - byte[] data) - : base(SignatureSubpacketTag.SignerUserId, critical, data) + bool critical, + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data) { } - public SignerUserId( - bool critical, - string userId) - : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId)) + public SignerUserId( + bool critical, + string userId) + : base(SignatureSubpacketTag.SignerUserId, critical, false, UserIdToBytes(userId)) { } - public string GetId() + public string GetId() { char[] chars = new char[data.Length]; diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs index bbadd3067..91458826d 100644 --- a/crypto/src/bcpg/sig/TrustSignature.cs +++ b/crypto/src/bcpg/sig/TrustSignature.cs @@ -16,17 +16,18 @@ namespace Org.BouncyCastle.Bcpg.Sig } public TrustSignature( - bool critical, - byte[] data) - : base(SignatureSubpacketTag.TrustSig, critical, data) + bool critical, + bool isLongLength, + byte[] data) + : base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data) { } public TrustSignature( - bool critical, - int depth, - int trustAmount) - : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount)) + bool critical, + int depth, + int trustAmount) + : base(SignatureSubpacketTag.TrustSig, critical, false, IntToByteArray(depth, trustAmount)) { } diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs index edb22dd3d..8cf5d370b 100644 --- a/crypto/src/cms/CMSTypedStream.cs +++ b/crypto/src/cms/CMSTypedStream.cs @@ -2,7 +2,6 @@ using System; using System.IO; using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Cms diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs index 20af29a50..581286a3f 100644 --- a/crypto/src/cms/SignerInformation.cs +++ b/crypto/src/cms/SignerInformation.cs @@ -345,9 +345,12 @@ namespace Org.BouncyCastle.Cms // if (sigParams != null) // throw new CmsException("unrecognised signature parameters provided"); - string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid); - sig = Helper.GetSignatureInstance(signatureName); + sig = Helper.GetSignatureInstance(signatureName); + + //sig = Helper.GetSignatureInstance(this.EncryptionAlgOid); + //sig = SignerUtilities.GetSigner(sigAlgOid); } try diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs new file mode 100644 index 000000000..c12bdaa1d --- /dev/null +++ b/crypto/src/crypto/IBlockResult.cs @@ -0,0 +1,24 @@ + +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Operators that reduce their input to a single block return an object + /// of this type. + /// </summary> + public interface IBlockResult + { + /// <summary> + /// Return the final result of the operation. + /// </summary> + /// <returns>A block of bytes, representing the result of an operation.</returns> + byte[] DoFinal(); + + /// <summary> + /// Store the final result of the operation by copying it into the destination array. + /// </summary> + /// <returns>The number of bytes copied into destination.</returns> + /// <param name="destination">The byte array to copy the result into.</param> + /// <param name="offset">The offset into destination to start copying the result at.</param> + int DoFinal(byte[] destination, int offset); + } +} diff --git a/crypto/src/crypto/ISignatureCalculator.cs b/crypto/src/crypto/ISignatureCalculator.cs new file mode 100644 index 000000000..bb733818d --- /dev/null +++ b/crypto/src/crypto/ISignatureCalculator.cs @@ -0,0 +1,23 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Base interface for operators that serve as stream-based signature calculators. + /// </summary> + public interface ISignatureCalculator + { + /// <summary>The algorithm details object for this calculator.</summary> + Object AlgorithmDetails { get ; } + + /// <summary> + /// Create a stream calculator for this signature calculator. The stream + /// calculator is used for the actual operation of entering the data to be signed + /// and producing the signature block. + /// </summary> + /// <returns>A calculator producing an IBlockResult with a signature in it.</returns> + IStreamCalculator CreateCalculator(); + } +} + + diff --git a/crypto/src/crypto/ISignatureVerifier.cs b/crypto/src/crypto/ISignatureVerifier.cs new file mode 100644 index 000000000..1f42a0256 --- /dev/null +++ b/crypto/src/crypto/ISignatureVerifier.cs @@ -0,0 +1,21 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Base interface for operators that serve as stream-based signature verifiers. + /// </summary> + public interface ISignatureVerifier + { + /// <summary>The algorithm details object for this verifier.</summary> + Object AlgorithmDetails { get ; } + + /// <summary> + /// Create a stream calculator for this verifier. The stream + /// calculator is used for the actual operation of entering the data to be verified + /// and producing a result which can be used to verify the original signature. + /// </summary> + /// <returns>A calculator producing an IVerifier which can verify the signature.</returns> + IStreamCalculator CreateCalculator(); + } +} diff --git a/crypto/src/crypto/ISignatureVerifierProvider.cs b/crypto/src/crypto/ISignatureVerifierProvider.cs new file mode 100644 index 000000000..20180e22a --- /dev/null +++ b/crypto/src/crypto/ISignatureVerifierProvider.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Base interface for a provider to support the dynamic creation of signature verifiers. + /// </summary> + public interface ISignatureVerifierProvider + { + /// <summary> + /// Return a signature verfier for signature algorithm described in the passed in algorithm details object. + /// </summary> + /// <param name="algorithmDetails">The details of the signature algorithm verification is required for.</param> + /// <returns>A new signature verifier.</returns> + ISignatureVerifier CreateSignatureVerifier (Object algorithmDetails); + } +} + diff --git a/crypto/src/crypto/IStreamCalculator.cs b/crypto/src/crypto/IStreamCalculator.cs new file mode 100644 index 000000000..19a542845 --- /dev/null +++ b/crypto/src/crypto/IStreamCalculator.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Base interface for cryptographic operations such as Hashes, MACs, and Signatures which reduce a stream of data + /// to a single value. + /// </summary> + public interface IStreamCalculator + { + /// <summary>Return a "sink" stream which only exists to update the implementing object.</summary> + /// <returns>A stream to write to in order to update the implementing object.</returns> + Stream Stream { get; } + + /// <summary> + /// Return the result of processing the stream. This value is only available once the stream + /// has been closed. + /// </summary> + /// <returns>The result of processing the stream.</returns> + Object GetResult(); + } +} diff --git a/crypto/src/crypto/IVerifier.cs b/crypto/src/crypto/IVerifier.cs new file mode 100644 index 000000000..560cabf8e --- /dev/null +++ b/crypto/src/crypto/IVerifier.cs @@ -0,0 +1,25 @@ +namespace Org.BouncyCastle.Crypto +{ + /// <summary> + /// Operators that reduce their input to the validation of a signature produce this type. + /// </summary> + public interface IVerifier + { + /// <summary> + /// Return true if the passed in data matches what is expected by the verification result. + /// </summary> + /// <param name="data">The bytes representing the signature.</param> + /// <returns>true if the signature verifies, false otherwise.</returns> + bool IsVerified(byte[] data); + + /// <summary> + /// Return true if the length bytes from off in the source array match the signature + /// expected by the verification result. + /// </summary> + /// <param name="source">Byte array containing the signature.</param> + /// <param name="off">The offset into the source array where the signature starts.</param> + /// <param name="length">The number of bytes in source making up the signature.</param> + /// <returns>true if the signature verifies, false otherwise.</returns> + bool IsVerified(byte[] source, int off, int length); + } +} diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs new file mode 100644 index 000000000..e9e2253a0 --- /dev/null +++ b/crypto/src/crypto/IXof.cs @@ -0,0 +1,22 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// <remarks> + /// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes. + /// This interface provides the extra method required to support variable output on a digest implementation. + /// </remarks> + public interface IXof + : IDigest + { + /** + * Output the results of the final calculation for this digest to outLen number of bytes. + * + * @param out output array to write the output bytes to. + * @param outOff offset to start writing the bytes at. + * @param outLen the number of output bytes requested. + * @return the number of bytes written + */ + int DoFinal(byte[] output, int outOff, int outLen); + } +} diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs new file mode 100644 index 000000000..2d6cf393c --- /dev/null +++ b/crypto/src/crypto/digests/KeccakDigest.cs @@ -0,0 +1,534 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /// <summary> + /// Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/ + /// </summary> + /// <remarks> + /// Following the naming conventions used in the C source code to enable easy review of the implementation. + /// </remarks> + 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) % 5) + 5 * ((0) % 5))] = rhoOffset; + x = 1; + y = 0; + for (t = 1; t < 25; t++) + { + //rhoOffset = ((t + 1) * (t + 2) / 2) % 64; + 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; + } + + protected byte[] state = new byte[(1600 / 8)]; + protected byte[] dataQueue = new byte[(1536 / 8)]; + protected int rate; + protected int bitsInQueue; + protected int fixedOutputLength; + protected bool squeezing; + protected int bitsAvailableForSqueezing; + protected byte[] chunk; + protected byte[] oneByte; + + private void ClearDataQueueSection(int off, int len) + { + for (int i = off; i != off + len; i++) + { + dataQueue[i] = 0; + } + } + + public KeccakDigest() + : this(288) + { + } + + public KeccakDigest(int bitLength) + { + Init(bitLength); + } + + public KeccakDigest(KeccakDigest source) + { + CopyIn(source); + } + + private void CopyIn(KeccakDigest source) + { + Array.Copy(source.state, 0, this.state, 0, source.state.Length); + Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length); + this.rate = source.rate; + this.bitsInQueue = source.bitsInQueue; + this.fixedOutputLength = source.fixedOutputLength; + this.squeezing = source.squeezing; + this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; + this.chunk = Arrays.Clone(source.chunk); + this.oneByte = Arrays.Clone(source.oneByte); + } + + public virtual string AlgorithmName + { + get { return "Keccak-" + fixedOutputLength; } + } + + public virtual int GetDigestSize() + { + return fixedOutputLength / 8; + } + + public virtual void Update(byte input) + { + oneByte[0] = input; + + Absorb(oneByte, 0, 8L); + } + + public virtual void BlockUpdate(byte[] input, int inOff, int len) + { + Absorb(input, inOff, len * 8L); + } + + public virtual int DoFinal(byte[] output, int outOff) + { + Squeeze(output, outOff, fixedOutputLength); + + Reset(); + + return GetDigestSize(); + } + + /* + * TODO Possible API change to support partial-byte suffixes. + */ + protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits) + { + if (partialBits > 0) + { + oneByte[0] = partialByte; + Absorb(oneByte, 0, partialBits); + } + + Squeeze(output, outOff, fixedOutputLength); + + Reset(); + + return GetDigestSize(); + } + + public virtual void Reset() + { + Init(fixedOutputLength); + } + + /** + * Return the size of block that the compression function is applied to in bytes. + * + * @return internal byte length of a block. + */ + public virtual int GetByteLength() + { + return rate / 8; + } + + private void Init(int bitLength) + { + switch (bitLength) + { + case 128: + InitSponge(1344, 256); + break; + case 224: + InitSponge(1152, 448); + break; + case 256: + InitSponge(1088, 512); + break; + case 288: + InitSponge(1024, 576); + break; + case 384: + InitSponge(832, 768); + break; + case 512: + InitSponge(576, 1024); + break; + default: + throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength"); + } + } + + private void InitSponge(int rate, int capacity) + { + if (rate + capacity != 1600) + { + throw new InvalidOperationException("rate + capacity != 1600"); + } + if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) + { + throw new InvalidOperationException("invalid rate value"); + } + + this.rate = rate; + // this is never read, need to check to see why we want to save it + // this.capacity = capacity; + this.fixedOutputLength = 0; + Arrays.Fill(this.state, (byte)0); + Arrays.Fill(this.dataQueue, (byte)0); + this.bitsInQueue = 0; + this.squeezing = false; + this.bitsAvailableForSqueezing = 0; + this.fixedOutputLength = capacity / 2; + this.chunk = new byte[rate / 8]; + this.oneByte = new byte[1]; + } + + private void AbsorbQueue() + { + KeccakAbsorb(state, dataQueue, rate / 8); + + bitsInQueue = 0; + } + + protected virtual void Absorb(byte[] data, int off, long databitlen) + { + long i, j, wholeBlocks; + + if ((bitsInQueue % 8) != 0) + { + throw new InvalidOperationException("attempt to absorb with odd length queue."); + } + if (squeezing) + { + throw new InvalidOperationException("attempt to absorb while squeezing."); + } + + i = 0; + while (i < databitlen) + { + if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate))) + { + wholeBlocks = (databitlen - i) / rate; + + for (j = 0; j < wholeBlocks; j++) + { + Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length); + + KeccakAbsorb(state, chunk, chunk.Length); + } + + i += wholeBlocks * rate; + } + else + { + int partialBlock = (int)(databitlen - i); + if (partialBlock + bitsInQueue > rate) + { + partialBlock = rate - bitsInQueue; + } + int partialByte = partialBlock % 8; + partialBlock -= partialByte; + Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8); + + bitsInQueue += partialBlock; + i += partialBlock; + if (bitsInQueue == rate) + { + AbsorbQueue(); + } + if (partialByte > 0) + { + int mask = (1 << partialByte) - 1; + dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask); + bitsInQueue += partialByte; + i += partialByte; + } + } + } + } + + private void PadAndSwitchToSqueezingPhase() + { + if (bitsInQueue + 1 == rate) + { + dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8)); + AbsorbQueue(); + ClearDataQueueSection(0, rate / 8); + } + else + { + ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8); + dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8)); + } + dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8)); + AbsorbQueue(); + + if (rate == 1024) + { + KeccakExtract1024bits(state, dataQueue); + bitsAvailableForSqueezing = 1024; + } + else + { + KeccakExtract(state, dataQueue, rate / 64); + bitsAvailableForSqueezing = rate; + } + + squeezing = true; + } + + protected virtual void Squeeze(byte[] output, int offset, long outputLength) + { + long i; + int partialBlock; + + if (!squeezing) + { + PadAndSwitchToSqueezingPhase(); + } + if ((outputLength % 8) != 0) + { + throw new InvalidOperationException("outputLength not a multiple of 8"); + } + + i = 0; + while (i < outputLength) + { + if (bitsAvailableForSqueezing == 0) + { + KeccakPermutation(state); + + if (rate == 1024) + { + KeccakExtract1024bits(state, dataQueue); + bitsAvailableForSqueezing = 1024; + } + else + { + KeccakExtract(state, dataQueue, rate / 64); + bitsAvailableForSqueezing = rate; + } + } + partialBlock = bitsAvailableForSqueezing; + if ((long)partialBlock > outputLength - i) + { + partialBlock = (int)(outputLength - i); + } + + Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8); + bitsAvailableForSqueezing -= partialBlock; + i += partialBlock; + } + } + + private static void FromBytesToWords(ulong[] stateAsWords, byte[] state) + { + for (int i = 0; i < (1600 / 64); i++) + { + stateAsWords[i] = 0; + int index = i * (64 / 8); + for (int j = 0; j < (64 / 8); j++) + { + stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j)); + } + } + } + + private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords) + { + for (int i = 0; i < (1600 / 64); i++) + { + int index = i * (64 / 8); + for (int j = 0; j < (64 / 8); j++) + { + state[index + j] = (byte)(stateAsWords[i] >> (8 * j)); + } + } + } + + private void KeccakPermutation(byte[] state) + { + ulong[] longState = new ulong[state.Length / 8]; + + FromBytesToWords(longState, state); + + KeccakPermutationOnWords(longState); + + FromWordsToBytes(state, longState); + } + + private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes) + { + for (int i = 0; i < dataLengthInBytes; i++) + { + state[i] ^= data[i]; + } + + KeccakPermutation(state); + } + + private void KeccakPermutationOnWords(ulong[] state) + { + int i; + + for (i = 0; i < 24; i++) + { + Theta(state); + Rho(state); + Pi(state); + Chi(state); + Iota(state, i); + } + } + + ulong[] C = new ulong[5]; + + private void Theta(ulong[] A) + { + for (int x = 0; x < 5; x++) + { + C[x] = 0; + for (int y = 0; y < 5; y++) + { + C[x] ^= A[x + 5 * y]; + } + } + for (int x = 0; x < 5; x++) + { + ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5]; + for (int y = 0; y < 5; y++) + { + A[x + 5 * y] ^= dX; + } + } + } + + private void Rho(ulong[] A) + { + for (int x = 0; x < 5; x++) + { + for (int y = 0; y < 5; y++) + { + int index = x + 5 * y; + A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]); + } + } + } + + ulong[] tempA = new ulong[25]; + + private void Pi(ulong[] A) + { + Array.Copy(A, 0, tempA, 0, tempA.Length); + + for (int x = 0; x < 5; x++) + { + for (int y = 0; y < 5; y++) + { + A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y]; + } + } + } + + ulong[] chiC = new ulong[5]; + + private void Chi(ulong[] A) + { + for (int y = 0; y < 5; y++) + { + for (int x = 0; x < 5; x++) + { + chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]); + } + for (int x = 0; x < 5; x++) + { + A[x + 5 * y] = chiC[x]; + } + } + } + + private static void Iota(ulong[] A, int indexRound) + { + A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound]; + } + + private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes) + { + KeccakPermutationAfterXor(byteState, data, dataInBytes); + } + + private void KeccakExtract1024bits(byte[] byteState, byte[] data) + { + Array.Copy(byteState, 0, data, 0, 128); + } + + private void KeccakExtract(byte[] byteState, byte[] data, int laneCount) + { + Array.Copy(byteState, 0, data, 0, laneCount * 8); + } + + public virtual IMemoable Copy() + { + return new KeccakDigest(this); + } + + public virtual void Reset(IMemoable other) + { + KeccakDigest d = (KeccakDigest)other; + + CopyIn(d); + } + } +} diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs index 2c6837b3c..890b665cf 100644 --- a/crypto/src/crypto/digests/SHA3Digest.cs +++ b/crypto/src/crypto/digests/SHA3Digest.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Org.BouncyCastle.Utilities; @@ -11,550 +12,75 @@ namespace Org.BouncyCastle.Crypto.Digests /// Following the naming conventions used in the C source code to enable easy review of the implementation. /// </remarks> public class Sha3Digest - : IDigest, IMemoable + : KeccakDigest { - 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) % 5) + 5 * ((0) % 5))] = rhoOffset; - x = 1; - y = 0; - for (t = 1; t < 25; t++) - { - //rhoOffset = ((t + 1) * (t + 2) / 2) % 64; - 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 byte[] state = new byte[(1600 / 8)]; - private byte[] dataQueue = new byte[(1536 / 8)]; - private int rate; - private int bitsInQueue; - private int fixedOutputLength; - private bool squeezing; - private int bitsAvailableForSqueezing; - private byte[] chunk; - private byte[] oneByte; - - private void ClearDataQueueSection(int off, int len) - { - for (int i = off; i != off + len; i++) - { - dataQueue[i] = 0; - } - } - - public Sha3Digest() - { - Init(0); - } - - public Sha3Digest(int bitLength) - { - Init(bitLength); - } - - public Sha3Digest(Sha3Digest source) - { - CopyIn(source); - } - - private void CopyIn(Sha3Digest source) - { - Array.Copy(source.state, 0, this.state, 0, source.state.Length); - Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length); - this.rate = source.rate; - this.bitsInQueue = source.bitsInQueue; - this.fixedOutputLength = source.fixedOutputLength; - this.squeezing = source.squeezing; - this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; - this.chunk = Arrays.Clone(source.chunk); - this.oneByte = Arrays.Clone(source.oneByte); - } - - public virtual string AlgorithmName - { - get { return "SHA3-" + fixedOutputLength; } - } - - public virtual int GetDigestSize() - { - return fixedOutputLength / 8; - } - - public virtual void Update(byte input) - { - oneByte[0] = input; - - DoUpdate(oneByte, 0, 8L); - } - - public virtual void BlockUpdate(byte[] input, int inOff, int len) - { - DoUpdate(input, inOff, len * 8L); - } - - public virtual int DoFinal(byte[] output, int outOff) - { - Squeeze(output, outOff, fixedOutputLength); - - Reset(); - - return GetDigestSize(); - } - - public virtual void Reset() - { - Init(fixedOutputLength); - } - - /** - * Return the size of block that the compression function is applied to in bytes. - * - * @return internal byte length of a block. - */ - public virtual int GetByteLength() - { - return rate / 8; - } - - private void Init(int bitLength) + private static int CheckBitLength(int bitLength) { switch (bitLength) { - case 0: - case 288: - InitSponge(1024, 576); - break; case 224: - InitSponge(1152, 448); - break; case 256: - InitSponge(1088, 512); - break; case 384: - InitSponge(832, 768); - break; case 512: - InitSponge(576, 1024); - break; + return bitLength; default: - throw new ArgumentException("must be one of 224, 256, 384, or 512.", "bitLength"); - } - } - - private void DoUpdate(byte[] data, int off, long databitlen) - { - if ((databitlen % 8) == 0) - { - Absorb(data, off, databitlen); - } - else - { - Absorb(data, off, databitlen - (databitlen % 8)); - - byte[] lastByte = new byte[1]; - - lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (int)(8 - (databitlen % 8))); - Absorb(lastByte, off, databitlen % 8); - } - } - - private void InitSponge(int rate, int capacity) - { - if (rate + capacity != 1600) - { - throw new InvalidOperationException("rate + capacity != 1600"); - } - if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) - { - throw new InvalidOperationException("invalid rate value"); - } - - this.rate = rate; - // this is never read, need to check to see why we want to save it - // this.capacity = capacity; - this.fixedOutputLength = 0; - Arrays.Fill(this.state, (byte)0); - Arrays.Fill(this.dataQueue, (byte)0); - this.bitsInQueue = 0; - this.squeezing = false; - this.bitsAvailableForSqueezing = 0; - this.fixedOutputLength = capacity / 2; - this.chunk = new byte[rate / 8]; - this.oneByte = new byte[1]; - } - - private void AbsorbQueue() - { - KeccakAbsorb(state, dataQueue, rate / 8); - - bitsInQueue = 0; - } - - private void Absorb(byte[] data, int off, long databitlen) - { - long i, j, wholeBlocks; - - if ((bitsInQueue % 8) != 0) - { - throw new InvalidOperationException("attempt to absorb with odd length queue."); - } - if (squeezing) - { - throw new InvalidOperationException("attempt to absorb while squeezing."); - } - - i = 0; - while (i < databitlen) - { - if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate))) - { - wholeBlocks = (databitlen - i) / rate; - - for (j = 0; j < wholeBlocks; j++) - { - Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length); - - //displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8); - - KeccakAbsorb(state, chunk, chunk.Length); - } - - i += wholeBlocks * rate; - } - else - { - int partialBlock = (int)(databitlen - i); - if (partialBlock + bitsInQueue > rate) - { - partialBlock = rate - bitsInQueue; - } - int partialByte = partialBlock % 8; - partialBlock -= partialByte; - Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8); - - bitsInQueue += partialBlock; - i += partialBlock; - if (bitsInQueue == rate) - { - AbsorbQueue(); - } - if (partialByte > 0) - { - int mask = (1 << partialByte) - 1; - dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask); - bitsInQueue += partialByte; - i += partialByte; - } - } + throw new ArgumentException(bitLength + " not supported for SHA-3", "bitLength"); } } - private void PadAndSwitchToSqueezingPhase() - { - if (bitsInQueue + 1 == rate) - { - dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8)); - AbsorbQueue(); - ClearDataQueueSection(0, rate / 8); - } - else - { - ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8); - dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8)); - } - dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8)); - AbsorbQueue(); - - //displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---"); - - if (rate == 1024) - { - KeccakExtract1024bits(state, dataQueue); - bitsAvailableForSqueezing = 1024; - } - else - { - KeccakExtract(state, dataQueue, rate / 64); - bitsAvailableForSqueezing = rate; - } - - //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); - - squeezing = true; - } - - private void Squeeze(byte[] output, int offset, long outputLength) - { - long i; - int partialBlock; - - if (!squeezing) - { - PadAndSwitchToSqueezingPhase(); - } - if ((outputLength % 8) != 0) - { - throw new InvalidOperationException("outputLength not a multiple of 8"); - } - - i = 0; - while (i < outputLength) - { - if (bitsAvailableForSqueezing == 0) - { - KeccakPermutation(state); - - if (rate == 1024) - { - KeccakExtract1024bits(state, dataQueue); - bitsAvailableForSqueezing = 1024; - } - else - - { - KeccakExtract(state, dataQueue, rate / 64); - bitsAvailableForSqueezing = rate; - } - - //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); - - } - partialBlock = bitsAvailableForSqueezing; - if ((long)partialBlock > outputLength - i) - { - partialBlock = (int)(outputLength - i); - } - - Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8); - bitsAvailableForSqueezing -= partialBlock; - i += partialBlock; - } - } - - private static void FromBytesToWords(ulong[] stateAsWords, byte[] state) - { - for (int i = 0; i < (1600 / 64); i++) - { - stateAsWords[i] = 0; - int index = i * (64 / 8); - for (int j = 0; j < (64 / 8); j++) - { - stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j)); - } - } - } - - private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords) + public Sha3Digest() + : this(256) { - for (int i = 0; i < (1600 / 64); i++) - { - int index = i * (64 / 8); - for (int j = 0; j < (64 / 8); j++) - { - state[index + j] = (byte)(stateAsWords[i] >> (8 * j)); - } - } } - private void KeccakPermutation(byte[] state) + public Sha3Digest(int bitLength) + : base(CheckBitLength(bitLength)) { - ulong[] longState = new ulong[state.Length / 8]; - - FromBytesToWords(longState, state); - - //displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState); - - KeccakPermutationOnWords(longState); - - //displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState); - - FromWordsToBytes(state, longState); } - private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes) + public Sha3Digest(Sha3Digest source) + : base(source) { - for (int i = 0; i < dataLengthInBytes; i++) - { - state[i] ^= data[i]; - } - - KeccakPermutation(state); } - private void KeccakPermutationOnWords(ulong[] state) + public override string AlgorithmName { - int i; - - //displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state); - - for (i = 0; i < 24; i++) - { - //displayIntermediateValues.displayRoundNumber(3, i); - - Theta(state); - //displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state); - - Rho(state); - //displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state); - - Pi(state); - //displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state); - - Chi(state); - //displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state); - - Iota(state, i); - //displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state); - } + get { return "SHA3-" + fixedOutputLength; } } - ulong[] C = new ulong[5]; - - private void Theta(ulong[] A) + public override int DoFinal(byte[] output, int outOff) { - for (int x = 0; x < 5; x++) - { - C[x] = 0; - for (int y = 0; y < 5; y++) - { - C[x] ^= A[x + 5 * y]; - } - } - for (int x = 0; x < 5; x++) - { - ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5]; - for (int y = 0; y < 5; y++) - { - A[x + 5 * y] ^= dX; - } - } - } + Absorb(new byte[]{ 0x02 }, 0, 2); - private void Rho(ulong[] A) - { - for (int x = 0; x < 5; x++) - { - for (int y = 0; y < 5; y++) - { - int index = x + 5 * y; - A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]); - } - } + return base.DoFinal(output, outOff); } - ulong[] tempA = new ulong[25]; - - private void Pi(ulong[] A) + /* + * TODO Possible API change to support partial-byte suffixes. + */ + protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits) { - Array.Copy(A, 0, tempA, 0, tempA.Length); - - for (int x = 0; x < 5; x++) - { - for (int y = 0; y < 5; y++) - { - A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y]; - } - } - } + if (partialBits < 0 || partialBits > 7) + throw new ArgumentException("must be in the range [0,7]", "partialBits"); - ulong[] chiC = new ulong[5]; + int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits); + Debug.Assert(finalInput >= 0); + int finalBits = partialBits + 2; - private void Chi(ulong[] A) - { - for (int y = 0; y < 5; y++) + if (finalBits >= 8) { - for (int x = 0; x < 5; x++) - { - chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]); - } - for (int x = 0; x < 5; x++) - { - A[x + 5 * y] = chiC[x]; - } + oneByte[0] = (byte)finalInput; + Absorb(oneByte, 0, 8); + finalBits -= 8; + finalInput >>= 8; } - } - - private static void Iota(ulong[] A, int indexRound) - { - A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound]; - } - - private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes) - { - KeccakPermutationAfterXor(byteState, data, dataInBytes); - } - - private void KeccakExtract1024bits(byte[] byteState, byte[] data) - { - Array.Copy(byteState, 0, data, 0, 128); - } - private void KeccakExtract(byte[] byteState, byte[] data, int laneCount) - { - Array.Copy(byteState, 0, data, 0, laneCount * 8); + return base.DoFinal(output, outOff, (byte)finalInput, finalBits); } - public IMemoable Copy() + public override IMemoable Copy() { return new Sha3Digest(this); } - - public void Reset(IMemoable other) - { - Sha3Digest d = (Sha3Digest)other; - - CopyIn(d); - } - - } } diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs new file mode 100644 index 000000000..fd7d85681 --- /dev/null +++ b/crypto/src/crypto/digests/ShakeDigest.cs @@ -0,0 +1,111 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /// <summary> + /// Implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/ + /// </summary> + /// <remarks> + /// Following the naming conventions used in the C source code to enable easy review of the implementation. + /// </remarks> + public class ShakeDigest + : KeccakDigest, IXof + { + private static int CheckBitLength(int bitLength) + { + switch (bitLength) + { + case 128: + case 256: + return bitLength; + default: + throw new ArgumentException(bitLength + " not supported for SHAKE", "bitLength"); + } + } + + public ShakeDigest() + : this(128) + { + } + + public ShakeDigest(int bitLength) + : base(CheckBitLength(bitLength)) + { + } + + public ShakeDigest(ShakeDigest source) + : base(source) + { + } + + public override string AlgorithmName + { + get { return "SHAKE" + fixedOutputLength; } + } + + public override int DoFinal(byte[] output, int outOff) + { + return DoFinal(output, outOff, GetDigestSize()); + } + + public virtual int DoFinal(byte[] output, int outOff, int outLen) + { + Absorb(new byte[]{ 0x0F }, 0, 4); + + Squeeze(output, outOff, ((long)outLen) * 8); + + Reset(); + + return outLen; + } + + /* + * TODO Possible API change to support partial-byte suffixes. + */ + protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits) + { + return DoFinal(output, outOff, GetDigestSize(), partialByte, partialBits); + } + + /* + * TODO Possible API change to support partial-byte suffixes. + */ + protected virtual int DoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits) + { + if (partialBits < 0 || partialBits > 7) + throw new ArgumentException("must be in the range [0,7]", "partialBits"); + + int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits); + Debug.Assert(finalInput >= 0); + int finalBits = partialBits + 4; + + if (finalBits >= 8) + { + oneByte[0] = (byte)finalInput; + Absorb(oneByte, 0, 8); + finalBits -= 8; + finalInput >>= 8; + } + + if (finalBits > 0) + { + oneByte[0] = (byte)finalInput; + Absorb(oneByte, 0, finalBits); + } + + Squeeze(output, outOff, ((long)outLen) * 8); + + Reset(); + + return outLen; + } + + public override IMemoable Copy() + { + return new ShakeDigest(this); + } + } +} diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs index 0f13b4571..51bb1829a 100644 --- a/crypto/src/crypto/ec/CustomNamedCurves.cs +++ b/crypto/src/crypto/ec/CustomNamedCurves.cs @@ -60,7 +60,7 @@ namespace Org.BouncyCastle.Crypto.EC * * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) */ - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A" + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9")); @@ -82,7 +82,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679"); ECCurve curve = ConfigureCurve(new SecP128R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "161FF7528B899B2D0C28607CA52C5B86" + "CF5AC8395BAFEB13C02DA292DDED7A83")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.EC new BigInteger("96341f1138933bc2f503fd44", 16), 176); ECCurve curve = ConfigureCurveGlv(new SecP160K1Curve(), glv); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + "938CF935318FDCED6BC28286531733C3F03C4FEE")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345"); ECCurve curve = ConfigureCurve(new SecP160R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "4A96B5688EF573284664698968C38BB913CBFC82" + "23A628553168947D59DCC912042351377AC5FB32")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -157,7 +157,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751"); ECCurve curve = ConfigureCurve(new SecP160R2Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -190,7 +190,7 @@ namespace Org.BouncyCastle.Crypto.EC new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), 208); ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -211,7 +211,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); ECCurve curve = ConfigureCurve(new SecP192R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Crypto.EC new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), 240); ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -265,7 +265,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); ECCurve curve = ConfigureCurve(new SecP224R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -298,7 +298,7 @@ namespace Org.BouncyCastle.Crypto.EC new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), 272); ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -319,7 +319,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90"); ECCurve curve = ConfigureCurve(new SecP256R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -340,7 +340,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); ECCurve curve = ConfigureCurve(new SecP384R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -361,7 +361,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); ECCurve curve = ConfigureCurve(new SecP521R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -382,7 +382,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); ECCurve curve = ConfigureCurve(new SecT113R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "009D73616F35F4AB1407D73562C10F" + "00A52830277958EE84D1315ED31886")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -403,7 +403,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D"); ECCurve curve = ConfigureCurve(new SecT113R2Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "01A57A6A7B26CA5EF52FCDB8164797" + "00B3ADC94ED1FE674C06E695BABA1D")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -424,7 +424,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2"); ECCurve curve = ConfigureCurve(new SecT131R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0081BAF91FDF9833C40F9C181343638399" + "078C6E7EA38C001F73C8134B1B4EF9E150")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -445,7 +445,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); ECCurve curve = ConfigureCurve(new SecT131R2Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0356DCD8F2F95031AD652D23951BB366A8" + "0648F06D867940A5366D9E265DE9EB240F")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -466,7 +466,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT163K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -487,7 +487,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); ECCurve curve = ConfigureCurve(new SecT163R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0369979697AB43897789566789567F787A7876A654" + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -508,7 +508,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); ECCurve curve = ConfigureCurve(new SecT163R2Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -529,7 +529,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30"); ECCurve curve = ConfigureCurve(new SecT193R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -550,7 +550,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211"); ECCurve curve = ConfigureCurve(new SecT193R2Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -571,7 +571,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT233K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -592,7 +592,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); ECCurve curve = ConfigureCurve(new SecT233R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -613,7 +613,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT239K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -634,7 +634,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT283K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -655,7 +655,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); ECCurve curve = ConfigureCurve(new SecT283R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -676,7 +676,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT409K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -697,7 +697,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); ECCurve curve = ConfigureCurve(new SecT409R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -718,7 +718,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = null; ECCurve curve = ConfigureCurve(new SecT571K1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); @@ -739,7 +739,7 @@ namespace Org.BouncyCastle.Crypto.EC { byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); ECCurve curve = ConfigureCurve(new SecT571R1Curve()); - ECPoint G = curve.DecodePoint(Hex.Decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs index 9d7f76c05..164c43ee9 100644 --- a/crypto/src/crypto/engines/AesEngine.cs +++ b/crypto/src/crypto/engines/AesEngine.cs @@ -237,12 +237,22 @@ namespace Org.BouncyCastle.Crypto.Engines private const uint m1 = 0x80808080; private const uint m2 = 0x7f7f7f7f; private const uint m3 = 0x0000001b; + private const uint m4 = 0xC0C0C0C0; + private const uint m5 = 0x3f3f3f3f; private static uint FFmulX(uint x) { return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3); } + private static uint FFmulX2(uint x) + { + uint t0 = (x & m5) << 2; + uint t1 = (x & m4); + t1 ^= (t1 >> 1); + return t0 ^ (t1 >> 2) ^ (t1 >> 5); + } + /* The following defines provide alternative definitions of FFmulX that might give improved performance if a fast 32-bit multiply is not available. @@ -255,12 +265,13 @@ namespace Org.BouncyCastle.Crypto.Engines private static uint Inv_Mcol(uint x) { - uint f2 = FFmulX(x); - uint f4 = FFmulX(f2); - uint f8 = FFmulX(f4); - uint f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + uint t0, t1; + t0 = x; + t1 = t0 ^ Shift(t0, 8); + t0 ^= FFmulX(t1); + t1 ^= FFmulX2(t0); + t0 ^= t1 ^ Shift(t1, 16); + return t0; } private static uint SubWord(uint x) diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs index a1b544568..38ce1a946 100644 --- a/crypto/src/crypto/engines/AesFastEngine.cs +++ b/crypto/src/crypto/engines/AesFastEngine.cs @@ -573,12 +573,22 @@ namespace Org.BouncyCastle.Crypto.Engines private const uint m1 = 0x80808080; private const uint m2 = 0x7f7f7f7f; private const uint m3 = 0x0000001b; + private const uint m4 = 0xC0C0C0C0; + private const uint m5 = 0x3f3f3f3f; private static uint FFmulX(uint x) { return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3); } + private static uint FFmulX2(uint x) + { + uint t0 = (x & m5) << 2; + uint t1 = (x & m4); + t1 ^= (t1 >> 1); + return t0 ^ (t1 >> 2) ^ (t1 >> 5); + } + /* The following defines provide alternative definitions of FFmulX that might give improved performance if a fast 32-bit multiply is not available. @@ -591,12 +601,13 @@ namespace Org.BouncyCastle.Crypto.Engines private static uint Inv_Mcol(uint x) { - uint f2 = FFmulX(x); - uint f4 = FFmulX(f2); - uint f8 = FFmulX(f4); - uint f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + uint t0, t1; + t0 = x; + t1 = t0 ^ Shift(t0, 8); + t0 ^= FFmulX(t1); + t1 ^= FFmulX2(t0); + t0 ^= t1 ^ Shift(t1, 16); + return t0; } private static uint SubWord(uint x) diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs index a6b9e3bd4..a42b34971 100644 --- a/crypto/src/crypto/engines/AesLightEngine.cs +++ b/crypto/src/crypto/engines/AesLightEngine.cs @@ -126,12 +126,22 @@ namespace Org.BouncyCastle.Crypto.Engines private const uint m1 = 0x80808080; private const uint m2 = 0x7f7f7f7f; private const uint m3 = 0x0000001b; + private const uint m4 = 0xC0C0C0C0; + private const uint m5 = 0x3f3f3f3f; private static uint FFmulX(uint x) { return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3); } + private static uint FFmulX2(uint x) + { + uint t0 = (x & m5) << 2; + uint t1 = (x & m4); + t1 ^= (t1 >> 1); + return t0 ^ (t1 >> 2) ^ (t1 >> 5); + } + /* The following defines provide alternative definitions of FFmulX that might give improved performance if a fast 32-bit multiply is not available. @@ -144,18 +154,21 @@ namespace Org.BouncyCastle.Crypto.Engines private static uint Mcol(uint x) { - uint f2 = FFmulX(x); - return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24); + uint t0, t1; + t0 = Shift(x, 8); + t1 = x ^ t0; + return Shift(t1, 16) ^ t0 ^ FFmulX(t1); } private static uint Inv_Mcol(uint x) { - uint f2 = FFmulX(x); - uint f4 = FFmulX(f2); - uint f8 = FFmulX(f4); - uint f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + uint t0, t1; + t0 = x; + t1 = t0 ^ Shift(t0, 8); + t0 ^= FFmulX(t1); + t1 ^= FFmulX2(t0); + t0 ^= t1 ^ Shift(t1, 16); + return t0; } private static uint SubWord(uint x) diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs index 037abf7e9..f95f145f6 100644 --- a/crypto/src/crypto/engines/RSABlindedEngine.cs +++ b/crypto/src/crypto/engines/RSABlindedEngine.cs @@ -7,118 +7,122 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Engines { - /** - * this does your basic RSA algorithm with blinding - */ - public class RsaBlindedEngine - : IAsymmetricBlockCipher - { - private readonly RsaCoreEngine core = new RsaCoreEngine(); - private RsaKeyParameters key; - private SecureRandom random; + /** + * this does your basic RSA algorithm with blinding + */ + public class RsaBlindedEngine + : IAsymmetricBlockCipher + { + private readonly RsaCoreEngine core = new RsaCoreEngine(); + private RsaKeyParameters key; + private SecureRandom random; public virtual string AlgorithmName - { - get { return "RSA"; } - } + { + get { return "RSA"; } + } - /** - * initialise the RSA engine. - * - * @param forEncryption true if we are encrypting, false otherwise. - * @param param the necessary RSA key parameters. - */ + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ public virtual void Init( - bool forEncryption, - ICipherParameters param) - { - core.Init(forEncryption, param); + bool forEncryption, + ICipherParameters param) + { + core.Init(forEncryption, param); - if (param is ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; - key = (RsaKeyParameters)rParam.Parameters; - random = rParam.Random; - } - else - { - key = (RsaKeyParameters)param; - random = new SecureRandom(); - } - } + key = (RsaKeyParameters)rParam.Parameters; + random = rParam.Random; + } + else + { + key = (RsaKeyParameters)param; + random = new SecureRandom(); + } + } - /** - * Return the maximum size for an input block to this engine. - * For RSA this is always one byte less than the key size on - * encryption, and the same length as the key size on decryption. - * - * @return maximum size for an input block. - */ + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ public virtual int GetInputBlockSize() - { - return core.GetInputBlockSize(); - } + { + return core.GetInputBlockSize(); + } - /** - * Return the maximum size for an output block to this engine. - * For RSA this is always one byte less than the key size on - * decryption, and the same length as the key size on encryption. - * - * @return maximum size for an output block. - */ + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ public virtual int GetOutputBlockSize() - { - return core.GetOutputBlockSize(); - } + { + return core.GetOutputBlockSize(); + } - /** - * Process a single block using the basic RSA algorithm. - * - * @param inBuf the input array. - * @param inOff the offset into the input buffer where the data starts. - * @param inLen the length of the data to be processed. - * @return the result of the RSA process. - * @exception DataLengthException the input block is too large. - */ + /** + * Process a single block using the basic RSA algorithm. + * + * @param inBuf the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @exception DataLengthException the input block is too large. + */ public virtual byte[] ProcessBlock( - byte[] inBuf, - int inOff, - int inLen) - { - if (key == null) - throw new InvalidOperationException("RSA engine not initialised"); + byte[] inBuf, + int inOff, + int inLen) + { + if (key == null) + throw new InvalidOperationException("RSA engine not initialised"); - BigInteger input = core.ConvertInput(inBuf, inOff, inLen); + BigInteger input = core.ConvertInput(inBuf, inOff, inLen); - BigInteger result; - if (key is RsaPrivateCrtKeyParameters) - { - RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key; - BigInteger e = k.PublicExponent; - if (e != null) // can't do blinding without a public exponent - { - BigInteger m = k.Modulus; - BigInteger r = BigIntegers.CreateRandomInRange( - BigInteger.One, m.Subtract(BigInteger.One), random); + BigInteger result; + if (key is RsaPrivateCrtKeyParameters) + { + RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key; + BigInteger e = k.PublicExponent; + if (e != null) // can't do blinding without a public exponent + { + BigInteger m = k.Modulus; + BigInteger r = BigIntegers.CreateRandomInRange( + BigInteger.One, m.Subtract(BigInteger.One), random); - BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m); - BigInteger blindedResult = core.ProcessBlock(blindedInput); + BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m); + BigInteger blindedResult = core.ProcessBlock(blindedInput); - BigInteger rInv = r.ModInverse(m); - result = blindedResult.Multiply(rInv).Mod(m); - } - else - { - result = core.ProcessBlock(input); - } - } - else - { - result = core.ProcessBlock(input); - } + BigInteger rInv = r.ModInverse(m); + result = blindedResult.Multiply(rInv).Mod(m); - return core.ConvertOutput(result); - } - } + // defence against Arjen Lenstra’s CRT attack + if (!input.Equals(result.ModPow(e, m))) + throw new InvalidOperationException("RSA engine faulty decryption/signing detected"); + } + else + { + result = core.ProcessBlock(input); + } + } + else + { + result = core.ProcessBlock(input); + } + + return core.ConvertOutput(result); + } + } } diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs index de41d88f4..d8ab2ca73 100644 --- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs +++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs @@ -46,6 +46,13 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm return tmp; } + internal static ulong[] OneAsUlongs() + { + ulong[] tmp = new ulong[2]; + tmp[0] = 1UL << 63; + return tmp; + } + internal static byte[] AsBytes(uint[] x) { return Pack.UInt32_To_BE(x); @@ -56,6 +63,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm Pack.UInt32_To_BE(x, z, 0); } + internal static byte[] AsBytes(ulong[] x) + { + byte[] z = new byte[16]; + Pack.UInt64_To_BE(x, z, 0); + return z; + } + + internal static void AsBytes(ulong[] x, byte[] z) + { + Pack.UInt64_To_BE(x, z, 0); + } + internal static uint[] AsUints(byte[] bs) { uint[] output = new uint[4]; @@ -68,6 +87,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm Pack.BE_To_UInt32(bs, 0, output); } + internal static ulong[] AsUlongs(byte[] x) + { + ulong[] z = new ulong[2]; + Pack.BE_To_UInt64(x, 0, z); + return z; + } + + public static void AsUlongs(byte[] x, ulong[] z) + { + Pack.BE_To_UInt64(x, 0, z); + } + internal static void Multiply(byte[] x, byte[] y) { uint[] t1 = GcmUtilities.AsUints(x); @@ -80,7 +111,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm { uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3]; uint r10 = 0, r11 = 0, r12 = 0, r13 = 0; - + for (int i = 0; i < 4; ++i) { int bits = (int)y[i]; @@ -93,9 +124,9 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm r13 ^= (r03 & m1); uint m2 = (uint)((int)(r03 << 31) >> 8); - r03 = (r03 >> 1) | (r02 << 63); - r02 = (r02 >> 1) | (r01 << 63); - r01 = (r01 >> 1) | (r00 << 63); + r03 = (r03 >> 1) | (r02 << 31); + r02 = (r02 >> 1) | (r01 << 31); + r01 = (r01 >> 1) | (r00 << 31); r00 = (r00 >> 1) ^ (m2 & E1); } } @@ -119,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm r10 ^= (r00 & m1); r11 ^= (r01 & m1); - ulong m2 = (r01 << 63) >> 8; + ulong m2 = (ulong)((long)(r01 << 63) >> 8); r01 = (r01 >> 1) | (r00 << 63); r00 = (r00 >> 1) ^ (m2 & E1L); } @@ -272,5 +303,17 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm z[2] = x[2] ^ y[2]; z[3] = x[3] ^ y[3]; } + + internal static void Xor(ulong[] x, ulong[] y) + { + x[0] ^= y[0]; + x[1] ^= y[1]; + } + + internal static void Xor(ulong[] x, ulong[] y, ulong[] z) + { + z[0] = x[0] ^ y[0]; + z[1] = x[1] ^ y[1]; + } } } diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs new file mode 100644 index 000000000..23151d9c4 --- /dev/null +++ b/crypto/src/crypto/operators/Asn1Signature.cs @@ -0,0 +1,560 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Crypto.Operators +{ + internal class X509Utilities + { + private static readonly Asn1Null derNull = DerNull.Instance; + + private static readonly IDictionary algorithms = Platform.CreateHashtable(); + private static readonly IDictionary exParams = Platform.CreateHashtable(); + private static readonly ISet noParams = new HashSet(); + + static X509Utilities() + { + algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224); + algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256); + algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384); + algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512); + algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224); + algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256); + algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384); + algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512); + algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512); + noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1); + noParams.Add(NistObjectIdentifiers.DsaWithSha224); + noParams.Add(NistObjectIdentifiers.DsaWithSha256); + noParams.Add(NistObjectIdentifiers.DsaWithSha384); + noParams.Add(NistObjectIdentifiers.DsaWithSha512); + + // + // RFC 4491 + // + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance); + exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance); + exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance); + exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance); + exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance); + exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64)); + } + + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather than the algorithm identifier (if possible). + */ + private static string GetDigestAlgName( + DerObjectIdentifier digestAlgOID) + { + if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID)) + { + return "MD5"; + } + else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID)) + { + return "SHA1"; + } + else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID)) + { + return "SHA224"; + } + else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID)) + { + return "SHA256"; + } + else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID)) + { + return "SHA384"; + } + else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID)) + { + return "SHA512"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID)) + { + return "RIPEMD128"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID)) + { + return "RIPEMD160"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID)) + { + return "RIPEMD256"; + } + else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID)) + { + return "GOST3411"; + } + else + { + return digestAlgOID.Id; + } + } + + internal static string GetSignatureName(AlgorithmIdentifier sigAlgId) + { + Asn1Encodable parameters = sigAlgId.Parameters; + + if (parameters != null && !derNull.Equals(parameters)) + { + if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss)) + { + RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters); + + return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1"; + } + if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2)) + { + Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters); + + return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA"; + } + } + + return sigAlgId.ObjectID.Id; + } + + private static RsassaPssParameters CreatePssParams( + AlgorithmIdentifier hashAlgId, + int saltSize) + { + return new RsassaPssParameters( + hashAlgId, + new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId), + new DerInteger(saltSize), + new DerInteger(1)); + } + + internal static DerObjectIdentifier GetAlgorithmOid( + string algorithmName) + { + algorithmName = Platform.ToUpperInvariant(algorithmName); + + if (algorithms.Contains(algorithmName)) + { + return (DerObjectIdentifier) algorithms[algorithmName]; + } + + return new DerObjectIdentifier(algorithmName); + } + + internal static AlgorithmIdentifier GetSigAlgID( + DerObjectIdentifier sigOid, + string algorithmName) + { + if (noParams.Contains(sigOid)) + { + return new AlgorithmIdentifier(sigOid); + } + + algorithmName = Platform.ToUpperInvariant(algorithmName); + + if (exParams.Contains(algorithmName)) + { + return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]); + } + + return new AlgorithmIdentifier(sigOid, DerNull.Instance); + } + + internal static IEnumerable GetAlgNames() + { + return new EnumerableProxy(algorithms.Keys); + } + } + + internal class SignerBucket + : Stream + { + protected readonly ISigner signer; + + public SignerBucket( + ISigner signer) + { + this.signer = signer; + } + + public override int Read( + byte[] buffer, + int offset, + int count) + { + throw new NotImplementedException (); + } + + public override int ReadByte() + { + throw new NotImplementedException (); + } + + public override void Write( + byte[] buffer, + int offset, + int count) + { + if (count > 0) + { + signer.BlockUpdate(buffer, offset, count); + } + } + + public override void WriteByte( + byte b) + { + signer.Update(b); + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override long Length + { + get { return 0; } + } + + public override long Position + { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + + public override void Flush() + { + } + + public override long Seek( + long offset, + SeekOrigin origin) + { + throw new NotImplementedException (); + } + + public override void SetLength( + long length) + { + throw new NotImplementedException (); + } + } + + /// <summary> + /// Calculator class for signature generation in ASN.1 based profiles that use an AlgorithmIdentifier to preserve + /// signature algorithm details. + /// </summary> + public class Asn1SignatureCalculator: ISignatureCalculator + { + private readonly AlgorithmIdentifier algID; + private readonly string algorithm; + private readonly AsymmetricKeyParameter privateKey; + private readonly SecureRandom random; + + /// <summary> + /// Base constructor. + /// </summary> + /// <param name="algorithm">The name of the signature algorithm to use.</param> + /// <param name="privateKey">The private key to be used in the signing operation.</param> + public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null) + { + } + + /// <summary> + /// Constructor which also specifies a source of randomness to be used if one is required. + /// </summary> + /// <param name="algorithm">The name of the signature algorithm to use.</param> + /// <param name="privateKey">The private key to be used in the signing operation.</param> + /// <param name="random">The source of randomness to be used in signature calculation.</param> + public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey, SecureRandom random) + { + DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm); + + this.algorithm = algorithm; + this.privateKey = privateKey; + this.random = random; + this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm); + } + + public Object AlgorithmDetails + { + get { return this.algID; } + } + + public IStreamCalculator CreateCalculator() + { + ISigner sig = SignerUtilities.GetSigner(algorithm); + + if (random != null) + { + sig.Init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.Init(true, privateKey); + } + + return new SigCalculator(sig); + } + + /// <summary> + /// Allows enumeration of the signature names supported by the verifier provider. + /// </summary> + public static IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } + + internal class SigCalculator : IStreamCalculator + { + private readonly ISigner sig; + private readonly Stream stream; + + internal SigCalculator(ISigner sig) + { + this.sig = sig; + this.stream = new SignerBucket(sig); + } + + public Stream Stream + { + get { return stream; } + } + + public object GetResult() + { + return new SigResult(sig); + } + } + + internal class SigResult : IBlockResult + { + private readonly ISigner sig; + + internal SigResult(ISigner sig) + { + this.sig = sig; + } + + public byte[] DoFinal() + { + return sig.GenerateSignature(); + } + + public int DoFinal(byte[] destination, int offset) + { + byte[] signature = DoFinal(); + + Array.Copy(signature, 0, destination, offset, signature.Length); + + return signature.Length; + } + } + + /// <summary> + /// Verifier class for signature verification in ASN.1 based profiles that use an AlgorithmIdentifier to preserve + /// signature algorithm details. + /// </summary> + public class Asn1SignatureVerifier: ISignatureVerifier + { + private readonly AlgorithmIdentifier algID; + private readonly AsymmetricKeyParameter publicKey; + + /// <summary> + /// Base constructor. + /// </summary> + /// <param name="algorithm">The name of the signature algorithm to use.</param> + /// <param name="publicKey">The public key to be used in the verification operation.</param> + public Asn1SignatureVerifier (String algorithm, AsymmetricKeyParameter publicKey) + { + DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm); + + this.publicKey = publicKey; + this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm); + } + + public Asn1SignatureVerifier (AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey) + { + this.publicKey = publicKey; + this.algID = algorithm; + } + + public Object AlgorithmDetails + { + get { return this.algID; } + } + + public IStreamCalculator CreateCalculator() + { + ISigner sig = SignerUtilities.GetSigner(X509Utilities.GetSignatureName(algID)); + + sig.Init(false, publicKey); + + return new VerifierCalculator(sig); + } + } + + internal class VerifierCalculator : IStreamCalculator + { + private readonly ISigner sig; + private readonly Stream stream; + + internal VerifierCalculator(ISigner sig) + { + this.sig = sig; + this.stream = new SignerBucket(sig); + } + + public Stream Stream + { + get { return stream; } + } + + public object GetResult() + { + return new VerifierResult(sig); + } + } + + internal class VerifierResult : IVerifier + { + private readonly ISigner sig; + + internal VerifierResult(ISigner sig) + { + this.sig = sig; + } + + public bool IsVerified(byte[] signature) + { + return sig.VerifySignature(signature); + } + + public bool IsVerified(byte[] signature, int off, int length) + { + byte[] sigBytes = new byte[length]; + + Array.Copy(signature, 0, sigBytes, off, sigBytes.Length); + + return sig.VerifySignature(signature); + } + } + + /// <summary> + /// Provider class which supports dynamic creation of signature verifiers. + /// </summary> + public class Asn1SignatureVerifierProvider: ISignatureVerifierProvider + { + private readonly AsymmetricKeyParameter publicKey; + + /// <summary> + /// Base constructor - specify the public key to be used in verification. + /// </summary> + /// <param name="publicKey">The public key to be used in creating verifiers provided by this object.</param> + public Asn1SignatureVerifierProvider(AsymmetricKeyParameter publicKey) + { + this.publicKey = publicKey; + } + + public ISignatureVerifier CreateSignatureVerifier(Object algorithmDetails) + { + return new Asn1SignatureVerifier ((AlgorithmIdentifier)algorithmDetails, publicKey); + } + + /// <summary> + /// Allows enumeration of the signature names supported by the verifier provider. + /// </summary> + public IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } +} + diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs index a0544e73b..4258df5c5 100644 --- a/crypto/src/crypto/parameters/DHParameters.cs +++ b/crypto/src/crypto/parameters/DHParameters.cs @@ -91,6 +91,7 @@ namespace Org.BouncyCastle.Crypto.Parameters throw new ArgumentException("m value must be < bitlength of p", "m"); if (l != 0) { + // TODO Check this against the Java version, which has 'l > p.BitLength' here if (l >= p.BitLength) throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l"); if (l < m) diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs index 1486656bd..fb117c19d 100644 --- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs +++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs @@ -26,29 +26,23 @@ namespace Org.BouncyCastle.Crypto.Signers return recoveredMessage; } + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerImplicit = 0xBC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerRipeMD160 = 0x31CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerRipeMD128 = 0x32CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha1 = 0x33CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha256 = 0x34CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha512 = 0x35CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha384 = 0x36CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerWhirlpool = 0x37CC; - private static readonly IDictionary trailerMap = Platform.CreateHashtable(); - - static Iso9796d2PssSigner() - { - trailerMap.Add("RIPEMD128", TrailerRipeMD128); - trailerMap.Add("RIPEMD160", TrailerRipeMD160); - trailerMap.Add("SHA-1", TrailerSha1); - trailerMap.Add("SHA-256", TrailerSha256); - trailerMap.Add("SHA-384", TrailerSha384); - trailerMap.Add("SHA-512", TrailerSha512); - - trailerMap.Add("Whirlpool", TrailerWhirlpool); - } - private IDigest digest; private IAsymmetricBlockCipher cipher; @@ -71,8 +65,7 @@ namespace Org.BouncyCastle.Crypto.Signers private int preTLength; /// <summary> - /// Generate a signer for the with either implicit or explicit trailers - /// for ISO9796-2, scheme 2 or 3. + /// Generate a signer with either implicit or explicit trailers for ISO9796-2, scheme 2 or 3. /// </summary> /// <param name="cipher">base cipher to use for signature creation/verification</param> /// <param name="digest">digest to use.</param> @@ -91,15 +84,15 @@ namespace Org.BouncyCastle.Crypto.Signers if (isImplicit) { - trailer = TrailerImplicit; + trailer = IsoTrailers.TRAILER_IMPLICIT; + } + else if (IsoTrailers.NoTrailerAvailable(digest)) + { + throw new ArgumentException("no valid trailer", "digest"); } else { - string digestAlg = digest.AlgorithmName; - if (!trailerMap.Contains(digestAlg)) - throw new ArgumentException("no valid trailer for digest"); - - trailer = (int)trailerMap[digestAlg]; + trailer = IsoTrailers.GetTrailer(digest); } } @@ -180,7 +173,7 @@ namespace Org.BouncyCastle.Crypto.Signers block = new byte[(keyBits + 7) / 8]; - if (trailer == TrailerImplicit) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1]; } @@ -247,11 +240,10 @@ namespace Org.BouncyCastle.Crypto.Signers { int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF); - string digestAlg = digest.AlgorithmName; - if (!trailerMap.Contains(digestAlg)) + if (IsoTrailers.NoTrailerAvailable(digest)) throw new ArgumentException("unrecognised hash in signature"); - if (sigTrail != (int)trailerMap[digestAlg]) + if (sigTrail != IsoTrailers.GetTrailer(digest)) throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail); tLength = 2; @@ -395,7 +387,7 @@ namespace Org.BouncyCastle.Crypto.Signers digest.DoFinal(hash, 0); int tLength = 2; - if (trailer == TrailerImplicit) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { tLength = 1; } @@ -415,9 +407,9 @@ namespace Org.BouncyCastle.Crypto.Signers Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen); - if (trailer == TrailerImplicit) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { - block[block.Length - 1] = (byte)TrailerImplicit; + block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT; } else { diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs index 4bb4d17a6..b90ed8f0b 100644 --- a/crypto/src/crypto/signers/Iso9796d2Signer.cs +++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs @@ -21,30 +21,23 @@ namespace Org.BouncyCastle.Crypto.Signers return recoveredMessage; } + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerImplicit = 0xBC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerRipeMD160 = 0x31CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerRipeMD128 = 0x32CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha1 = 0x33CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha256 = 0x34CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha512 = 0x35CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerSha384 = 0x36CC; + [Obsolete("Use 'IsoTrailers' instead")] public const int TrailerWhirlpool = 0x37CC; - private static IDictionary trailerMap = Platform.CreateHashtable(); - - static Iso9796d2Signer() - { - trailerMap.Add("RIPEMD128", TrailerRipeMD128); - trailerMap.Add("RIPEMD160", TrailerRipeMD160); - - trailerMap.Add("SHA-1", TrailerSha1); - trailerMap.Add("SHA-256", TrailerSha256); - trailerMap.Add("SHA-384", TrailerSha384); - trailerMap.Add("SHA-512", TrailerSha512); - - trailerMap.Add("Whirlpool", TrailerWhirlpool); - } - private IDigest digest; private IAsymmetricBlockCipher cipher; @@ -60,8 +53,7 @@ namespace Org.BouncyCastle.Crypto.Signers private byte[] preBlock; /// <summary> - /// Generate a signer for the with either implicit or explicit trailers - /// for ISO9796-2. + /// Generate a signer with either implicit or explicit trailers for ISO9796-2. /// </summary> /// <param name="cipher">base cipher to use for signature creation/verification</param> /// <param name="digest">digest to use.</param> @@ -76,20 +68,15 @@ namespace Org.BouncyCastle.Crypto.Signers if (isImplicit) { - trailer = TrailerImplicit; + trailer = IsoTrailers.TRAILER_IMPLICIT; + } + else if (IsoTrailers.NoTrailerAvailable(digest)) + { + throw new ArgumentException("no valid trailer", "digest"); } else { - string digestName = digest.AlgorithmName; - - if (trailerMap.Contains(digestName)) - { - trailer = (int)trailerMap[digest.AlgorithmName]; - } - else - { - throw new System.ArgumentException("no valid trailer for digest"); - } + trailer = IsoTrailers.GetTrailer(digest); } } @@ -119,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Signers keyBits = kParam.Modulus.BitLength; block = new byte[(keyBits + 7) / 8]; - if (trailer == TrailerImplicit) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { mBuf = new byte[block.Length - digest.GetDigestSize() - 2]; } @@ -195,10 +182,10 @@ namespace Org.BouncyCastle.Crypto.Signers { int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF); - string digestName = digest.AlgorithmName; - if (!trailerMap.Contains(digestName)) + if (IsoTrailers.NoTrailerAvailable(digest)) throw new ArgumentException("unrecognised hash in signature"); - if (sigTrail != (int)trailerMap[digestName]) + + if (sigTrail != IsoTrailers.GetTrailer(digest)) throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail); delta = 2; @@ -319,12 +306,12 @@ namespace Org.BouncyCastle.Crypto.Signers int t = 0; int delta = 0; - if (trailer == TrailerImplicit) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { t = 8; delta = block.Length - digSize - 1; digest.DoFinal(block, delta); - block[block.Length - 1] = (byte) TrailerImplicit; + block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT; } else { @@ -424,10 +411,10 @@ namespace Org.BouncyCastle.Crypto.Signers { int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF); - string digestName = digest.AlgorithmName; - if (!trailerMap.Contains(digestName)) + if (IsoTrailers.NoTrailerAvailable(digest)) throw new ArgumentException("unrecognised hash in signature"); - if (sigTrail != (int)trailerMap[digestName]) + + if (sigTrail != IsoTrailers.GetTrailer(digest)) throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail); delta = 2; diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs new file mode 100644 index 000000000..497ffaf78 --- /dev/null +++ b/crypto/src/crypto/signers/IsoTrailers.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Crypto.Signers +{ + public class IsoTrailers + { + public const int TRAILER_IMPLICIT = 0xBC; + public const int TRAILER_RIPEMD160 = 0x31CC; + public const int TRAILER_RIPEMD128 = 0x32CC; + public const int TRAILER_SHA1 = 0x33CC; + public const int TRAILER_SHA256 = 0x34CC; + public const int TRAILER_SHA512 = 0x35CC; + public const int TRAILER_SHA384 = 0x36CC; + public const int TRAILER_WHIRLPOOL = 0x37CC; + public const int TRAILER_SHA224 = 0x38CC; + public const int TRAILER_SHA512_224 = 0x39CC; + public const int TRAILER_SHA512_256 = 0x40CC; + + private static IDictionary CreateTrailerMap() + { + IDictionary trailers = Platform.CreateHashtable(); + + trailers.Add("RIPEMD128", TRAILER_RIPEMD128); + trailers.Add("RIPEMD160", TRAILER_RIPEMD160); + + trailers.Add("SHA-1", TRAILER_SHA1); + trailers.Add("SHA-224", TRAILER_SHA224); + trailers.Add("SHA-256", TRAILER_SHA256); + trailers.Add("SHA-384", TRAILER_SHA384); + trailers.Add("SHA-512", TRAILER_SHA512); + trailers.Add("SHA-512/224", TRAILER_SHA512_224); + trailers.Add("SHA-512/256", TRAILER_SHA512_256); + + trailers.Add("Whirlpool", TRAILER_WHIRLPOOL); + + return CollectionUtilities.ReadOnly(trailers); + } + + // IDictionary is (string -> Int32) + private static readonly IDictionary trailerMap = CreateTrailerMap(); + + public static int GetTrailer(IDigest digest) + { + return (int)trailerMap[digest.AlgorithmName]; + } + + public static bool NoTrailerAvailable(IDigest digest) + { + return !trailerMap.Contains(digest.AlgorithmName); + } + } +} diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs index 89f512b78..36483fe17 100644 --- a/crypto/src/crypto/signers/X931Signer.cs +++ b/crypto/src/crypto/signers/X931Signer.cs @@ -20,31 +20,24 @@ namespace Org.BouncyCastle.Crypto.Signers public class X931Signer : ISigner { - public const int TRAILER_IMPLICIT = 0xBC; - public const int TRAILER_RIPEMD160 = 0x31CC; - public const int TRAILER_RIPEMD128 = 0x32CC; - public const int TRAILER_SHA1 = 0x33CC; - public const int TRAILER_SHA256 = 0x34CC; - public const int TRAILER_SHA512 = 0x35CC; - public const int TRAILER_SHA384 = 0x36CC; - public const int TRAILER_WHIRLPOOL = 0x37CC; - public const int TRAILER_SHA224 = 0x38CC; - - private static readonly IDictionary trailerMap = Platform.CreateHashtable(); - - static X931Signer() - { - trailerMap.Add("RIPEMD128", TRAILER_RIPEMD128); - trailerMap.Add("RIPEMD160", TRAILER_RIPEMD160); - - trailerMap.Add("SHA-1", TRAILER_SHA1); - trailerMap.Add("SHA-224", TRAILER_SHA224); - trailerMap.Add("SHA-256", TRAILER_SHA256); - trailerMap.Add("SHA-384", TRAILER_SHA384); - trailerMap.Add("SHA-512", TRAILER_SHA512); - - trailerMap.Add("Whirlpool", TRAILER_WHIRLPOOL); - } + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_IMPLICIT = 0xBC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_RIPEMD160 = 0x31CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_RIPEMD128 = 0x32CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_SHA1 = 0x33CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_SHA256 = 0x34CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_SHA512 = 0x35CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_SHA384 = 0x36CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_WHIRLPOOL = 0x37CC; + [Obsolete("Use 'IsoTrailers' instead")] + public const int TRAILER_SHA224 = 0x38CC; private IDigest digest; private IAsymmetricBlockCipher cipher; @@ -55,8 +48,7 @@ namespace Org.BouncyCastle.Crypto.Signers private byte[] block; /** - * Generate a signer for the with either implicit or explicit trailers - * for ISO9796-2. + * Generate a signer with either implicit or explicit trailers for X9.31. * * @param cipher base cipher to use for signature creation/verification * @param digest digest to use. @@ -69,15 +61,15 @@ namespace Org.BouncyCastle.Crypto.Signers if (isImplicit) { - trailer = TRAILER_IMPLICIT; + trailer = IsoTrailers.TRAILER_IMPLICIT; + } + else if (IsoTrailers.NoTrailerAvailable(digest)) + { + throw new ArgumentException("no valid trailer", "digest"); } else { - string name = digest.AlgorithmName; - if (!trailerMap.Contains(name)) - throw new ArgumentException("no valid trailer", "digest"); - - trailer = (int)trailerMap[name]; + trailer = IsoTrailers.GetTrailer(digest); } } @@ -161,12 +153,11 @@ namespace Org.BouncyCastle.Crypto.Signers int digSize = digest.GetDigestSize(); int delta; - - if (trailer == TRAILER_IMPLICIT) + if (trailer == IsoTrailers.TRAILER_IMPLICIT) { delta = block.Length - digSize - 1; digest.DoFinal(block, delta); - block[block.Length - 1] = (byte)TRAILER_IMPLICIT; + block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT; } else { diff --git a/crypto/src/crypto/tls/AbstractTlsContext.cs b/crypto/src/crypto/tls/AbstractTlsContext.cs index e283ee58c..ae7efc64d 100644 --- a/crypto/src/crypto/tls/AbstractTlsContext.cs +++ b/crypto/src/crypto/tls/AbstractTlsContext.cs @@ -12,10 +12,21 @@ namespace Org.BouncyCastle.Crypto.Tls { private static long counter = Times.NanoTime(); +#if NETCF_1_0 + private static object counterLock = new object(); + private static long NextCounterValue() + { + lock (counterLock) + { + return ++counter; + } + } +#else private static long NextCounterValue() { return Interlocked.Increment(ref counter); } +#endif private readonly IRandomGenerator mNonceRandom; private readonly SecureRandom mSecureRandom; @@ -26,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Tls private TlsSession mSession = null; private object mUserObject = null; - internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters) + internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters) { IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256); byte[] seed = new byte[d.GetDigestSize()]; diff --git a/crypto/src/crypto/tls/ByteQueueStream.cs b/crypto/src/crypto/tls/ByteQueueStream.cs new file mode 100644 index 000000000..3b8ffb02f --- /dev/null +++ b/crypto/src/crypto/tls/ByteQueueStream.cs @@ -0,0 +1,115 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class ByteQueueStream + : Stream + { + private readonly ByteQueue buffer; + + public ByteQueueStream() + { + this.buffer = new ByteQueue(); + } + + public virtual int Available + { + get { return buffer.Available; } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + + public override void Flush() + { + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public virtual int Peek(byte[] buf) + { + int bytesToRead = System.Math.Min(buffer.Available, buf.Length); + buffer.Read(buf, 0, bytesToRead, 0); + return bytesToRead; + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public virtual int Read(byte[] buf) + { + return Read(buf, 0, buf.Length); + } + + public override int Read(byte[] buf, int off, int len) + { + int bytesToRead = System.Math.Min(buffer.Available, len); + buffer.RemoveData(buf, off, bytesToRead, 0); + return bytesToRead; + } + + public override int ReadByte() + { + if (buffer.Available == 0) + return -1; + + return buffer.RemoveData(1, 0)[0] & 0xFF; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public virtual int Skip(int n) + { + int bytesToSkip = System.Math.Min(buffer.Available, n); + buffer.RemoveData(bytesToSkip); + return bytesToSkip; + } + + public virtual void Write(byte[] buf) + { + buffer.AddData(buf, 0, buf.Length); + } + + public override void Write(byte[] buf, int off, int len) + { + buffer.AddData(buf, off, len); + } + + public override void WriteByte(byte b) + { + buffer.AddData(new byte[]{ b }, 0, 1); + } + } +} diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs index e5d0febeb..4c57da502 100644 --- a/crypto/src/crypto/tls/RecordStream.cs +++ b/crypto/src/crypto/tls/RecordStream.cs @@ -8,6 +8,11 @@ namespace Org.BouncyCastle.Crypto.Tls { private const int DEFAULT_PLAINTEXT_LIMIT = (1 << 14); + internal const int TLS_HEADER_SIZE = 5; + internal const int TLS_HEADER_TYPE_OFFSET = 0; + internal const int TLS_HEADER_VERSION_OFFSET = 1; + internal const int TLS_HEADER_LENGTH_OFFSET = 3; + private TlsProtocol mHandler; private Stream mInput; private Stream mOutput; @@ -116,11 +121,11 @@ namespace Org.BouncyCastle.Crypto.Tls internal virtual bool ReadRecord() { - byte[] recordHeader = TlsUtilities.ReadAllOrNothing(5, mInput); + byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput); if (recordHeader == null) return false; - byte type = TlsUtilities.ReadUint8(recordHeader, 0); + byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET); /* * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an @@ -130,13 +135,13 @@ namespace Org.BouncyCastle.Crypto.Tls if (!mRestrictReadVersion) { - int version = TlsUtilities.ReadVersionRaw(recordHeader, 1); + int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET); if ((version & 0xffffff00) != 0x0300) throw new TlsFatalAlert(AlertDescription.illegal_parameter); } else { - ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, 1); + ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET); if (mReadVersion == null) { mReadVersion = version; @@ -147,7 +152,7 @@ namespace Org.BouncyCastle.Crypto.Tls } } - int length = TlsUtilities.ReadUint16(recordHeader, 3); + int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET); byte[] plaintext = DecodeAndVerify(type, mInput, length); mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length); return true; @@ -247,11 +252,11 @@ namespace Org.BouncyCastle.Crypto.Tls */ CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error); - byte[] record = new byte[ciphertext.Length + 5]; - TlsUtilities.WriteUint8(type, record, 0); - TlsUtilities.WriteVersion(mWriteVersion, record, 1); - TlsUtilities.WriteUint16(ciphertext.Length, record, 3); - Array.Copy(ciphertext, 0, record, 5, ciphertext.Length); + byte[] record = new byte[ciphertext.Length + TLS_HEADER_SIZE]; + TlsUtilities.WriteUint8(type, record, TLS_HEADER_TYPE_OFFSET); + TlsUtilities.WriteVersion(mWriteVersion, record, TLS_HEADER_VERSION_OFFSET); + TlsUtilities.WriteUint16(ciphertext.Length, record, TLS_HEADER_LENGTH_OFFSET); + Array.Copy(ciphertext, 0, record, TLS_HEADER_SIZE, ciphertext.Length); mOutput.Write(record, 0, record.Length); mOutput.Flush(); } diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs index 7b8439acc..14c1cf4a4 100644 --- a/crypto/src/crypto/tls/TlsClientProtocol.cs +++ b/crypto/src/crypto/tls/TlsClientProtocol.cs @@ -21,21 +21,56 @@ namespace Org.BouncyCastle.Crypto.Tls protected CertificateStatus mCertificateStatus = null; protected CertificateRequest mCertificateRequest = null; + /** + * Constructor for blocking mode. + * @param stream The bi-directional stream of data to/from the server + * @param secureRandom Random number generator for various cryptographic functions + */ public TlsClientProtocol(Stream stream, SecureRandom secureRandom) - : base(stream, secureRandom) + : base(stream, secureRandom) { } + /** + * Constructor for blocking mode. + * @param input The stream of data from the server + * @param output The stream of data to the server + * @param secureRandom Random number generator for various cryptographic functions + */ public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom) - : base(input, output, secureRandom) + : base(input, output, secureRandom) + { + } + + /** + * Constructor for non-blocking mode.<br> + * <br> + * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to + * provide the received ciphertext, then use + * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br> + * <br> + * Similarly, when data needs to be sent, use + * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use + * {@link #readOutput(byte[], int, int)} to get the corresponding + * ciphertext. + * + * @param secureRandom + * Random number generator for various cryptographic functions + */ + public TlsClientProtocol(SecureRandom secureRandom) + : base(secureRandom) { } /** - * Initiates a TLS handshake in the role of client + * Initiates a TLS handshake in the role of client.<br> + * <br> + * In blocking mode, this will not return until the handshake is complete. + * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to + * receive a callback when the handshake is complete. * * @param tlsClient The {@link TlsClient} to use for the handshake. - * @throws IOException If handshake was not successful. + * @throws IOException If in blocking mode and handshake was not successful. */ public virtual void Connect(TlsClient tlsClient) { @@ -71,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Tls SendClientHelloMessage(); this.mConnectionState = CS_CLIENT_HELLO; - CompleteHandshake(); + BlockForHandshake(); } protected override void CleanupHandshake() @@ -116,6 +151,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.mConnectionState = CS_CLIENT_FINISHED; this.mConnectionState = CS_END; + CompleteHandshake(); return; } @@ -208,6 +244,8 @@ namespace Org.BouncyCastle.Crypto.Tls ProcessFinishedMessage(buf); this.mConnectionState = CS_SERVER_FINISHED; this.mConnectionState = CS_END; + + CompleteHandshake(); break; } default: diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs index b80290fc4..56dd25605 100644 --- a/crypto/src/crypto/tls/TlsProtocol.cs +++ b/crypto/src/crypto/tls/TlsProtocol.cs @@ -72,6 +72,10 @@ namespace Org.BouncyCastle.Crypto.Tls protected bool mAllowCertificateStatus = false; protected bool mExpectSessionTicket = false; + protected bool mBlocking = true; + protected ByteQueueStream mInputBuffers = null; + protected ByteQueueStream mOutputBuffer = null; + public TlsProtocol(Stream stream, SecureRandom secureRandom) : this(stream, stream, secureRandom) { @@ -83,6 +87,15 @@ namespace Org.BouncyCastle.Crypto.Tls this.mSecureRandom = secureRandom; } + public TlsProtocol(SecureRandom secureRandom) + { + this.mBlocking = false; + this.mInputBuffers = new ByteQueueStream(); + this.mOutputBuffer = new ByteQueueStream(); + this.mRecordStream = new RecordStream(this, mInputBuffers, mOutputBuffer); + this.mSecureRandom = secureRandom; + } + protected abstract TlsContext Context { get; } internal abstract AbstractTlsContext ContextAdmin { get; } @@ -140,13 +153,10 @@ namespace Org.BouncyCastle.Crypto.Tls this.mExpectSessionTicket = false; } - protected virtual void CompleteHandshake() + protected virtual void BlockForHandshake() { - try + if (mBlocking) { - /* - * We will now read data, until we have completed the handshake. - */ while (this.mConnectionState != CS_END) { if (this.mClosed) @@ -156,7 +166,13 @@ namespace Org.BouncyCastle.Crypto.Tls SafeReadRecord(); } + } + } + protected virtual void CompleteHandshake() + { + try + { this.mRecordStream.FinaliseHandshake(); this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context); @@ -168,7 +184,10 @@ namespace Org.BouncyCastle.Crypto.Tls { this.mAppDataReady = true; - this.mTlsStream = new TlsStream(this); + if (mBlocking) + { + this.mTlsStream = new TlsStream(this); + } } if (this.mTlsSession != null) @@ -573,9 +592,156 @@ namespace Org.BouncyCastle.Crypto.Tls } /// <summary>The secure bidirectional stream for this connection</summary> + /// <remarks>Only allowed in blocking mode.</remarks> public virtual Stream Stream { - get { return this.mTlsStream; } + get + { + if (!mBlocking) + throw new InvalidOperationException("Cannot use Stream in non-blocking mode! Use OfferInput()/OfferOutput() instead."); + return this.mTlsStream; + } + } + + /** + * Offer input from an arbitrary source. Only allowed in non-blocking mode.<br> + * <br> + * After this method returns, the input buffer is "owned" by this object. Other code + * must not attempt to do anything with it.<br> + * <br> + * This method will decrypt and process all records that are fully available. + * If only part of a record is available, the buffer will be retained until the + * remainder of the record is offered.<br> + * <br> + * If any records containing application data were processed, the decrypted data + * can be obtained using {@link #readInput(byte[], int, int)}. If any records + * containing protocol data were processed, a response may have been generated. + * You should always check to see if there is any available output after calling + * this method by calling {@link #getAvailableOutputBytes()}. + * @param input The input buffer to offer + * @throws IOException If an error occurs while decrypting or processing a record + */ + public virtual void OfferInput(byte[] input) + { + if (mBlocking) + throw new InvalidOperationException("Cannot use OfferInput() in blocking mode! Use Stream instead."); + if (mClosed) + throw new IOException("Connection is closed, cannot accept any more input"); + + mInputBuffers.Write(input); + + // loop while there are enough bytes to read the length of the next record + while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE) + { + byte[] header = new byte[RecordStream.TLS_HEADER_SIZE]; + mInputBuffers.Peek(header); + + int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE; + if (mInputBuffers.Available < totalLength) + { + // not enough bytes to read a whole record + break; + } + + SafeReadRecord(); + } + } + + /** + * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)} + * is guaranteed to be able to return at least this much data.<br> + * <br> + * Only allowed in non-blocking mode. + * @return The number of bytes of available application data + */ + public virtual int GetAvailableInputBytes() + { + if (mBlocking) + throw new InvalidOperationException("Cannot use GetAvailableInputBytes() in blocking mode! Use ApplicationDataAvailable() instead."); + + return ApplicationDataAvailable(); + } + + /** + * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check + * how much application data is currently available. This method functions similarly to + * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data + * is available, nothing will be copied and zero will be returned.<br> + * <br> + * Only allowed in non-blocking mode. + * @param buffer The buffer to hold the application data + * @param offset The start offset in the buffer at which the data is written + * @param length The maximum number of bytes to read + * @return The total number of bytes copied to the buffer. May be less than the + * length specified if the length was greater than the amount of available data. + */ + public virtual int ReadInput(byte[] buffer, int offset, int length) + { + if (mBlocking) + throw new InvalidOperationException("Cannot use ReadInput() in blocking mode! Use Stream instead."); + + return ReadApplicationData(buffer, offset, System.Math.Min(length, ApplicationDataAvailable())); + } + + /** + * Offer output from an arbitrary source. Only allowed in non-blocking mode.<br> + * <br> + * After this method returns, the specified section of the buffer will have been + * processed. Use {@link #readOutput(byte[], int, int)} to get the bytes to + * transmit to the other peer.<br> + * <br> + * This method must not be called until after the handshake is complete! Attempting + * to call it before the handshake is complete will result in an exception. + * @param buffer The buffer containing application data to encrypt + * @param offset The offset at which to begin reading data + * @param length The number of bytes of data to read + * @throws IOException If an error occurs encrypting the data, or the handshake is not complete + */ + public virtual void OfferOutput(byte[] buffer, int offset, int length) + { + if (mBlocking) + throw new InvalidOperationException("Cannot use OfferOutput() in blocking mode! Use Stream instead."); + if (!mAppDataReady) + throw new IOException("Application data cannot be sent until the handshake is complete!"); + + WriteData(buffer, offset, length); + } + + /** + * Gets the amount of encrypted data available to be sent. A call to + * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at + * least this much data.<br> + * <br> + * Only allowed in non-blocking mode. + * @return The number of bytes of available encrypted data + */ + public virtual int GetAvailableOutputBytes() + { + if (mBlocking) + throw new InvalidOperationException("Cannot use GetAvailableOutputBytes() in blocking mode! Use Stream instead."); + + return mOutputBuffer.Available; + } + + /** + * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check + * how much encrypted data is currently available. This method functions similarly to + * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data + * is available, nothing will be copied and zero will be returned.<br> + * <br> + * Only allowed in non-blocking mode. + * @param buffer The buffer to hold the encrypted data + * @param offset The start offset in the buffer at which the data is written + * @param length The maximum number of bytes to read + * @return The total number of bytes copied to the buffer. May be less than the + * length specified if the length was greater than the amount of available data. + */ + public virtual int ReadOutput(byte[] buffer, int offset, int length) + { + if (mBlocking) + throw new InvalidOperationException("Cannot use ReadOutput() in blocking mode! Use Stream instead."); + + return mOutputBuffer.Read(buffer, offset, length); } /** @@ -764,7 +930,7 @@ namespace Org.BouncyCastle.Crypto.Tls mRecordStream.Flush(); } - protected internal virtual bool IsClosed + public virtual bool IsClosed { get { return mClosed; } } diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs index b73cb5a30..27f7a1dfd 100644 --- a/crypto/src/crypto/tls/TlsServerProtocol.cs +++ b/crypto/src/crypto/tls/TlsServerProtocol.cs @@ -22,21 +22,57 @@ namespace Org.BouncyCastle.Crypto.Tls protected short mClientCertificateType = -1; protected TlsHandshakeHash mPrepareFinishHash = null; + /** + * Constructor for blocking mode. + * @param stream The bi-directional stream of data to/from the client + * @param output The stream of data to the client + * @param secureRandom Random number generator for various cryptographic functions + */ public TlsServerProtocol(Stream stream, SecureRandom secureRandom) - : base(stream, secureRandom) + : base(stream, secureRandom) { } + /** + * Constructor for blocking mode. + * @param input The stream of data from the client + * @param output The stream of data to the client + * @param secureRandom Random number generator for various cryptographic functions + */ public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom) - : base(input, output, secureRandom) + : base(input, output, secureRandom) + { + } + + /** + * Constructor for non-blocking mode.<br> + * <br> + * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to + * provide the received ciphertext, then use + * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br> + * <br> + * Similarly, when data needs to be sent, use + * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use + * {@link #readOutput(byte[], int, int)} to get the corresponding + * ciphertext. + * + * @param secureRandom + * Random number generator for various cryptographic functions + */ + public TlsServerProtocol(SecureRandom secureRandom) + : base(secureRandom) { } /** - * Receives a TLS handshake in the role of server + * Receives a TLS handshake in the role of server.<br> + * <br> + * In blocking mode, this will not return until the handshake is complete. + * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to + * receive a callback when the handshake is complete. * - * @param mTlsServer - * @throws IOException If handshake was not successful. + * @param tlsServer + * @throws IOException If in blocking mode and handshake was not successful. */ public virtual void Accept(TlsServer tlsServer) { @@ -60,7 +96,7 @@ namespace Org.BouncyCastle.Crypto.Tls this.mRecordStream.SetRestrictReadVersion(false); - CompleteHandshake(); + BlockForHandshake(); } protected override void CleanupHandshake() @@ -329,6 +365,8 @@ namespace Org.BouncyCastle.Crypto.Tls SendFinishedMessage(); this.mConnectionState = CS_SERVER_FINISHED; this.mConnectionState = CS_END; + + CompleteHandshake(); break; } default: diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs index 087cb7cea..dc00ab450 100644 --- a/crypto/src/crypto/util/Pack.cs +++ b/crypto/src/crypto/util/Pack.cs @@ -117,6 +117,22 @@ namespace Org.BouncyCastle.Crypto.Utilities UInt32_To_BE((uint)(n), bs, off + 4); } + internal static byte[] UInt64_To_BE(ulong[] ns) + { + byte[] bs = new byte[8 * ns.Length]; + UInt64_To_BE(ns, bs, 0); + return bs; + } + + internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.Length; ++i) + { + UInt64_To_BE(ns[i], bs, off); + off += 8; + } + } + internal static ulong BE_To_UInt64(byte[] bs) { uint hi = BE_To_UInt32(bs); @@ -131,6 +147,15 @@ namespace Org.BouncyCastle.Crypto.Utilities return ((ulong)hi << 32) | (ulong)lo; } + internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns) + { + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = BE_To_UInt64(bs, off); + off += 8; + } + } + internal static void UInt16_To_LE(ushort n, byte[] bs) { bs[0] = (byte)(n); diff --git a/crypto/src/math/Primes.cs b/crypto/src/math/Primes.cs index b57977983..420c3cc5a 100644 --- a/crypto/src/math/Primes.cs +++ b/crypto/src/math/Primes.cs @@ -1,18 +1,69 @@ using System; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math { - public static class Primes + /** + * Utility methods for generating primes and testing for primality. + */ + public abstract class Primes { private static readonly BigInteger One = BigInteger.One; private static readonly BigInteger Two = BigInteger.Two; private static readonly BigInteger Three = BigInteger.Three; /** - * Used to return the output from the {@linkplain #generateSTRandomPrime(Digest) Shawe-Taylor Random_Prime Routine} + * Used to return the output from the + * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced + * Miller-Rabin Probabilistic Primality Test} + */ + public class MROutput + { + internal static MROutput ProbablyPrime() + { + return new MROutput(false, null); + } + + internal static MROutput ProvablyCompositeWithFactor(BigInteger factor) + { + return new MROutput(true, factor); + } + + internal static MROutput ProvablyCompositeNotPrimePower() + { + return new MROutput(true, null); + } + + private readonly bool mProvablyComposite; + private readonly BigInteger mFactor; + + private MROutput(bool provablyComposite, BigInteger factor) + { + this.mProvablyComposite = provablyComposite; + this.mFactor = factor; + } + + public BigInteger Factor + { + get { return mFactor; } + } + + public bool IsProvablyComposite + { + get { return mProvablyComposite; } + } + + public bool IsNotPrimePower + { + get { return mProvablyComposite && mFactor == null; } + } + } + + /** + * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine} */ public class STOutput { @@ -51,11 +102,11 @@ namespace Org.BouncyCastle.Math * @param hash * the {@link Digest} instance to use (as "Hash()"). Cannot be null. * @param length - * the length (in bits) of the prime to be generated. Must be >= 2. + * the length (in bits) of the prime to be generated. Must be at least 2. * @param inputSeed * the seed to be used for the generation of the requested prime. Cannot be null or * empty. - * @returns an {@link STOutput} instance containing the requested prime. + * @return an {@link STOutput} instance containing the requested prime. */ public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed) { @@ -71,6 +122,269 @@ namespace Org.BouncyCastle.Math return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed)); } + /** + * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test + * + * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an + * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more + * information about a composite candidate, which may be useful when generating or validating + * RSA moduli. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param random + * the source of randomness to use to choose bases. + * @param iterations + * the number of randomly-chosen bases to perform the test for. + * @return an {@link MROutput} instance that can be further queried for details. + */ + public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations) + { + CheckCandidate(candidate, "candidate"); + + if (random == null) + throw new ArgumentNullException("random"); + if (iterations < 1) + throw new ArgumentException("must be > 0", "iterations"); + + if (candidate.BitLength == 2) + return MROutput.ProbablyPrime(); + + if (!candidate.TestBit(0)) + return MROutput.ProvablyCompositeWithFactor(Two); + + BigInteger w = candidate; + BigInteger wSubOne = candidate.Subtract(One); + BigInteger wSubTwo = candidate.Subtract(Two); + + int a = wSubOne.GetLowestSetBit(); + BigInteger m = wSubOne.ShiftRight(a); + + for (int i = 0; i < iterations; ++i) + { + BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random); + BigInteger g = b.Gcd(w); + + if (g.CompareTo(One) > 0) + return MROutput.ProvablyCompositeWithFactor(g); + + BigInteger z = b.ModPow(m, w); + + if (z.Equals(One) || z.Equals(wSubOne)) + continue; + + bool primeToBase = false; + + BigInteger x = z; + for (int j = 1; j < a; ++j) + { + z = z.ModPow(Two, w); + + if (z.Equals(wSubOne)) + { + primeToBase = true; + break; + } + + if (z.Equals(One)) + break; + + x = z; + } + + if (!primeToBase) + { + if (!z.Equals(One)) + { + x = z; + z = z.ModPow(Two, w); + + if (!z.Equals(One)) + { + x = z; + } + } + + g = x.Subtract(One).Gcd(w); + + if (g.CompareTo(One) > 0) + return MROutput.ProvablyCompositeWithFactor(g); + + return MROutput.ProvablyCompositeNotPrimePower(); + } + } + + return MROutput.ProbablyPrime(); + } + + /** + * A fast check for small divisors, up to some implementation-specific limit. + * + * @param candidate + * the {@link BigInteger} instance to test for division by small factors. + * + * @return <code>true</code> if the candidate is found to have any small factors, + * <code>false</code> otherwise. + */ + public static bool HasAnySmallFactors(BigInteger candidate) + { + CheckCandidate(candidate, "candidate"); + + return ImplHasAnySmallFactors(candidate); + } + + /** + * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test + * + * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param random + * the source of randomness to use to choose bases. + * @param iterations + * the number of randomly-chosen bases to perform the test for. + * @return <code>false</code> if any witness to compositeness is found amongst the chosen bases + * (so <code>candidate</code> is definitely NOT prime), or else <code>true</code> + * (indicating primality with some probability dependent on the number of iterations + * that were performed). + */ + public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations) + { + CheckCandidate(candidate, "candidate"); + + if (random == null) + throw new ArgumentException("cannot be null", "random"); + if (iterations < 1) + throw new ArgumentException("must be > 0", "iterations"); + + if (candidate.BitLength == 2) + return true; + if (!candidate.TestBit(0)) + return false; + + BigInteger w = candidate; + BigInteger wSubOne = candidate.Subtract(One); + BigInteger wSubTwo = candidate.Subtract(Two); + + int a = wSubOne.GetLowestSetBit(); + BigInteger m = wSubOne.ShiftRight(a); + + for (int i = 0; i < iterations; ++i) + { + BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random); + + if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b)) + return false; + } + + return true; + } + + /** + * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base). + * + * Run a single iteration of the Miller-Rabin algorithm against the specified base. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param baseValue + * the base value to use for this iteration. + * @return <code>false</code> if the specified base is a witness to compositeness (so + * <code>candidate</code> is definitely NOT prime), or else <code>true</code>. + */ + public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue) + { + CheckCandidate(candidate, "candidate"); + CheckCandidate(baseValue, "baseValue"); + + if (baseValue.CompareTo(candidate.Subtract(One)) >= 0) + throw new ArgumentException("must be < ('candidate' - 1)", "baseValue"); + + if (candidate.BitLength == 2) + return true; + + BigInteger w = candidate; + BigInteger wSubOne = candidate.Subtract(One); + + int a = wSubOne.GetLowestSetBit(); + BigInteger m = wSubOne.ShiftRight(a); + + return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue); + } + + private static void CheckCandidate(BigInteger n, string name) + { + if (n == null || n.SignValue < 1 || n.BitLength < 2) + throw new ArgumentException("must be non-null and >= 2", name); + } + + private static bool ImplHasAnySmallFactors(BigInteger x) + { + /* + * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders. + */ + int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23; + int r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0 + && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0) + { + m = 29 * 31 * 37 * 41 * 43; + r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0) + { + m = 47 * 53 * 59 * 61 * 67; + r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0) + { + m = 71 * 73 * 79 * 83; + r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0) + { + m = 89 * 97 * 101 * 103; + r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0) + { + m = 107 * 109 * 113 * 127; + r = x.Mod(BigInteger.ValueOf(m)).IntValue; + if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0) + { + return false; + } + } + } + } + } + } + return true; + } + + private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b) + { + BigInteger z = b.ModPow(m, w); + + if (z.Equals(One) || z.Equals(wSubOne)) + return true; + + bool result = false; + + for (int j = 1; j < a; ++j) + { + z = z.ModPow(Two, w); + + if (z.Equals(wSubOne)) + { + result = true; + break; + } + + if (z.Equals(One)) + return false; + } + + return result; + } + private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed) { int dLen = d.GetDigestSize(); @@ -131,7 +445,7 @@ namespace Org.BouncyCastle.Math /* * TODO Since the candidate primes are generated by constant steps ('c0x2'), - * sieving could be used here in place of the 'mightBePrime' approach. + * sieving could be used here in place of the 'HasAnySmallFactors' approach. */ for (;;) { @@ -149,7 +463,7 @@ namespace Org.BouncyCastle.Math * * NOTE: 'primeSeed' is still incremented as if we performed the full check! */ - if (MightBePrime(c)) + if (!ImplHasAnySmallFactors(c)) { BigInteger a = HashGen(d, primeSeed, iterations + 1); a = a.Mod(c.Subtract(Three)).Add(Two); @@ -266,45 +580,5 @@ namespace Org.BouncyCastle.Math } } } - - private static bool MightBePrime(BigInteger x) - { - /* - * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders. - */ - int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23; - int r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0 - && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0) - { - m = 29 * 31 * 37 * 41 * 43; - r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0) - { - m = 47 * 53 * 59 * 61 * 67; - r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0) - { - m = 71 * 73 * 79 * 83; - r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0) - { - m = 89 * 97 * 101 * 103; - r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0) - { - m = 107 * 109 * 113 * 127; - r = x.Mod(BigInteger.ValueOf(m)).IntValue; - if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0) - { - return true; - } - } - } - } - } - } - return false; - } } } diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs index 9fe9e32fd..40b46ce72 100644 --- a/crypto/src/math/ec/ECCurve.cs +++ b/crypto/src/math/ec/ECCurve.cs @@ -677,28 +677,110 @@ namespace Org.BouncyCastle.Math.EC switch (this.CoordinateSystem) { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - if (X.IsZero) + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: { - if (!Y.Square().Equals(B)) - throw new ArgumentException(); + if (X.IsZero) + { + if (!Y.Square().Equals(B)) + throw new ArgumentException(); + } + else + { + // Y becomes Lambda (X + Y/X) here + Y = Y.Divide(X).Add(X); + } + break; } - else + default: { - // Y becomes Lambda (X + Y/X) here - Y = Y.Divide(X).Add(X); + break; } - break; } - default: + + return CreateRawPoint(X, Y, withCompression); + } + + protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement xp = FromBigInteger(X1), yp = null; + if (xp.IsZero) { - break; + yp = B.Sqrt(); } + else + { + ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp); + ECFieldElement z = SolveQuadradicEquation(beta); + + if (z != null) + { + if (z.TestBitZero() != (yTilde == 1)) + { + z = z.AddOne(); + } + + switch (this.CoordinateSystem) + { + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: + { + yp = z.Add(xp); + break; + } + default: + { + yp = z.Multiply(xp); + break; + } + } + } } - return CreateRawPoint(X, Y, withCompression); + if (yp == null) + throw new ArgumentException("Invalid point compression"); + + return CreateRawPoint(xp, yp, true); + } + + /** + * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 + * D.1.6) The other solution is <code>z + 1</code>. + * + * @param beta + * The value to solve the qradratic 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) + { + if (beta.IsZero) + return beta; + + ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero); + + int m = FieldSize; + Random rand = new Random(); + do + { + ECFieldElement t = FromBigInteger(new BigInteger(m, rand)); + z = zeroElement; + ECFieldElement w = beta; + for (int i = 1; i < m; i++) + { + ECFieldElement w2 = w.Square(); + z = z.Square().Add(w2.Multiply(t)); + w = w2.Add(beta); + } + if (!w.IsZero) + { + return null; + } + gamma = z.Square().Add(z); + } + while (gamma.IsZero); + + return z; } /** @@ -994,92 +1076,6 @@ namespace Org.BouncyCastle.Math.EC get { return m_infinity; } } - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement xp = FromBigInteger(X1), yp = null; - if (xp.IsZero) - { - yp = m_b.Sqrt(); - } - else - { - ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp); - ECFieldElement z = SolveQuadradicEquation(beta); - - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - yp = z.Add(xp); - break; - } - default: - { - yp = z.Multiply(xp); - break; - } - } - } - } - - if (yp == null) - throw new ArgumentException("Invalid point compression"); - - return CreateRawPoint(xp, yp, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * The value to solve the qradratic 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) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(m, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < m; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - { - return null; - } - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public int M { get { return m; } diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs index dbb645e6f..640c6e787 100644 --- a/crypto/src/math/ec/custom/sec/SecT113Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs @@ -37,6 +37,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat128.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion + + ulong[] t0 = Nat128.Create64(); + ulong[] t1 = Nat128.Create64(); + + Square(x, t0); + Multiply(t0, x, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 3, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 7, t0); + Multiply(t0, t1, t0); + SquareN(t0, 14, t1); + Multiply(t1, t0, t1); + SquareN(t1, 28, t0); + Multiply(t0, t1, t0); + SquareN(t0, 56, t1); + Multiply(t1, t0, t1); + Square(t1, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat128.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs index e3a923f62..f217e28cb 100644 --- a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT113FieldElement( - AbstractF2mCurve.Inverse(113, new int[]{ 9 }, ToBigInteger())); + ulong[] z = Nat128.Create64(); + SecT113Field.Invert(x, z); + return new SecT113FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs index 04e69e2a8..2705c94aa 100644 --- a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs @@ -65,101 +65,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return new SecT113R1Point(this, x, y, zs, withCompression); } - public override bool IsKoblitz + public override bool IsKoblitz { get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(113, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 113; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 113; } diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs index a02db6b25..abfd26d5b 100644 --- a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs @@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(113, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 113; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 113; } diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs index 6a1d2a960..47f97078c 100644 --- a/crypto/src/math/ec/custom/sec/SecT131Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs @@ -40,6 +40,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat192.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion + + ulong[] t0 = Nat192.Create64(); + ulong[] t1 = Nat192.Create64(); + + Square(x, t0); + Multiply(t0, x, t0); + SquareN(t0, 2, t1); + Multiply(t1, t0, t1); + SquareN(t1, 4, t0); + Multiply(t0, t1, t0); + SquareN(t0, 8, t1); + Multiply(t1, t0, t1); + SquareN(t1, 16, t0); + Multiply(t0, t1, t0); + SquareN(t0, 32, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 65, t0); + Multiply(t0, t1, t0); + Square(t0, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat192.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs index 65aaf01ba..0ea00ea07 100644 --- a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT131FieldElement( - AbstractF2mCurve.Inverse(131, new int[] { 2, 3, 8 }, ToBigInteger())); + ulong[] z = Nat192.Create64(); + SecT131Field.Invert(x, z); + return new SecT131FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs index 789e3c0c3..b73964c39 100644 --- a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs @@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(131, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 131; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 131; } diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs index 2004f84ca..724921c94 100644 --- a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs @@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(131, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 131; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 131; } diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs index 165d5b841..f921a5bc7 100644 --- a/crypto/src/math/ec/custom/sec/SecT163Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs @@ -41,6 +41,47 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat192.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion with bases { 2, 3 } + + ulong[] t0 = Nat192.Create64(); + ulong[] t1 = Nat192.Create64(); + + Square(x, t0); + + // 3 | 162 + SquareN(t0, 1, t1); + Multiply(t0, t1, t0); + SquareN(t1, 1, t1); + Multiply(t0, t1, t0); + + // 3 | 54 + SquareN(t0, 3, t1); + Multiply(t0, t1, t0); + SquareN(t1, 3, t1); + Multiply(t0, t1, t0); + + // 3 | 18 + SquareN(t0, 9, t1); + Multiply(t0, t1, t0); + SquareN(t1, 9, t1); + Multiply(t0, t1, t0); + + // 3 | 6 + SquareN(t0, 27, t1); + Multiply(t0, t1, t0); + SquareN(t1, 27, t1); + Multiply(t0, t1, t0); + + // 2 | 2 + SquareN(t0, 81, t1); + Multiply(t0, t1, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat192.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs index 3ab383a1d..c7a0b5639 100644 --- a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT163FieldElement( - AbstractF2mCurve.Inverse(163, new int[] { 3, 6, 7 }, ToBigInteger())); + ulong[] z = Nat192.Create64(); + SecT163Field.Invert(x, z); + return new SecT163FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs index 1cfd09e1c..68ff646ca 100644 --- a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs @@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(163, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 163; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 163; } diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs index fc18e1094..8ae58ccef 100644 --- a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs @@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(163, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 163; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 163; } diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs index 9efe11c3e..5a4fa5ad1 100644 --- a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs @@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(163, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 163; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 163; } diff --git a/crypto/src/math/ec/custom/sec/SecT193Field.cs b/crypto/src/math/ec/custom/sec/SecT193Field.cs index 85db061c3..5154f1e0a 100644 --- a/crypto/src/math/ec/custom/sec/SecT193Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT193Field.cs @@ -44,6 +44,49 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat256.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion with bases { 2, 3 } + + ulong[] t0 = Nat256.Create64(); + ulong[] t1 = Nat256.Create64(); + + Square(x, t0); + + // 3 | 192 + SquareN(t0, 1, t1); + Multiply(t0, t1, t0); + SquareN(t1, 1, t1); + Multiply(t0, t1, t0); + + // 2 | 64 + SquareN(t0, 3, t1); + Multiply(t0, t1, t0); + + // 2 | 32 + SquareN(t0, 6, t1); + Multiply(t0, t1, t0); + + // 2 | 16 + SquareN(t0, 12, t1); + Multiply(t0, t1, t0); + + // 2 | 8 + SquareN(t0, 24, t1); + Multiply(t0, t1, t0); + + // 2 | 4 + SquareN(t0, 48, t1); + Multiply(t0, t1, t0); + + // 2 | 2 + SquareN(t0, 96, t1); + Multiply(t0, t1, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat256.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs index 995d2ebdd..eba4d10e6 100644 --- a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT193FieldElement( - AbstractF2mCurve.Inverse(193, new int[] { 15 }, ToBigInteger())); + ulong[] z = Nat256.Create64(); + SecT193Field.Invert(x, z); + return new SecT193FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs index 802954b01..a2cb5a8ac 100644 --- a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs @@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(193, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 193; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 193; } diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs index b5345730c..1c84a3eac 100644 --- a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs @@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(193, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 193; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 193; } diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs index b36ffba2e..a2f73fd5d 100644 --- a/crypto/src/math/ec/custom/sec/SecT233Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs @@ -45,6 +45,39 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat256.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion + + ulong[] t0 = Nat256.Create64(); + ulong[] t1 = Nat256.Create64(); + + Square(x, t0); + Multiply(t0, x, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 3, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 7, t0); + Multiply(t0, t1, t0); + SquareN(t0, 14, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 29, t0); + Multiply(t0, t1, t0); + SquareN(t0, 58, t1); + Multiply(t1, t0, t1); + SquareN(t1, 116, t0); + Multiply(t0, t1, t0); + Square(t0, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat256.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs index 60b204604..a9041efde 100644 --- a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT233FieldElement( - AbstractF2mCurve.Inverse(233, new int[] { 74 }, ToBigInteger())); + ulong[] z = Nat256.Create64(); + SecT233Field.Invert(x, z); + return new SecT233FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs index 8768eaa81..72935913d 100644 --- a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs @@ -76,98 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(233, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 233; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 233; } diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs index 92795b8a7..db6e6e1d4 100644 --- a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs @@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(233, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 233; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 233; } diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs index 6dab907dd..6b8ad696f 100644 --- a/crypto/src/math/ec/custom/sec/SecT239Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs @@ -45,6 +45,43 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat256.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion + + ulong[] t0 = Nat256.Create64(); + ulong[] t1 = Nat256.Create64(); + + Square(x, t0); + Multiply(t0, x, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 3, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 7, t0); + Multiply(t0, t1, t0); + SquareN(t0, 14, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 29, t0); + Multiply(t0, t1, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 59, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 119, t0); + Multiply(t0, t1, t0); + Square(t0, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat256.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs index e7bfffd1f..de074c55f 100644 --- a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT239FieldElement( - AbstractF2mCurve.Inverse(239, new int[] { 158 }, ToBigInteger())); + ulong[] z = Nat256.Create64(); + SecT239Field.Invert(x, z); + return new SecT239FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs index 2c73d941f..a499d48b4 100644 --- a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs @@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(239, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 239; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 239; } diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs index 435787467..903ea02ff 100644 --- a/crypto/src/math/ec/custom/sec/SecT283Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs @@ -48,6 +48,41 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat320.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion + + ulong[] t0 = Nat320.Create64(); + ulong[] t1 = Nat320.Create64(); + + Square(x, t0); + Multiply(t0, x, t0); + SquareN(t0, 2, t1); + Multiply(t1, t0, t1); + SquareN(t1, 4, t0); + Multiply(t0, t1, t0); + SquareN(t0, 8, t1); + Multiply(t1, t0, t1); + Square(t1, t1); + Multiply(t1, x, t1); + SquareN(t1, 17, t0); + Multiply(t0, t1, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 35, t1); + Multiply(t1, t0, t1); + SquareN(t1, 70, t0); + Multiply(t0, t1, t0); + Square(t0, t0); + Multiply(t0, x, t0); + SquareN(t0, 141, t1); + Multiply(t1, t0, t1); + Square(t1, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat320.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs index 9181b8685..e02108f73 100644 --- a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT283FieldElement( - AbstractF2mCurve.Inverse(283, new int[] { 5, 7, 12 }, ToBigInteger())); + ulong[] z = Nat320.Create64(); + SecT283Field.Invert(x, z); + return new SecT283FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs index 42414401f..4053287ec 100644 --- a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs @@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(283, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 283; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 283; } diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs index d8c462eeb..e659675ce 100644 --- a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs @@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(283, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 283; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 283; } diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs index ce6f43f2e..84eada96e 100644 --- a/crypto/src/math/ec/custom/sec/SecT409Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs @@ -47,6 +47,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat448.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion with bases { 2, 3 } + + ulong[] t0 = Nat448.Create64(); + ulong[] t1 = Nat448.Create64(); + ulong[] t2 = Nat448.Create64(); + + Square(x, t0); + + // 3 | 408 + SquareN(t0, 1, t1); + Multiply(t0, t1, t0); + SquareN(t1, 1, t1); + Multiply(t0, t1, t0); + + // 2 | 136 + SquareN(t0, 3, t1); + Multiply(t0, t1, t0); + + // 2 | 68 + SquareN(t0, 6, t1); + Multiply(t0, t1, t0); + + // 2 | 34 + SquareN(t0, 12, t1); + Multiply(t0, t1, t2); + + // ! {2,3} | 17 + SquareN(t2, 24, t0); + SquareN(t0, 24, t1); + Multiply(t0, t1, t0); + + // 2 | 8 + SquareN(t0, 48, t1); + Multiply(t0, t1, t0); + + // 2 | 4 + SquareN(t0, 96, t1); + Multiply(t0, t1, t0); + + // 2 | 2 + SquareN(t0, 192, t1); + Multiply(t0, t1, t0); + + Multiply(t0, t2, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat448.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs index b60ceafee..581ea73df 100644 --- a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT409FieldElement( - AbstractF2mCurve.Inverse(409, new int[] { 87 }, ToBigInteger())); + ulong[] z = Nat448.Create64(); + SecT409Field.Invert(x, z); + return new SecT409FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs index edfe1a293..4f573553e 100644 --- a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs @@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(409, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 409; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 409; } diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs index e679094ad..9212fb5d2 100644 --- a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs @@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(409, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 409; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 409; } diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs index 921c841a9..fc84e336b 100644 --- a/crypto/src/math/ec/custom/sec/SecT571Field.cs +++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs @@ -59,6 +59,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec return z; } + public static void Invert(ulong[] x, ulong[] z) + { + if (Nat576.IsZero64(x)) + throw new InvalidOperationException(); + + // Itoh-Tsujii inversion with bases { 2, 3, 5 } + + ulong[] t0 = Nat576.Create64(); + ulong[] t1 = Nat576.Create64(); + ulong[] t2 = Nat576.Create64(); + + Square(x, t2); + + // 5 | 570 + Square(t2, t0); + Square(t0, t1); + Multiply(t0, t1, t0); + SquareN(t0, 2, t1); + Multiply(t0, t1, t0); + Multiply(t0, t2, t0); + + // 3 | 114 + SquareN(t0, 5, t1); + Multiply(t0, t1, t0); + SquareN(t1, 5, t1); + Multiply(t0, t1, t0); + + // 2 | 38 + SquareN(t0, 15, t1); + Multiply(t0, t1, t2); + + // ! {2,3,5} | 19 + SquareN(t2, 30, t0); + SquareN(t0, 30, t1); + Multiply(t0, t1, t0); + + // 3 | 9 + SquareN(t0, 60, t1); + Multiply(t0, t1, t0); + SquareN(t1, 60, t1); + Multiply(t0, t1, t0); + + // 3 | 3 + SquareN(t0, 180, t1); + Multiply(t0, t1, t0); + SquareN(t1, 180, t1); + Multiply(t0, t1, t0); + + Multiply(t0, t2, z); + } + public static void Multiply(ulong[] x, ulong[] y, ulong[] z) { ulong[] tt = Nat576.CreateExt64(); diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs index a26e1e336..5d5458412 100644 --- a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs +++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs @@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec public override ECFieldElement Invert() { - return new SecT571FieldElement( - AbstractF2mCurve.Inverse(571, new int[] { 2, 5, 10 }, ToBigInteger())); + ulong[] z = Nat576.Create64(); + SecT571Field.Invert(x, z); + return new SecT571FieldElement(z); } public override ECFieldElement Sqrt() diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs index fb136c967..f5806f09c 100644 --- a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs @@ -76,98 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return true; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - y = B.Sqrt(); - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - { - return beta; - } - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(571, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 571; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 571; } diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs index 05d58863e..082afa5bd 100644 --- a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs +++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs @@ -74,97 +74,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec get { return false; } } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement x = FromBigInteger(X1), y = null; - if (x.IsZero) - { - // y = B.Sqrt(); - y = SecT571R1_B_SQRT; - } - else - { - ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x); - ECFieldElement z = SolveQuadraticEquation(beta); - if (z != null) - { - if (z.TestBitZero() != (yTilde == 1)) - { - z = z.AddOne(); - } - - switch (this.CoordinateSystem) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - y = z.Add(x); - break; - } - default: - { - y = z.Multiply(x); - break; - } - } - } - } - - if (y == null) - throw new ArgumentException("Invalid point compression"); - - return this.CreateRawPoint(x, y, true); - } - - /** - * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 - * D.1.6) The other solution is <code>z + 1</code>. - * - * @param beta - * 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 SolveQuadraticEquation(ECFieldElement beta) - { - if (beta.IsZero) - return beta; - - ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = FromBigInteger(new BigInteger(571, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i < 571; i++) - { - ECFieldElement w2 = w.Square(); - z = z.Square().Add(w2.Multiply(t)); - w = w2.Add(beta); - } - if (!w.IsZero) - return null; - gamma = z.Square().Add(z); - } - while (gamma.IsZero); - - return z; - } - public virtual int M { get { return 571; } diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs index 9755c9d6f..a45ee1e08 100644 --- a/crypto/src/math/raw/Interleave.cs +++ b/crypto/src/math/raw/Interleave.cs @@ -4,67 +4,92 @@ namespace Org.BouncyCastle.Math.Raw { internal abstract class Interleave { + private const ulong M32 = 0x55555555UL; + private const ulong M64 = 0x5555555555555555UL; + /* * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. * In a binary field, this operation is the same as squaring an 8 bit number. */ - private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[] - { - 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, - 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, - 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, - 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, - 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, - 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, - 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, - 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, - 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, - 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, - 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, - 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, - 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, - 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, - 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, - 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, - 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, - 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, - 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, - 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, - 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, - 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, - 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, - 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, - 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, - 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, - 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, - 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, - 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, - 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, - 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, - 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 - }; + //private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[] + //{ + // 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, + // 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, + // 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, + // 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, + // 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, + // 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, + // 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, + // 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, + // 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, + // 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, + // 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, + // 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, + // 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, + // 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, + // 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, + // 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, + // 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, + // 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, + // 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, + // 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, + // 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, + // 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, + // 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, + // 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, + // 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, + // 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, + // 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, + // 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, + // 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, + // 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, + // 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, + // 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 + //}; internal static uint Expand8to16(uint x) { - return INTERLEAVE2_TABLE[x & 0xFF]; + x &= 0xFFU; + x = (x | (x << 4)) & 0x0F0FU; + x = (x | (x << 2)) & 0x3333U; + x = (x | (x << 1)) & 0x5555U; + return x; } internal static uint Expand16to32(uint x) { - return (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16); + x &= 0xFFFFU; + x = (x | (x << 8)) & 0x00FF00FFU; + x = (x | (x << 4)) & 0x0F0F0F0FU; + x = (x | (x << 2)) & 0x33333333U; + x = (x | (x << 1)) & 0x55555555U; + return x; } internal static ulong Expand32to64(uint x) { - uint r00 = (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16); - uint r32 = (uint)(INTERLEAVE2_TABLE[(x >> 16) & 0xFF] | INTERLEAVE2_TABLE[x >> 24] << 16); - return (ulong)r32 << 32 | (ulong)r00; + // "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 >> 1) & M32) << 32 | (x & M32); } internal static void Expand64To128(ulong x, ulong[] z, int zOff) { - z[zOff ] = Expand32to64((uint)x); - z[zOff + 1] = Expand32to64((uint)(x >> 32)); + // "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 ) & M64; + z[zOff + 1] = (x >> 1) & M64; } } } diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs index f46f99d37..2a2e63961 100644 --- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs +++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs @@ -3,10 +3,13 @@ using System.Collections; using System.Diagnostics; using System.IO; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -79,70 +82,133 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp : EncMethod { internal PgpPublicKey pubKey; - internal BigInteger[] data; + internal byte[][] data; - internal PubMethod( - PgpPublicKey pubKey) + internal PubMethod(PgpPublicKey pubKey) { this.pubKey = pubKey; } - public override void AddSessionInfo( - byte[] si, + public override void AddSessionInfo( + byte[] sessionInfo, SecureRandom random) { - IBufferedCipher c; + byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random); + + this.data = ProcessSessionInfo(encryptedSessionInfo); + } - switch (pubKey.Algorithm) + private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random) + { + if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH) { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); - break; - case PublicKeyAlgorithmTag.Dsa: - throw new PgpException("Can't use DSA for encryption."); - case PublicKeyAlgorithmTag.ECDsa: - throw new PgpException("Can't use ECDSA for encryption."); - default: - throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); + IBufferedCipher c; + switch (pubKey.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.Dsa: + throw new PgpException("Can't use DSA for encryption."); + case PublicKeyAlgorithmTag.ECDsa: + throw new PgpException("Can't use ECDSA for encryption."); + default: + throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); + } + + AsymmetricKeyParameter akp = pubKey.GetKey(); + c.Init(true, new ParametersWithRandom(akp, random)); + return c.DoFinal(sessionInfo); } - AsymmetricKeyParameter akp = pubKey.GetKey(); + ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key; + + // Generate the ephemeral key pair + IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH"); + gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random)); + + AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair(); + ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private; + ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public; + + ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey(); + ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize(); + + KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S)); + + IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm); + w.Init(true, new ParametersWithRandom(key, random)); + + byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo); + + byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length); + byte[] VB = new MPInteger(new BigInteger(1, ephPub.Q.GetEncoded(false))).GetEncoded(); - c.Init(true, new ParametersWithRandom(akp, random)); + byte[] rv = new byte[VB.Length + 1 + C.Length]; - byte[] encKey = c.DoFinal(si); + Array.Copy(VB, 0, rv, 0, VB.Length); + rv[VB.Length] = (byte)C.Length; + Array.Copy(C, 0, rv, VB.Length + 1, C.Length); - switch (pubKey.Algorithm) + return rv; + } + + private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo) + { + byte[][] data; + + switch (pubKey.Algorithm) { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - data = new BigInteger[]{ new BigInteger(1, encKey) }; - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - int halfLength = encKey.Length / 2; - data = new BigInteger[] - { - new BigInteger(1, encKey, 0, halfLength), - new BigInteger(1, encKey, halfLength, halfLength) - }; - break; - default: - throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm); + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + data = new byte[][] { ConvertToEncodedMpi(encryptedSessionInfo) }; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + int halfLength = encryptedSessionInfo.Length / 2; + byte[] b1 = new byte[halfLength]; + byte[] b2 = new byte[halfLength]; + + Array.Copy(encryptedSessionInfo, 0, b1, 0, halfLength); + Array.Copy(encryptedSessionInfo, halfLength, b2, 0, halfLength); + + data = new byte[][] { + ConvertToEncodedMpi(b1), + ConvertToEncodedMpi(b2), + }; + break; + case PublicKeyAlgorithmTag.ECDH: + data = new byte[][]{ encryptedSessionInfo }; + break; + default: + throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); } + + return data; } - public override void Encode(BcpgOutputStream pOut) + private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo) + { + try + { + return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded(); + } + catch (IOException e) + { + throw new PgpException("Invalid MPI encoding: " + e.Message, e); + } + } + + public override void Encode(BcpgOutputStream pOut) { - PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket( - pubKey.KeyId, pubKey.Algorithm, data); + PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data); - pOut.WritePacket(pk); + pOut.WritePacket(pk); } } diff --git a/crypto/src/openpgp/PgpKeyPair.cs b/crypto/src/openpgp/PgpKeyPair.cs index 6efb03a42..9cf78fa6f 100644 --- a/crypto/src/openpgp/PgpKeyPair.cs +++ b/crypto/src/openpgp/PgpKeyPair.cs @@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp DateTime time) { this.pub = new PgpPublicKey(algorithm, pubKey, time); - this.priv = new PgpPrivateKey(privKey, pub.KeyId); + this.priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey); } /// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary> diff --git a/crypto/src/openpgp/PgpPad.cs b/crypto/src/openpgp/PgpPad.cs new file mode 100644 index 000000000..48f7f2f44 --- /dev/null +++ b/crypto/src/openpgp/PgpPad.cs @@ -0,0 +1,45 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// <remarks>Padding functions.</remarks> + public sealed class PgpPad + { + private PgpPad() + { + } + + public static byte[] PadSessionData(byte[] sessionInfo) + { + byte[] result = new byte[40]; + + Array.Copy(sessionInfo, 0, result, 0, sessionInfo.Length); + + byte padValue = (byte)(result.Length - sessionInfo.Length); + + for (int i = sessionInfo.Length; i != result.Length; i++) + { + result[i] = padValue; + } + + return result; + } + + public static byte[] UnpadSessionData(byte[] encoded) + { + byte padValue = encoded[encoded.Length - 1]; + + for (int i = encoded.Length - padValue; i != encoded.Length; i++) + { + if (encoded[i] != padValue) + throw new PgpException("bad padding found in session data"); + } + + byte[] taggedKey = new byte[encoded.Length - padValue]; + + Array.Copy(encoded, 0, taggedKey, 0, taggedKey.Length); + + return taggedKey; + } + } +} diff --git a/crypto/src/openpgp/PgpPrivateKey.cs b/crypto/src/openpgp/PgpPrivateKey.cs index 154c87cd7..61487a5b2 100644 --- a/crypto/src/openpgp/PgpPrivateKey.cs +++ b/crypto/src/openpgp/PgpPrivateKey.cs @@ -7,33 +7,42 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks> public class PgpPrivateKey { - private readonly long keyId; + private readonly long keyID; + private readonly PublicKeyPacket publicKeyPacket; private readonly AsymmetricKeyParameter privateKey; - /// <summary> - /// Create a PgpPrivateKey from a regular private key and the ID of its - /// associated public key. + /// <summary> + /// Create a PgpPrivateKey from a keyID, the associated public data packet, and a regular private key. /// </summary> - /// <param name="privateKey">Private key to use.</param> - /// <param name="keyId">ID of the corresponding public key.</param> - public PgpPrivateKey( - AsymmetricKeyParameter privateKey, - long keyId) + /// <param name="keyID">ID of the corresponding public key.</param> + /// <param name="publicKeyPacket">the public key data packet to be associated with this private key.</param> + /// <param name="privateKey">the private key data packet to be associated with this private key.</param> + public PgpPrivateKey( + long keyID, + PublicKeyPacket publicKeyPacket, + AsymmetricKeyParameter privateKey) { if (!privateKey.IsPrivate) throw new ArgumentException("Expected a private key", "privateKey"); - this.privateKey = privateKey; - this.keyId = keyId; + this.keyID = keyID; + this.publicKeyPacket = publicKeyPacket; + this.privateKey = privateKey; } - /// <summary>The keyId associated with the contained private key.</summary> + /// <summary>The keyId associated with the contained private key.</summary> public long KeyId { - get { return keyId; } + get { return keyID; } } - /// <summary>The contained private key.</summary> + /// <summary>The public key packet associated with this private key, if available.</summary> + public PublicKeyPacket PublicKeyPacket + { + get { return publicKeyPacket; } + } + + /// <summary>The contained private key.</summary> public AsymmetricKeyParameter Key { get { return privateKey; } diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs index 5bde2c8fe..904e29913 100644 --- a/crypto/src/openpgp/PgpPublicKey.cs +++ b/crypto/src/openpgp/PgpPublicKey.cs @@ -2,10 +2,14 @@ using System; using System.Collections; using System.IO; +using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; @@ -15,6 +19,54 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <remarks>General class to handle a PGP public key object.</remarks> public class PgpPublicKey { + public static byte[] CalculateFingerprint(PublicKeyPacket publicPk) + { + IBcpgKey key = publicPk.Key; + IDigest digest; + + if (publicPk.Version <= 3) + { + RsaPublicBcpgKey rK = (RsaPublicBcpgKey)key; + + try + { + digest = DigestUtilities.GetDigest("MD5"); + UpdateDigest(digest, rK.Modulus); + UpdateDigest(digest, rK.PublicExponent); + } + catch (Exception e) + { + throw new PgpException("can't encode key components: " + e.Message, e); + } + } + else + { + try + { + byte[] kBytes = publicPk.GetEncodedContents(); + + digest = DigestUtilities.GetDigest("SHA1"); + + digest.Update(0x99); + digest.Update((byte)(kBytes.Length >> 8)); + digest.Update((byte)kBytes.Length); + digest.BlockUpdate(kBytes, 0, kBytes.Length); + } + catch (Exception e) + { + throw new PgpException("can't encode key components: " + e.Message, e); + } + } + + return DigestUtilities.DoFinal(digest); + } + + private static void UpdateDigest(IDigest d, BigInteger b) + { + byte[] bytes = b.ToByteArrayUnsigned(); + d.BlockUpdate(bytes, 0, bytes.Length); + } + private static readonly int[] MasterKeyCertificationTypes = new int[] { PgpSignature.PositiveCertification, @@ -39,51 +91,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { IBcpgKey key = publicPk.Key; + this.fingerprint = CalculateFingerprint(publicPk); + if (publicPk.Version <= 3) { RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key; this.keyId = rK.Modulus.LongValue; - - try - { - IDigest digest = DigestUtilities.GetDigest("MD5"); - - byte[] bytes = rK.Modulus.ToByteArrayUnsigned(); - digest.BlockUpdate(bytes, 0, bytes.Length); - - bytes = rK.PublicExponent.ToByteArrayUnsigned(); - digest.BlockUpdate(bytes, 0, bytes.Length); - - this.fingerprint = DigestUtilities.DoFinal(digest); - } - //catch (NoSuchAlgorithmException) - catch (Exception e) - { - throw new IOException("can't find MD5", e); - } - this.keyStrength = rK.Modulus.BitLength; } else { - byte[] kBytes = publicPk.GetEncodedContents(); - - try - { - IDigest digest = DigestUtilities.GetDigest("SHA1"); - - digest.Update(0x99); - digest.Update((byte)(kBytes.Length >> 8)); - digest.Update((byte)kBytes.Length); - digest.BlockUpdate(kBytes, 0, kBytes.Length); - this.fingerprint = DigestUtilities.DoFinal(digest); - } - catch (Exception e) - { - throw new IOException("can't find SHA1", e); - } - this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) | ((ulong)fingerprint[fingerprint.Length - 7] << 48) | ((ulong)fingerprint[fingerprint.Length - 6] << 40) @@ -107,7 +125,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } else if (key is ECPublicBcpgKey) { - this.keyStrength = ECNamedCurveTable.GetByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize; + this.keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize; } } } @@ -146,6 +164,23 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y); } + else if (pubKey is ECPublicKeyParameters) + { + ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey; + + if (algorithm == PublicKeyAlgorithmTag.ECDH) + { + bcpgKey = new ECDHPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128); + } + else if (algorithm == PublicKeyAlgorithmTag.ECDsa) + { + bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q); + } + else + { + throw new PgpException("unknown EC algorithm"); + } + } else if (pubKey is ElGamalPublicKeyParameters) { ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey; @@ -172,6 +207,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + public PgpPublicKey(PublicKeyPacket publicPk) + : this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList()) + { + } + /// <summary>Constructor for a sub-key.</summary> internal PgpPublicKey( PublicKeyPacket publicPk, @@ -426,14 +466,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaSign: - RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key; + RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key; return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); case PublicKeyAlgorithmTag.Dsa: - DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key; + DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key; return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); + case PublicKeyAlgorithmTag.ECDsa: + return GetECKey("ECDSA"); + case PublicKeyAlgorithmTag.ECDH: + return GetECKey("ECDH"); case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: - ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key; + ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key; return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); default: throw new PgpException("unknown public key algorithm encountered"); @@ -449,6 +493,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + private ECPublicKeyParameters GetECKey(string algorithm) + { + ECPublicBcpgKey ecK = (ECPublicBcpgKey)publicPk.Key; + X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(ecK.CurveOid); + ECPoint q = x9.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(ecK.EncodedPoint)); + return new ECPublicKeyParameters(algorithm, q, ecK.CurveOid); + } + /// <summary>Allows enumeration of any user IDs associated with the key.</summary> /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns> public IEnumerable GetUserIds() diff --git a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs index b6504cbcd..c2a351182 100644 --- a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs +++ b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs @@ -1,10 +1,13 @@ using System; using System.IO; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; @@ -77,22 +80,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm( PgpPrivateKey privKey) { - byte[] plain = fetchSymmetricKeyData(privKey); + byte[] sessionData = RecoverSessionData(privKey); - return (SymmetricKeyAlgorithmTag) plain[0]; + return (SymmetricKeyAlgorithmTag)sessionData[0]; } - /// <summary>Return the decrypted data stream for the packet.</summary> + /// <summary>Return the decrypted data stream for the packet.</summary> public Stream GetDataStream( PgpPrivateKey privKey) { - byte[] plain = fetchSymmetricKeyData(privKey); + byte[] sessionData = RecoverSessionData(privKey); - IBufferedCipher c2; - string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]); + if (!ConfirmCheckSum(sessionData)) + throw new PgpKeyValidationException("key checksum failed"); + + SymmetricKeyAlgorithmTag symmAlg = (SymmetricKeyAlgorithmTag)sessionData[0]; + if (symmAlg == SymmetricKeyAlgorithmTag.Null) + return encData.GetInputStream(); + + IBufferedCipher cipher; + string cipherName = PgpUtilities.GetSymmetricCipherName(symmAlg); string cName = cipherName; - try + try { if (encData is SymmetricEncIntegrityPacket) { @@ -103,7 +113,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp cName += "/OpenPGPCFB/NoPadding"; } - c2 = CipherUtilities.GetCipher(cName); + cipher = CipherUtilities.GetCipher(cName); } catch (PgpException e) { @@ -114,19 +124,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp throw new PgpException("exception creating cipher", e); } - if (c2 == null) - return encData.GetInputStream(); - - try + try { KeyParameter key = ParameterUtilities.CreateKeyParameter( - cipherName, plain, 1, plain.Length - 3); + cipherName, sessionData, 1, sessionData.Length - 3); - byte[] iv = new byte[c2.GetBlockSize()]; + byte[] iv = new byte[cipher.GetBlockSize()]; - c2.Init(false, new ParametersWithIV(key, iv)); + cipher.Init(false, new ParametersWithIV(key, iv)); - encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null)); + encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null)); if (encData is SymmetricEncIntegrityPacket) { @@ -178,75 +185,88 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private byte[] fetchSymmetricKeyData( - PgpPrivateKey privKey) + private byte[] RecoverSessionData(PgpPrivateKey privKey) { - IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm); + byte[][] secKeyData = keyData.GetEncSessionKey(); + + if (keyData.Algorithm == PublicKeyAlgorithmTag.ECDH) + { + ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key; + X9ECParameters x9Params = ECKeyPairGenerator.FindECCurveByOid(ecKey.CurveOid); + + byte[] enc = secKeyData[0]; + + int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8; + byte[] pEnc = new byte[pLen]; + + Array.Copy(enc, 2, pEnc, 0, pLen); + + byte[] keyEnc = new byte[enc[pLen + 2]]; + + Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length); + + ECPoint publicPoint = x9Params.Curve.DecodePoint(pEnc); + + ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters)privKey.Key; + ECPoint S = publicPoint.Multiply(privKeyParams.D).Normalize(); + + KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, S)); + + IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm); + w.Init(false, key); - try + return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length)); + } + + IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm); + + try { - c1.Init(false, privKey.Key); + cipher.Init(false, privKey.Key); } catch (InvalidKeyException e) { throw new PgpException("error setting asymmetric cipher", e); } - BigInteger[] keyD = keyData.GetEncSessionKey(); - - if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt + if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral) { - c1.ProcessBytes(keyD[0].ToByteArrayUnsigned()); + byte[] bi = secKeyData[0]; + + cipher.ProcessBytes(bi, 2, bi.Length - 2); } else { ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key; int size = (k.Parameters.P.BitLength + 7) / 8; - byte[] bi = keyD[0].ToByteArray(); - - int diff = bi.Length - size; - if (diff >= 0) - { - c1.ProcessBytes(bi, diff, size); - } - else - { - byte[] zeros = new byte[-diff]; - c1.ProcessBytes(zeros); - c1.ProcessBytes(bi); - } - - bi = keyD[1].ToByteArray(); - - diff = bi.Length - size; - if (diff >= 0) - { - c1.ProcessBytes(bi, diff, size); - } - else - { - byte[] zeros = new byte[-diff]; - c1.ProcessBytes(zeros); - c1.ProcessBytes(bi); - } + ProcessEncodedMpi(cipher, size, secKeyData[0]); + ProcessEncodedMpi(cipher, size, secKeyData[1]); } - byte[] plain; - try + try { - plain = c1.DoFinal(); + return cipher.DoFinal(); } catch (Exception e) { throw new PgpException("exception decrypting secret key", e); } - - if (!ConfirmCheckSum(plain)) - throw new PgpKeyValidationException("key checksum failed"); - - return plain; } + + private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc) + { + if (mpiEnc.Length - 2 > size) // leading Zero? Shouldn't happen but... + { + cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3); + } + else + { + byte[] tmp = new byte[size]; + Array.Copy(mpiEnc, 2, tmp, tmp.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2); + cipher.ProcessBytes(tmp, 0, tmp.Length); + } + } } } diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs index 872316dd7..980f9222b 100644 --- a/crypto/src/openpgp/PgpSecretKey.cs +++ b/crypto/src/openpgp/PgpSecretKey.cs @@ -2,8 +2,11 @@ using System; using System.Collections; using System.IO; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -59,6 +62,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key; secKey = new DsaSecretBcpgKey(dsK.X); break; + case PublicKeyAlgorithmTag.ECDH: + case PublicKeyAlgorithmTag.ECDsa: + ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key; + secKey = new ECSecretBcpgKey(ecK.D); + break; case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key; @@ -309,24 +317,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp private byte[] ExtractKeyData( char[] passPhrase) { - SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm; + SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm; byte[] encData = secret.GetSecretKeyData(); - if (alg == SymmetricKeyAlgorithmTag.Null) + if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) // TODO Check checksum here? return encData; - IBufferedCipher c = null; - try - { - string cName = PgpUtilities.GetSymmetricCipherName(alg); - c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); - } - catch (Exception e) - { - throw new PgpException("Exception creating cipher", e); - } - // TODO Factor this block out as 'decryptData' try { @@ -336,9 +333,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp if (secret.PublicKeyPacket.Version >= 4) { - c.Init(false, new ParametersWithIV(key, iv)); - - data = c.DoFinal(encData); + data = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, 0, encData.Length); bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2); @@ -364,15 +359,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp for (int i = 0; i != 4; i++) { - c.Init(false, new ParametersWithIV(key, iv)); - int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; pos += 2; - c.DoFinal(encData, pos, encLen, data, pos); + byte[] tmp = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, pos, encLen); + Array.Copy(tmp, 0, data, pos, encLen); pos += encLen; if (i != 3) @@ -416,6 +410,25 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding, + KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen) + { + IBufferedCipher c; + try + { + string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); + c = CipherUtilities.GetCipher(cName + modeAndPadding); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + + c.Init(false, new ParametersWithIV(key, iv)); + + return c.DoFinal(keyData, keyOff, keyLen); + } + /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary> public PgpPrivateKey ExtractPrivateKey( char[] passPhrase) @@ -453,6 +466,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G); privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); break; + case PublicKeyAlgorithmTag.ECDH: + privateKey = GetECKey("ECDH", bcpgIn); + break; + case PublicKeyAlgorithmTag.ECDsa: + privateKey = GetECKey("ECDSA", bcpgIn); + break; case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; @@ -464,7 +483,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp throw new PgpException("unknown public key algorithm encountered"); } - return new PgpPrivateKey(privateKey, KeyId); + return new PgpPrivateKey(KeyId, pubPk, privateKey); } catch (PgpException e) { @@ -476,6 +495,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn) + { + ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key; + ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn); + return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid); + } + private static byte[] Checksum( bool useSha1, byte[] bytes, @@ -698,5 +724,174 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return c.DoFinal(rawKeyData); } + + /** + * Parse a secret key from one of the GPG S expression keys associating it with the passed in public key. + * + * @return a secret key object. + */ + public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (type.Equals("protected-private-key")) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string curveName; + + string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (keyType.Equals("ecc")) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + + SXprUtilities.SkipCloseParenthesis(inputStream); + } + else + { + throw new PgpException("no curve details found"); + } + + byte[] qVal; + + SXprUtilities.SkipOpenParenthesis(inputStream); + + type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (type.Equals("q")) + { + qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); + } + else + { + throw new PgpException("no q value found"); + } + + SXprUtilities.SkipCloseParenthesis(inputStream); + + byte[] dValue = GetDValue(inputStream, passPhrase, curveName); + // TODO: check SHA-1 hash. + + return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, + new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey); + } + + throw new PgpException("unknown key type found"); + } + + /** + * Parse a secret key from one of the GPG S expression keys. + * + * @return a secret key object. + */ + public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (type.Equals("protected-private-key")) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string curveName; + + string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (keyType.Equals("ecc")) + { + SXprUtilities.SkipOpenParenthesis(inputStream); + + string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + + if (curveName.StartsWith("NIST ")) + { + curveName = curveName.Substring("NIST ".Length); + } + + SXprUtilities.SkipCloseParenthesis(inputStream); + } + else + { + throw new PgpException("no curve details found"); + } + + byte[] qVal; + + SXprUtilities.SkipOpenParenthesis(inputStream); + + type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (type.Equals("q")) + { + qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); + } + else + { + throw new PgpException("no q value found"); + } + + PublicKeyPacket pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow, + new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(curveName), new BigInteger(1, qVal))); + + SXprUtilities.SkipCloseParenthesis(inputStream); + + byte[] dValue = GetDValue(inputStream, passPhrase, curveName); + // TODO: check SHA-1 hash. + + return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null, + new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(pubPacket)); + } + + throw new PgpException("unknown key type found"); + } + + private static byte[] GetDValue(Stream inputStream, char[] passPhrase, string curveName) + { + string type; + SXprUtilities.SkipOpenParenthesis(inputStream); + + string protection; + S2k s2k; + byte[] iv; + byte[] secKeyData; + + type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + if (type.Equals("protected")) + { + protection = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); + + SXprUtilities.SkipOpenParenthesis(inputStream); + + s2k = SXprUtilities.ParseS2k(inputStream); + + iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); + + SXprUtilities.SkipCloseParenthesis(inputStream); + + secKeyData = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); + } + else + { + throw new PgpException("protected block not found"); + } + + // TODO: recognise other algorithms + KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, passPhrase); + + byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, secKeyData, 0, secKeyData.Length); + + // + // parse the secret key S-expr + // + Stream keyIn = new MemoryStream(data, false); + + SXprUtilities.SkipOpenParenthesis(keyIn); + SXprUtilities.SkipOpenParenthesis(keyIn); + SXprUtilities.SkipOpenParenthesis(keyIn); + String name = SXprUtilities.ReadString(keyIn, keyIn.ReadByte()); + return SXprUtilities.ReadBytes(keyIn, keyIn.ReadByte()); + } } } diff --git a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs index 4adf64012..d2177d09c 100644 --- a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs +++ b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs @@ -25,7 +25,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp list.Add(new Exportable(isCritical, isExportable)); } - /// <summary> + public void SetFeature( + bool isCritical, + byte feature) + { + list.Add(new Features(isCritical, feature)); + } + + /// <summary> /// Add a TrustSignature packet to the signature. The values for depth and trust are largely /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13. /// </summary> @@ -117,7 +124,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp list.Add(new SignerUserId(isCritical, userId)); } - public void SetEmbeddedSignature( + public void SetSignerUserId( + bool isCritical, + byte[] rawUserId) + { + if (rawUserId == null) + throw new ArgumentNullException("rawUserId"); + + list.Add(new SignerUserId(isCritical, false, rawUserId)); + } + + public void SetEmbeddedSignature( bool isCritical, PgpSignature pgpSignature) { @@ -136,7 +153,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length); - list.Add(new EmbeddedSignature(isCritical, data)); + list.Add(new EmbeddedSignature(isCritical, false, data)); } public void SetPrimaryUserId( diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs index 68fe4b594..156243f4e 100644 --- a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs +++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs @@ -209,7 +209,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return list; } - [Obsolete("Use 'Count' property instead")] + public Features GetFeatures() + { + SignatureSubpacket p = this.GetSubpacket(SignatureSubpacketTag.Features); + + if (p == null) + return null; + + return new Features(p.IsCritical(), p.IsLongLength(), p.GetData()); + } + + [Obsolete("Use 'Count' property instead")] public int Size { get { return packets.Length; } diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs index cd53cc029..89c85a5f7 100644 --- a/crypto/src/openpgp/PgpUtilities.cs +++ b/crypto/src/openpgp/PgpUtilities.cs @@ -86,7 +86,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp case PublicKeyAlgorithmTag.Dsa: encAlg = "DSA"; break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases. + case PublicKeyAlgorithmTag.ECDH: + encAlg = "ECDH"; + break; + case PublicKeyAlgorithmTag.ECDsa: + encAlg = "ECDSA"; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases. case PublicKeyAlgorithmTag.ElGamalGeneral: encAlg = "ElGamal"; break; @@ -135,7 +141,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm) + public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm) { int keySize; switch (algorithm) @@ -193,7 +199,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp char[] passPhrase) { int keySize = GetKeySize(algorithm); - byte[] pBytes = Strings.ToByteArray(new string(passPhrase)); + byte[] pBytes = Encoding.UTF8.GetBytes(passPhrase); byte[] keyBytes = new byte[(keySize + 7) / 8]; int generatedBytes = 0; @@ -433,5 +439,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return new ArmoredInputStream(inputStream, hasHeaders); } } + + internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm) + { + switch (encAlgorithm) + { + case SymmetricKeyAlgorithmTag.Aes128: + case SymmetricKeyAlgorithmTag.Aes192: + case SymmetricKeyAlgorithmTag.Aes256: + return WrapperUtilities.GetWrapper("AESWRAP"); + case SymmetricKeyAlgorithmTag.Camellia128: + case SymmetricKeyAlgorithmTag.Camellia192: + case SymmetricKeyAlgorithmTag.Camellia256: + return WrapperUtilities.GetWrapper("CAMELLIAWRAP"); + default: + throw new PgpException("unknown wrap algorithm: " + encAlgorithm); + } + } } } diff --git a/crypto/src/openpgp/Rfc6637Utilities.cs b/crypto/src/openpgp/Rfc6637Utilities.cs new file mode 100644 index 000000000..5d992ec51 --- /dev/null +++ b/crypto/src/openpgp/Rfc6637Utilities.cs @@ -0,0 +1,138 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public sealed class Rfc6637Utilities + { + private Rfc6637Utilities() + { + } + + // "Anonymous Sender ", which is the octet sequence + private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020"); + + public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData) + { + ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key; + + switch (ecKey.HashAlgorithm) + { + case HashAlgorithmTag.Sha256: + return "ECCDHwithSHA256CKDF"; + case HashAlgorithmTag.Sha384: + return "ECCDHwithSHA384CKDF"; + case HashAlgorithmTag.Sha512: + return "ECCDHwithSHA512CKDF"; + default: + throw new ArgumentException("Unknown hash algorithm specified: " + ecKey.HashAlgorithm); + } + } + + public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID) + { + switch (algID) + { + case SymmetricKeyAlgorithmTag.Aes128: + return NistObjectIdentifiers.IdAes128Wrap; + case SymmetricKeyAlgorithmTag.Aes192: + return NistObjectIdentifiers.IdAes192Wrap; + case SymmetricKeyAlgorithmTag.Aes256: + return NistObjectIdentifiers.IdAes256Wrap; + default: + throw new PgpException("unknown symmetric algorithm ID: " + algID); + } + } + + public static int GetKeyLength(SymmetricKeyAlgorithmTag algID) + { + switch (algID) + { + case SymmetricKeyAlgorithmTag.Aes128: + return 16; + case SymmetricKeyAlgorithmTag.Aes192: + return 24; + case SymmetricKeyAlgorithmTag.Aes256: + return 32; + default: + throw new PgpException("unknown symmetric algorithm ID: " + algID); + } + } + + public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s) + { + byte[] userKeyingMaterial = CreateUserKeyingMaterial(pubKeyData); + + ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key; + + return Kdf(ecKey.HashAlgorithm, s, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial); + } + + // RFC 6637 - Section 8 + // curve_OID_len = (byte)len(curve_OID); + // Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 + // || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous + // Sender " || recipient_fingerprint; + // Z_len = the key size for the KEK_alg_ID used with AESKeyWrap + // Compute Z = KDF( S, Z_len, Param ); + public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData) + { + MemoryStream pOut = new MemoryStream(); + ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key; + byte[] encOid = ecKey.CurveOid.GetEncoded(); + + pOut.Write(encOid, 1, encOid.Length - 1); + pOut.WriteByte((byte)pubKeyData.Algorithm); + pOut.WriteByte(0x03); + pOut.WriteByte(0x01); + pOut.WriteByte((byte)ecKey.HashAlgorithm); + pOut.WriteByte((byte)ecKey.SymmetricKeyAlgorithm); + pOut.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length); + + byte[] fingerprint = PgpPublicKey.CalculateFingerprint(pubKeyData); + pOut.Write(fingerprint, 0, fingerprint.Length); + + return pOut.ToArray(); + } + + // RFC 6637 - Section 7 + // Implements KDF( X, oBits, Param ); + // Input: point X = (x,y) + // oBits - the desired size of output + // hBits - the size of output of hash function Hash + // Param - octets representing the parameters + // Assumes that oBits <= hBits + // Convert the point X to the octet string, see section 6: + // ZB' = 04 || x || y + // and extract the x portion from ZB' + // ZB = x; + // MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param ); + // return oBits leftmost bits of MB. + private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters) + { + byte[] ZB = s.XCoord.GetEncoded(); + + string digestName = PgpUtilities.GetDigestName(digestAlg); + IDigest digest = DigestUtilities.GetDigest(digestName); + + digest.Update(0x00); + digest.Update(0x00); + digest.Update(0x00); + digest.Update(0x01); + digest.BlockUpdate(ZB, 0, ZB.Length); + digest.BlockUpdate(parameters, 0, parameters.Length); + + byte[] hash = DigestUtilities.DoFinal(digest); + + return Arrays.CopyOfRange(hash, 0, keyLen); + } + } +} diff --git a/crypto/src/openpgp/SXprUtilities.cs b/crypto/src/openpgp/SXprUtilities.cs new file mode 100644 index 000000000..68ff373a8 --- /dev/null +++ b/crypto/src/openpgp/SXprUtilities.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /** + * Utility functions for looking a S-expression keys. This class will move when it finds a better home! + * <p> + * Format documented here: + * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master + * </p> + */ + public sealed class SXprUtilities + { + private SXprUtilities() + { + } + + private static int ReadLength(Stream input, int ch) + { + int len = ch - '0'; + + while ((ch = input.ReadByte()) >= 0 && ch != ':') + { + len = len * 10 + ch - '0'; + } + + return len; + } + + internal static string ReadString(Stream input, int ch) + { + int len = ReadLength(input, ch); + + char[] chars = new char[len]; + + for (int i = 0; i != chars.Length; i++) + { + chars[i] = (char)input.ReadByte(); + } + + return new string(chars); + } + + internal static byte[] ReadBytes(Stream input, int ch) + { + int len = ReadLength(input, ch); + + byte[] data = new byte[len]; + + Streams.ReadFully(input, data); + + return data; + } + + internal static S2k ParseS2k(Stream input) + { + SkipOpenParenthesis(input); + + string alg = ReadString(input, input.ReadByte()); + byte[] iv = ReadBytes(input, input.ReadByte()); + long iterationCount = Int64.Parse(ReadString(input, input.ReadByte())); + + SkipCloseParenthesis(input); + + // we have to return the actual iteration count provided. + return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount); + } + + internal static void SkipOpenParenthesis(Stream input) + { + int ch = input.ReadByte(); + if (ch != '(') + throw new IOException("unknown character encountered"); + } + + internal static void SkipCloseParenthesis(Stream input) + { + int ch = input.ReadByte(); + if (ch != ')') + throw new IOException("unknown character encountered"); + } + + private class MyS2k : S2k + { + private readonly long mIterationCount64; + + internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64) + : base(algorithm, iv, (int)iterationCount64) + { + this.mIterationCount64 = iterationCount64; + } + + public override long IterationCount + { + get { return mIterationCount64; } + } + } + } +} diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs index e57797427..60a1fbb0b 100644 --- a/crypto/src/openpgp/WrappedGeneratorStream.cs +++ b/crypto/src/openpgp/WrappedGeneratorStream.cs @@ -1,6 +1,6 @@ using System.IO; -using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Bcpg.OpenPgp { diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs index 8c19fe601..ec5d1b414 100644 --- a/crypto/src/openssl/PEMReader.cs +++ b/crypto/src/openssl/PEMReader.cs @@ -109,6 +109,7 @@ namespace Org.BouncyCastle.OpenSsl case "X509 CERTIFICATE": return ReadCertificate(obj); case "PKCS7": + case "CMS": return ReadPkcs7(obj); case "X509 CRL": return ReadCrl(obj); diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs index 9f24eb18a..e32510aaa 100644 --- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs +++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs @@ -15,6 +15,7 @@ using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.Pkcs { @@ -198,17 +199,18 @@ namespace Org.BouncyCastle.Pkcs Stream input) : base((Asn1Sequence) Asn1Object.FromStream(input)) { - } - - /// <summary> - /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials. - /// </summary> - ///<param name="signatureAlgorithm">Name of Sig Alg.</param> - /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param> - /// <param name="publicKey">Public Key to be included in cert reqest.</param> - /// <param name="attributes">ASN1Set of Attributes.</param> - /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param> - public Pkcs10CertificationRequest( + } + + /// <summary> + /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials. + /// </summary> + ///<param name="signatureAlgorithm">Name of Sig Alg.</param> + /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param> + /// <param name="publicKey">Public Key to be included in cert reqest.</param> + /// <param name="attributes">ASN1Set of Attributes.</param> + /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param> + [Obsolete("Use constructor with an ISignatureCalculator")] + public Pkcs10CertificationRequest( string signatureAlgorithm, X509Name subject, AsymmetricKeyParameter publicKey, @@ -226,79 +228,84 @@ namespace Org.BouncyCastle.Pkcs if (!signingKey.IsPrivate) throw new ArgumentException("key for signing must be private", "signingKey"); -// DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm); - string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm); - DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName]; - - if (sigOid == null) - { - try - { - sigOid = new DerObjectIdentifier(algorithmName); - } - catch (Exception e) - { - throw new ArgumentException("Unknown signature type requested", e); - } - } - - if (noParams.Contains(sigOid)) - { - this.sigAlgId = new AlgorithmIdentifier(sigOid); - } - else if (exParams.Contains(algorithmName)) - { - this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]); - } - else - { - this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance); - } - - SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); - - this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes); - - ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm); - - sig.Init(true, signingKey); - - try - { - // Encode. - byte[] b = reqInfo.GetDerEncoded(); - sig.BlockUpdate(b, 0, b.Length); - } - catch (Exception e) - { - throw new ArgumentException("exception encoding TBS cert request", e); - } - - // Generate Signature. - sigBits = new DerBitString(sig.GenerateSignature()); + init(new Asn1SignatureCalculator(signatureAlgorithm, signingKey), subject, publicKey, attributes, signingKey); } -// internal Pkcs10CertificationRequest( -// Asn1InputStream seqStream) -// { -// Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject(); -// try -// { -// this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]); -// this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]); -// this.sigBits = (DerBitString) seq[2]; -// } -// catch (Exception ex) -// { -// throw new ArgumentException("Create From Asn1Sequence: " + ex.Message); -// } -// } - - /// <summary> - /// Get the public key. - /// </summary> - /// <returns>The public key.</returns> - public AsymmetricKeyParameter GetPublicKey() + /// <summary> + /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials. + /// </summary> + ///<param name="signatureCalculator">The signature calculator to sign the PKCS#10 request with.</param> + /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param> + /// <param name="publicKey">Public Key to be included in cert reqest.</param> + /// <param name="attributes">ASN1Set of Attributes.</param> + /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param> + public Pkcs10CertificationRequest( + ISignatureCalculator signatureCalculator, + X509Name subject, + AsymmetricKeyParameter publicKey, + Asn1Set attributes, + AsymmetricKeyParameter signingKey) + { + if (signatureCalculator == null) + throw new ArgumentNullException("signatureCalculator"); + if (subject == null) + throw new ArgumentNullException("subject"); + if (publicKey == null) + throw new ArgumentNullException("publicKey"); + if (publicKey.IsPrivate) + throw new ArgumentException("expected public key", "publicKey"); + if (!signingKey.IsPrivate) + throw new ArgumentException("key for signing must be private", "signingKey"); + + init(signatureCalculator, subject, publicKey, attributes, signingKey); + } + + private void init( + ISignatureCalculator signatureCalculator, + X509Name subject, + AsymmetricKeyParameter publicKey, + Asn1Set attributes, + AsymmetricKeyParameter signingKey) + { + this.sigAlgId = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails; + + SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); + + this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes); + + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); + + byte[] reqInfoData = reqInfo.GetDerEncoded(); + + streamCalculator.Stream.Write(reqInfoData, 0, reqInfoData.Length); + + streamCalculator.Stream.Dispose(); + + // Generate Signature. + sigBits = new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal()); + } + + // internal Pkcs10CertificationRequest( + // Asn1InputStream seqStream) + // { + // Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject(); + // try + // { + // this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]); + // this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]); + // this.sigBits = (DerBitString) seq[2]; + // } + // catch (Exception ex) + // { + // throw new ArgumentException("Create From Asn1Sequence: " + ex.Message); + // } + // } + + /// <summary> + /// Get the public key. + /// </summary> + /// <returns>The public key.</returns> + public AsymmetricKeyParameter GetPublicKey() { return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo); } @@ -315,55 +322,47 @@ namespace Org.BouncyCastle.Pkcs public bool Verify( AsymmetricKeyParameter publicKey) { - ISigner sig; - - try - { - sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId)); - } - catch (Exception e) - { - // try an alternate - string alt = (string) oids[sigAlgId.ObjectID]; - - if (alt != null) - { - sig = SignerUtilities.GetSigner(alt); - } - else - { - throw e; - } - } - - SetSignatureParameters(sig, sigAlgId.Parameters); - - sig.Init(false, publicKey); - - try - { - byte[] b = reqInfo.GetDerEncoded(); - sig.BlockUpdate(b, 0, b.Length); - } - catch (Exception e) - { - throw new SignatureException("exception encoding TBS cert request", e); - } - - return sig.VerifySignature(sigBits.GetBytes()); + return Verify(new Asn1SignatureVerifierProvider(publicKey)); } -// /// <summary> -// /// Get the Der Encoded Pkcs10 Certification Request. -// /// </summary> -// /// <returns>A byte array.</returns> -// public byte[] GetEncoded() -// { -// return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded(); -// } - - // TODO Figure out how to set parameters on an ISigner - private void SetSignatureParameters( + public bool Verify( + ISignatureVerifierProvider verifierProvider) + { + return Verify(verifierProvider.CreateSignatureVerifier(sigAlgId)); + } + + public bool Verify( + ISignatureVerifier verifier) + { + try + { + byte[] b = reqInfo.GetDerEncoded(); + + IStreamCalculator streamCalculator = verifier.CreateCalculator(); + + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Dispose(); + + return ((IVerifier)streamCalculator.GetResult()).IsVerified(sigBits.GetBytes()); + } + catch (Exception e) + { + throw new SignatureException("exception encoding TBS cert request", e); + } + } + + // /// <summary> + // /// Get the Der Encoded Pkcs10 Certification Request. + // /// </summary> + // /// <returns>A byte array.</returns> + // public byte[] GetEncoded() + // { + // return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded(); + // } + + // TODO Figure out how to set parameters on an ISigner + private void SetSignatureParameters( ISigner signature, Asn1Encodable asn1Params) { diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs index 4c61ac354..12d427c8c 100644 --- a/crypto/src/security/AgreementUtilities.cs +++ b/crypto/src/security/AgreementUtilities.cs @@ -22,14 +22,14 @@ namespace Org.BouncyCastle.Security private static readonly IDictionary algorithms = Platform.CreateHashtable(); //private static readonly IDictionary oids = Platform.CreateHashtable(); - static AgreementUtilities() + static AgreementUtilities() { - //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?; + algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF"; algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF"; algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF"; } - public static IBasicAgreement GetBasicAgreement( + public static IBasicAgreement GetBasicAgreement( DerObjectIdentifier oid) { return GetBasicAgreement(oid.Id); @@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Security if (mechanism == "ECDH") return new ECDHBasicAgreement(); - if (mechanism == "ECDHC") - return new ECDHCBasicAgreement(); + if (mechanism == "ECDHC" || mechanism == "ECCDH") + return new ECDHCBasicAgreement(); if (mechanism == "ECMQV") return new ECMqvBasicAgreement(); diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs index ec3f63940..7ddf6c8e4 100644 --- a/crypto/src/security/DigestUtilities.cs +++ b/crypto/src/security/DigestUtilities.cs @@ -21,11 +21,13 @@ namespace Org.BouncyCastle.Security { private enum DigestAlgorithm { GOST3411, + KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512, MD2, MD4, MD5, RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320, SHA_1, SHA_224, SHA_256, SHA_384, SHA_512, SHA_512_224, SHA_512_256, SHA3_224, SHA3_256, SHA3_384, SHA3_512, + SHAKE128, SHAKE256, TIGER, WHIRLPOOL, }; @@ -72,7 +74,12 @@ namespace Org.BouncyCastle.Security algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411"; - + algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224"; + algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256"; + algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384"; + algorithms[NistObjectIdentifiers.IdSha3_512.Id] = "SHA3-512"; + algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128"; + algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256"; oids["MD2"] = PkcsObjectIdentifiers.MD2; oids["MD4"] = PkcsObjectIdentifiers.MD4; @@ -84,6 +91,12 @@ namespace Org.BouncyCastle.Security oids["SHA-512"] = NistObjectIdentifiers.IdSha512; oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224; oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256; + oids["SHA3-224"] = NistObjectIdentifiers.IdSha3_224; + oids["SHA3-256"] = NistObjectIdentifiers.IdSha3_256; + oids["SHA3-384"] = NistObjectIdentifiers.IdSha3_384; + oids["SHA3-512"] = NistObjectIdentifiers.IdSha3_512; + oids["SHAKE128"] = NistObjectIdentifiers.IdShake128; + oids["SHAKE256"] = NistObjectIdentifiers.IdShake256; oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128; oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160; oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256; @@ -141,7 +154,12 @@ namespace Org.BouncyCastle.Security switch (digestAlgorithm) { case DigestAlgorithm.GOST3411: return new Gost3411Digest(); - case DigestAlgorithm.MD2: return new MD2Digest(); + 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(); @@ -159,6 +177,8 @@ namespace Org.BouncyCastle.Security 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(); } diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs index dc91069a1..4745c0bae 100644 --- a/crypto/src/security/SecureRandom.cs +++ b/crypto/src/security/SecureRandom.cs @@ -13,12 +13,16 @@ namespace Org.BouncyCastle.Security { private static long counter = Times.NanoTime(); +#if NETCF_1_0 || PCL + private static object counterLock = new object(); private static long NextCounterValue() { - return Interlocked.Increment(ref counter); + lock (counterLock) + { + return ++counter; + } } -#if NETCF_1_0 || PCL private static readonly SecureRandom[] master = { null }; private static SecureRandom Master { @@ -43,6 +47,11 @@ namespace Org.BouncyCastle.Security } } #else + private static long NextCounterValue() + { + return Interlocked.Increment(ref counter); + } + private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator()); private static SecureRandom Master { diff --git a/crypto/src/util/io/FilterStream.cs b/crypto/src/util/io/FilterStream.cs new file mode 100644 index 000000000..1aa1f9889 --- /dev/null +++ b/crypto/src/util/io/FilterStream.cs @@ -0,0 +1,70 @@ +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO +{ + public class FilterStream : Stream + { + public FilterStream(Stream s) + { + this.s = s; + } + public override bool CanRead + { + get { return s.CanRead; } + } + public override bool CanSeek + { + get { return s.CanSeek; } + } + public override bool CanWrite + { + get { return s.CanWrite; } + } + public override long Length + { + get { return s.Length; } + } + public override long Position + { + get { return s.Position; } + set { s.Position = value; } + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + s.Dispose(); + } + base.Dispose(disposing); + } + public override void Flush() + { + s.Flush(); + } + public override long Seek(long offset, SeekOrigin origin) + { + return s.Seek(offset, origin); + } + public override void SetLength(long value) + { + s.SetLength(value); + } + public override int Read(byte[] buffer, int offset, int count) + { + return s.Read(buffer, offset, count); + } + public override int ReadByte() + { + return s.ReadByte(); + } + public override void Write(byte[] buffer, int offset, int count) + { + s.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + s.WriteByte(value); + } + protected readonly Stream s; + } +} diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs index f156f3147..415130044 100644 --- a/crypto/src/x509/X509Certificate.cs +++ b/crypto/src/x509/X509Certificate.cs @@ -14,6 +14,7 @@ using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.X509.Extension; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -546,30 +547,38 @@ namespace Org.BouncyCastle.X509 public virtual void Verify( AsymmetricKeyParameter key) { - string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm); - ISigner signature = SignerUtilities.GetSigner(sigName); - - CheckSignature(key, signature); + CheckSignature(new Asn1SignatureVerifier(c.SignatureAlgorithm, key)); } - protected virtual void CheckSignature( - AsymmetricKeyParameter publicKey, - ISigner signature) + /// <summary> + /// Verify the certificate's signature using a verifier created using the passed in verifier provider. + /// </summary> + /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param> + /// <returns>True if the signature is valid.</returns> + /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception> + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier (c.SignatureAlgorithm)); + } + + protected virtual void CheckSignature( + ISignatureVerifier verifier) { if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature)) throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; - X509SignatureUtilities.SetSignatureParameters(signature, parameters); - - signature.Init(false, publicKey); + IStreamCalculator streamCalculator = verifier.CreateCalculator(); byte[] b = this.GetTbsCertificate(); - signature.BlockUpdate(b, 0, b.Length); - byte[] sig = this.GetSignature(); - if (!signature.VerifySignature(sig)) + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Dispose(); + + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) { throw new InvalidKeyException("Public key presented not for certificate signature"); } diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs index 7d0e7aa72..c7740781e 100644 --- a/crypto/src/x509/X509Crl.cs +++ b/crypto/src/x509/X509Crl.cs @@ -14,6 +14,7 @@ using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.X509.Extension; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -83,24 +84,46 @@ namespace Org.BouncyCastle.X509 public virtual void Verify( AsymmetricKeyParameter publicKey) { - if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature)) - { - throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList."); - } + Verify(new Asn1SignatureVerifierProvider(publicKey)); + } - ISigner sig = SignerUtilities.GetSigner(SigAlgName); - sig.Init(false, publicKey); + /// <summary> + /// Verify the CRL's signature using a verifier created using the passed in verifier provider. + /// </summary> + /// <param name="verifierProvider">An appropriate provider for verifying the CRL's signature.</param> + /// <returns>True if the signature is valid.</returns> + /// <exception cref="Exception">If verifier provider is not appropriate or the CRL algorithm is invalid.</exception> + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier(c.SignatureAlgorithm)); + } - byte[] encoded = this.GetTbsCertList(); - sig.BlockUpdate(encoded, 0, encoded.Length); + protected virtual void CheckSignature( + ISignatureVerifier verifier) + { + if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature)) + { + throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList."); + } - if (!sig.VerifySignature(this.GetSignature())) - { - throw new SignatureException("CRL does not verify with supplied public key."); - } - } + Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; + + IStreamCalculator streamCalculator = verifier.CreateCalculator(); + + byte[] b = this.GetTbsCertList(); + + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Dispose(); + + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) + { + throw new InvalidKeyException("CRL does not verify with supplied public key."); + } + } - public virtual int Version + public virtual int Version { get { return c.Version; } } diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs index 02b58a198..354b91b8d 100644 --- a/crypto/src/x509/X509V1CertificateGenerator.cs +++ b/crypto/src/x509/X509V1CertificateGenerator.cs @@ -1,10 +1,12 @@ using System; +using System.IO; using System.Collections; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Operators; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; @@ -119,6 +121,7 @@ namespace Org.BouncyCastle.X509 /// This can be either a name or an OID, names are treated as case insensitive. /// </summary> /// <param name="signatureAlgorithm">string representation of the algorithm name</param> + [Obsolete("Not needed if Generate used with an ISignatureCalculator")] public void SetSignatureAlgorithm( string signatureAlgorithm) { @@ -143,6 +146,7 @@ namespace Org.BouncyCastle.X509 /// </summary> /// <param name="privateKey">The private key of the issuer used to sign this certificate.</param> /// <returns>An X509Certificate.</returns> + [Obsolete("Use Generate with an ISignatureCalculator")] public X509Certificate Generate( AsymmetricKeyParameter privateKey) { @@ -155,43 +159,43 @@ namespace Org.BouncyCastle.X509 /// <param name="privateKey">The private key of the issuer used to sign this certificate.</param> /// <param name="random">The Secure Random you want to use.</param> /// <returns>An X509Certificate.</returns> + [Obsolete("Use Generate with an ISignatureCalculator")] public X509Certificate Generate( AsymmetricKeyParameter privateKey, SecureRandom random) { + return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random)); + } + + /// <summary> + /// Generate a new X509Certificate using the passed in SignatureCalculator. + /// </summary> + /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param> + /// <returns>An X509Certificate.</returns> + public X509Certificate Generate(ISignatureCalculator signatureCalculator) + { + tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails); + TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); - byte[] signature; - try - { - signature = X509Utilities.GetSignatureForObject( - sigOID, signatureAlgorithm, privateKey, random, tbsCert); - } - catch (Exception e) - { - // TODO -// throw new ExtCertificateEncodingException("exception encoding TBS cert", e); - throw new CertificateEncodingException("exception encoding TBS cert", e); - } + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); - try - { - return GenerateJcaObject(tbsCert, signature); - } - catch (CertificateParsingException e) - { - // TODO - // throw new ExtCertificateEncodingException("exception producing certificate object", e); - throw new CertificateEncodingException("exception producing certificate object", e); - } + byte[] encoded = tbsCert.GetDerEncoded(); + + streamCalculator.Stream.Write(encoded, 0, encoded.Length); + + streamCalculator.Stream.Dispose(); + + return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); } private X509Certificate GenerateJcaObject( TbsCertificateStructure tbsCert, + AlgorithmIdentifier sigAlg, byte[] signature) { return new X509Certificate( - new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature))); + new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature))); } /// <summary> diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs index 117ac4cc2..56a7fc7a7 100644 --- a/crypto/src/x509/X509V2AttributeCertificate.cs +++ b/crypto/src/x509/X509V2AttributeCertificate.cs @@ -9,6 +9,7 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -151,29 +152,48 @@ namespace Org.BouncyCastle.X509 return cert.SignatureValue.GetBytes(); } - public virtual void Verify( - AsymmetricKeyParameter publicKey) - { - if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature)) + public virtual void Verify( + AsymmetricKeyParameter key) + { + CheckSignature(new Asn1SignatureVerifier(cert.SignatureAlgorithm, key)); + } + + /// <summary> + /// Verify the certificate's signature using a verifier created using the passed in verifier provider. + /// </summary> + /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param> + /// <returns>True if the signature is valid.</returns> + /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception> + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier(cert.SignatureAlgorithm)); + } + + protected virtual void CheckSignature( + ISignatureVerifier verifier) + { + if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature)) { throw new CertificateException("Signature algorithm in certificate info not same as outer certificate"); } - ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id); - - signature.Init(false, publicKey); + IStreamCalculator streamCalculator = verifier.CreateCalculator(); try { - byte[] b = cert.ACInfo.GetEncoded(); - signature.BlockUpdate(b, 0, b.Length); - } + byte[] b = this.cert.ACInfo.GetEncoded(); + + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Dispose(); + } catch (IOException e) { throw new SignatureException("Exception encoding certificate info object", e); } - if (!signature.VerifySignature(this.GetSignature())) + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) { throw new InvalidKeyException("Public key presented not for certificate signature"); } diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs index a683d5e20..507d00de8 100644 --- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs +++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs @@ -8,6 +8,8 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Crypto.Operators; +using System.IO; namespace Org.BouncyCastle.X509 { @@ -66,12 +68,13 @@ namespace Org.BouncyCastle.X509 acInfoGen.SetEndDate(new DerGeneralizedTime(date)); } - /// <summary> - /// Set the signature algorithm. This can be either a name or an OID, names - /// are treated as case insensitive. - /// </summary> - /// <param name="signatureAlgorithm">The algorithm name.</param> - public void SetSignatureAlgorithm( + /// <summary> + /// Set the signature algorithm. This can be either a name or an OID, names + /// are treated as case insensitive. + /// </summary> + /// <param name="signatureAlgorithm">The algorithm name.</param> + [Obsolete("Not needed if Generate used with an ISignatureCalculator")] + public void SetSignatureAlgorithm( string signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; @@ -127,37 +130,57 @@ namespace Org.BouncyCastle.X509 extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue); } - /// <summary> - /// Generate an X509 certificate, based on the current issuer and subject. - /// </summary> - public IX509AttributeCertificate Generate( - AsymmetricKeyParameter publicKey) + /// <summary> + /// Generate an X509 certificate, based on the current issuer and subject. + /// </summary> + [Obsolete("Use Generate with an ISignatureCalculator")] + public IX509AttributeCertificate Generate( + AsymmetricKeyParameter privateKey) { - return Generate(publicKey, null); + return Generate(privateKey, null); } - /// <summary> - /// Generate an X509 certificate, based on the current issuer and subject, - /// using the supplied source of randomness, if required. - /// </summary> - public IX509AttributeCertificate Generate( - AsymmetricKeyParameter publicKey, + /// <summary> + /// Generate an X509 certificate, based on the current issuer and subject, + /// using the supplied source of randomness, if required. + /// </summary> + [Obsolete("Use Generate with an ISignatureCalculator")] + public IX509AttributeCertificate Generate( + AsymmetricKeyParameter privateKey, SecureRandom random) - { - if (!extGenerator.IsEmpty) + { + return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random)); + } + + /// <summary> + /// Generate a new X.509 Attribute Certificate using the passed in SignatureCalculator. + /// </summary> + /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param> + /// <returns>An IX509AttributeCertificate.</returns> + public IX509AttributeCertificate Generate(ISignatureCalculator signatureCalculator) + { + if (!extGenerator.IsEmpty) { acInfoGen.SetExtensions(extGenerator.Generate()); } AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo(); - Asn1EncodableVector v = new Asn1EncodableVector(); + byte[] encoded = acInfo.GetDerEncoded(); + + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); + + streamCalculator.Stream.Write(encoded, 0, encoded.Length); + + streamCalculator.Stream.Dispose(); + + Asn1EncodableVector v = new Asn1EncodableVector(); - v.Add(acInfo, sigAlgId); + v.Add(acInfo, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails); try { - v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo))); + v.Add(new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal())); return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v))); } diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs index a2293b333..1f22e88b3 100644 --- a/crypto/src/x509/X509V2CRLGenerator.cs +++ b/crypto/src/x509/X509V2CRLGenerator.cs @@ -10,6 +10,7 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -129,13 +130,12 @@ namespace Org.BouncyCastle.X509 } } - /** - * Set the signature algorithm. This can be either a name or an oid, names - * are treated as case insensitive. - * - * @param signatureAlgorithm string representation of the algorithm name. - */ - public void SetSignatureAlgorithm( + /// <summary> + /// Set the signature algorithm that will be used to sign this CRL. + /// </summary> + /// <param name="signatureAlgorithm"/> + [Obsolete("Not needed if Generate used with an ISignatureCalculator")] + public void SetSignatureAlgorithm( string signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; @@ -198,40 +198,55 @@ namespace Org.BouncyCastle.X509 extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue)); } - /// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary> - /// <param name="privateKey">The key used for signing.</param> - public X509Crl Generate( - AsymmetricKeyParameter privateKey) - { - return Generate(privateKey, null); - } + /// <summary> + /// Generate an X.509 CRL, based on the current issuer and subject. + /// </summary> + /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param> + /// <returns>An X509Crl.</returns> + [Obsolete("Use Generate with an ISignatureCalculator")] + public X509Crl Generate( + AsymmetricKeyParameter privateKey) + { + return Generate(privateKey, null); + } - /// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary> - /// <param name="privateKey">The key used for signing.</param> - /// <param name="random">A user-defined source of randomness.</param> - public X509Crl Generate( - AsymmetricKeyParameter privateKey, - SecureRandom random) - { - TbsCertificateList tbsCrl = GenerateCertList(); - byte[] signature; + /// <summary> + /// Generate an X.509 CRL, based on the current issuer and subject using the specified secure random. + /// </summary> + /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param> + /// <param name="random">Your Secure Random instance.</param> + /// <returns>An X509Crl.</returns> + [Obsolete("Use Generate with an ISignatureCalculator")] + public X509Crl Generate( + AsymmetricKeyParameter privateKey, + SecureRandom random) + { + return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random)); + } - try - { - signature = X509Utilities.GetSignatureForObject( - sigOID, signatureAlgorithm, privateKey, random, tbsCrl); - } - catch (IOException e) - { - // TODO -// throw new ExtCrlException("cannot generate CRL encoding", e); - throw new CrlException("cannot generate CRL encoding", e); - } + /// <summary> + /// Generate a new X509Crl using the passed in SignatureCalculator. + /// </summary> + /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param> + /// <returns>An X509Crl.</returns> + public X509Crl Generate(ISignatureCalculator signatureCalculator) + { + tbsGen.SetSignature((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails); - return GenerateJcaObject(tbsCrl, signature); - } + TbsCertificateList tbsCertList = GenerateCertList(); + + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); + + byte[] encoded = tbsCertList.GetDerEncoded(); + + streamCalculator.Stream.Write(encoded, 0, encoded.Length); + + streamCalculator.Stream.Dispose(); + + return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); + } - private TbsCertificateList GenerateCertList() + private TbsCertificateList GenerateCertList() { if (!extGenerator.IsEmpty) { @@ -243,11 +258,12 @@ namespace Org.BouncyCastle.X509 private X509Crl GenerateJcaObject( TbsCertificateList tbsCrl, + AlgorithmIdentifier algId, byte[] signature) { return new X509Crl( CertificateList.GetInstance( - new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature)))); + new DerSequence(tbsCrl, algId, new DerBitString(signature)))); } /// <summary> diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs index bb0dd9cbc..5af5dca3b 100644 --- a/crypto/src/x509/X509V3CertificateGenerator.cs +++ b/crypto/src/x509/X509V3CertificateGenerator.cs @@ -1,9 +1,11 @@ using System; using System.Collections; +using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Operators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; @@ -110,6 +112,7 @@ namespace Org.BouncyCastle.X509 /// Set the signature algorithm that will be used to sign this certificate. /// </summary> /// <param name="signatureAlgorithm"/> + [Obsolete("Not needed if Generate used with an ISignatureCalculator")] public void SetSignatureAlgorithm( string signatureAlgorithm) { @@ -274,7 +277,8 @@ namespace Org.BouncyCastle.X509 /// </summary> /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param> /// <returns>An X509Certificate.</returns> - public X509Certificate Generate( + [Obsolete("Use Generate with an ISignatureCalculator")] + public X509Certificate Generate( AsymmetricKeyParameter privateKey) { return Generate(privateKey, null); @@ -286,53 +290,48 @@ namespace Org.BouncyCastle.X509 /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param> /// <param name="random">You Secure Random instance.</param> /// <returns>An X509Certificate.</returns> + [Obsolete("Use Generate with an ISignatureCalculator")] public X509Certificate Generate( AsymmetricKeyParameter privateKey, SecureRandom random) { - TbsCertificateStructure tbsCert = GenerateTbsCert(); - byte[] signature; - - try - { - signature = X509Utilities.GetSignatureForObject( - sigOid, signatureAlgorithm, privateKey, random, tbsCert); - } - catch (Exception e) - { - // TODO -// throw new ExtCertificateEncodingException("exception encoding TBS cert", e); - throw new CertificateEncodingException("exception encoding TBS cert", e); - } - - try - { - return GenerateJcaObject(tbsCert, signature); - } - catch (CertificateParsingException e) - { - // TODO - // throw new ExtCertificateEncodingException("exception producing certificate object", e); - throw new CertificateEncodingException("exception producing certificate object", e); - } + return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random)); } - private TbsCertificateStructure GenerateTbsCert() + /// <summary> + /// Generate a new X509Certificate using the passed in SignatureCalculator. + /// </summary> + /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param> + /// <returns>An X509Certificate.</returns> + public X509Certificate Generate(ISignatureCalculator signatureCalculator) { - if (!extGenerator.IsEmpty) - { - tbsGen.SetExtensions(extGenerator.Generate()); - } + tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails); + + if (!extGenerator.IsEmpty) + { + tbsGen.SetExtensions(extGenerator.Generate()); + } + + TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); + + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); + + byte[] encoded = tbsCert.GetDerEncoded(); + + streamCalculator.Stream.Write (encoded, 0, encoded.Length); + + streamCalculator.Stream.Dispose (); - return tbsGen.GenerateTbsCertificate(); + return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); } private X509Certificate GenerateJcaObject( TbsCertificateStructure tbsCert, + AlgorithmIdentifier sigAlg, byte[] signature) { return new X509Certificate( - new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature))); + new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature))); } /// <summary> |