internal PbeMethod(
     SymmetricKeyAlgorithmTag  encAlgorithm,
     S2k                       s2k,
     KeyParameter              key)
 {
     this.encAlgorithm = encAlgorithm;
     this.s2k = s2k;
     this.key = key;
 }
        private static byte[] EncryptKeyDataV3(
            byte[]						rawKeyData,
            SymmetricKeyAlgorithmTag	encAlgorithm,
            byte[]						rawPassPhrase,
            bool                        clearPassPhrase,
            SecureRandom				random,
            out S2k						s2k,
            out byte[]					iv)
        {
            // Version 2 or 3 - RSA Keys only

            s2k = null;
            iv = null;

            KeyParameter encKey = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);

            byte[] keyData = new byte[rawKeyData.Length];

            //
            // process 4 numbers
            //
            int pos = 0;
            for (int i = 0; i != 4; i++)
            {
                int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8;

                keyData[pos] = rawKeyData[pos];
                keyData[pos + 1] = rawKeyData[pos + 1];

                byte[] tmp;
                if (i == 0)
                {
                    tmp = EncryptData(encAlgorithm, encKey, rawKeyData, pos + 2, encLen, random, ref iv);
                }
                else
                {
                    byte[] tmpIv = Arrays.CopyOfRange(keyData, pos - iv.Length, pos);

                    tmp = EncryptData(encAlgorithm, encKey, rawKeyData, pos + 2, encLen, random, ref tmpIv);
                }

                Array.Copy(tmp, 0, keyData, pos + 2, tmp.Length);
                pos += 2 + encLen;
            }

            //
            // copy in checksum.
            //
            keyData[pos] = rawKeyData[pos];
            keyData[pos + 1] = rawKeyData[pos + 1];

            return keyData;
        }
 /// <remarks>
 /// Allows the caller to handle the encoding of the passphrase to bytes.
 /// </remarks>
 public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
 {
     return DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, false);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SecretSubkeyPacket"/> class.
 /// </summary>
 /// <param name="pubKeyPacket">The pub key packet.</param>
 /// <param name="encAlgorithm">The enc algorithm.</param>
 /// <param name="s2KUsage">The s2 K usage.</param>
 /// <param name="s2K">The s2 K.</param>
 /// <param name="iv">The iv.</param>
 /// <param name="secKeyData">The sec key data.</param>
 public SecretSubkeyPacket(IPublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, int s2KUsage, S2k s2K, byte[] iv, byte[] secKeyData)
     : base(pubKeyPacket, encAlgorithm, s2KUsage, s2K, iv, secKeyData)
 {
 }
Exemple #5
0
 /// <remarks>
 /// Allows the caller to handle the encoding of the passphrase to bytes.
 /// </remarks>
 public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
 {
     return(DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, false));
 }
Exemple #6
0
        internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
        {
            S2k s2k = PgpUtilities.GenerateS2k(s2kDigest, 0x60, rand);

            methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SecretSubkeyPacket"/> class.
 /// </summary>
 /// <param name="pubKeyPacket">The pub key packet.</param>
 /// <param name="encAlgorithm">The enc algorithm.</param>
 /// <param name="s2KUsage">The s2 K usage.</param>
 /// <param name="s2K">The s2 K.</param>
 /// <param name="iv">The iv.</param>
 /// <param name="secKeyData">The sec key data.</param>
 public SecretSubkeyPacket(IPublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, int s2KUsage, S2k s2K, byte[] iv, byte[] secKeyData)
     : base(pubKeyPacket, encAlgorithm, s2KUsage, s2K, iv, secKeyData)
 {
 }
Exemple #8
0
 public SecretKeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, byte[] iv, byte[] secKeyData)
 {
     this.pubKeyPacket = pubKeyPacket;
     this.encAlgorithm = encAlgorithm;
     if (encAlgorithm != 0)
     {
         s2kUsage = 255;
     }
     else
     {
         s2kUsage = 0;
     }
     this.s2k        = s2k;
     this.iv         = Arrays.Clone(iv);
     this.secKeyData = secKeyData;
 }
        internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
        {
            int keySize = GetKeySize(algorithm);

            byte[] array = new byte[(keySize + 7) / 8];
            int    num   = 0;
            int    num2  = 0;

            while (num < array.Length)
            {
                IDigest digest;
                if (s2k != null)
                {
                    string digestName = GetDigestName(s2k.HashAlgorithm);
                    try
                    {
                        digest = DigestUtilities.GetDigest(digestName);
                    }
                    catch (global::System.Exception exception)
                    {
                        throw new PgpException("can't find S2k digest", exception);
                    }
                    for (int i = 0; i != num2; i++)
                    {
                        digest.Update(0);
                    }
                    byte[] iV = s2k.GetIV();
                    switch (s2k.Type)
                    {
                    case 0:
                        digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
                        break;

                    case 1:
                        digest.BlockUpdate(iV, 0, iV.Length);
                        digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
                        break;

                    case 3:
                    {
                        long iterationCount = s2k.IterationCount;
                        digest.BlockUpdate(iV, 0, iV.Length);
                        digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
                        iterationCount -= iV.Length + rawPassPhrase.Length;
                        while (iterationCount > 0)
                        {
                            if (iterationCount < iV.Length)
                            {
                                digest.BlockUpdate(iV, 0, (int)iterationCount);
                                break;
                            }
                            digest.BlockUpdate(iV, 0, iV.Length);
                            iterationCount -= iV.Length;
                            if (iterationCount < rawPassPhrase.Length)
                            {
                                digest.BlockUpdate(rawPassPhrase, 0, (int)iterationCount);
                                iterationCount = 0L;
                            }
                            else
                            {
                                digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
                                iterationCount -= rawPassPhrase.Length;
                            }
                        }
                        break;
                    }

                    default:
                        throw new PgpException(string.Concat((object)"unknown S2k type: ", (object)s2k.Type));
                    }
                }
                else
                {
                    try
                    {
                        digest = DigestUtilities.GetDigest("MD5");
                        for (int j = 0; j != num2; j++)
                        {
                            digest.Update(0);
                        }
                        digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
                    }
                    catch (global::System.Exception exception2)
                    {
                        throw new PgpException("can't find MD5 digest", exception2);
                    }
                }
                byte[] array2 = DigestUtilities.DoFinal(digest);
                if (array2.Length > array.Length - num)
                {
                    global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)array, num, array.Length - num);
                }
                else
                {
                    global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)array, num, array2.Length);
                }
                num += array2.Length;
                num2++;
            }
            if (clearPassPhrase && rawPassPhrase != null)
            {
                global::System.Array.Clear((global::System.Array)rawPassPhrase, 0, rawPassPhrase.Length);
            }
            return(MakeKey(algorithm, array));
        }
 internal PbeMethod(
     PgpEncryptedDataGenerator outer,
     SymmetricKeyAlgorithmTag  encAlgorithm,
     S2k                       s2k,
     KeyParameter              key)
 {
     this.outer = outer;
     this.encAlgorithm = encAlgorithm;
     this.s2k = s2k;
     this.key = key;
 }
Exemple #11
0
        private static byte[] EncryptKeyDataV4(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv)
        {
            s2k = PgpUtilities.GenerateS2k(hashAlgorithm, 96, random);
            KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);

            iv = null;
            return(EncryptData(encAlgorithm, key, rawKeyData, 0, rawKeyData.Length, random, ref iv));
        }
Exemple #12
0
        private static byte[] EncryptKeyDataV3(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv)
        {
            s2k = null;
            iv  = null;
            KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);

            byte[] array = new byte[rawKeyData.Length];
            int    num   = 0;

            for (int i = 0; i != 4; i++)
            {
                int num2 = (((rawKeyData[num] << 8) | (rawKeyData[num + 1] & 0xFF)) + 7) / 8;
                array[num]     = rawKeyData[num];
                array[num + 1] = rawKeyData[num + 1];
                byte[] array2;
                if (i == 0)
                {
                    array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv);
                }
                else
                {
                    byte[] iv2 = Arrays.CopyOfRange(array, num - iv.Length, num);
                    array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv2);
                }
                global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)array, num + 2, array2.Length);
                num += 2 + num2;
            }
            array[num]     = rawKeyData[num];
            array[num + 1] = rawKeyData[num + 1];
            return(array);
        }
Exemple #13
0
 internal PbeMethod(SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, KeyParameter key)
 {
     base.encAlgorithm = encAlgorithm;
     this.s2k          = s2k;
     base.key          = key;
 }
Exemple #14
0
 public SecretKeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, int s2kUsage, S2k s2k, byte[] iv, byte[] secKeyData)
 {
     this.pubKeyPacket = pubKeyPacket;
     this.encAlgorithm = encAlgorithm;
     this.s2kUsage     = s2kUsage;
     this.s2k          = s2k;
     this.iv           = Arrays.Clone(iv);
     this.secKeyData   = secKeyData;
 }
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="oldPassPhrase">The current password for the key.</param>
        /// <param name="newPassPhrase">The new password for the key.</param>
        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
        /// <param name="rand">Source of randomness.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            char[]                                              oldPassPhrase,
            char[]                                              newPassPhrase,
            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)
            {
                s2kUsage = SecretKeyPacket.UsageNone;
                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)   // SHA-1 hash, need to rewrite Checksum
                {
                    keyData = new byte[rawKeyData.Length - 18];

                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);

                    byte[] check = Checksum(false, keyData, keyData.Length - 2);

                    keyData[keyData.Length - 2] = check[0];
                    keyData[keyData.Length - 1] = check[1];
                }
                else
                {
                    keyData = rawKeyData;
                }
            }
            else
            {
                try
                {
                    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)
                {
                    throw e;
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception encrypting key", e);
                }
            }

            SecretKeyPacket secret;

            if (key.secret is SecretSubkeyPacket)
            {
                secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }
            else
            {
                secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }

            return(new PgpSecretKey(secret, key.pub));
        }
        private static byte[] EncryptKeyData(
            byte[] rawKeyData,
            SymmetricKeyAlgorithmTag encAlgorithm,
            char[] passPhrase,
            ISecureRandom random,
            out S2k s2K,
            out byte[] iv)
        {
            IBufferedCipher c;
            try
            {
                var cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
                c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
            }
            catch (Exception e)
            {
                throw new PgpException("Exception creating cipher", e);
            }

            var s2KIv = new byte[8];
            random.NextBytes(s2KIv);
            s2K = new S2k(HashAlgorithmTag.Sha1, s2KIv, 0x60);

            var kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2K, passPhrase);

            iv = new byte[c.GetBlockSize()];
            random.NextBytes(iv);

            c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random));

            return c.DoFinal(rawKeyData);
        }
Exemple #17
0
        internal PgpSecretKey(
            PgpKeyPair keyPair,
            SymmetricKeyAlgorithmTag encAlgorithm,
            char[]                                              passPhrase,
            bool useSHA1,
            SecureRandom rand)
        {
            PublicKeyPacket pubPk = keyPair.PublicKey.publicPk;

            BcpgObject secKey;

            switch (keyPair.PublicKey.Algorithm)
            {
            case PublicKeyAlgorithmTag.RsaEncrypt:
            case PublicKeyAlgorithmTag.RsaSign:
            case PublicKeyAlgorithmTag.RsaGeneral:
                RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters)keyPair.PrivateKey.Key;
                secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
                break;

            case PublicKeyAlgorithmTag.Dsa:
                DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters)keyPair.PrivateKey.Key;
                secKey = new DsaSecretBcpgKey(dsK.X);
                break;

            case PublicKeyAlgorithmTag.ElGamalEncrypt:
            case PublicKeyAlgorithmTag.ElGamalGeneral:
                ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters)keyPair.PrivateKey.Key;
                secKey = new ElGamalSecretBcpgKey(esK.X);
                break;

            default:
                throw new PgpException("unknown key class");
            }

            string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);

            IBufferedCipher c = null;

            if (cName != null)
            {
                try
                {
                    c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception creating cipher", e);
                }
            }

            try
            {
                MemoryStream     bOut = new MemoryStream();
                BcpgOutputStream pOut = new BcpgOutputStream(bOut);

                pOut.WriteObject(secKey);

                byte[] keyData       = bOut.ToArray();
                byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length);

                pOut.Write(checksumBytes);

                byte[] bOutData = bOut.ToArray();

                if (c != null)
                {
                    byte[] iv = new byte[8];
                    rand.NextBytes(iv);

                    S2k          s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
                    KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);

                    iv = new byte[c.GetBlockSize()];
                    rand.NextBytes(iv);
                    c.Init(true, new ParametersWithIV(key, iv));

                    byte[] encData = c.DoFinal(bOutData);

                    int usage = useSHA1
                                                ?       SecretKeyPacket.UsageSha1
                                                :       SecretKeyPacket.UsageChecksum;

                    this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData);
                }
                else
                {
                    this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData);
                }

                this.trust = null;
            }
            catch (PgpException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new PgpException("Exception encrypting key", e);
            }

            this.keySigs = new ArrayList();
        }
 public SecretSubkeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, byte[] iv, byte[] secKeyData)
     : base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData)
 {
 }
Exemple #19
0
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="oldPassPhrase">The current password for the key.</param>
        /// <param name="newPassPhrase">The new password for the key.</param>
        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
        /// <param name="rand">Source of randomness.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            char[]                                              oldPassPhrase,
            char[]                                              newPassPhrase,
            SymmetricKeyAlgorithmTag newEncAlgorithm,
            SecureRandom rand)
        {
            byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase);
            int    s2kUsage   = key.secret.S2kUsage;

            byte[] iv  = null;
            S2k    s2k = null;

            byte[] keyData = null;

            if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
            {
                s2kUsage = SecretKeyPacket.UsageNone;
                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)                   // SHA-1 hash, need to rewrite Checksum
                {
                    keyData = new byte[rawKeyData.Length - 18];

                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);

                    byte[] check = Checksum(false, keyData, keyData.Length - 2);

                    keyData[keyData.Length - 2] = check[0];
                    keyData[keyData.Length - 1] = check[1];
                }
                else
                {
                    keyData = rawKeyData;
                }
            }
            else
            {
                IBufferedCipher c;
                try
                {
                    string cName = PgpUtilities.GetSymmetricCipherName(newEncAlgorithm);
                    c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception creating cipher", e);
                }

                iv = new byte[8];
                rand.NextBytes(iv);
                s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
                try
                {
                    KeyParameter sKey = PgpUtilities.MakeKeyFromPassPhrase(newEncAlgorithm, s2k, newPassPhrase);
                    iv = new byte[c.GetBlockSize()];
                    rand.NextBytes(iv);
                    c.Init(true, new ParametersWithIV(sKey, iv));

                    keyData = c.DoFinal(rawKeyData);
                }
                catch (PgpException e)
                {
                    throw e;
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception encrypting key", e);
                }
            }

            SecretKeyPacket secret;

            if (key.secret is SecretSubkeyPacket)
            {
                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
                                                newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }
            else
            {
                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
                                             newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }

            if (key.subSigs == null)
            {
                return(new PgpSecretKey(secret, key.trust, key.keySigs, key.ids,
                                        key.idTrusts, key.idSigs, key.pub));
            }

            return(new PgpSecretKey(secret, key.trust, key.subSigs, key.pub));
        }
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="oldPassPhrase">The current password for the key.</param>
        /// <param name="newPassPhrase">The new password for the key.</param>
        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
        /// <param name="rand">Source of randomness.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            char[]                                              oldPassPhrase,
            char[]                                              newPassPhrase,
            SymmetricKeyAlgorithmTag newEncAlgorithm,
            SecureRandom rand)
        {
            byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase);
            int    s2kUsage   = key.secret.S2kUsage;

            byte[] iv  = null;
            S2k    s2k = null;

            byte[] keyData;

            if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
            {
                s2kUsage = SecretKeyPacket.UsageNone;
                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)                   // SHA-1 hash, need to rewrite Checksum
                {
                    keyData = new byte[rawKeyData.Length - 18];

                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);

                    byte[] check = Checksum(false, keyData, keyData.Length - 2);

                    keyData[keyData.Length - 2] = check[0];
                    keyData[keyData.Length - 1] = check[1];
                }
                else
                {
                    keyData = rawKeyData;
                }
            }
            else
            {
                try
                {
                    keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
                }
                catch (PgpException e)
                {
                    throw e;
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception encrypting key", e);
                }
            }

            SecretKeyPacket secret;

            if (key.secret is SecretSubkeyPacket)
            {
                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
                                                newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }
            else
            {
                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
                                             newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }

            return(new PgpSecretKey(secret, key.pub));
        }
Exemple #21
0
        private static SecretKeyPacket buildSecretKeyPacket(bool isMasterKey, PgpPrivateKey privKey, PgpPublicKey pubKey, IPbeSecretKeyEncryptor keyEncryptor)
        {
            BcpgObject secKey = (BcpgObject)privKey.Key;

            if (secKey == null)
            {
                if (isMasterKey)
                {
                    return(new SecretKeyPacket(pubKey.publicPk, SymmetricKeyAlgorithmTag.Null, null, null, new byte[0]));
                }
                else
                {
                    return(new SecretSubkeyPacket(pubKey.publicPk, SymmetricKeyAlgorithmTag.Null, null, null, new byte[0]));
                }
            }

            try
            {
                MemoryOutputStream bOut = new MemoryOutputStream();
                BcpgOutputStream   pOut = new BcpgOutputStream(bOut);

                pOut.WriteObject(secKey);

                byte[] keyData   = bOut.ToArray();
                byte[] checkData = checksum(keyEncryptor.ChecksumCalculatorFactory, keyData, keyData.Length);

                pOut.Write(checkData, 0, checkData.Length);

                PgpPbeKeyEncryptionParameters encParams = keyEncryptor.AlgorithmDetails;

                SymmetricKeyAlgorithmTag encAlgorithm = (keyEncryptor != null) ? encParams.Algorithm : SymmetricKeyAlgorithmTag.Null;

                if (encAlgorithm != SymmetricKeyAlgorithmTag.Null)
                {
                    keyData = bOut.ToArray(); // include checksum

                    byte[] encData = keyEncryptor.Wrap(keyData).Collect();
                    byte[] iv      = encParams.GetIV();

                    S2k s2k = encParams.S2k;

                    int s2kUsage;

                    if (keyEncryptor.ChecksumCalculatorFactory != null)
                    {
                        if (keyEncryptor.ChecksumCalculatorFactory.AlgorithmDetails.Algorithm != HashAlgorithmTag.Sha1)
                        {
                            throw new PgpException("only SHA1 supported for key checksum calculations.");
                        }
                        s2kUsage = SecretKeyPacket.UsageSha1;
                    }
                    else
                    {
                        s2kUsage = SecretKeyPacket.UsageChecksum;
                    }

                    if (isMasterKey)
                    {
                        return(new SecretKeyPacket(pubKey.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData));
                    }
                    else
                    {
                        return(new SecretSubkeyPacket(pubKey.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData));
                    }
                }
                else
                {
                    if (isMasterKey)
                    {
                        return(new SecretKeyPacket(pubKey.publicPk, encAlgorithm, null, null, bOut.ToArray()));
                    }
                    else
                    {
                        return(new SecretSubkeyPacket(pubKey.publicPk, encAlgorithm, null, null, bOut.ToArray()));
                    }
                }
            }
            catch (PgpException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new PgpException("Exception encrypting key", e);
            }
        }
Exemple #22
0
 /// <remarks>
 /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
 /// </remarks>
 public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
 {
     return(DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, true), true));
 }
Exemple #23
0
        /**
         * Return a copy of the passed in secret key, encrypted using a new
         * password and the passed in algorithm.
         *
         * @param key the PgpSecretKey to be copied.
         * @param oldKeyDecryptor the current decryptor based on the current password for key.
         * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key material.
         */
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            IPbeSecretKeyDecryptorProvider oldKeyDecryptor,
            IPbeSecretKeyEncryptor newKeyEncryptor)
        {
            if (key.IsPrivateKeyEmpty)
            {
                throw new PgpException("no private key in this SecretKey - public key present only.");
            }

            byte[] rawKeyData = key.extractKeyData(oldKeyDecryptor);
            int    s2kUsage   = key.secret.S2kUsage;

            byte[] iv  = null;
            S2k    s2k = null;

            byte[] keyData = null;
            SymmetricKeyAlgorithmTag newEncAlgorithm = SymmetricKeyAlgorithmTag.Null;

            if (newKeyEncryptor == null || newKeyEncryptor.AlgorithmDetails.Algorithm == SymmetricKeyAlgorithmTag.Null)
            {
                s2kUsage = SecretKeyPacket.UsageNone;
                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)   // SHA-1 hash, need to rewrite checksum
                {
                    keyData = new byte[rawKeyData.Length - 18];

                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);

                    byte[] check = checksum(null, keyData, keyData.Length - 2);

                    keyData[keyData.Length - 2] = check[0];
                    keyData[keyData.Length - 1] = check[1];
                }
                else
                {
                    keyData = rawKeyData;
                }
            }
            else
            {
                if (s2kUsage == SecretKeyPacket.UsageNone)
                {
                    s2kUsage = SecretKeyPacket.UsageChecksum;
                }
                if (key.secret.PublicKeyPacket.Version < 4)
                {
                    // Version 2 or 3 - RSA Keys only
                    keyData = new byte[rawKeyData.Length];

                    if (newKeyEncryptor.ChecksumCalculatorFactory.AlgorithmDetails.Algorithm != HashAlgorithmTag.MD5)
                    {
                        throw new PgpException("MD5 Digest Calculator required for version 3 key encryptor.");
                    }

                    //
                    // process 4 numbers
                    //
                    int pos = 0;
                    for (int i = 0; i != 4; i++)
                    {
                        int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8;

                        keyData[pos]     = rawKeyData[pos];
                        keyData[pos + 1] = rawKeyData[pos + 1];

                        byte[] tmp;

                        if (i == 0)
                        {
                            tmp = newKeyEncryptor.Wrap(Arrays.CopyOfRange(rawKeyData, pos + 2, pos + 2 + encLen)).Collect();
                            iv  = newKeyEncryptor.AlgorithmDetails.GetIV();
                        }
                        else
                        {
                            byte[] tmpIv = new byte[iv.Length];

                            Array.Copy(keyData, pos - iv.Length, tmpIv, 0, tmpIv.Length);
                            newKeyEncryptor = newKeyEncryptor.WithIV(tmpIv);
                            tmp             = newKeyEncryptor.Wrap(Arrays.CopyOfRange(rawKeyData, pos + 2, pos + 2 + encLen)).Collect();
                        }

                        Array.Copy(tmp, 0, keyData, pos + 2, tmp.Length);
                        pos += 2 + encLen;
                    }

                    //
                    // copy in checksum.
                    //
                    keyData[pos]     = rawKeyData[pos];
                    keyData[pos + 1] = rawKeyData[pos + 1];

                    s2k             = newKeyEncryptor.AlgorithmDetails.S2k;
                    newEncAlgorithm = newKeyEncryptor.AlgorithmDetails.Algorithm;
                }
                else
                {
                    keyData = newKeyEncryptor.Wrap(rawKeyData).Collect();

                    iv = newKeyEncryptor.AlgorithmDetails.GetIV();

                    s2k = newKeyEncryptor.AlgorithmDetails.S2k;

                    newEncAlgorithm = newKeyEncryptor.AlgorithmDetails.Algorithm;
                }
            }

            SecretKeyPacket secret;

            if (key.secret is SecretSubkeyPacket)
            {
                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
                                                newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }
            else
            {
                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
                                             newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }

            return(new PgpSecretKey(secret, key.pub));
        }
Exemple #24
0
        internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
        {
            int keySize = GetKeySize(algorithm);

            byte[] pBytes   = rawPassPhrase;
            byte[] keyBytes = new byte[(keySize + 7) / 8];

            int generatedBytes = 0;
            int loopCount      = 0;

            while (generatedBytes < keyBytes.Length)
            {
                IDigest digest;
                if (s2k != null)
                {
                    string digestName = GetDigestName(s2k.HashAlgorithm);

                    try
                    {
                        digest = DigestUtilities.GetDigest(digestName);
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find S2k digest", e);
                    }

                    for (int i = 0; i != loopCount; i++)
                    {
                        digest.Update(0);
                    }

                    byte[] iv = s2k.GetIV();

                    switch (s2k.Type)
                    {
                    case S2k.Simple:
                        digest.BlockUpdate(pBytes, 0, pBytes.Length);
                        break;

                    case S2k.Salted:
                        digest.BlockUpdate(iv, 0, iv.Length);
                        digest.BlockUpdate(pBytes, 0, pBytes.Length);
                        break;

                    case S2k.SaltedAndIterated:
                        long count = s2k.IterationCount;
                        digest.BlockUpdate(iv, 0, iv.Length);
                        digest.BlockUpdate(pBytes, 0, pBytes.Length);

                        count -= iv.Length + pBytes.Length;

                        while (count > 0)
                        {
                            if (count < iv.Length)
                            {
                                digest.BlockUpdate(iv, 0, (int)count);
                                break;
                            }
                            else
                            {
                                digest.BlockUpdate(iv, 0, iv.Length);
                                count -= iv.Length;
                            }

                            if (count < pBytes.Length)
                            {
                                digest.BlockUpdate(pBytes, 0, (int)count);
                                count = 0;
                            }
                            else
                            {
                                digest.BlockUpdate(pBytes, 0, pBytes.Length);
                                count -= pBytes.Length;
                            }
                        }
                        break;

                    default:
                        throw new PgpException("unknown S2k type: " + s2k.Type);
                    }
                }
                else
                {
                    try
                    {
                        digest = DigestUtilities.GetDigest("MD5");

                        for (int i = 0; i != loopCount; i++)
                        {
                            digest.Update(0);
                        }

                        digest.BlockUpdate(pBytes, 0, pBytes.Length);
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find MD5 digest", e);
                    }
                }

                byte[] dig = DigestUtilities.DoFinal(digest);

                if (dig.Length > (keyBytes.Length - generatedBytes))
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
                }
                else
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
                }

                generatedBytes += dig.Length;

                loopCount++;
            }

            if (clearPassPhrase && rawPassPhrase != null)
            {
                Array.Clear(rawPassPhrase, 0, rawPassPhrase.Length);
            }

            return(MakeKey(algorithm, keyBytes));
        }
Exemple #25
0
        internal PgpSecretKey(
            PgpKeyPair					keyPair,
            SymmetricKeyAlgorithmTag	encAlgorithm,
            char[]						passPhrase,
			bool						useSHA1,
			SecureRandom				rand)
        {
            PublicKeyPacket pubPk = keyPair.PublicKey.publicPk;

            BcpgObject secKey;
            switch (keyPair.PublicKey.Algorithm)
            {
                case PublicKeyAlgorithmTag.RsaEncrypt:
                case PublicKeyAlgorithmTag.RsaSign:
                case PublicKeyAlgorithmTag.RsaGeneral:
                    RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) keyPair.PrivateKey.Key;
                    secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
                    break;
                case PublicKeyAlgorithmTag.Dsa:
                    DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) keyPair.PrivateKey.Key;
                    secKey = new DsaSecretBcpgKey(dsK.X);
                    break;
                case PublicKeyAlgorithmTag.ElGamalEncrypt:
                case PublicKeyAlgorithmTag.ElGamalGeneral:
                    ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) keyPair.PrivateKey.Key;
                    secKey = new ElGamalSecretBcpgKey(esK.X);
                    break;
                default:
                    throw new PgpException("unknown key class");
            }

            string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);

            IBufferedCipher c = null;
            if (cName != null)
            {
                try
                {
                    c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception creating cipher", e);
                }
            }

            try
            {
                MemoryStream bOut = new MemoryStream();
                BcpgOutputStream pOut = new BcpgOutputStream(bOut);

                pOut.WriteObject(secKey);

                byte[] keyData = bOut.ToArray();
                byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length);

                pOut.Write(checksumBytes);

                byte[] bOutData = bOut.ToArray();

                if (c != null)
                {
                    byte[] iv = new byte[8];
                    rand.NextBytes(iv);

                    S2k s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
                    KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);

                    iv = new byte[c.GetBlockSize()];
                    rand.NextBytes(iv);
                    c.Init(true, new ParametersWithIV(key, iv));

                    byte[] encData = c.DoFinal(bOutData);

                    int usage = useSHA1
                        ?	SecretKeyPacket.UsageSha1
                        :	SecretKeyPacket.UsageChecksum;

                    this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData);
                }
                else
                {
                    this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData);
                }

                this.trust = null;
            }
            catch (PgpException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new PgpException("Exception encrypting key", e);
            }

            this.keySigs = new ArrayList();
        }
 /// <remarks>
 /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
 /// </remarks>
 public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
 {
     return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, true), true);
 }
Exemple #27
0
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="oldPassPhrase">The current password for the key.</param>
        /// <param name="newPassPhrase">The new password for the key.</param>
        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
        /// <param name="rand">Source of randomness.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey				key,
            char[]						oldPassPhrase,
            char[]						newPassPhrase,
            SymmetricKeyAlgorithmTag	newEncAlgorithm,
            SecureRandom				rand)
        {
            byte[]	rawKeyData = key.ExtractKeyData(oldPassPhrase);
            int		s2kUsage = key.secret.S2kUsage;
            byte[]	iv = null;
            S2k		s2k = null;
            byte[]	keyData;

            if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
            {
                s2kUsage = SecretKeyPacket.UsageNone;
                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)   // SHA-1 hash, need to rewrite Checksum
                {
                    keyData = new byte[rawKeyData.Length - 18];

                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);

                    byte[] check = Checksum(false, keyData, keyData.Length - 2);

                    keyData[keyData.Length - 2] = check[0];
                    keyData[keyData.Length - 1] = check[1];
                }
                else
                {
                    keyData = rawKeyData;
                }
            }
            else
            {
                IBufferedCipher c;
                try
                {
                    string cName = PgpUtilities.GetSymmetricCipherName(newEncAlgorithm);
                    c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception creating cipher", e);
                }

                iv = new byte[8];
                rand.NextBytes(iv);
                s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
                try
                {
                    KeyParameter sKey = PgpUtilities.MakeKeyFromPassPhrase(newEncAlgorithm, s2k, newPassPhrase);
                    iv = new byte[c.GetBlockSize()];
                    rand.NextBytes(iv);
                    c.Init(true, new ParametersWithIV(sKey, iv));

                    keyData = c.DoFinal(rawKeyData);
                }
                catch (PgpException e)
                {
                    throw e;
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception encrypting key", e);
                }
            }

            SecretKeyPacket secret;
            if (key.secret is SecretSubkeyPacket)
            {
                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
                    newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }
            else
            {
                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
                    newEncAlgorithm, s2kUsage, s2k, iv, keyData);
            }

            if (key.subSigs == null)
            {
                return new PgpSecretKey(secret, key.trust, key.keySigs, key.ids,
                    key.idTrusts, key.idSigs, key.pub);
            }

            return new PgpSecretKey(secret, key.trust, key.subSigs, key.pub);
        }
        private static byte[] EncryptKeyDataV4(
            byte[]						rawKeyData,
            SymmetricKeyAlgorithmTag	encAlgorithm,
            HashAlgorithmTag            hashAlgorithm,
            byte[]						rawPassPhrase,
            bool                        clearPassPhrase,
            SecureRandom				random,
            out S2k						s2k,
            out byte[]					iv)
        {
            s2k = PgpUtilities.GenerateS2k(hashAlgorithm, 0x60, random);

            KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);

            iv = null;
            return EncryptData(encAlgorithm, key, rawKeyData, 0, rawKeyData.Length, random, ref iv);
        }
 internal PbeMethod(SymmetricKeyAlgorithmTag encAlgorithm, S2k s2K, KeyParameter key)
 {
     this.EncAlgorithm = encAlgorithm;
     this._s2K = s2K;
     this.Key = key;
 }
		/// <summary>Add a PBE encryption method to the encrypted object.</summary>
        public void AddMethod(
 			char[]				passPhrase,
			HashAlgorithmTag	s2kDigest)
        {
            byte[] iv = new byte[8];
			rand.NextBytes(iv);

			S2k s2k = new S2k(s2kDigest, iv, 0x60);

			methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase)));
        }
        /// <summary>Add a PBE encryption method to the encrypted object.</summary>
        public void AddMethod(char[] passPhrase, HashAlgorithmTag s2KDigest)
        {
            var iv = new byte[8];
            _rand.NextBytes(iv);

            var s2K = new S2k(s2KDigest, iv, 0x60);
            _methods.Add(new PbeMethod(_defAlgorithm, s2K, PgpUtilities.MakeKeyFromPassPhrase(_defAlgorithm, s2K, passPhrase)));
        }
		public static KeyParameter MakeKeyFromPassPhrase(
            SymmetricKeyAlgorithmTag	algorithm,
            S2k							s2k,
            char[]						passPhrase)
        {
			// Changed pBytes to get string via encoding
			// this should use the OS encoding.
			//
			// vvv EDDINGTON
			var encoding = System.Text.Encoding.UTF8;

			int keySize = GetKeySize(algorithm);
			byte[] pBytes = encoding.GetBytes(new string(passPhrase));
			byte[] keyBytes = new byte[(keySize + 7) / 8];
			// ^^^ EDDINGTON

			int generatedBytes = 0;
            int loopCount = 0;

			while (generatedBytes < keyBytes.Length)
            {
				IDigest digest;
				if (s2k != null)
                {
					string digestName = GetDigestName(s2k.HashAlgorithm);

                    try
                    {
						digest = DigestUtilities.GetDigest(digestName);
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find S2k digest", e);
                    }

					for (int i = 0; i != loopCount; i++)
                    {
                        digest.Update(0);
                    }

					byte[] iv = s2k.GetIV();

					switch (s2k.Type)
                    {
						case S2k.Simple:
							digest.BlockUpdate(pBytes, 0, pBytes.Length);
							break;
						case S2k.Salted:
							digest.BlockUpdate(iv, 0, iv.Length);
							digest.BlockUpdate(pBytes, 0, pBytes.Length);
							break;
						case S2k.SaltedAndIterated:
							long count = s2k.IterationCount;
							digest.BlockUpdate(iv, 0, iv.Length);
							digest.BlockUpdate(pBytes, 0, pBytes.Length);

							count -= iv.Length + pBytes.Length;

							while (count > 0)
							{
								if (count < iv.Length)
								{
									digest.BlockUpdate(iv, 0, (int)count);
									break;
								}
								else
								{
									digest.BlockUpdate(iv, 0, iv.Length);
									count -= iv.Length;
								}

								if (count < pBytes.Length)
								{
									digest.BlockUpdate(pBytes, 0, (int)count);
									count = 0;
								}
								else
								{
									digest.BlockUpdate(pBytes, 0, pBytes.Length);
									count -= pBytes.Length;
								}
							}
							break;
						default:
							throw new PgpException("unknown S2k type: " + s2k.Type);
                    }
                }
                else
                {
                    try
                    {
                        digest = DigestUtilities.GetDigest("MD5");

						for (int i = 0; i != loopCount; i++)
                        {
                            digest.Update(0);
                        }

						digest.BlockUpdate(pBytes, 0, pBytes.Length);
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find MD5 digest", e);
                    }
                }

				byte[] dig = DigestUtilities.DoFinal(digest);

				if (dig.Length > (keyBytes.Length - generatedBytes))
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
                }
                else
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
                }

				generatedBytes += dig.Length;

				loopCount++;
            }

			Array.Clear(pBytes, 0, pBytes.Length);

			return MakeKey(algorithm, keyBytes);
        }
 public PgpPbeKeyEncryptionParameters(SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, byte[] iv)
 {
     this.Algorithm = encAlgorithm;
     this.S2k       = s2k;
     this.mIv       = Arrays.Clone(iv);
 }
Exemple #34
0
		public static KeyParameter MakeKeyFromPassPhrase(
            SymmetricKeyAlgorithmTag	algorithm,
            S2k							s2k,
            char[]						passPhrase)
        {
			int keySize = GetKeySize(algorithm);
			byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
			byte[] keyBytes = new byte[(keySize + 7) / 8];

			int generatedBytes = 0;
            int loopCount = 0;

			while (generatedBytes < keyBytes.Length)
            {
				IDigest digest;
				if (s2k != null)
                {
                    try
                    {
                        switch (s2k.HashAlgorithm)
                        {
							case HashAlgorithmTag.Sha1:
								digest = DigestUtilities.GetDigest("SHA1");
								break;
							default:
								throw new PgpException("unknown hash algorithm: " + s2k.HashAlgorithm);
                        }
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find S2k digest", e);
                    }

					for (int i = 0; i != loopCount; i++)
                    {
                        digest.Update(0);
                    }

					byte[] iv = s2k.GetIV();

					switch (s2k.Type)
                    {
						case S2k.Simple:
							digest.BlockUpdate(pBytes, 0, pBytes.Length);
							break;
						case S2k.Salted:
							digest.BlockUpdate(iv, 0, iv.Length);
							digest.BlockUpdate(pBytes, 0, pBytes.Length);
							break;
						case S2k.SaltedAndIterated:
							long count = s2k.IterationCount;
							digest.BlockUpdate(iv, 0, iv.Length);
							digest.BlockUpdate(pBytes, 0, pBytes.Length);

							count -= iv.Length + pBytes.Length;

							while (count > 0)
							{
								if (count < iv.Length)
								{
									digest.BlockUpdate(iv, 0, (int)count);
									break;
								}
								else
								{
									digest.BlockUpdate(iv, 0, iv.Length);
									count -= iv.Length;
								}

								if (count < pBytes.Length)
								{
									digest.BlockUpdate(pBytes, 0, (int)count);
									count = 0;
								}
								else
								{
									digest.BlockUpdate(pBytes, 0, pBytes.Length);
									count -= pBytes.Length;
								}
							}
							break;
						default:
							throw new PgpException("unknown S2k type: " + s2k.Type);
                    }
                }
                else
                {
                    try
                    {
                        digest = DigestUtilities.GetDigest("MD5");

						for (int i = 0; i != loopCount; i++)
                        {
                            digest.Update(0);
                        }

						digest.BlockUpdate(pBytes, 0, pBytes.Length);
                    }
                    catch (Exception e)
                    {
                        throw new PgpException("can't find MD5 digest", e);
                    }
                }

				byte[] dig = DigestUtilities.DoFinal(digest);

				if (dig.Length > (keyBytes.Length - generatedBytes))
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
                }
                else
                {
                    Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
                }

				generatedBytes += dig.Length;

				loopCount++;
            }

			Array.Clear(pBytes, 0, pBytes.Length);

			return MakeKey(algorithm, keyBytes);
        }
        internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
        {
            byte[] iv = new byte[8];
            rand.NextBytes(iv);

            S2k s2k = new S2k(s2kDigest, iv, 0x60);

            methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
        }