diff options
-rw-r--r-- | crypto/src/asn1/bc/BCObjectIdentifiers.cs | 21 | ||||
-rw-r--r-- | crypto/src/bcpg/SignatureSubpacketsReader.cs | 58 | ||||
-rw-r--r-- | crypto/src/crypto/encodings/OaepEncoding.cs | 34 | ||||
-rw-r--r-- | crypto/src/crypto/engines/CamelliaEngine.cs | 12 | ||||
-rw-r--r-- | crypto/src/crypto/engines/CamelliaLightEngine.cs | 12 | ||||
-rw-r--r-- | crypto/src/crypto/engines/SEEDEngine.cs | 3 | ||||
-rw-r--r-- | crypto/src/openpgp/PgpPublicKey.cs | 7 | ||||
-rw-r--r-- | crypto/src/openpgp/PgpUtilities.cs | 62 |
8 files changed, 153 insertions, 56 deletions
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs index 0ffd65dfc..7266e4b4c 100644 --- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs +++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs @@ -110,5 +110,26 @@ namespace Org.BouncyCastle.Asn1.BC public static readonly DerObjectIdentifier bc_ext = bc.Branch("4"); public static readonly DerObjectIdentifier linkedCertificate = bc_ext.Branch("1"); + + /** + * KEM(4) algorithms + */ + public static readonly DerObjectIdentifier bc_kem = bc.Branch("5"); + + /** + * Classic McEliece + */ + public static readonly DerObjectIdentifier pqc_kem_mceliece = bc_kem.Branch("1"); + + public static readonly DerObjectIdentifier mceliece348864_r3 = pqc_kem_mceliece.Branch("1"); + public static readonly DerObjectIdentifier mceliece348864f_r3 = pqc_kem_mceliece.Branch("2"); + public static readonly DerObjectIdentifier mceliece460896_r3 = pqc_kem_mceliece.Branch("3"); + public static readonly DerObjectIdentifier mceliece460896f_r3 = pqc_kem_mceliece.Branch("4"); + public static readonly DerObjectIdentifier mceliece6688128_r3 = pqc_kem_mceliece.Branch("5"); + public static readonly DerObjectIdentifier mceliece6688128f_r3 = pqc_kem_mceliece.Branch("6"); + public static readonly DerObjectIdentifier mceliece6960119_r3 = pqc_kem_mceliece.Branch("7"); + public static readonly DerObjectIdentifier mceliece6960119f_r3 = pqc_kem_mceliece.Branch("8"); + public static readonly DerObjectIdentifier mceliece8192128_r3 = pqc_kem_mceliece.Branch("9"); + public static readonly DerObjectIdentifier mceliece8192128f_r3 = pqc_kem_mceliece.Branch("10"); } } diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs index 45dc96885..86ad11207 100644 --- a/crypto/src/bcpg/SignatureSubpacketsReader.cs +++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs @@ -90,33 +90,37 @@ namespace Org.BouncyCastle.Bcpg switch (type) { - case SignatureSubpacketTag.CreationTime: - return new SignatureCreationTime(isCritical, isLongLength, data); - case SignatureSubpacketTag.KeyExpireTime: - return new KeyExpirationTime(isCritical, isLongLength, data); - case SignatureSubpacketTag.ExpireTime: - return new SignatureExpirationTime(isCritical, isLongLength, data); - case SignatureSubpacketTag.Revocable: - return new Revocable(isCritical, isLongLength, data); - case SignatureSubpacketTag.Exportable: - return new Exportable(isCritical, isLongLength, data); - case SignatureSubpacketTag.IssuerKeyId: - return new IssuerKeyId(isCritical, isLongLength, data); - case SignatureSubpacketTag.TrustSig: - return new TrustSignature(isCritical, isLongLength, data); - case SignatureSubpacketTag.PreferredCompressionAlgorithms: - case SignatureSubpacketTag.PreferredHashAlgorithms: - case SignatureSubpacketTag.PreferredSymmetricAlgorithms: - return new PreferredAlgorithms(type, isCritical, isLongLength, data); - case SignatureSubpacketTag.KeyFlags: - return new KeyFlags(isCritical, isLongLength, data); - case SignatureSubpacketTag.PrimaryUserId: - return new PrimaryUserId(isCritical, isLongLength, data); - case SignatureSubpacketTag.SignerUserId: - return new SignerUserId(isCritical, isLongLength, data); - case SignatureSubpacketTag.NotationData: - return new NotationData(isCritical, isLongLength, data); - } + case SignatureSubpacketTag.CreationTime: + return new SignatureCreationTime(isCritical, isLongLength, data); + case SignatureSubpacketTag.KeyExpireTime: + return new KeyExpirationTime(isCritical, isLongLength, data); + case SignatureSubpacketTag.ExpireTime: + return new SignatureExpirationTime(isCritical, isLongLength, data); + case SignatureSubpacketTag.Revocable: + return new Revocable(isCritical, isLongLength, data); + case SignatureSubpacketTag.Exportable: + return new Exportable(isCritical, isLongLength, data); + case SignatureSubpacketTag.IssuerKeyId: + return new IssuerKeyId(isCritical, isLongLength, data); + case SignatureSubpacketTag.TrustSig: + return new TrustSignature(isCritical, isLongLength, data); + case SignatureSubpacketTag.PreferredCompressionAlgorithms: + case SignatureSubpacketTag.PreferredHashAlgorithms: + case SignatureSubpacketTag.PreferredSymmetricAlgorithms: + return new PreferredAlgorithms(type, isCritical, isLongLength, data); + case SignatureSubpacketTag.KeyFlags: + return new KeyFlags(isCritical, isLongLength, data); + case SignatureSubpacketTag.PrimaryUserId: + return new PrimaryUserId(isCritical, isLongLength, data); + case SignatureSubpacketTag.SignerUserId: + return new SignerUserId(isCritical, isLongLength, data); + case SignatureSubpacketTag.NotationData: + return new NotationData(isCritical, isLongLength, data); + case SignatureSubpacketTag.RevocationReason: + return new RevocationReason(isCritical, isLongLength, data); + case SignatureSubpacketTag.RevocationKey: + return new RevocationKey(isCritical, isLongLength, data); + } return new SignatureSubpacket(type, isCritical, isLongLength, data); } diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs index 295a43aac..f3550b9cd 100644 --- a/crypto/src/crypto/encodings/OaepEncoding.cs +++ b/crypto/src/crypto/encodings/OaepEncoding.cs @@ -213,7 +213,8 @@ namespace Org.BouncyCastle.Crypto.Encodings // on encryption, we need to make sure our decrypted block comes back // the same size. // - bool wrongData = (block.Length < (2 * defHash.Length) + 1); + // i.e. wrong when block.length < (2 * defHash.length) + 1 + int wrongMask = (block.Length - ((2 * defHash.Length) + 1)) >> 31; if (data.Length <= block.Length) { @@ -222,7 +223,7 @@ namespace Org.BouncyCastle.Crypto.Encodings else { Array.Copy(data, 0, block, 0, block.Length); - wrongData = true; + wrongMask |= 1; } // @@ -250,39 +251,38 @@ namespace Org.BouncyCastle.Crypto.Encodings // check the hash of the encoding params. // long check to try to avoid this been a source of a timing attack. // - bool defHashWrong = false; - for (int i = 0; i != defHash.Length; i++) { - if (defHash[i] != block[defHash.Length + i]) - { - defHashWrong = true; - } + wrongMask |= defHash[i] ^ block[defHash.Length + i]; } // // find the data block // - int start = block.Length; + int start = -1; for (int index = 2 * defHash.Length; index != block.Length; index++) { - if (block[index] != 0 & start == block.Length) - { - start = index; - } - } + int octet = block[index]; - bool dataStartWrong = (start > (block.Length - 1) | block[start] != 1); + // i.e. mask will be 0xFFFFFFFF if octet is non-zero and start is (still) negative, else 0. + int shouldSetMask = (-octet & start) >> 31; - start++; + start += index & shouldSetMask; + } - if (defHashWrong | wrongData | dataStartWrong) + wrongMask |= start >> 31; + ++start; + wrongMask |= block[start] ^ 1; + + if (wrongMask != 0) { Arrays.Fill(block, 0); throw new InvalidCipherTextException("data wrong"); } + ++start; + // // extract the data block // diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs index 71bd1b0dc..2222e4b7c 100644 --- a/crypto/src/crypto/engines/CamelliaEngine.cs +++ b/crypto/src/crypto/engines/CamelliaEngine.cs @@ -18,7 +18,6 @@ namespace Org.BouncyCastle.Crypto.Engines private uint[] subkey = new uint[24 * 4]; private uint[] kw = new uint[4 * 2]; // for whitening private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1) - private uint[] state = new uint[4]; // for encryption and decryption private static readonly uint[] SIGMA = new uint[]{ 0xa09e667f, 0x3bcc908b, @@ -540,10 +539,11 @@ namespace Org.BouncyCastle.Crypto.Engines private int processBlock128(byte[] input, int inOff, byte[] output, int outOff) { + uint[] state = new uint[4]; + for (int i = 0; i < 4; i++) { - state[i] = bytes2uint(input, inOff + (i * 4)); - state[i] ^= kw[i]; + state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i]; } camelliaF2(state, subkey, 0); @@ -573,10 +573,11 @@ namespace Org.BouncyCastle.Crypto.Engines private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff) { + uint[] state = new uint[4]; + for (int i = 0; i < 4; i++) { - state[i] = bytes2uint(input, inOff + (i * 4)); - state[i] ^= kw[i]; + state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i]; } camelliaF2(state, subkey, 0); @@ -604,6 +605,7 @@ namespace Org.BouncyCastle.Crypto.Engines uint2bytes(state[3], output, outOff + 4); uint2bytes(state[0], output, outOff + 8); uint2bytes(state[1], output, outOff + 12); + return BLOCK_SIZE; } diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs index a132227c5..daf0316e2 100644 --- a/crypto/src/crypto/engines/CamelliaLightEngine.cs +++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs @@ -18,7 +18,6 @@ namespace Org.BouncyCastle.Crypto.Engines private uint[] subkey = new uint[24 * 4]; private uint[] kw = new uint[4 * 2]; // for whitening private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1) - private uint[] state = new uint[4]; // for encryption and decryption private static readonly uint[] SIGMA = { 0xa09e667f, 0x3bcc908b, @@ -452,10 +451,11 @@ namespace Org.BouncyCastle.Crypto.Engines private int processBlock128(byte[] input, int inOff, byte[] output, int outOff) { + uint[] state = new uint[4]; + for (int i = 0; i < 4; i++) { - state[i] = bytes2uint(input, inOff + (i * 4)); - state[i] ^= kw[i]; + state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i]; } camelliaF2(state, subkey, 0); @@ -485,10 +485,11 @@ namespace Org.BouncyCastle.Crypto.Engines private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff) { + uint[] state = new uint[4]; + for (int i = 0; i < 4; i++) { - state[i] = bytes2uint(input, inOff + (i * 4)); - state[i] ^= kw[i]; + state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i]; } camelliaF2(state, subkey, 0); @@ -516,6 +517,7 @@ namespace Org.BouncyCastle.Crypto.Engines uint2bytes(state[3], output, outOff + 4); uint2bytes(state[0], output, outOff + 8); uint2bytes(state[1], output, outOff + 12); + return BLOCK_SIZE; } diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs index f615b8476..d4142c867 100644 --- a/crypto/src/crypto/engines/SEEDEngine.cs +++ b/crypto/src/crypto/engines/SEEDEngine.cs @@ -240,6 +240,9 @@ namespace Org.BouncyCastle.Crypto.Engines private int[] createWorkingKey( byte[] inKey) { + if (inKey.Length != 16) + throw new ArgumentException("key size must be 128 bits"); + int[] key = new int[32]; long lower = bytesToLong(inKey, 0); long upper = bytesToLong(inKey, 8); diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs index 9b8a956f2..33fabc8aa 100644 --- a/crypto/src/openpgp/PgpPublicKey.cs +++ b/crypto/src/openpgp/PgpPublicKey.cs @@ -460,7 +460,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <summary>True, if this could be a master key.</summary> public bool IsMasterKey { - get { return (subSigs == null) && !(this.IsEncryptionKey && publicPk.Algorithm != PublicKeyAlgorithmTag.RsaGeneral); } + get + { + // this might seem a bit excessive, but we're also trying to flag something can't be a master key. + return !(publicPk is PublicSubkeyPacket) + && !(this.IsEncryptionKey && publicPk.Algorithm != PublicKeyAlgorithmTag.RsaGeneral); + } } /// <summary>The algorithm code associated with the public key.</summary> diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs index fd5ab6232..fcc4f672c 100644 --- a/crypto/src/openpgp/PgpUtilities.cs +++ b/crypto/src/openpgp/PgpUtilities.cs @@ -1,8 +1,12 @@ using System; +using System.Collections; using System.IO; using System.Text; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; @@ -16,6 +20,37 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <remarks>Basic utility class.</remarks> public sealed class PgpUtilities { + private static IDictionary NameToHashID = CreateNameToHashID(); + private static IDictionary OidToName = CreateOidToName(); + + private static IDictionary CreateNameToHashID() + { + IDictionary d = Platform.CreateHashtable(); + d.Add("sha1", HashAlgorithmTag.Sha1); + d.Add("sha224", HashAlgorithmTag.Sha224); + d.Add("sha256", HashAlgorithmTag.Sha256); + d.Add("sha384", HashAlgorithmTag.Sha384); + d.Add("sha512", HashAlgorithmTag.Sha512); + d.Add("ripemd160", HashAlgorithmTag.RipeMD160); + d.Add("rmd160", HashAlgorithmTag.RipeMD160); + d.Add("md2", HashAlgorithmTag.MD2); + d.Add("tiger", HashAlgorithmTag.Tiger192); + d.Add("haval", HashAlgorithmTag.Haval5pass160); + d.Add("md5", HashAlgorithmTag.MD5); + return d; + } + + private static IDictionary CreateOidToName() + { + IDictionary d = Platform.CreateHashtable(); + d.Add(EdECObjectIdentifiers.id_X25519, "Curve25519"); + d.Add(EdECObjectIdentifiers.id_Ed25519, "Ed25519"); + d.Add(SecObjectIdentifiers.SecP256r1, "NIST P-256"); + d.Add(SecObjectIdentifiers.SecP384r1, "NIST P-384"); + d.Add(SecObjectIdentifiers.SecP521r1, "NIST P-521"); + return d; + } + private PgpUtilities() { } @@ -75,7 +110,32 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - public static string GetSignatureName( + public static int GetDigestIDForName(string name) + { + name = Platform.ToLowerInvariant(name); + if (NameToHashID.Contains(name)) + return (Int32)NameToHashID[name]; + + throw new ArgumentException("unable to map " + name + " to a hash id", "name"); + } + + /** + * Return the EC curve name for the passed in OID. + * + * @param oid the EC curve object identifier in the PGP key + * @return a string representation of the OID. + */ + public static string GetCurveName(DerObjectIdentifier oid) + { + string name = (string)OidToName[oid]; + if (name != null) + return name; + + // fall back + return ECNamedCurveTable.GetName(oid); + } + + public static string GetSignatureName( PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm) { |