package com.wesabe.grendel.openpgp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import com.wesabe.grendel.util.Iterators;
/**
* A {@link MasterKey} and {@link SubKey} pair.
*
* @author coda
*/
public class KeySet {
private final MasterKey masterKey;
private final SubKey subKey;
/**
* Loads a {@link KeySet} from an array of bytes.
*
* @throws CryptographicException if the encoded {@link KeySet} is malformed
*/
public static KeySet load(byte[] encoded) throws CryptographicException {
return load(new ByteArrayInputStream(encoded));
}
/**
* Loads a {@link KeySet} from a {@link PGPSecretKeyRing}.
*/
public static KeySet load(PGPSecretKeyRing keyRing) throws CryptographicException {
final List<PGPSecretKey> secretKeys = Iterators.toList(keyRing.getSecretKeys());
final MasterKey masterKey = MasterKey.load(secretKeys.get(0));
final SubKey subKey = SubKey.load(secretKeys.get(1), masterKey);
return new KeySet(masterKey, subKey);
}
/**
* Loads a {@link KeySet} from an {@link InputStream}.
*/
public static KeySet load(InputStream input) throws CryptographicException {
try {
final PGPSecretKeyRing keyRing = new PGPSecretKeyRing(input);
input.close();
return load(keyRing);
} catch (IOException e) {
throw new CryptographicException(e);
} catch (PGPException e) {
throw new CryptographicException(e);
}
}
protected KeySet(MasterKey masterKey, SubKey subKey) {
this.masterKey = masterKey;
this.subKey = subKey;
}
/**
* Returns the keyset's {@link MasterKey}.
*/
public MasterKey getMasterKey() {
return masterKey;
}
/**
* Returns the keyset's {@link SubKey}.
*/
public SubKey getSubKey() {
return subKey;
}
/**
* Returns the keyset's user ID.
*/
public String getUserID() {
return masterKey.getUserID();
}
/**
* Writes the keyset in encoded form, to {@code output}.
*
* @param output an {@link OutputStream}
* @throws IOException if there is an error writing to {@code output}
*/
public void encode(OutputStream output) throws IOException {
masterKey.getSecretKey().encode(output);
subKey.getSecretKey().encode(output);
}
/**
* Returns the keyset in encoded form.
*/
public byte[] getEncoded() {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
encode(output);
} catch (IOException e) {
throw new RuntimeException(e);
}
return output.toByteArray();
}
@Override
public String toString() {
return String.format("[%s, %s]", masterKey, subKey);
}
/**
* Given the keyset's passphrase, unlocks the secret keys and returns an
* {@link UnlockedKeySet} equivalent of {@code this}.
*
* @param passphrase the key's passphrase
* @return a {@link UnlockedKeySet} equivalent of {@code this}
* @throws CryptographicException if {@code passphrase} is incorrect
*/
public UnlockedKeySet unlock(char[] passphrase) throws CryptographicException {
final UnlockedMasterKey unlockedMasterKey = masterKey.unlock(passphrase);
final UnlockedSubKey unlockedSubKey = subKey.unlock(passphrase);
return new UnlockedKeySet(unlockedMasterKey, unlockedSubKey);
}
}