/*
* Kontalk Android client
* Copyright (C) 2017 Kontalk Devteam <devteam@kontalk.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kontalk.crypto;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemWriter;
import org.kontalk.provider.Keyring;
/**
* Exporter for a personal key.
* @author Daniele Ricci
*/
public class PersonalKeyExporter implements PersonalKeyPack {
public void save(byte[] privateKey, byte[] publicKey, OutputStream dest, String passphrase, String exportPassphrase, byte[] bridgeCert,
Map<String, Keyring.TrustedFingerprint> trustedKeys, String phoneNumber)
throws PGPException, IOException, CertificateException, NoSuchProviderException, KeyStoreException, NoSuchAlgorithmException {
// put everything in a zip file
ZipOutputStream zip = new ZipOutputStream(dest);
// custom export passphrase -- re-encrypt private key
if (exportPassphrase != null) {
privateKey = PGP.copySecretKeyRingWithNewPassword(privateKey,
passphrase, exportPassphrase)
.getEncoded();
}
else {
// use provided passphrase for export
exportPassphrase = passphrase;
}
OutputStream out;
ByteArrayOutputStream stream;
if (bridgeCert != null) {
// export bridge certificate
zip.putNextEntry(new ZipEntry(BRIDGE_CERT_FILENAME));
stream = new ByteArrayOutputStream();
PemWriter writer = new PemWriter(new OutputStreamWriter(stream));
writer.writeObject(new PemObject(X509Bridge.PEM_TYPE_CERTIFICATE, bridgeCert));
writer.close();
stream.writeTo(zip);
zip.closeEntry();
// export bridge private key
zip.putNextEntry(new ZipEntry(BRIDGE_KEY_FILENAME));
PrivateKey bridgeKey = PGP.convertPrivateKey(privateKey, exportPassphrase);
stream = new ByteArrayOutputStream();
writer = new PemWriter(new OutputStreamWriter(stream));
writer.writeObject(new PemObject(X509Bridge.PEM_TYPE_PRIVATE_KEY, bridgeKey.getEncoded()));
writer.close();
stream.writeTo(zip);
zip.closeEntry();
// certificate pack in PKCS#12
zip.putNextEntry(new ZipEntry(BRIDGE_CERTPACK_FILENAME));
X509Certificate certificate = X509Bridge.load(bridgeCert);
KeyStore pkcs12 = X509Bridge.exportCertificate(certificate, bridgeKey);
pkcs12.store(zip, exportPassphrase.toCharArray());
zip.closeEntry();
}
// export public key
zip.putNextEntry(new ZipEntry(PUBLIC_KEY_FILENAME));
stream = new ByteArrayOutputStream();
out = new ArmoredOutputStream(stream);
out.write(publicKey);
out.close();
stream.writeTo(zip);
zip.closeEntry();
// export private key
zip.putNextEntry(new ZipEntry(PRIVATE_KEY_FILENAME));
stream = new ByteArrayOutputStream();
out = new ArmoredOutputStream(stream);
out.write(privateKey);
out.close();
stream.writeTo(zip);
zip.closeEntry();
if (trustedKeys != null) {
// export trusted keys
Properties prop = new Properties();
for (Map.Entry<String, Keyring.TrustedFingerprint> tk : trustedKeys.entrySet())
prop.put(tk.getKey(), tk.getValue().toString());
zip.putNextEntry(new ZipEntry(TRUSTED_KEYS_FILENAME));
prop.store(zip, null);
zip.closeEntry();
}
// export account info
Properties info = new Properties();
info.setProperty("phoneNumber", phoneNumber);
zip.putNextEntry(new ZipEntry(ACCOUNT_INFO_FILENAME));
info.store(zip, null);
zip.closeEntry();
// finalize the zip file
zip.close();
}
}