Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}
11 changes: 11 additions & 0 deletions android/.project
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,15 @@
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>0</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
11 changes: 11 additions & 0 deletions android/.settings/org.eclipse.buildship.core.prefs
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
arguments=
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-15.jdk/Contents/Home
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true
22 changes: 13 additions & 9 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

buildscript {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
Expand All @@ -17,19 +17,19 @@ buildscript {
}

dependencies {
classpath("com.android.tools.build:gradle:3.5.3")
classpath("com.android.tools.build:gradle:4.2.2")
}
}
}
apply plugin: 'com.android.library'

android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
compileSdkVersion safeExtGet('compileSdkVersion', 30)
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
targetSdkVersion safeExtGet('targetSdkVersion', 30)
versionCode 1
versionName "1.0"
ndk {
Expand All @@ -55,8 +55,12 @@ allprojects {

dependencies {
implementation 'com.facebook.react:react-native:+'
implementation 'com.madgag.spongycastle:core:1.56.0.0'
implementation 'com.madgag.spongycastle:prov:1.56.0.0'
implementation 'com.madgag.spongycastle:bcpkix-jdk15on:1.56.0.0'
// implementation 'com.madgag.spongycastle:core:1.58.0.0'
// implementation 'com.madgag.spongycastle:prov:1.58.0.0'
// implementation 'com.madgag.spongycastle:bcpkix-jdk15on:1.58.0.0'
// See https://www.bouncycastle.org/releasenotes.html for latest revision
implementation 'org.bouncycastle:bcpkix-jdk15to18:1.68'
implementation 'org.bouncycastle:bcprov-jdk15to18:1.68'

}

2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip
Empty file modified android/gradlew
100644 → 100755
Empty file.
217 changes: 118 additions & 99 deletions android/src/main/java/com/RNRSA/CsrHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

import android.util.Log;

import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.spongycastle.asn1.x500.X500Name;
import org.spongycastle.asn1.x509.AlgorithmIdentifier;
import org.spongycastle.asn1.x509.ExtensionsGenerator;
import org.spongycastle.operator.ContentSigner;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.pkcs.PKCS10CertificationRequest;
import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand All @@ -25,101 +25,120 @@
import java.util.Map;

public class CsrHelper {
private static final String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
private static final String CN_PATTERN = "CN=%s";

private static class JCESigner implements ContentSigner {
private static Map<String, AlgorithmIdentifier> ALGOS = new HashMap<String, AlgorithmIdentifier>();

static {
ALGOS.put(
"SHA256withECDSA".toLowerCase(),
new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.10045.4.3.2"))
);
ALGOS.put(
"SHA256withRSA".toLowerCase(),
new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.11")
)
);
ALGOS.put(
"SHA1withRSA".toLowerCase(),
new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")
)
);
}

private final static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
private final static String CN_PATTERN = "CN=%s";

private static class JCESigner implements ContentSigner {

private static Map<String, AlgorithmIdentifier> ALGOS = new HashMap<String, AlgorithmIdentifier>();

static {
ALGOS.put("SHA256withECDSA".toLowerCase(), new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.10045.4.3.2")));
ALGOS.put("SHA256withRSA".toLowerCase(), new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.11")));
ALGOS.put("SHA1withRSA".toLowerCase(), new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")));

}

private String mAlgo;
private Signature signature;
private ByteArrayOutputStream outputStream;

public JCESigner( String sigAlgo, String keyTag) {
mAlgo = sigAlgo.toLowerCase();
try {
KeyStore.Entry entry = getEntry(keyTag);
this.outputStream = new ByteArrayOutputStream();
this.signature = Signature.getInstance(sigAlgo);
PrivateKey key = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
this.signature.initSign(key);
} catch (GeneralSecurityException gse) {
Log.e("generateCSR", "generateCSR: " + gse.getMessage());
throw new IllegalArgumentException(gse.getMessage());
}
catch (IOException gse) {
Log.e("generateCSR", "IOException: " + gse.getMessage());
throw new IllegalArgumentException(gse.getMessage());
}
}

public KeyStore.Entry getEntry (String keyTag) throws GeneralSecurityException, IOException {


KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
return ks.getEntry(keyTag, null);
}

@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
AlgorithmIdentifier id = ALGOS.get(mAlgo);
if (id == null) {
throw new IllegalArgumentException("Does not support algo: " +
mAlgo);
}
return id;
}

@Override
public OutputStream getOutputStream() {
return outputStream;
}

@Override
public byte[] getSignature() {
try {
signature.update(outputStream.toByteArray());
return signature.sign();
} catch (GeneralSecurityException gse) {
gse.printStackTrace();
return null;
}
}
private String mAlgo;
private Signature signature;
private ByteArrayOutputStream outputStream;

public JCESigner(String sigAlgo, String keyTag) {
mAlgo = sigAlgo.toLowerCase();
try {
KeyStore.Entry entry = getEntry(keyTag);
this.outputStream = new ByteArrayOutputStream();
this.signature = Signature.getInstance(sigAlgo);
PrivateKey key = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
this.signature.initSign(key);
} catch (GeneralSecurityException gse) {
Log.e("generateCSR", "generateCSR: " + gse.getMessage());
throw new IllegalArgumentException(gse.getMessage());
} catch (IOException gse) {
Log.e("generateCSR", "IOException: " + gse.getMessage());
throw new IllegalArgumentException(gse.getMessage());
}
}

//Create the certificate signing request (CSR) from private and public keys
public static PKCS10CertificationRequest generateCSR(PublicKey publicKey, String cn, String keyTag, String withAlgorithm) throws IOException,
OperatorCreationException {
public KeyStore.Entry getEntry(String keyTag)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
return ks.getEntry(keyTag, null);
}

String principal = String.format(CN_PATTERN, cn);
ContentSigner signer = new JCESigner(withAlgorithm, keyTag);
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(
new X500Name(principal), publicKey);
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
AlgorithmIdentifier id = ALGOS.get(mAlgo);
if (id == null) {
throw new IllegalArgumentException("Does not support algo: " + mAlgo);
}
return id;
}

ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
// extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(
// true));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
extensionsGenerator.generate());
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
@Override
public OutputStream getOutputStream() {
return outputStream;
}

public static PKCS10CertificationRequest generateCSRWithEC(PublicKey publicKey, String commonName, String keyTag) throws IOException, OperatorCreationException {
return generateCSR(publicKey, commonName, keyTag, DEFAULT_SIGNATURE_ALGORITHM);
@Override
public byte[] getSignature() {
try {
signature.update(outputStream.toByteArray());
return signature.sign();
} catch (GeneralSecurityException gse) {
gse.printStackTrace();
return null;
}
}
}

//Create the certificate signing request (CSR) from private and public keys
public static PKCS10CertificationRequest generateCSR(
PublicKey publicKey,
String cn,
String keyTag,
String withAlgorithm
)
throws IOException, OperatorCreationException {
String principal = String.format(CN_PATTERN, cn);
ContentSigner signer = new JCESigner(withAlgorithm, keyTag);
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(
new X500Name(principal),
publicKey
);

ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
csrBuilder.addAttribute(
PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
extensionsGenerator.generate()
);
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
}

public static PKCS10CertificationRequest generateCSRWithEC(
PublicKey publicKey,
String commonName,
String keyTag
)
throws IOException, OperatorCreationException {
return generateCSR(
publicKey,
commonName,
keyTag,
DEFAULT_SIGNATURE_ALGORITHM
);
}
}

34 changes: 15 additions & 19 deletions android/src/main/java/com/RNRSA/RSA.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,24 @@



import org.spongycastle.asn1.ASN1InputStream;
import org.spongycastle.asn1.ASN1Encodable;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.ASN1Primitive;
import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
import org.spongycastle.asn1.pkcs.RSAPublicKey;
import org.spongycastle.asn1.pkcs.RSAPrivateKey;
import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.pkcs.PKCS10CertificationRequest;
import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemWriter;
import org.spongycastle.util.io.pem.PemReader;
import org.spongycastle.asn1.pkcs.RSAPublicKey;
import org.spongycastle.openssl.PEMParser;
import org.spongycastle.util.io.pem.PemObject;


import static android.security.keystore.KeyProperties.*;

import static java.nio.charset.StandardCharsets.UTF_8;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;

import java.nio.charset.Charset;


Expand Down Expand Up @@ -318,7 +314,7 @@ public void generate(String keyTag, int keySize, Context context) throws IOExcep
)
.setKeySize(keySize)
.setDigests(DIGEST_SHA256, DIGEST_SHA512, DIGEST_SHA1)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setEncryptionPaddings(ENCRYPTION_PADDING_RSA_PKCS1)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build()
);
Expand Down
Loading