/* * 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.IOException; import java.security.NoSuchProviderException; import java.security.cert.CertificateException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.openpgp.PGPException; import org.kontalk.crypto.PGP.PGPKeyPairRing; import org.kontalk.provider.Keyring; import org.kontalk.util.ByteArrayInOutStream; import org.kontalk.util.MessageUtils; /** * Importer for a personal key pack. * @author Daniele Ricci */ public class PersonalKeyImporter implements PersonalKeyPack { private static final long MAX_KEY_SIZE = 102400; // 100 KB private ZipInputStream mKeyPack; private String mPassphrase; private ByteArrayInOutStream mPublicKey; private ByteArrayInOutStream mPrivateKey; private ByteArrayInOutStream mTrustedKeys; private ByteArrayInOutStream mAccountInfo; public PersonalKeyImporter(ZipInputStream keypack, String passphrase) { mKeyPack = keypack; mPassphrase = passphrase; } public void load() throws IOException { ByteArrayInOutStream publicKey = null, privateKey = null, trustedKeys = null, accountInfo = null; IOException zipException = null; ZipEntry entry; try { while ((entry = mKeyPack.getNextEntry()) != null) { // PGP public key if (PUBLIC_KEY_FILENAME.equals(entry.getName())) { // I don't really know if this is good... publicKey = MessageUtils.readFully(mKeyPack, MAX_KEY_SIZE); } // PGP private key else if (PRIVATE_KEY_FILENAME.equals(entry.getName())) { // I don't really know if this is good... privateKey = MessageUtils.readFully(mKeyPack, MAX_KEY_SIZE); } // trusted keys else if (TRUSTED_KEYS_FILENAME.equals(entry.getName())) { // I don't really know if this is good... trustedKeys = MessageUtils.readFully(mKeyPack, MAX_KEY_SIZE); } // account info else if (ACCOUNT_INFO_FILENAME.equals(entry.getName())) { // I don't really know if this is good... accountInfo = MessageUtils.readFully(mKeyPack, MAX_KEY_SIZE); } } } catch (IOException e) { // this is to workaround any problem // this exception will be logged if data is corrupted or not present zipException = e; } if (privateKey == null || publicKey == null) { IOException e = new IOException("invalid data"); e.initCause(zipException); throw e; } mPrivateKey = privateKey; mPublicKey = publicKey; mTrustedKeys = trustedKeys; mAccountInfo = accountInfo; } /** Releases all resources of imported data. */ public void close() throws IOException { if (mPrivateKey != null) mPrivateKey.close(); if (mPublicKey != null) mPublicKey.close(); } /** Creates a {@link PersonalKey} out of the imported data, if possible. */ public PersonalKey createPersonalKey() throws PGPException, NoSuchProviderException, CertificateException, IOException { if (mPrivateKey != null && mPublicKey != null) return PersonalKey.load( new ArmoredInputStream(mPrivateKey.getInputStream()), new ArmoredInputStream(mPublicKey.getInputStream()), mPassphrase, null); return null; } public PGPKeyPairRing createKeyPairRing() throws PGPException, NoSuchProviderException, CertificateException, IOException { if (mPrivateKey != null && mPublicKey != null) return PersonalKey.test( new ArmoredInputStream(mPrivateKey.getInputStream()), new ArmoredInputStream(mPublicKey.getInputStream()), mPassphrase, null); return null; } public byte[] getPrivateKeyData() { return mPrivateKey != null ? mPrivateKey.toByteArray() : null; } public byte[] getPublicKeyData() { return mPublicKey != null ? mPublicKey.toByteArray() : null; } @SuppressWarnings("unchecked") public Map<String, Keyring.TrustedFingerprint> getTrustedKeys() throws IOException { if (mTrustedKeys != null) { Properties prop = new Properties(); prop.load(mTrustedKeys.getInputStream()); try { return Keyring.fromTrustedFingerprintMap((Map) prop); } catch (Exception ex) { throw new IOException("invalid trusted keys file", ex); } } return null; } @SuppressWarnings("unchecked") public Map<String, String> getAccountInfo() throws IOException { if (mAccountInfo != null) { Properties prop = new Properties(); prop.load(mAccountInfo.getInputStream()); return new HashMap<>((Map) prop); } return null; } }