diff options
Diffstat (limited to 'crypto/src/openpgp/PgpPublicKeyEncryptedData.cs')
-rw-r--r-- | crypto/src/openpgp/PgpPublicKeyEncryptedData.cs | 140 |
1 files changed, 80 insertions, 60 deletions
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); + } + } } } |