From 653f318d37790163f08c1d7e0c70c3d016cae21f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 23 May 2018 15:21:10 +0200 Subject: [PATCH] Implement restoring secret key --- .../BouncyCastleOpenPgpProvider.java | 46 ++++++++++++++++++- .../smackx/ox/OpenPgpManager.java | 15 ++++++ .../smackx/ox/OpenPgpProvider.java | 2 + 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProvider.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProvider.java index 5c83c4f48..c551dd63b 100644 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProvider.java +++ b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProvider.java @@ -42,6 +42,7 @@ import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.exception.CorruptedOpenPgpKeyException; import name.neuhalfen.projects.crypto.bouncycastle.openpgp.BouncyGPG; +import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPHashAlgorithms; import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPSymmetricEncryptionAlgorithms; import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeySize; import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallbacks; @@ -52,13 +53,16 @@ import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.Keyring import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyRingGenerator; +import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.Streams; @@ -67,8 +71,8 @@ import org.jxmpp.jid.BareJid; public class BouncyCastleOpenPgpProvider implements OpenPgpProvider { private final BareJid ourJid; - private final InMemoryKeyring ourKeys; - private final Long ourKeyId; + private InMemoryKeyring ourKeys; + private Long ourKeyId; private final Map theirKeys = new HashMap<>(); public BouncyCastleOpenPgpProvider(BareJid ourJid) throws IOException, PGPException, NoSuchAlgorithmException { @@ -146,6 +150,44 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider { } + @Override + public void restoreSecretKeyElement(SecretkeyElement secretkeyElement, String password) + throws CorruptedOpenPgpKeyException { + byte[] encoded = Base64.decode(secretkeyElement.getB64Data()); + + try { + PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(BouncyGPG.getProvider()) + .build(); + + InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys( + KeyringConfigCallbacks.withPassword(password)); + keyring.addSecretKey(encoded); + for (PGPSecretKeyRing r : keyring.getSecretKeyRings()) { + PGPSecretKey s = r.getSecretKey(); + PGPPrivateKey privateKey = s.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(calculatorProvider).build(password.toCharArray())); + PGPPublicKey publicKey = s.getPublicKey(); + PGPSecretKey secretKey = new PGPSecretKey( + privateKey, + publicKey, + calculatorProvider.get(PGPHashAlgorithms.SHA1.getAlgorithmId()), + true, + null); + + InMemoryKeyring newKeyring = KeyringConfigs.forGpgExportedKeys( + KeyringConfigCallbacks.withUnprotectedKeys()); + + newKeyring.addSecretKey(secretKey.getEncoded()); + newKeyring.addPublicKey(secretKey.getPublicKey().getEncoded()); + + ourKeys = newKeyring; + ourKeyId = secretKey.getKeyID(); + } + } catch (PGPException | IOException e) { + e.printStackTrace(); + } + } + @Override public OpenPgpElement signAndEncrypt(SigncryptElement element, Set recipients) throws Exception { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java index e7290c763..db51d82fc 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java @@ -31,6 +31,7 @@ import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.Async; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.ox.callback.AskForBackupCodeCallback; import org.jivesoftware.smackx.ox.callback.DisplayBackupCodeCallback; import org.jivesoftware.smackx.ox.element.PubkeyElement; import org.jivesoftware.smackx.ox.element.PublicKeysListElement; @@ -296,6 +297,20 @@ public final class OpenPgpManager extends Manager { callback.displayBackupCode(password); } + public void fetchSecretKey(AskForBackupCodeCallback callback) + throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, + SmackException.NotConnectedException, SmackException.NoResponseException, CorruptedOpenPgpKeyException { + PubSubManager pm = PubSubManager.getInstance(connection()); + LeafNode secretKeyNode = pm.getOrCreateLeafNode(PEP_NODE_SECRET_KEY); + List> list = secretKeyNode.getItems(1); + if (list.size() == 0) { + LOGGER.log(Level.INFO, "No secret key published!"); + return; + } + SecretkeyElement secretkeyElement = list.get(0).getPayload(); + provider.restoreSecretKeyElement(secretkeyElement, callback.askForBackupCode()); + } + /** * Return the upper-case hex encoded OpenPGP v4 fingerprint of our key pair. * diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java index 8a8401d1d..4a8b18281 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java @@ -154,4 +154,6 @@ public interface OpenPgpProvider { String getFingerprint() throws CorruptedOpenPgpKeyException; SecretkeyElement createSecretkeyElement(String password) throws CorruptedOpenPgpKeyException; + + void restoreSecretKeyElement(SecretkeyElement secretkeyElement, String password) throws CorruptedOpenPgpKeyException; }