Generate ECDH with SC key pair

This commit is contained in:
Thomas 2021-02-26 15:24:57 +01:00
parent 48312017ef
commit 5215576c8f
5 changed files with 99 additions and 30 deletions

View File

@ -173,10 +173,9 @@ dependencies {
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
implementation 'com.huangyz0918:androidwm-light:0.1.2'
implementation "com.madgag.spongycastle:bctls-jdk15on:1.58.0.0"
implementation "com.madgag.spongycastle:prov:1.58.0.0"
implementation "com.madgag.spongycastle:bcpkix-jdk15on:1.58.0.0"
implementation "com.madgag.spongycastle:bcpg-jdk15on:1.58.0.0"
//implementation 'org.bouncycastle:bcprov-jdk15on:1.64'
implementation 'com.github.UnifiedPush:android-connector:1.0.0'
//Flavors

View File

@ -48,11 +48,11 @@ public class PostSubscriptionAsyncTask {
protected void doInBackground() {
new Thread(() -> {
apiResponse = new API(contextReference.get(), account.getInstance(), account.getToken()).getPushSubscription();
if (apiResponse == null || apiResponse.getPushSubscription() == null) {
if (apiResponse == null || apiResponse.getPushSubscription() == null || endpoint.compareTo(apiResponse.getPushSubscription().getEndpoint()) != 0) {
apiResponse = new API(contextReference.get(), account.getInstance(), account.getToken()).pushSubscription(endpoint, account);
} else if (apiResponse != null && endpoint.compareTo(apiResponse.getPushSubscription().getEndpoint()) != 0) {
apiResponse = new API(contextReference.get(), account.getInstance(), account.getToken()).updatePushSubscription(endpoint);
}
//TODO: remove this line
apiResponse = new API(contextReference.get(), account.getInstance(), account.getToken()).pushSubscription(endpoint, account);
List<Account> accountList = new ArrayList<>();
accountList.add(account);
apiResponse.setAccounts(accountList);

View File

@ -27,7 +27,7 @@ import android.util.Log;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@ -5790,8 +5790,8 @@ public class API {
PushSubscription pushSubscription = null;
try {
String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/push/subscription"), 10, null, prefKeyOauthTokenT);
Log.v(Helper.TAG, "response GET: " + response);
pushSubscription = parsePushNotifications(new JSONObject(response));
Log.v(Helper.TAG, "response2: " + response);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
e.printStackTrace();
@ -5818,14 +5818,21 @@ public class API {
boolean notif_status = sharedpreferences.getBoolean(Helper.SET_NOTIF_STATUS, true);
boolean notif_poll = sharedpreferences.getBoolean(Helper.SET_NOTIF_POLL, true);
HashMap<String, String> params = new HashMap<>();
try {
endpoint = URLEncoder.encode(endpoint, "UTF-8");
} catch (UnsupportedEncodingException ignored) {
}
params.put("subscription[endpoint]", endpoint);
params.put("data[alerts][follow]", String.valueOf(notif_follow));
params.put("data[alerts][mention]", String.valueOf(notif_mention));
params.put("data[alerts][favourite]", String.valueOf(notif_add));
params.put("data[alerts][reblog]", String.valueOf(notif_share));
params.put("data[alerts][poll]", String.valueOf(notif_poll));
params.put("subscription[endpoint]", endpoint);
try {
String response = new HttpsConnection(context, this.instance).put(getAbsoluteUrl("/push/subscription"), 10, params, prefKeyOauthTokenT);
pushSubscription = parsePushNotifications(new JSONObject(response));
Log.v(Helper.TAG, "response3: " + response);
@ -5855,23 +5862,56 @@ public class API {
boolean notif_poll = sharedpreferences.getBoolean(Helper.SET_NOTIF_POLL, true);
HashMap<String, String> params = new HashMap<>();
params.put("data[alerts][follow]", String.valueOf(notif_follow));
params.put("data[alerts][mention]", String.valueOf(notif_mention));
params.put("data[alerts][favourite]", String.valueOf(notif_add));
params.put("data[alerts][reblog]", String.valueOf(notif_share));
params.put("data[alerts][poll]", String.valueOf(notif_poll));
params.put("subscription[endpoint]", endpoint);
/*try {
endpoint = URLEncoder.encode(endpoint, "UTF-8");
} catch (UnsupportedEncodingException ignored) {
}*/
ECDH ecdh = ECDH.getInstance();
String pubKey = ecdh.getPublicKey(context);
byte[] randBytes = new byte[16];
new Random().nextBytes(randBytes);
String auth = Base64.encodeToString(randBytes, Base64.DEFAULT);
params.put("subscription[keys][p256dh]", pubKey);
params.put("subscription[keys][auth]", auth);
String auth = ECDH.base64Encode(randBytes);
/*try {
pubKey = URLEncoder.encode(pubKey.replaceAll("\n",""), "UTF-8");
} catch (UnsupportedEncodingException ignored) {
}
try {
String response = new HttpsConnection(context, this.instance).post(getAbsoluteUrl("/push/subscription"), 10, params, prefKeyOauthTokenT);
auth = URLEncoder.encode(auth.replaceAll("\n",""), "UTF-8");
} catch (UnsupportedEncodingException ignored) {
}*/
JSONObject jsonObject = new JSONObject();
try {
JSONObject jsonObjectSub = new JSONObject();
jsonObjectSub.put("endpoint", endpoint);
JSONObject jsonObjectkey = new JSONObject();
jsonObjectkey.put("p256dh", pubKey);
jsonObjectkey.put("auth", auth);
jsonObjectSub.put("keys", jsonObjectkey);
jsonObject.put("subscription", jsonObjectSub);
JSONObject jsonObjectdata = new JSONObject();
JSONObject jsonObjectarlerts = new JSONObject();
jsonObjectarlerts.put("follow", notif_follow);
jsonObjectarlerts.put("mention", notif_mention);
jsonObjectarlerts.put("favourite", notif_add);
jsonObjectarlerts.put("reblog", notif_share);
jsonObjectarlerts.put("poll", notif_poll);
jsonObjectdata.put("alerts", jsonObjectarlerts);
jsonObject.put("data", jsonObjectdata);
} catch (JSONException e) {
e.printStackTrace();
}
Log.v(Helper.TAG, "jsonObject: " + jsonObject);
try {
String response = new HttpsConnection(context, this.instance).postJson(getAbsoluteUrl("/push/subscription"), 10, jsonObject, prefKeyOauthTokenT);
pushSubscription = parsePushNotifications(new JSONObject(response));
Log.v(Helper.TAG, "response: " + response);
ecdh.saveServerKey(context, account, pushSubscription.getServer_key());

View File

@ -19,6 +19,7 @@ import android.content.SharedPreferences;
import android.os.Build;
import android.text.Html;
import android.text.SpannableString;
import android.util.Log;
import com.google.gson.JsonObject;
@ -368,6 +369,7 @@ public class HttpsConnection {
postData.append('=');
postData.append(param.getValue());
}
Log.v(Helper.TAG, "postData: " + postData);
byte[] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);
if (proxy != null)
httpURLConnection = (HttpsURLConnection) url.openConnection(proxy);

View File

@ -8,7 +8,15 @@ import android.util.Log;
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.ECPublicKeyParameters;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@ -37,14 +45,15 @@ public class ECDH {
private static final String TAG = ECDH.class.getSimpleName();
private static final String PROVIDER = "SC";
private static final String PROVIDER = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
private static final String KEGEN_ALG = "ECDH";
private static ECDH instance;
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
// Security.removeProvider("BC");
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}
private final KeyFactory kf;
@ -68,8 +77,11 @@ public class ECDH {
return instance;
}
static String base64Encode(byte[] b) {
return Base64.encodeToString(b, Base64.DEFAULT);
public static String base64Encode(byte[] b) {
byte[] encoded = Base64.encode(
b, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
return new String(encoded);
}
static byte[] base64Decode(String str) {
@ -78,7 +90,7 @@ public class ECDH {
synchronized KeyPair generateKeyPair()
throws Exception {
ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp256k1");
ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("prime256v1");
kpg.initialize(ecParamSpec);
return kpg.generateKeyPair();
@ -119,17 +131,29 @@ public class ECDH {
KeyPair newPair(Context context) {
SharedPreferences.Editor prefsEditor = PreferenceManager
.getDefaultSharedPreferences(context).edit();
KeyPair kp = null;
KeyPair kp;
try {
kp = generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
return null;
}
ECPublicKey key = (ECPublicKey) kp.getPublic();
byte[] x = key.getW().getAffineX().toByteArray();
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");
ECCurve curve = x9.getCurve();
ECPoint point = curve.createPoint(xbi, ybi);
ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(point, dParams);
prefsEditor.putString(kp_public, base64Encode(kp.getPublic().getEncoded()));
String keyString = base64Encode(pubKey.getQ().getEncoded(false));
prefsEditor.putString(kp_public, keyString);
prefsEditor.putString(kp_private, base64Encode(kp.getPrivate().getEncoded()));
prefsEditor.commit();
return kp;
@ -142,7 +166,7 @@ public class ECDH {
String strPub = prefs.getString(kp_public, "");
String strPriv = prefs.getString(kp_private, "");
if (strPub.isEmpty() || strPriv.isEmpty()) {
if (strPub.isEmpty() || strPriv.isEmpty() || 1 == 1) {
return newPair(context);
}
try {
@ -154,7 +178,11 @@ public class ECDH {
}
public String getPublicKey(Context context) {
return base64Encode(getPair(context).getPublic().getEncoded());
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
String strPub = prefs.getString(kp_public, "");
return strPub;
}
public void saveServerKey(Context context, Account account, String strPeerPublic) {