/** * 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)); }
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); } }