mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-24 04:52:05 +01:00
Move backup related methods to Helper class
This commit is contained in:
parent
d86f3ef2e1
commit
ed3c4236cf
8 changed files with 192 additions and 66 deletions
|
@ -38,7 +38,6 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
|
||||||
private OpenPgpV4Fingerprint primaryKeyFingerprint = null;
|
private OpenPgpV4Fingerprint primaryKeyFingerprint = null;
|
||||||
private final SecretKeyRingProtector secretKeyRingProtector;
|
private final SecretKeyRingProtector secretKeyRingProtector;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() {
|
public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() {
|
||||||
return primaryKeyFingerprint;
|
return primaryKeyFingerprint;
|
||||||
|
|
|
@ -373,7 +373,12 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
if (publicKeyRings == null) {
|
if (publicKeyRings == null) {
|
||||||
publicKeyRings = new PGPPublicKeyRingCollection(Collections.singleton(ring));
|
publicKeyRings = new PGPPublicKeyRingCollection(Collections.singleton(ring));
|
||||||
} else {
|
} else {
|
||||||
publicKeyRings = PGPPublicKeyRingCollection.addPublicKeyRing(publicKeyRings, ring);
|
try {
|
||||||
|
publicKeyRings = PGPPublicKeyRingCollection.addPublicKeyRing(publicKeyRings, ring);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.log(Level.INFO, "Skip key " + Long.toHexString(ring.getPublicKey().getKeyID()) +
|
||||||
|
" as it is already in the public key ring.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
getStore().storePublicKeyRing(owner, publicKeyRings);
|
getStore().storePublicKeyRing(owner, publicKeyRings);
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
|
@ -392,8 +397,6 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
throw new SmackOpenPgpException("Could not deserialize PGP secret key of " + owner.toString(), e);
|
throw new SmackOpenPgpException("Could not deserialize PGP secret key of " + owner.toString(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setPrimaryOpenPgpKeyPairFingerprint(getFingerprint(importSecretKeys.getPublicKey()));
|
|
||||||
|
|
||||||
if (!new BareJidUserId.SecRingSelectionStrategy().accept(owner, importSecretKeys)) {
|
if (!new BareJidUserId.SecRingSelectionStrategy().accept(owner, importSecretKeys)) {
|
||||||
throw new MissingUserIdOnKeyException(owner, importSecretKeys.getPublicKey().getKeyID());
|
throw new MissingUserIdOnKeyException(owner, importSecretKeys.getPublicKey().getKeyID());
|
||||||
}
|
}
|
||||||
|
@ -426,6 +429,12 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
return getFingerprint(publicKeys.getPublicKey());
|
return getFingerprint(publicKeys.getPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpV4Fingerprint importSecretKey(byte[] bytes)
|
||||||
|
throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException {
|
||||||
|
return importSecretKey(owner, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
||||||
byte[] hex = Hex.encode(publicKey.getFingerprint());
|
byte[] hex = Hex.encode(publicKey.getFingerprint());
|
||||||
return new OpenPgpV4Fingerprint(hex);
|
return new OpenPgpV4Fingerprint(hex);
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.FileUtils;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
import org.jivesoftware.smackx.ox.SecretKeyBackupHelper;
|
||||||
|
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||||
|
import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.UnprotectedKeysProtector;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.JidTestUtil;
|
||||||
|
|
||||||
|
public class BackupRestoreTest extends OxTestSuite {
|
||||||
|
|
||||||
|
private static final File backupPath = FileUtils.getTempDir("ox-backup");
|
||||||
|
private static final File restorePath = FileUtils.getTempDir("ox-restore");
|
||||||
|
private static final BareJid owner = JidTestUtil.BARE_JID_1;
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@AfterClass
|
||||||
|
public static void deletePaths() {
|
||||||
|
FileUtils.deleteDirectory(backupPath);
|
||||||
|
FileUtils.deleteDirectory(restorePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test()
|
||||||
|
throws NoSuchAlgorithmException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException,
|
||||||
|
SmackOpenPgpException, MissingUserIdOnKeyException, InvalidBackupCodeException,
|
||||||
|
MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
||||||
|
FileBasedPainlessOpenPgpStore backupStore = new FileBasedPainlessOpenPgpStore(backupPath, new UnprotectedKeysProtector());
|
||||||
|
FileBasedPainlessOpenPgpStore restoreStore = new FileBasedPainlessOpenPgpStore(restorePath, new UnprotectedKeysProtector());
|
||||||
|
|
||||||
|
PainlessOpenPgpProvider backupProvider = new PainlessOpenPgpProvider(owner, backupStore);
|
||||||
|
PainlessOpenPgpProvider restoreProvider = new PainlessOpenPgpProvider(owner, restoreStore);
|
||||||
|
|
||||||
|
KeyBytesAndFingerprint key = backupProvider.generateOpenPgpKeyPair(owner);
|
||||||
|
backupProvider.importSecretKey(key.getBytes());
|
||||||
|
|
||||||
|
final String backupCode = SecretKeyBackupHelper.generateBackupPassword();
|
||||||
|
SecretkeyElement backup = SecretKeyBackupHelper.createSecretkeyElement(backupProvider, owner, Collections.singleton(key.getFingerprint()), backupCode);
|
||||||
|
|
||||||
|
OpenPgpV4Fingerprint fingerprint = SecretKeyBackupHelper.restoreSecretKeyBackup(restoreProvider, backup, backupCode);
|
||||||
|
|
||||||
|
assertEquals(key.getFingerprint(), fingerprint);
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(backupStore.getSecretKeyRingBytes(owner, fingerprint), restoreStore.getSecretKeyRingBytes(owner, fingerprint)));
|
||||||
|
assertTrue(Arrays.equals(backupStore.getPublicKeyRingBytes(owner, fingerprint), restoreStore.getPublicKeyRingBytes(owner, fingerprint)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,12 +21,10 @@ import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEY
|
||||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.fetchPubkey;
|
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.fetchPubkey;
|
||||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.publishPublicKey;
|
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.publishPublicKey;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -65,6 +63,7 @@ import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
|
||||||
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||||
import org.jivesoftware.smackx.ox.listener.internal.CryptElementReceivedListener;
|
import org.jivesoftware.smackx.ox.listener.internal.CryptElementReceivedListener;
|
||||||
import org.jivesoftware.smackx.ox.listener.internal.SignElementReceivedListener;
|
import org.jivesoftware.smackx.ox.listener.internal.SignElementReceivedListener;
|
||||||
|
@ -297,11 +296,11 @@ public final class OpenPgpManager extends Manager {
|
||||||
|
|
||||||
BareJid ownJid = connection().getUser().asBareJid();
|
BareJid ownJid = connection().getUser().asBareJid();
|
||||||
|
|
||||||
String backupCode = generateBackupPassword();
|
String backupCode = SecretKeyBackupHelper.generateBackupPassword();
|
||||||
Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid);
|
Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid);
|
||||||
Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
|
Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
|
||||||
|
|
||||||
SecretkeyElement secretKey = createSecretkeyElement(ownJid, selectedKeyPairs, backupCode);
|
SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode);
|
||||||
|
|
||||||
PubSubDelegate.depositSecretKey(connection(), secretKey);
|
PubSubDelegate.depositSecretKey(connection(), secretKey);
|
||||||
displayCodeCallback.displayBackupCode(backupCode);
|
displayCodeCallback.displayBackupCode(backupCode);
|
||||||
|
@ -339,18 +338,19 @@ public final class OpenPgpManager extends Manager {
|
||||||
SecretKeyRestoreSelectionCallback selectionCallback)
|
SecretKeyRestoreSelectionCallback selectionCallback)
|
||||||
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
||||||
SmackException.NotConnectedException, SmackException.NoResponseException, SmackOpenPgpException,
|
SmackException.NotConnectedException, SmackException.NoResponseException, SmackOpenPgpException,
|
||||||
InvalidBackupCodeException, SmackException.NotLoggedInException, IOException, MissingUserIdOnKeyException {
|
InvalidBackupCodeException, SmackException.NotLoggedInException, IOException, MissingUserIdOnKeyException,
|
||||||
|
NoBackupFoundException {
|
||||||
throwIfNoProviderSet();
|
throwIfNoProviderSet();
|
||||||
throwIfNotAuthenticated();
|
throwIfNotAuthenticated();
|
||||||
SecretkeyElement backup = PubSubDelegate.fetchSecretKey(connection());
|
SecretkeyElement backup = PubSubDelegate.fetchSecretKey(connection());
|
||||||
if (backup == null) {
|
if (backup == null) {
|
||||||
// TODO
|
throw new NoBackupFoundException();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
byte[] encrypted = Base64.decode(backup.getB64Data());
|
|
||||||
byte[] decrypted = provider.symmetricallyDecryptWithPassword(encrypted, codeCallback.askForBackupCode());
|
String backupCode = codeCallback.askForBackupCode();
|
||||||
provider.importSecretKey(connection().getUser().asBareJid(), decrypted);
|
|
||||||
// TODO: catch InvalidBackupCodeException in order to prevent re-fetching the backup on next try.
|
OpenPgpV4Fingerprint fingerprint = SecretKeyBackupHelper.restoreSecretKeyBackup(provider, backup, backupCode);
|
||||||
|
provider.getStore().setPrimaryOpenPgpKeyPairFingerprint(fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -505,34 +505,6 @@ public final class OpenPgpManager extends Manager {
|
||||||
provider.importPublicKey(owner, Base64.decode(base64));
|
provider.importPublicKey(owner, Base64.decode(base64));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a secure backup code.
|
|
||||||
*
|
|
||||||
* @see <a href="https://xmpp.org/extensions/xep-0373.html#sect-idm140425111347232">XEP-0373 §5.3</a>
|
|
||||||
* @return backup code
|
|
||||||
*/
|
|
||||||
private static String generateBackupPassword() {
|
|
||||||
final String alphabet = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
StringBuilder code = new StringBuilder();
|
|
||||||
|
|
||||||
// 6 blocks
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
|
|
||||||
// of 4 chars
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
char c = alphabet.charAt(random.nextInt(alphabet.length()));
|
|
||||||
code.append(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// dash after every block except the last one
|
|
||||||
if (i != 5) {
|
|
||||||
code.append('-');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PubkeyElement createPubkeyElement(BareJid owner,
|
private PubkeyElement createPubkeyElement(BareJid owner,
|
||||||
OpenPgpV4Fingerprint fingerprint,
|
OpenPgpV4Fingerprint fingerprint,
|
||||||
Date date)
|
Date date)
|
||||||
|
@ -545,28 +517,6 @@ public final class OpenPgpManager extends Manager {
|
||||||
return new PubkeyElement(new PubkeyElement.PubkeyDataElement(Base64.encode(bytes)), date);
|
return new PubkeyElement(new PubkeyElement.PubkeyDataElement(Base64.encode(bytes)), date);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretkeyElement createSecretkeyElement(BareJid owner,
|
|
||||||
Set<OpenPgpV4Fingerprint> fingerprints,
|
|
||||||
String backupCode) throws SmackOpenPgpException, IOException {
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = provider.getStore().getSecretKeyRingBytes(owner, fingerprint);
|
|
||||||
buffer.write(bytes);
|
|
||||||
} catch (MissingOpenPgpKeyPairException | IOException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return createSecretkeyElement(buffer.toByteArray(), backupCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecretkeyElement createSecretkeyElement(byte[] keys, String backupCode)
|
|
||||||
throws SmackOpenPgpException, IOException {
|
|
||||||
byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode);
|
|
||||||
return new SecretkeyElement(Base64.encode(encrypted));
|
|
||||||
}
|
|
||||||
|
|
||||||
void addSigncryptReceivedListener(SigncryptElementReceivedListener listener) {
|
void addSigncryptReceivedListener(SigncryptElementReceivedListener listener) {
|
||||||
signcryptElementReceivedListeners.add(listener);
|
signcryptElementReceivedListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,5 +139,8 @@ public interface OpenPgpProvider {
|
||||||
OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes)
|
OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes)
|
||||||
throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException;
|
throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException;
|
||||||
|
|
||||||
|
OpenPgpV4Fingerprint importSecretKey(byte[] bytes)
|
||||||
|
throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException;
|
||||||
|
|
||||||
OpenPgpStore getStore();
|
OpenPgpStore getStore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package org.jivesoftware.smackx.ox;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
|
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class SecretKeyBackupHelper {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(SecretKeyBackupHelper.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a secure backup code.
|
||||||
|
*
|
||||||
|
* @see <a href="https://xmpp.org/extensions/xep-0373.html#sect-idm140425111347232">XEP-0373 §5.3</a>
|
||||||
|
* @return backup code
|
||||||
|
*/
|
||||||
|
public static String generateBackupPassword() {
|
||||||
|
final String alphabet = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
StringBuilder code = new StringBuilder();
|
||||||
|
|
||||||
|
// 6 blocks
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
|
||||||
|
// of 4 chars
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
char c = alphabet.charAt(random.nextInt(alphabet.length()));
|
||||||
|
code.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dash after every block except the last one
|
||||||
|
if (i != 5) {
|
||||||
|
code.append('-');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
|
||||||
|
BareJid owner,
|
||||||
|
Set<OpenPgpV4Fingerprint> fingerprints,
|
||||||
|
String backupCode) throws SmackOpenPgpException, IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = provider.getStore().getSecretKeyRingBytes(owner, fingerprint);
|
||||||
|
buffer.write(bytes);
|
||||||
|
} catch (MissingOpenPgpKeyPairException | IOException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return createSecretkeyElement(provider, buffer.toByteArray(), backupCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
|
||||||
|
byte[] keys,
|
||||||
|
String backupCode)
|
||||||
|
throws SmackOpenPgpException, IOException {
|
||||||
|
byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode);
|
||||||
|
return new SecretkeyElement(Base64.encode(encrypted));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OpenPgpV4Fingerprint restoreSecretKeyBackup(OpenPgpProvider provider, SecretkeyElement backup, String backupCode)
|
||||||
|
throws InvalidBackupCodeException, IOException, MissingUserIdOnKeyException, SmackOpenPgpException {
|
||||||
|
byte[] encrypted = Base64.decode(backup.getB64Data());
|
||||||
|
|
||||||
|
byte[] decrypted;
|
||||||
|
try {
|
||||||
|
decrypted = provider.symmetricallyDecryptWithPassword(encrypted, backupCode);
|
||||||
|
} catch (IOException | SmackOpenPgpException e) {
|
||||||
|
throw new InvalidBackupCodeException("Could not decrypt secret key backup. Possibly wrong passphrase?", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.importSecretKey(decrypted);
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,4 +22,8 @@ package org.jivesoftware.smackx.ox.exception;
|
||||||
public class InvalidBackupCodeException extends Exception {
|
public class InvalidBackupCodeException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public InvalidBackupCodeException(String message, Throwable e) {
|
||||||
|
super(message, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.exception;
|
package org.jivesoftware.smackx.ox.exception;
|
||||||
|
|
||||||
public class NoBackupFoundException {
|
public class NoBackupFoundException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue