/** * 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, PBESecretKeyDecryptor oldKeyDecryptor, PBESecretKeyEncryptor newKeyEncryptor) throws PGPException { 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.getS2KUsage(); byte[] iv = null; S2K s2k = null; byte[] keyData; int newEncAlgorithm = SymmetricKeyAlgorithmTags.NULL; if (newKeyEncryptor == null || newKeyEncryptor.getAlgorithm() == SymmetricKeyAlgorithmTags.NULL) { s2kUsage = SecretKeyPacket.USAGE_NONE; if (key.secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1) // SHA-1 hash, need to rewrite checksum { keyData = new byte[rawKeyData.length - 18]; System.arraycopy(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 (key.secret.getPublicKeyPacket().getVersion() < 4) { // Version 2 or 3 - RSA Keys only byte[] encKey = newKeyEncryptor.getKey(); keyData = new byte[rawKeyData.length]; if (newKeyEncryptor.getS2K() != null) { 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.encryptKeyData(encKey, rawKeyData, pos + 2, encLen); iv = newKeyEncryptor.getCipherIV(); } else { byte[] tmpIv = new byte[iv.length]; System.arraycopy(keyData, pos - iv.length, tmpIv, 0, tmpIv.length); tmp = newKeyEncryptor.encryptKeyData(encKey, tmpIv, rawKeyData, pos + 2, encLen); } System.arraycopy(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.getS2K(); newEncAlgorithm = newKeyEncryptor.getAlgorithm(); } else { keyData = newKeyEncryptor.encryptKeyData(rawKeyData, 0, rawKeyData.length); iv = newKeyEncryptor.getCipherIV(); s2k = newKeyEncryptor.getS2K(); newEncAlgorithm = newKeyEncryptor.getAlgorithm(); } } SecretKeyPacket secret; if (key.secret instanceof SecretSubkeyPacket) { secret = new SecretSubkeyPacket( key.secret.getPublicKeyPacket(), newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket( key.secret.getPublicKeyPacket(), newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return new PGPSecretKey(secret, key.pub); }
PGPSecretKey( PGPPrivateKey privKey, PGPPublicKey pubKey, PGPDigestCalculator checksumCalculator, boolean isMasterKey, PBESecretKeyEncryptor keyEncryptor) throws PGPException { this.pub = pubKey; BCPGObject secKey = (BCPGObject) privKey.getPrivateKeyDataPacket(); try { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); BCPGOutputStream pOut = new BCPGOutputStream(bOut); pOut.writeObject(secKey); byte[] keyData = bOut.toByteArray(); pOut.write(checksum(checksumCalculator, keyData, keyData.length)); int encAlgorithm = keyEncryptor.getAlgorithm(); if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL) { keyData = bOut.toByteArray(); // include checksum byte[] encData = keyEncryptor.encryptKeyData(keyData, 0, keyData.length); byte[] iv = keyEncryptor.getCipherIV(); S2K s2k = keyEncryptor.getS2K(); int s2kUsage; if (checksumCalculator != null) { if (checksumCalculator.getAlgorithm() != HashAlgorithmTags.SHA1) { throw new PGPException("only SHA1 supported for key checksum calculations."); } s2kUsage = SecretKeyPacket.USAGE_SHA1; } else { s2kUsage = SecretKeyPacket.USAGE_CHECKSUM; } if (isMasterKey) { this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData); } else { this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData); } } else { if (isMasterKey) { this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, bOut.toByteArray()); } else { this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, bOut.toByteArray()); } } } catch (PGPException e) { throw e; } catch (Exception e) { throw new PGPException("Exception encrypting key", e); } }