예제 #1
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));
        }
예제 #2
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);
            }
        }