package com.wesabe.grendel.openpgp; import java.security.NoSuchProviderException; import java.util.List; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPSecretKey; /** * A PGP subkey, used for encrypting and decrypting data. <b>Must</b> be * certified by a {@link MasterKey}. * * @author coda */ public class SubKey extends AbstractKey { private final MasterKey masterKey; /** * Loads a subkey from a {@link PGPSecretKey} instance and verifies the * certification by the given {@link MasterKey}. * * @param key a {@link PGPSecretKey} instance * @param masterKey the signing {@link MasterKey} * @return a {@link SubKey} instance * @throws CryptographicException if {@code masterKey}'s certification is invalid */ public static SubKey load(PGPSecretKey key, MasterKey masterKey) throws CryptographicException { final SubKey subKey = new SubKey(key, masterKey); if (verify(subKey, masterKey)) { return subKey; } throw new CryptographicException("not a valid subkey"); } private static boolean verify(SubKey subKey, MasterKey masterKey) { return subKey.signature.verifyCertification(subKey, masterKey); } protected SubKey(PGPSecretKey key, MasterKey masterKey) { super(key, masterKey.getSecretKey(), SignatureType.SUBKEY_BINDING); this.masterKey = masterKey; } @Override public String getUserID() { return masterKey.getUserID(); } @Override public List<String> getUserIDs() { return masterKey.getUserIDs(); } @Override public List<CompressionAlgorithm> getPreferredCompressionAlgorithms() { return masterKey.getPreferredCompressionAlgorithms(); } @Override public List<HashAlgorithm> getPreferredHashAlgorithms() { return masterKey.getPreferredHashAlgorithms(); } @Override public List<SymmetricAlgorithm> getPreferredSymmetricAlgorithms() { return masterKey.getPreferredSymmetricAlgorithms(); } /** * Returns the paired {@link MasterKey}. */ public MasterKey getMasterKey() { return masterKey; } @Override public UnlockedSubKey unlock(char[] passphrase) throws CryptographicException { try { final PGPPrivateKey privateKey = secretKey.extractPrivateKey(passphrase, "BC"); return new UnlockedSubKey(secretKey, masterKey, privateKey); } catch (NoSuchProviderException e) { throw new CryptographicException(e); } catch (PGPException e) { throw new CryptographicException("incorrect passphrase"); } } }