mirror of
https://github.com/nextcloud/android.git
synced 2024-11-28 18:28:59 +03:00
check e2e keys
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
f6d14856a4
commit
df2714ffad
3 changed files with 85 additions and 9 deletions
|
@ -52,6 +52,8 @@ import java.util.HashSet;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||||
|
@ -144,6 +146,33 @@ public class EncryptionTestIT {
|
||||||
assertTrue(Arrays.equals(key1, key2));
|
assertTrue(Arrays.equals(key1, key2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void encryptStringAsymmetricCorrectPublicKey() throws Exception {
|
||||||
|
KeyPair keyPair = EncryptionUtils.generateKeyPair();
|
||||||
|
|
||||||
|
byte[] key1 = generateKey();
|
||||||
|
String base64encodedKey = encodeBytesToBase64String(key1);
|
||||||
|
|
||||||
|
String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey, keyPair.getPublic());
|
||||||
|
String decryptedString = decryptStringAsymmetric(encryptedString, keyPair.getPrivate());
|
||||||
|
|
||||||
|
byte[] key2 = decodeStringToBase64Bytes(decryptedString);
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(key1, key2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BadPaddingException.class)
|
||||||
|
public void encryptStringAsymmetricWrongPublicKey() throws Exception {
|
||||||
|
KeyPair keyPair1 = EncryptionUtils.generateKeyPair();
|
||||||
|
KeyPair keyPair2 = EncryptionUtils.generateKeyPair();
|
||||||
|
|
||||||
|
byte[] key1 = generateKey();
|
||||||
|
String base64encodedKey = encodeBytesToBase64String(key1);
|
||||||
|
|
||||||
|
String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey, keyPair1.getPublic());
|
||||||
|
decryptStringAsymmetric(encryptedString, keyPair2.getPrivate());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encryptStringSymmetricRandom() throws Exception {
|
public void encryptStringSymmetricRandom() throws Exception {
|
||||||
int max = 500;
|
int max = 500;
|
||||||
|
|
|
@ -52,6 +52,7 @@ import com.owncloud.android.utils.theme.ThemeColorUtils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -61,6 +62,11 @@ import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
|
||||||
|
import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes;
|
||||||
|
import static com.owncloud.android.utils.EncryptionUtils.decryptStringAsymmetric;
|
||||||
|
import static com.owncloud.android.utils.EncryptionUtils.encodeBytesToBase64String;
|
||||||
|
import static com.owncloud.android.utils.EncryptionUtils.generateKey;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dialog to setup encryption
|
* Dialog to setup encryption
|
||||||
*/
|
*/
|
||||||
|
@ -187,24 +193,43 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
||||||
String privateKey = task.get();
|
String privateKey = task.get();
|
||||||
String mnemonicUnchanged = passwordField.getText().toString();
|
String mnemonicUnchanged = passwordField.getText().toString();
|
||||||
String mnemonic = passwordField.getText().toString().replaceAll("\\s", "")
|
String mnemonic = passwordField.getText().toString().replaceAll("\\s", "")
|
||||||
.toLowerCase(Locale.ROOT);
|
.toLowerCase(Locale.ROOT);
|
||||||
String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey,
|
String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
|
|
||||||
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
|
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
|
||||||
EncryptionUtils.PRIVATE_KEY, decryptedPrivateKey);
|
EncryptionUtils.PRIVATE_KEY, decryptedPrivateKey);
|
||||||
|
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
Log_OC.d(TAG, "Private key successfully decrypted and stored");
|
Log_OC.d(TAG, "Private key successfully decrypted and stored");
|
||||||
|
|
||||||
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), EncryptionUtils.MNEMONIC,
|
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
|
||||||
mnemonicUnchanged);
|
EncryptionUtils.MNEMONIC,
|
||||||
|
mnemonicUnchanged);
|
||||||
|
|
||||||
|
// check if private key and public key match
|
||||||
|
String publicKey = arbitraryDataProvider.getValue(user.getAccountName(),
|
||||||
|
EncryptionUtils.PUBLIC_KEY);
|
||||||
|
|
||||||
|
byte[] key1 = generateKey();
|
||||||
|
String base64encodedKey = encodeBytesToBase64String(key1);
|
||||||
|
|
||||||
|
String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey,
|
||||||
|
publicKey);
|
||||||
|
String decryptedString = decryptStringAsymmetric(encryptedString,
|
||||||
|
decryptedPrivateKey);
|
||||||
|
|
||||||
|
byte[] key2 = decodeStringToBase64Bytes(decryptedString);
|
||||||
|
|
||||||
|
if (!Arrays.equals(key1, key2)) {
|
||||||
|
throw new Exception("Keys do not match");
|
||||||
|
}
|
||||||
|
|
||||||
Intent intentExisting = new Intent();
|
Intent intentExisting = new Intent();
|
||||||
intentExisting.putExtra(SUCCESS, true);
|
intentExisting.putExtra(SUCCESS, true);
|
||||||
intentExisting.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
|
intentExisting.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
|
||||||
getTargetFragment().onActivityResult(getTargetRequestCode(),
|
getTargetFragment().onActivityResult(getTargetRequestCode(),
|
||||||
SETUP_ENCRYPTION_RESULT_CODE, intentExisting);
|
SETUP_ENCRYPTION_RESULT_CODE, intentExisting);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
textView.setText(R.string.end_to_end_encryption_wrong_password);
|
textView.setText(R.string.end_to_end_encryption_wrong_password);
|
||||||
|
@ -257,7 +282,8 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
||||||
Log_OC.d(TAG, "public key successful downloaded for " + user.getAccountName());
|
Log_OC.d(TAG, "public key successful downloaded for " + user.getAccountName());
|
||||||
|
|
||||||
String publicKeyFromServer = (String) publicKeyResult.getData().get(0);
|
String publicKeyFromServer = (String) publicKeyResult.getData().get(0);
|
||||||
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY,
|
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
|
||||||
|
EncryptionUtils.PUBLIC_KEY,
|
||||||
publicKeyFromServer);
|
publicKeyFromServer);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -384,7 +384,7 @@ public final class EncryptionUtils {
|
||||||
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
|
||||||
String trimmedCert = cert.replace("-----BEGIN CERTIFICATE-----\n", "")
|
String trimmedCert = cert.replace("-----BEGIN CERTIFICATE-----\n", "")
|
||||||
.replace("-----END CERTIFICATE-----\n", "");
|
.replace("-----END CERTIFICATE-----\n", "");
|
||||||
byte[] encodedCert = trimmedCert.getBytes(StandardCharsets.UTF_8);
|
byte[] encodedCert = trimmedCert.getBytes(StandardCharsets.UTF_8);
|
||||||
byte[] decodedCert = org.apache.commons.codec.binary.Base64.decodeBase64(encodedCert);
|
byte[] decodedCert = org.apache.commons.codec.binary.Base64.decodeBase64(encodedCert);
|
||||||
|
|
||||||
|
@ -401,6 +401,17 @@ public final class EncryptionUtils {
|
||||||
return encodeBytesToBase64String(cryptedBytes);
|
return encodeBytesToBase64String(cryptedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String encryptStringAsymmetric(String string, PublicKey publicKey) throws NoSuchPaddingException,
|
||||||
|
NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
|
||||||
|
byte[] bytes = encodeStringToBase64Bytes(string);
|
||||||
|
byte[] cryptedBytes = cipher.doFinal(bytes);
|
||||||
|
|
||||||
|
return encodeBytesToBase64String(cryptedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding
|
* Decrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding
|
||||||
|
@ -414,7 +425,7 @@ public final class EncryptionUtils {
|
||||||
throws NoSuchAlgorithmException,
|
throws NoSuchAlgorithmException,
|
||||||
NoSuchPaddingException, InvalidKeyException,
|
NoSuchPaddingException, InvalidKeyException,
|
||||||
BadPaddingException, IllegalBlockSizeException,
|
BadPaddingException, IllegalBlockSizeException,
|
||||||
InvalidKeySpecException {
|
InvalidKeySpecException {
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
|
||||||
|
@ -431,6 +442,16 @@ public final class EncryptionUtils {
|
||||||
return decodeBase64BytesToString(encodedBytes);
|
return decodeBase64BytesToString(encodedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String decryptStringAsymmetric(String string, PrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
|
||||||
|
byte[] bytes = decodeStringToBase64Bytes(string);
|
||||||
|
byte[] encodedBytes = cipher.doFinal(bytes);
|
||||||
|
|
||||||
|
return decodeBase64BytesToString(encodedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding Asymmetric encryption, with private
|
* Encrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding Asymmetric encryption, with private
|
||||||
* and public key
|
* and public key
|
||||||
|
|
Loading…
Reference in a new issue