summary refs log tree commit diff
path: root/crypto/src/openpgp/PgpSecretKey.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/openpgp/PgpSecretKey.cs')
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs78
1 files changed, 57 insertions, 21 deletions
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 94c892a87..872316dd7 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -5,6 +5,7 @@ using System.IO;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
@@ -75,28 +76,36 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 pOut.WriteObject(secKey);
 
                 byte[] keyData = bOut.ToArray();
-                byte[] checksumBytes = Checksum(useSha1, keyData, keyData.Length);
+                byte[] checksumData = Checksum(useSha1, keyData, keyData.Length);
 
-                pOut.Write(checksumBytes);
-
-                byte[] bOutData = bOut.ToArray();
+                keyData = Arrays.Concatenate(keyData, checksumData);
 
                 if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
                 {
                     if (isMasterKey)
                     {
-                        this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData);
+                        this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
                     }
                     else
                     {
-                        this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData);
+                        this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
                     }
                 }
                 else
                 {
                     S2k s2k;
                     byte[] iv;
-                    byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv);
+
+                    byte[] encData;
+                    if (pub.Version >= 4)
+                    {
+                        encData = EncryptKeyData(keyData, encAlgorithm, passPhrase, rand, out s2k, out iv);
+                    }
+                    else
+                    {
+                        // TODO v3 RSA key encryption
+                        throw Platform.CreateNotImplementedException("v3 RSA");
+                    }
 
                     int s2kUsage = useSha1
                         ?	SecretKeyPacket.UsageSha1
@@ -145,11 +154,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             PgpSignatureSubpacketVector	hashedPackets,
             PgpSignatureSubpacketVector	unhashedPackets,
             SecureRandom				rand)
-            : this(keyPair.PrivateKey, certifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true)
+            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true)
         {
         }
 
-        private static PgpPublicKey certifiedPublicKey(
+        private static PgpPublicKey CertifiedPublicKey(
             int							certificationLevel,
             PgpKeyPair					keyPair,
             string						id,
@@ -254,6 +263,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             get { return pub.IsMasterKey; }
         }
 
+        /// <summary>Detect if the Secret Key's Private Key is empty or not</summary>
+        public bool IsPrivateKeyEmpty
+        {
+            get
+            {
+                byte[] secKeyData = secret.GetSecretKeyData();
+
+                return secKeyData == null || secKeyData.Length < 1;
+            }
+        }
+
         /// <summary>The algorithm the key is encrypted with.</summary>
         public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
         {
@@ -293,9 +313,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             byte[] encData = secret.GetSecretKeyData();
 
             if (alg == SymmetricKeyAlgorithmTag.Null)
+                // TODO Check checksum here?
                 return encData;
 
-            byte[] data;
             IBufferedCipher c = null;
             try
             {
@@ -307,13 +327,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 throw new PgpException("Exception creating cipher", e);
             }
 
-            // TODO Factor this block out as 'encryptData'
+            // TODO Factor this block out as 'decryptData'
             try
             {
                 KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
                 byte[] iv = secret.GetIV();
+                byte[] data;
 
-                if (secret.PublicKeyPacket.Version == 4)
+                if (secret.PublicKeyPacket.Version >= 4)
                 {
                     c.Init(false, new ParametersWithIV(key, iv));
 
@@ -334,6 +355,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 {
                     data = new byte[encData.Length];
 
+                    iv = Arrays.Clone(iv);
+
                     //
                     // read in the four numbers
                     //
@@ -359,11 +382,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     }
 
                     //
-                    // verify Checksum
+                    // verify and copy checksum
                     //
+
+                    data[pos] = encData[pos];
+                    data[pos + 1] = encData[pos + 1];
+
                     int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
                     int calcCs = 0;
-                    for (int j=0; j < data.Length-2; j++)
+                    for (int j = 0; j < pos; j++)
                     {
                         calcCs += data[j] & 0xff;
                     }
@@ -393,8 +420,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         public PgpPrivateKey ExtractPrivateKey(
             char[] passPhrase)
         {
-            byte[] secKeyData = secret.GetSecretKeyData();
-            if (secKeyData == null || secKeyData.Length < 1)
+            if (IsPrivateKeyEmpty)
                 return null;
 
             PublicKeyPacket pubPk = secret.PublicKeyPacket;
@@ -559,11 +585,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             SymmetricKeyAlgorithmTag	newEncAlgorithm,
             SecureRandom				rand)
         {
+            if (key.IsPrivateKeyEmpty)
+                throw new PgpException("no private key in this SecretKey - public key present only.");
+
             byte[]	rawKeyData = key.ExtractKeyData(oldPassPhrase);
             int		s2kUsage = key.secret.S2kUsage;
             byte[]	iv = null;
             S2k		s2k = null;
             byte[]	keyData;
+            PublicKeyPacket pubKeyPacket = key.secret.PublicKeyPacket;
 
             if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
             {
@@ -588,7 +618,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             {
                 try
                 {
-                    keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                    if (pubKeyPacket.Version >= 4)
+                    {
+                        keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                    }
+                    else
+                    {
+                        // TODO v3 RSA key encryption
+                        throw Platform.CreateNotImplementedException("v3 RSA");
+                    }
                 }
                 catch (PgpException e)
                 {
@@ -603,13 +641,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             SecretKeyPacket secret;
             if (key.secret is SecretSubkeyPacket)
             {
-                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
-                    newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+                secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
             }
             else
             {
-                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
-                    newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+                secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
             }
 
             return new PgpSecretKey(secret, key.pub);