Esempio n. 1
0
        /**
         * Extract a PgpPrivate key from the SecretKey's encrypted contents.
         *
         * @param decryptorFactory  factory to use to generate a decryptor for the passed in secretKey.
         * @return PgpPrivateKey  the unencrypted private key.
         * @throws PgpException on failure.
         */
        public PgpPrivateKey ExtractPrivateKey(
            IPbeSecretKeyDecryptorProvider decryptorProvider)
        {
            if (IsPrivateKeyEmpty)
            {
                return(null);
            }

            PublicKeyPacket pubPk = secret.PublicKeyPacket;

            try
            {
                byte[]          data  = extractKeyData(decryptorProvider);
                BcpgInputStream input = BcpgInputStream.Wrap(new MemoryInputStream(data));


                switch (pubPk.Algorithm)
                {
                case PublicKeyAlgorithmTag.RsaEncrypt:
                case PublicKeyAlgorithmTag.RsaGeneral:
                case PublicKeyAlgorithmTag.RsaSign:
                    RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(input);

                    return(new PgpPrivateKey(this.KeyId, pubPk, rsaPriv));

                case PublicKeyAlgorithmTag.Dsa:
                    DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(input);

                    return(new PgpPrivateKey(this.KeyId, pubPk, dsaPriv));

                case PublicKeyAlgorithmTag.ElGamalEncrypt:
                case PublicKeyAlgorithmTag.ElGamalGeneral:
                    ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(input);

                    return(new PgpPrivateKey(this.KeyId, pubPk, elPriv));

                case PublicKeyAlgorithmTag.ECDH:
                case PublicKeyAlgorithmTag.ECDsa:
                    ECSecretBcpgKey ecPriv = new ECSecretBcpgKey(input);

                    return(new PgpPrivateKey(this.KeyId, pubPk, ecPriv));

                default:
                    throw new PgpException("unknown public key algorithm encountered");
                }
            }
            catch (PgpException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new PgpException("Exception constructing key", e);
            }
        }
Esempio n. 2
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));
        }
Esempio n. 3
0
        private byte[] extractKeyData(
            IPbeSecretKeyDecryptorProvider decryptorFactory)
        {
            byte[] encData = secret.GetSecretKeyData();
            byte[] data;
            if (secret.EncAlgorithm != SymmetricKeyAlgorithmTag.Null)
            {
                try
                {
                    if (secret.PublicKeyPacket.Version == 4)
                    {
                        IKeyUnwrapper <PgpPbeKeyEncryptionParameters> unwrapper = decryptorFactory.CreateKeyUnwrapper(new PgpPbeKeyEncryptionParameters(secret.EncAlgorithm, secret.S2k, secret.GetIV()));

                        data = unwrapper.Unwrap(encData, 0, encData.Length).Collect();

                        bool   useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
                        byte[] check   = checksum(useSHA1 ? decryptorFactory.CreateDigestFactory(new PgpDigestTypeIdentifier(HashAlgorithmTag.Sha1)) : null, data, (useSHA1) ? data.Length - 20 : data.Length - 2);

                        for (int i = 0; i != check.Length; i++)
                        {
                            if (check[i] != data[data.Length - check.Length + i])
                            {
                                throw new PgpException("checksum mismatch at " + i + " of " + check.Length);
                            }
                        }
                    }
                    else // version 2 or 3, Rsa only.
                    {
                        IKeyUnwrapper <PgpPbeKeyEncryptionParameters> unwrapper = decryptorFactory.CreateKeyUnwrapper(new PgpPbeKeyEncryptionParameters(secret.EncAlgorithm, secret.S2k, secret.GetIV()));

                        data = new byte[encData.Length];

                        byte[] iv = new byte[secret.GetIV().Length];

                        Array.Copy(secret.GetIV(), 0, iv, 0, iv.Length);

                        //
                        // read in the four numbers
                        //
                        int pos = 0;

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

                            data[pos]     = encData[pos];
                            data[pos + 1] = encData[pos + 1];

                            byte[] tmp = unwrapper.Unwrap(encData, pos + 2, encLen).Collect();
                            Array.Copy(tmp, 0, data, pos + 2, tmp.Length);
                            pos += 2 + encLen;

                            if (i != 3)
                            {
                                Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length);
                            }
                        }

                        //
                        // 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++)
                        {
                            calcCs += data[j] & 0xff;
                        }

                        calcCs &= 0xffff;
                        if (calcCs != cs)
                        {
                            throw new PgpException("checksum mismatch: passphrase wrong, expected "
                                                   + cs.ToString("X")
                                                   + " found " + calcCs.ToString("X"));
                        }
                    }
                }
                catch (PgpException e)
                {
                    throw e;
                }
                catch (Exception e)
                {
                    throw new PgpException("Exception decrypting key", e);
                }
            }
            else
            {
                data = encData;
            }

            return(data);
        }