From 5930f71fe60000b89fdaf51b1410a89290747fce Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 3 Mar 2021 14:30:45 +0100 Subject: [PATCH] Improvements --- .../java/app/fedilab/android/client/API.java | 3 +- .../java/app/fedilab/android/helper/ECDH.java | 84 ++++++++----------- .../android/services/UnifiedPushService.java | 4 +- 3 files changed, 41 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/client/API.java b/app/src/main/java/app/fedilab/android/client/API.java index 7205d25ee..252dc9ee7 100644 --- a/app/src/main/java/app/fedilab/android/client/API.java +++ b/app/src/main/java/app/fedilab/android/client/API.java @@ -112,7 +112,6 @@ import app.fedilab.android.sqlite.TimelineCacheDAO; import static app.fedilab.android.helper.ECDH.kp_private; import static app.fedilab.android.helper.ECDH.kp_public; -import static app.fedilab.android.helper.ECDH.newPair; /** @@ -5866,7 +5865,7 @@ public class API { String strPriv = prefs.getString(kp_private, ""); ECDH ecdh = ECDH.getInstance(); if (strPub.trim().isEmpty() || strPriv.trim().isEmpty()) { - newPair(context); + ecdh.newPair(context); } String pubKey = ecdh.getPublicKey(context); byte[] randBytes = new byte[16]; diff --git a/app/src/main/java/app/fedilab/android/helper/ECDH.java b/app/src/main/java/app/fedilab/android/helper/ECDH.java index 46a6247ff..82cc80874 100644 --- a/app/src/main/java/app/fedilab/android/helper/ECDH.java +++ b/app/src/main/java/app/fedilab/android/helper/ECDH.java @@ -19,28 +19,21 @@ import android.content.Context; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.util.Base64; - import androidx.preference.PreferenceManager; - - import org.spongycastle.asn1.ASN1ObjectIdentifier; import org.spongycastle.asn1.x9.ECNamedCurveTable; import org.spongycastle.asn1.x9.X9ECParameters; import org.spongycastle.crypto.params.ECNamedDomainParameters; import org.spongycastle.crypto.params.ECPrivateKeyParameters; import org.spongycastle.crypto.params.ECPublicKeyParameters; -import org.spongycastle.jce.provider.BouncyCastleProvider; import org.spongycastle.jce.spec.ECNamedCurveSpec; import org.spongycastle.jce.spec.ECParameterSpec; import org.spongycastle.jce.spec.ECPrivateKeySpec; import org.spongycastle.jce.spec.ECPublicKeySpec; -import org.spongycastle.jce.spec.IEKeySpec; import org.spongycastle.math.ec.ECCurve; import org.spongycastle.math.ec.ECPoint; -import java.io.ByteArrayInputStream; import java.math.BigInteger; -import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -51,20 +44,16 @@ import java.security.PublicKey; import java.security.Security; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.ArrayList; import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; import javax.crypto.KeyAgreement; -import javax.crypto.spec.SecretKeySpec; import app.fedilab.android.client.Entities.Account; import app.fedilab.android.sqlite.AccountDAO; import app.fedilab.android.sqlite.Sqlite; -// https://github.com/nelenkov/ecdh-kx/blob/master/src/org/nick/ecdhkx/Crypto.java + public class ECDH { @@ -76,24 +65,26 @@ public class ECDH { public static final String kp_private = "kp_private"; public static final String KEGEN_ALG = "ECDH"; + public static final String name = "prime256v1"; + private static final String kp_public_affine_x = "kp_public_affine_x"; private static final String kp_public_affine_y = "kp_public_affine_y"; private static ECDH instance; - static { Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); } - public static KeyFactory kf = null; - private static KeyPairGenerator kpg = null; + public final KeyFactory kf; + private final KeyPairGenerator kpg; public ECDH() { try { kf = KeyFactory.getInstance(KEGEN_ALG, PROVIDER); kpg = KeyPairGenerator.getInstance(KEGEN_ALG, PROVIDER); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); throw new RuntimeException(e); @@ -104,7 +95,6 @@ public class ECDH { if (instance == null) { instance = new ECDH(); } - return instance; } @@ -119,16 +109,15 @@ public class ECDH { return Base64.decode(str, Base64.DEFAULT); } - static synchronized KeyPair generateKeyPair() + synchronized KeyPair generateKeyPair() throws Exception { - ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("prime256v1"); + ECGenParameterSpec ecParamSpec = new ECGenParameterSpec(name); kpg.initialize(ecParamSpec); return kpg.generateKeyPair(); } - private static byte[] generateSecret(PrivateKey myPrivKey, PublicKey otherPubKey) throws Exception { - + private byte[] generateSecret(PrivateKey myPrivKey, PublicKey otherPubKey) throws Exception { KeyAgreement keyAgreement = KeyAgreement.getInstance(KEGEN_ALG); keyAgreement.init(myPrivKey); keyAgreement.doPhase(otherPubKey, true); @@ -137,13 +126,13 @@ public class ECDH { } - static synchronized KeyPair readKeyPair(Context context) + synchronized KeyPair readKeyPair(Context context) throws Exception { return new KeyPair(readMyPublicKey(context), readMyPrivateKey(context)); } @SuppressLint("ApplySharedPref") - public static KeyPair newPair(Context context) { + public KeyPair newPair(Context context) { SharedPreferences.Editor prefsEditor = PreferenceManager .getDefaultSharedPreferences(context).edit(); KeyPair kp; @@ -159,8 +148,8 @@ public class ECDH { byte[] y = key.getW().getAffineY().toByteArray(); BigInteger xbi = new BigInteger(1, x); BigInteger ybi = new BigInteger(1, y); - X9ECParameters x9 = ECNamedCurveTable.getByName("prime256v1"); - ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID("prime256v1"); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name); ECCurve curve = x9.getCurve(); ECPoint point = curve.createPoint(xbi, ybi); @@ -184,10 +173,10 @@ public class ECDH { } - static synchronized PublicKey readMyPublicKey(Context context) throws Exception { + synchronized PublicKey readMyPublicKey(Context context) throws Exception { - X9ECParameters x9 = ECNamedCurveTable.getByName("prime256v1"); - ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID("prime256v1"); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); @@ -198,24 +187,23 @@ public class ECDH { x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); - ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec("prime256v1", dParams.getCurve(), dParams.getG(), dParams.getN()); + ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec(name, dParams.getCurve(), dParams.getG(), dParams.getN()); java.security.spec.ECPoint w = new java.security.spec.ECPoint(xbi, ybi); return kf.generatePublic(new java.security.spec.ECPublicKeySpec(w, ecNamedCurveSpec)); } - public static String uncryptMessage(Context context, String cyphered, String slug) { + public String uncryptMessage(Context context, String cyphered, String slug) { getInstance(); SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String[] slugArray = slug.split("@"); Account account = new AccountDAO(context, db).getUniqAccountUsernameInstance(slugArray[0], slugArray[1]); byte[] privateKey = getSharedSecret(context, account); try { - Cipher outCipher = Cipher.getInstance("ECIES", "SC"); + Cipher outCipher = Cipher.getInstance("ECIES", PROVIDER); // outCipher.init(Cipher.DECRYPT_MODE, readPrivateKey(privateKey)); outCipher.init(Cipher.DECRYPT_MODE, readPrivateKey(privateKey)); - - byte[] plaintext = outCipher.doFinal(cyphered.getBytes(StandardCharsets.UTF_8)); + byte[] plaintext = outCipher.doFinal(Base64.decode(cyphered, Base64.DEFAULT)); String finalText = new String(plaintext); return finalText; } catch (Exception e) { @@ -226,9 +214,8 @@ public class ECDH { } - public static PublicKey readPublicKey(String keyStr) throws Exception { - KeyFactory kf = KeyFactory.getInstance("ECDH", new BouncyCastleProvider()); - ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec("prime256v1"); + public PublicKey readPublicKey(String keyStr) throws Exception { + ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec(name); ECCurve curve = parameterSpec.getCurve(); ECPoint point = curve.decodePoint(base64Decode(keyStr)); ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec); @@ -236,33 +223,32 @@ public class ECDH { } - public static PrivateKey readPrivateKey(byte[] key) throws Exception { - KeyFactory kf = KeyFactory.getInstance("ECDH", new BouncyCastleProvider()); - ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec("prime256v1"); + public PrivateKey readPrivateKey(byte[] key) throws Exception { + ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec(name); ECPrivateKeySpec pubSpec = new ECPrivateKeySpec(new BigInteger(1, key), parameterSpec); return kf.generatePrivate(pubSpec); } - static synchronized PrivateKey readMyPrivateKey(Context context) throws Exception { - X9ECParameters x9 = ECNamedCurveTable.getByName("prime256v1"); - ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID("prime256v1"); + synchronized PrivateKey readMyPrivateKey(Context context) throws Exception { + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); BigInteger ybi = new BigInteger(prefs.getString(kp_public_affine_y, "0")); ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); - ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec("prime256v1", dParams.getCurve(), dParams.getG(), dParams.getN()); + ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec(name, dParams.getCurve(), dParams.getG(), dParams.getN()); return kf.generatePrivate(new java.security.spec.ECPrivateKeySpec(ybi, ecNamedCurveSpec)); } - private static synchronized KeyPair getPair(Context context) { + private synchronized KeyPair getPair(Context context) { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); String strPub = prefs.getString(kp_public, ""); String strPriv = prefs.getString(kp_private, ""); - if (strPub.trim().isEmpty() || strPriv.trim().isEmpty() || 1 == 1) { + if (strPub.trim().isEmpty() || strPriv.trim().isEmpty()) { return newPair(context); } try { @@ -273,7 +259,7 @@ public class ECDH { return null; } - static PublicKey getServerKey(Context context, Account account) throws Exception { + PublicKey getServerKey(Context context, Account account) throws Exception { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); String serverKey = prefs.getString(peer_public + account.getId() + account.getInstance(), ""); @@ -281,13 +267,17 @@ public class ECDH { } @SuppressWarnings({"unused", "RedundantSuppression"}) - public static byte[] getSharedSecret(Context context, Account account) { + public byte[] getSharedSecret(Context context, Account account) { try { - return generateSecret(getPair(context).getPrivate(), getServerKey(context, account)); + KeyPair keyPair = getPair(context); + if (keyPair != null) { + return generateSecret(keyPair.getPrivate(), getServerKey(context, account)); + } } catch (Exception e) { e.printStackTrace(); return null; } + return null; } public String getPublicKey(Context context) { diff --git a/app/src/main/java/app/fedilab/android/services/UnifiedPushService.java b/app/src/main/java/app/fedilab/android/services/UnifiedPushService.java index bd244299d..e9ffec29b 100644 --- a/app/src/main/java/app/fedilab/android/services/UnifiedPushService.java +++ b/app/src/main/java/app/fedilab/android/services/UnifiedPushService.java @@ -23,6 +23,7 @@ import org.unifiedpush.android.connector.MessagingReceiverHandler; import app.fedilab.android.client.Entities.Account; +import app.fedilab.android.helper.ECDH; import app.fedilab.android.helper.NotificationsHelper; import app.fedilab.android.helper.PushNotifications; import app.fedilab.android.sqlite.AccountDAO; @@ -39,7 +40,8 @@ class handler implements MessagingReceiverHandler { if (context != null) { SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String[] slugArray = slug.split("@"); - //ECDH.uncryptMessage(context, s, slug); + ECDH ecdh = ECDH.getInstance(); + //ecdh.uncryptMessage(context, s, slug); Account account = new AccountDAO(context, db).getUniqAccountUsernameInstance(slugArray[0], slugArray[1]); NotificationsHelper.task(context, account); }