aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJán Jančár2024-03-27 17:44:43 +0100
committerGitHub2024-03-27 17:44:43 +0100
commit14bb8dce2ec147970c3ad1d0433d59b0e0c55450 (patch)
treed269c72270caa8123620c0a10e3ae99de7c24284
parent96f21ccff6cc3daa5728e4700459d655238f5b93 (diff)
parent88e480904c24d4c93ef6420acb6bf92ae95871af (diff)
downloadECTester-14bb8dce2ec147970c3ad1d0433d59b0e0c55450.tar.gz
ECTester-14bb8dce2ec147970c3ad1d0433d59b0e0c55450.tar.zst
ECTester-14bb8dce2ec147970c3ad1d0433d59b0e0c55450.zip
-rw-r--r--.github/workflows/build.yml122
-rw-r--r--.gitmodules3
-rw-r--r--README.md24
-rw-r--r--applet/build.gradle.kts4
-rw-r--r--common/build.gradle.kts4
m---------ext/wolfcrypt-jni0
-rw-r--r--ext/wolfcrypt-jni.jarbin83453 -> 98431 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin43462 -> 43453 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--reader/build.gradle.kts28
-rw-r--r--standalone/build.gradle.kts33
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java10
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java10
-rw-r--r--standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c93
-rw-r--r--standalone/src/test/java/cz/crcs/ectester/reader/IdentTests.java14
-rw-r--r--standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java147
-rw-r--r--standalone/src/test/java/cz/crcs/ectester/standalone/IdentTests.java49
-rw-r--r--standalone/src/test/java/cz/crcs/ectester/standalone/LibTests.java54
18 files changed, 514 insertions, 83 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index eb4b902..d3e45cf 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,18 +7,92 @@ on:
branches: [ "master" ]
jobs:
- build:
-
+ applet:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
- java: [ "8", "11", "17", "21" ]
+ java: [ "8", "11", "17"]
env:
JAVA_VERSION: ${{ matrix.java }}
- name: Build Java ${{ matrix.java }}
+ name: Build applet with Java ${{ matrix.java }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up JDK
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java }}
+ distribution: "temurin"
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v3
+
+ - name: Build applets
+ run: ./gradlew applet:buildJavaCard
+
+ - name: Test
+ run: ./gradlew applet:test
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: built-applet-${{ matrix.java }}
+ path: |
+ applet/build/javacard/*.cap
+
+ reader:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+
+ strategy:
+ matrix:
+ java: [ "11", "17", "21" ]
+ name: Build reader on Java ${{ matrix.java }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up JDK
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java }}
+ distribution: "temurin"
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v3
+
+ - name: Build reader
+ run: ./gradlew reader:uberJar
+
+ - name: Test
+ run: ./gradlew reader:test
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: built-reader-${{ matrix.java }}
+ path: |
+ reader/build/libs/ECTesterReader.jar
+
+ standalone:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+
+ strategy:
+ matrix:
+ java: [ "11", "17", "21" ]
+ env:
+ # ffs: https://github.com/adoptium/adoptium-support/issues/485 !!!
+ LD_LIBRARY_PATH: "/usr/lib/x86_64-linux-gnu/"
+ name: Build standalone on Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v4
with:
@@ -40,60 +114,72 @@ jobs:
echo "BORINGSSL_VERSION=$(git submodule status ext/boringssl | cut -f2 -d' ')" >> $GITHUB_ENV
echo "LIBRESSL_VERSION=$(git submodule status ext/libressl | cut -f2 -d' ')" >> $GITHUB_ENV
echo "IPPCP_VERSION=$(git submodule status ext/ipp-crypto | cut -f2 -d' ')" >> $GITHUB_ENV
-
- - name: Build applets
- run: if [ $JAVA_VERSION != 21 ]; then ./gradlew applet:buildJavaCard; fi
-
- - name: Build reader
- run: ./gradlew reader:uberJar
+ echo "WOLFCRYPT_VERSION=$(git submodule status ext/wolfcrypt-jni | cut -f2 -d' ')" >> $GITHUB_ENV
+ echo "WOLFSSL_VERSION=$(dpkg -s libwolfssl-dev | grep 'Version' | cut -f2 -d' ')" >> $GITHUB_ENV
- name: Cache libs
uses: actions/cache@v4
id: cache-libs
with:
- key: libs-${{ env.BORINGSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.IPPCP_VERSION }}
+ key: libs-${{ env.BORINGSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.IPPCP_VERSION }}-${{ env.WOLFCRYPT_VERSION }}-${{ env.WOLFSSL_VERSION }}
path: |
ext/boringssl/build/crypto/libcrypto.so
ext/libressl/build/crypto/libcrypto.so
ext/ipp-crypto/build/.build/RELEASE/lib/libippcp.so
+ ext/wolfcrypt-jni/lib/wolfcrypt-jni.jar
+ ext/wolfcrypt-jni/lib/libwolfcryptjni.so
- name: Build libs
if: steps.cache-libs.outputs.cache-hit != 'true'
run: |
+ # ------------ Build BoringSSL ------------
cd ext/boringssl
cmake -DBUILD_SHARED_LIBS=1 -Bbuild
cd build
make -j4 crypto
cd ../../..
+ # ------------ Build LibreSSL ------------
cd ext/libressl
./autogen.sh
cmake -DBUILD_SHARED_LIBS=ON -Bbuild
cd build
make -j4 crypto
cd ../../..
+ # ------------ Build IPP-crypto ------------
cd ext/ipp-crypto
CC=clang CXX=clang++ cmake CMakeLists.txt -Bbuild -DARCH=intel64
cd build
make -j4
cd ../../..
+ # ------------ Build wolfcrypt-jni ------------
+ cd ext/wolfcrypt-jni
+ mkdir junit
+ wget -P junit/ https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
+ wget -P junit/ https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar
+ make -j4 -f makefile.linux
+ env JUNIT_HOME=junit/ ant build-jce-release
+ cd ../../..
- name: Build standalone
run: |
./gradlew standalone:libs || true
./gradlew standalone:uberJar
- # ffs: https://github.com/adoptium/adoptium-support/issues/485 !!!
- name: List libraries
- run: env LD_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu/" ./gradlew standalone:run --args="list-libs"
+ run: ./gradlew standalone:run --args="list-libs"
- name: Test
- run: ./gradlew test
+ run: ./gradlew standalone:test
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
- name: built-${{ matrix.java }}
+ name: built-standalone-${{ matrix.java }}
path: |
- applet/build/javacard/*.cap
- reader/build/libs/ECTesterReader.jar
- standalone/build/libs/ECTesterStandalone.jar \ No newline at end of file
+ standalone/build/libs/ECTesterStandalone.jar
+
+ - name: Upload code coverage
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ slug: crocs-muni/ECTester \ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 603e4d9..54819aa 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,3 +16,6 @@
[submodule "ext/ipp-crypto"]
path = ext/ipp-crypto
url = https://github.com/intel/ipp-crypto
+[submodule "ext/wolfcrypt-jni"]
+ path = ext/wolfcrypt-jni
+ url = https://github.com/wolfSSL/wolfcrypt-jni
diff --git a/README.md b/README.md
index 8c1da32..ed0741d 100644
--- a/README.md
+++ b/README.md
@@ -308,7 +308,7 @@ For more information on ECC libraries see [LIBS](docs/LIBS.md).
### Setup
```shell
-./gradlew :standalone:libs # To build the native library shims. (Necessary
+./gradlew :standalone:libs # To build the native library shims.
./gradlew :standalone:uberJar # To build the standalone tool (jar) -> "standalone/build/libs/ECTesterStandalone.jar"
```
Simply doing the above should build everything necessary to test libraries via the standalone app,
@@ -356,9 +356,9 @@ g++ -fPIC -shared -O2 -o botan_provider.so -Wl,-rpath,'$ORIGIN/lib' botan.o cpp_
g++ -fPIC -shared -O2 -o cryptopp_provider.so -Wl,-rpath,'$ORIGIN/lib' cryptopp.o cpp_utils.o -L. -L/usr/local/lib -lcryptopp -l:lib_timing.so
```
-BoringSSL, LibreSSL and ipp-crypto are included as git submodules. Make sure you run: `git submodule update --init --recursive`
+BoringSSL, LibreSSL, ipp-crypto and partially wolfCrypt are included as git submodules. Make sure you run: `git submodule update --init --recursive`
after checking out the ECTester repository to initialize them. To build BoringSSL do:
-```
+```shell
cd ext/boringssl
cmake -GNinja -Bbuild -DBUILD_SHARED_LIBS=1
cd build
@@ -366,7 +366,7 @@ ninja
```
To build LibreSSL do:
-```
+```shell
cd ext/libressl
./autogen.sh
cmake -GNinja -Bbuild -DBUILD_SHARED_LIBS=1
@@ -376,13 +376,27 @@ ninja
To build ipp-crypto do:
(Make sure you have the necessary [build requirements](https://github.com/intel/ipp-crypto/blob/develop/BUILD.md))
-```
+```shell
cd ext/ipp-crypto
CC=clang CXX=clang++ cmake CMakeLists.txt -GNinja -Bbuild -DARCH=intel64 # Does not work with GCC 12+
cd build
ninja
```
+To build wolfCrypt-JNI do:
+(You need to have wolfSSL installed and ready for development)
+```shell
+cd ext/wolfcrypt-jni
+mkdir junit
+wget -P junit/ https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
+wget -P junit/ https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar
+make -f makefile.linux
+env JUNIT_HOME=junit/ ant build-jce-release
+```
+The produced `lib/wolfcrypt-jni.jar` will be automatically included into the standalone JAR when building `standalone:uberJar`.
+However, the produced `lib/libwolfcryptjni.so` native library will not be automatically loaded. You thus need to include it
+on `LD_LIBRARY_PATH`.
+
#### Java
diff --git a/applet/build.gradle.kts b/applet/build.gradle.kts
index 5380bae..d5ef7f4 100644
--- a/applet/build.gradle.kts
+++ b/applet/build.gradle.kts
@@ -51,6 +51,10 @@ dependencies {
runtimeOnly("com.klinec:gradle-javacard:1.8.0")
}
+java {
+ sourceCompatibility = if (JavaVersion.current() == JavaVersion.VERSION_1_8) JavaVersion.VERSION_1_8 else JavaVersion.VERSION_11
+}
+
tasks.named<Test>("test") {
useJUnitPlatform()
}
diff --git a/common/build.gradle.kts b/common/build.gradle.kts
index 5829d8c..0aca7fb 100644
--- a/common/build.gradle.kts
+++ b/common/build.gradle.kts
@@ -20,4 +20,8 @@ dependencies {
api("org.yaml:snakeyaml:2.2")
// https://mvnrepository.com/artifact/com.klinec/jcardsim
api("com.klinec:jcardsim:3.0.5.11")
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
} \ No newline at end of file
diff --git a/ext/wolfcrypt-jni b/ext/wolfcrypt-jni
new file mode 160000
+Subproject 0497ee767c994775beda2f2091009593961e5c7
diff --git a/ext/wolfcrypt-jni.jar b/ext/wolfcrypt-jni.jar
index 890ae14..be579ee 100644
--- a/ext/wolfcrypt-jni.jar
+++ b/ext/wolfcrypt-jni.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd49..e644113 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a80b22c..b82aa23 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/reader/build.gradle.kts b/reader/build.gradle.kts
index b0c5fea..ac32214 100644
--- a/reader/build.gradle.kts
+++ b/reader/build.gradle.kts
@@ -1,5 +1,7 @@
plugins {
application
+ jacoco
+ id("com.adarshr.test-logger") version "4.0.0"
}
repositories {
@@ -13,6 +15,15 @@ repositories {
dependencies {
implementation(project(":common"))
implementation(project(":applet"))
+
+ testImplementation(platform("org.junit:junit-bom:5.10.2"))
+ testImplementation("org.junit.jupiter:junit-jupiter")
+ testImplementation("org.junit-pioneer:junit-pioneer:2.2.0")
+ testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
}
application {
@@ -21,6 +32,23 @@ application {
version = "0.3.3"
}
+tasks.named<Test>("test") {
+ useJUnitPlatform()
+ // Report is always generated after tests run
+ finalizedBy(tasks.jacocoTestReport)
+}
+
+tasks.jacocoTestReport {
+ reports {
+ xml.required = true
+ }
+}
+
+testlogger {
+ theme = com.adarshr.gradle.testlogger.theme.ThemeType.MOCHA
+ showStandardStreams = true
+}
+
tasks.register<Jar>("uberJar") {
archiveFileName = "ECTesterReader.jar"
duplicatesStrategy = DuplicatesStrategy.WARN
diff --git a/standalone/build.gradle.kts b/standalone/build.gradle.kts
index 68bfd13..d05480d 100644
--- a/standalone/build.gradle.kts
+++ b/standalone/build.gradle.kts
@@ -1,7 +1,8 @@
-
plugins {
application
+ jacoco
id("com.google.osdetector") version "1.7.3"
+ id("com.adarshr.test-logger") version "4.0.0"
}
repositories {
@@ -9,14 +10,24 @@ repositories {
}
dependencies {
- implementation(files("$rootDir/ext/wolfcrypt-jni.jar"))
+ // Fallback to bundled wolfcrypt-jni if the submodule one is not built.
+ if (file("$rootDir/ext/wolfcrypt-jni/lib/wolfcrypt-jni.jar").exists()) {
+ implementation(files("$rootDir/ext/wolfcrypt-jni/lib/wolfcrypt-jni.jar"))
+ } else {
+ implementation(files("$rootDir/ext/wolfcrypt-jni.jar"))
+ }
implementation(project(":common"))
testImplementation(platform("org.junit:junit-bom:5.10.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
+ testImplementation("org.junit-pioneer:junit-pioneer:2.2.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
+}
+
application {
applicationName = "ECTesterStandalone"
mainClass = "cz.crcs.ectester.standalone.ECTesterStandalone"
@@ -25,6 +36,23 @@ application {
tasks.named<Test>("test") {
useJUnitPlatform()
+ // Report is always generated after tests run
+ finalizedBy(tasks.jacocoTestReport)
+ // Add wolfcrypt JNI lib path to LD_LIBRARY_PATH (as our native library loading does not handle it)
+ environment(
+ "LD_LIBRARY_PATH", "$rootDir/ext/wolfcrypt-jni/lib/:" + System.getenv("LD_LIBRARY_PATH")
+ )
+}
+
+tasks.jacocoTestReport {
+ reports {
+ xml.required = true
+ }
+}
+
+testlogger {
+ theme = com.adarshr.gradle.testlogger.theme.ThemeType.MOCHA
+ showStandardStreams = true
}
tasks.withType<JavaCompile> {
@@ -48,6 +76,7 @@ tasks.register<Exec>("libs") {
tasks.register<Jar>("uberJar") {
archiveFileName = "ECTesterStandalone.jar"
+ duplicatesStrategy = DuplicatesStrategy.WARN
from(sourceSets.main.get().output)
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 57ab98f..cfdb964 100644
--- a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -839,9 +839,13 @@ public class ECTesterStandalone {
KeyPair kp = kpg.genKeyPair();
ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
ECParameterSpec params = privateKey.getParams();
- System.out.println(params);
- EC_Curve curve = EC_Curve.fromSpec(params);
- curve.writeCSV(System.out);
+ if (params == null) {
+ System.err.println("Parameters could not be exported (they are NULL).");
+ } else {
+ System.out.println(params);
+ EC_Curve curve = EC_Curve.fromSpec(params);
+ curve.writeCSV(System.out);
+ }
}
public static void main(String[] args) {
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
index b58eb91..ff592d1 100644
--- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
@@ -12,6 +12,16 @@ public class WolfCryptLib extends ProviderECLibrary {
}
@Override
+ public boolean initialize() {
+ try {
+ System.loadLibrary("wolfcryptjni");
+ return super.initialize();
+ } catch (UnsatisfiedLinkError ule) {
+ return false;
+ }
+ }
+
+ @Override
public Set<String> getCurves() {
return new HashSet<>();
}
diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c
index e8d874a..d4fa0a5 100644
--- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c
+++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c
@@ -75,27 +75,42 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa
return JNI_FALSE;
}
-static const struct ecc_curve* create_curve(JNIEnv *env, const char* curve_name) {
- const struct ecc_curve* curve = NULL;
- if (curve_name) {
- if (strcasecmp("secp192r1", curve_name) == 0) {
- curve = nettle_get_secp_192r1();
- }
- if (strcasecmp("secp224r1", curve_name) == 0) {
- curve = nettle_get_secp_224r1();
- }
- if (strcasecmp("secp256r1", curve_name) == 0) {
- curve = nettle_get_secp_256r1();
- }
- if (strcasecmp("secp384r1", curve_name) == 0) {
- curve = nettle_get_secp_384r1();
- }
- if (strcasecmp("secp521r1", curve_name) == 0) {
- curve = nettle_get_secp_521r1();
- }
- return curve;
- }
- return NULL;
+static const struct ecc_curve* create_curve_from_name(JNIEnv *env, const char* curve_name) {
+ if (!curve_name) {
+ return NULL;
+ }
+ if (strcasecmp("secp192r1", curve_name) == 0) {
+ return nettle_get_secp_192r1();
+ }
+ if (strcasecmp("secp224r1", curve_name) == 0) {
+ return nettle_get_secp_224r1();
+ }
+ if (strcasecmp("secp256r1", curve_name) == 0) {
+ return nettle_get_secp_256r1();
+ }
+ if (strcasecmp("secp384r1", curve_name) == 0) {
+ return nettle_get_secp_384r1();
+ }
+ if (strcasecmp("secp521r1", curve_name) == 0) {
+ return nettle_get_secp_521r1();
+ }
+}
+
+static const struct ecc_curve* create_curve_from_size(JNIEnv *env, jint keysize) {
+ switch (keysize) {
+ case 192:
+ return nettle_get_secp_192r1();
+ case 224:
+ return nettle_get_secp_224r1();
+ case 256:
+ return nettle_get_secp_256r1();
+ case 384:
+ return nettle_get_secp_384r1();
+ case 521:
+ return nettle_get_secp_521r1();
+ default:
+ return NULL;
+ }
}
JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_paramsSupported(JNIEnv *env, jobject self, jobject params){
@@ -153,7 +168,6 @@ static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, j
mpz_export((unsigned char*) key_priv + diff, &size, 1, sizeof(unsigned char), 0, 0, private_value);
(*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
-
unsigned long key_len = 2*byte_size + 1;
jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
mpz_t pub_value_x;
@@ -175,7 +189,6 @@ static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, j
mpz_export((unsigned char*) key_pub + 1 + byte_size + diff, &yLen, 1, sizeof(unsigned char), 0, 0, pub_value_y);
(*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
-
jobject ec_pub_param_spec = (*env)->NewLocalRef(env, spec);
jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
@@ -189,39 +202,41 @@ static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, j
ecc_point_clear(&pub);
ecc_scalar_clear(&priv);
return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
-
-
}
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
- throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ const struct ecc_curve* curve = create_curve_from_size(env, keysize);
+ if (!curve) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+ }
+ int byte_size = (keysize + 7) / 8;
+ jobject result = generate_from_curve(env, curve, NULL, byte_size);
+ return result;
return NULL;
}
-
-
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2(JNIEnv *env, jobject self, jobject params, jobject random, jobject spec) {
-
if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
return NULL;
} else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
jstring name = (*env)->CallObjectMethod(env, params, get_name);
const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
- const struct ecc_curve* curve;
+ const struct ecc_curve* curve = NULL;
int byte_size;
char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
int byte_sizes[] = {24, 28, 32, 48, 66};
for (int i = 0; i < sizeof(curve_name); i++) {
if (strcasecmp(utf_name, curve_name[i]) == 0) {
- curve = create_curve(env, curve_name[i]);
+ curve = create_curve_from_name(env, curve_name[i]);
byte_size = byte_sizes[i];
break;
}
}
(*env)->ReleaseStringUTFChars(env, name, utf_name);
if (!curve) {
- throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve with given name not found.");
return NULL;
}
jobject result = generate_from_curve(env, curve, spec, byte_size);
@@ -263,13 +278,13 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
jstring name = (*env)->CallObjectMethod(env, params, get_name);
const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
- const struct ecc_curve* curve;
+ const struct ecc_curve* curve = NULL;
char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
int byte_sizes[] = {24, 28, 32, 48, 66};
int byte_size;
for (int i = 0; i < sizeof(curve_name); i++) {
if (strcasecmp(utf_name, curve_name[i]) == 0) {
- curve = create_curve(env, curve_name[i]);
+ curve = create_curve_from_name(env, curve_name[i]);
byte_size = byte_sizes[i];
break;
}
@@ -412,20 +427,19 @@ int der_to_signature(struct dsa_signature* signature, unsigned char* der) {
size_t sLength = der[index++];
mpz_import(signature->s, sLength, 1, sizeof(unsigned char), 0, 0, der + index);
return 1;
-
}
JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
jstring name = (*env)->CallObjectMethod(env, params, get_name);
const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
- const struct ecc_curve* curve;
+ const struct ecc_curve* curve = NULL;
int byte_size;
char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
int byte_sizes[] = {24, 28, 32, 48, 66};
for (int i = 0; i < sizeof(curve_name); i++) {
if (strcasecmp(utf_name, curve_name[i]) == 0) {
- curve = create_curve(env, curve_name[i]);
+ curve = create_curve_from_name(env, curve_name[i]);
byte_size = byte_sizes[i] + 1;
break;
}
@@ -451,7 +465,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
(*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
-
jsize sig_len = signature_to_der(&signature, NULL, byte_size);
jbyteArray result = (*env)->NewByteArray(env, sig_len);
jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
@@ -467,11 +480,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
jstring name = (*env)->CallObjectMethod(env, params, get_name);
const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
- const struct ecc_curve* curve;
+ const struct ecc_curve* curve = NULL;
char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
for (int i = 0; i < sizeof(curve_name); i++) {
if (strcasecmp(utf_name, curve_name[i]) == 0) {
- curve = create_curve(env, curve_name[i]);
+ curve = create_curve_from_name(env, curve_name[i]);
break;
}
}
diff --git a/standalone/src/test/java/cz/crcs/ectester/reader/IdentTests.java b/standalone/src/test/java/cz/crcs/ectester/reader/IdentTests.java
deleted file mode 100644
index 2940f1e..0000000
--- a/standalone/src/test/java/cz/crcs/ectester/reader/IdentTests.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package cz.crcs.ectester.reader;
-
-import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-public class IdentTests {
- @Test
- void kaIdents() {
- for (KeyAgreementIdent keyAgreementIdent : KeyAgreementIdent.list()) {
- assertNotNull(keyAgreementIdent.getBaseAlgo());
- }
- }
-}
diff --git a/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java b/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java
new file mode 100644
index 0000000..1fdde0c
--- /dev/null
+++ b/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java
@@ -0,0 +1,147 @@
+package cz.crcs.ectester.standalone;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.junitpioneer.jupiter.StdIo;
+import org.junitpioneer.jupiter.StdOut;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class AppTests {
+
+ @Test
+ @StdIo()
+ public void help(StdOut out) {
+ ECTesterStandalone.main(new String[]{"-h"});
+ String s = out.capturedString();
+ assertTrue(s.contains("ECTesterStandalone"));
+ }
+
+ @Test
+ @StdIo()
+ public void listLibraries(StdOut out) {
+ ECTesterStandalone.main(new String[]{"list-libs"});
+ String s = out.capturedString();
+ assertTrue(s.contains("BouncyCastle"));
+ }
+
+ @Test
+ @StdIo()
+ public void listData(StdOut out) {
+ ECTesterStandalone.main(new String[]{"list-data"});
+ String s = out.capturedString();
+ assertTrue(s.contains("secg"));
+ }
+
+ @Test
+ @StdIo()
+ public void listSuites(StdOut out) {
+ ECTesterStandalone.main(new String[]{"list-suites"});
+ String s = out.capturedString();
+ assertTrue(s.contains("default test suite"));
+ }
+
+ @Test
+ @StdIo()
+ public void listIdents(StdOut out) {
+ ECTesterStandalone.main(new String[]{"list-types"});
+ String s = out.capturedString();
+ assertTrue(s.contains("NONEwithECDSA"));
+ }
+
+ @SuppressWarnings("JUnitMalformedDeclaration")
+ @ParameterizedTest
+ @ValueSource(strings = {"Bouncy", "Sun", "libtomcrypt", "Botan", "Crypto++", "OpenSSL 3", "BoringSSL", "libgcrypt", "mbed TLS", "2021" /* IPPCP */, "Nettle", "LibreSSL", "wolfCrypt"})
+ @StdIo()
+ public void defaultSuite(String libName, StdOut out) {
+ String[] args = new String[]{"test", "default", libName};
+ if (libName.equals("Botan") || libName.equals("Crypto++")) {
+ args = new String[]{"test", "--kpg-type", "ECDH", "default", libName};
+ }
+ ECTesterStandalone.main(args);
+ String sout = out.capturedString();
+ if (sout.contains("Exception")) {
+ System.err.printf("%s: Default suite has exceptions.%n", libName);
+ }
+ }
+
+ @SuppressWarnings("JUnitMalformedDeclaration")
+ @ParameterizedTest
+ @ValueSource(strings = {"Bouncy", "Sun", "libtomcrypt", "Botan", "Crypto++", "OpenSSL 3", "BoringSSL", "libgcrypt", "mbed TLS", "2021" /* IPPCP */, "Nettle", "LibreSSL", "wolfCrypt"})
+ @StdIo()
+ public void generate(String libName, StdOut out) {
+ String[] args = new String[]{"generate", "-n", "10", "-nc", "secg/secp256r1", libName};
+ switch (libName) {
+ case "Botan":
+ case "Crypto++":
+ args = new String[]{"generate", "-n", "10", "-nc", "secg/secp256r1", "-t", "ECDH", libName};
+ break;
+ case "Nettle":
+ case "libgcrypt":
+ args = new String[]{"generate", "-n", "10", "-cn", "secp256r1", libName};
+ break;
+ case "BoringSSL":
+ args = new String[]{"generate", "-n", "10", "-cn", "prime256v1", libName};
+ break;
+ }
+ ECTesterStandalone.main(args);
+ }
+
+ @SuppressWarnings("JUnitMalformedDeclaration")
+ @ParameterizedTest
+ @ValueSource(strings = {"Bouncy", "Sun", "libtomcrypt", "Botan", "Crypto++", "OpenSSL 3", "BoringSSL", "libgcrypt", "mbed TLS", "2021" /* IPPCP */, "Nettle", "LibreSSL", "wolfCrypt"})
+ @StdIo()
+ public void ecdh(String libName, StdOut out) {
+ String[] args = new String[]{"ecdh", "-n", "10", "-nc", "secg/secp256r1", libName};
+ switch (libName) {
+ case "Nettle":
+ case "libgcrypt":
+ args = new String[]{"ecdh", "-n", "10", "-cn", "secp256r1", libName};
+ break;
+ case "BoringSSL":
+ args = new String[]{"ecdh", "-n", "10", "-cn", "prime256v1", libName};
+ break;
+ }
+ ECTesterStandalone.main(args);
+ }
+
+ @SuppressWarnings("JUnitMalformedDeclaration")
+ @ParameterizedTest
+ @ValueSource(strings = {"Bouncy", "Sun", "libtomcrypt", "Botan", "Crypto++", "OpenSSL 3", "BoringSSL", "libgcrypt", "mbed TLS", "2021" /* IPPCP */, "Nettle", "LibreSSL", "wolfCrypt"})
+ @StdIo()
+ public void ecdsa(String libName, StdOut out) {
+ String[] args = new String[]{"ecdsa", "-n", "10", "-nc", "secg/secp256r1", libName};
+ switch (libName) {
+ case "Nettle":
+ case "libgcrypt":
+ args = new String[]{"ecdsa", "-n", "10", "-cn", "secp256r1", "-t", "NONEwithECDSA", libName};
+ break;
+ case "BoringSSL":
+ args = new String[]{"ecdsa", "-n", "10", "-cn", "prime256v1", "-t", "NONEwithECDSA", libName};
+ break;
+ case "OpenSSL 3":
+ case "libtomcrypt":
+ case "LibreSSL":
+ case "2021":
+ args = new String[]{"ecdsa", "-n", "10", "-nc", "secg/secp256r1", "-t", "NONEwithECDSA", libName};
+ break;
+ }
+ ECTesterStandalone.main(args);
+ }
+
+ @SuppressWarnings("JUnitMalformedDeclaration")
+ @ParameterizedTest
+ @ValueSource(strings = {"Bouncy", "Sun", "libtomcrypt", "Botan", "Crypto++", "OpenSSL 3", "BoringSSL", "libgcrypt", "mbed TLS", "2021" /* IPPCP */, "Nettle", "LibreSSL", "wolfCrypt"})
+ @StdIo()
+ public void export(String libName, StdOut out) {
+ String[] args = new String[]{"export", "-b", "256", libName};
+ switch (libName) {
+ case "Botan":
+ case "Crypto++":
+ args = new String[]{"export", "-b", "256", "-t", "ECDH", libName};
+ break;
+ }
+ ECTesterStandalone.main(args);
+ System.err.println(out.capturedString());
+ }
+}
diff --git a/standalone/src/test/java/cz/crcs/ectester/standalone/IdentTests.java b/standalone/src/test/java/cz/crcs/ectester/standalone/IdentTests.java
new file mode 100644
index 0000000..e6f520e
--- /dev/null
+++ b/standalone/src/test/java/cz/crcs/ectester/standalone/IdentTests.java
@@ -0,0 +1,49 @@
+package cz.crcs.ectester.standalone;
+
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.Test;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class IdentTests {
+
+ Provider bc = new BouncyCastleProvider();
+
+ @Test
+ void kaIdents() throws NoSuchAlgorithmException {
+ for (KeyAgreementIdent keyAgreementIdent : KeyAgreementIdent.list()) {
+ assertNotNull(keyAgreementIdent.getBaseAlgo());
+ }
+ KeyAgreementIdent ecdh = KeyAgreementIdent.get("ECDH");
+ assertNotNull(ecdh);
+ KeyAgreement instance = ecdh.getInstance(bc);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void kpgIdents() throws NoSuchAlgorithmException {
+ assertFalse(KeyPairGeneratorIdent.list().isEmpty());
+ KeyPairGeneratorIdent kpg = KeyPairGeneratorIdent.get("ECDH");
+ assertNotNull(kpg);
+ KeyPairGenerator instance = kpg.getInstance(bc);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void sigIdents() throws NoSuchAlgorithmException {
+ assertFalse(SignatureIdent.list().isEmpty());
+ SignatureIdent ecdsa = SignatureIdent.get("NONEwithECDSA");
+ assertNotNull(ecdsa);
+ Signature instance = ecdsa.getInstance(bc);
+ assertNotNull(instance);
+ }
+}
diff --git a/standalone/src/test/java/cz/crcs/ectester/standalone/LibTests.java b/standalone/src/test/java/cz/crcs/ectester/standalone/LibTests.java
new file mode 100644
index 0000000..6e11ccd
--- /dev/null
+++ b/standalone/src/test/java/cz/crcs/ectester/standalone/LibTests.java
@@ -0,0 +1,54 @@
+package cz.crcs.ectester.standalone;
+import cz.crcs.ectester.standalone.libs.*;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+import java.util.List;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class LibTests {
+
+ ProviderECLibrary[] libs;
+
+ @BeforeAll
+ public void loadLibs() {
+ List<ProviderECLibrary> libObjects = new LinkedList<>();
+ Class<?>[] libClasses = new Class[]{SunECLib.class,
+ BouncyCastleLib.class,
+ TomcryptLib.class,
+ BotanLib.class,
+ CryptoppLib.class,
+ OpensslLib.class,
+ BoringsslLib.class,
+ GcryptLib.class,
+ MscngLib.class,
+ WolfCryptLib.class,
+ MbedTLSLib.class,
+ IppcpLib.class,
+ MatrixsslLib.class,
+ NettleLib.class,
+ LibresslLib.class};
+ for (Class<?> c : libClasses) {
+ try {
+ libObjects.add((ProviderECLibrary) c.getDeclaredConstructor().newInstance());
+ } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
+ InvocationTargetException ignored) {
+ }
+ }
+ libs = libObjects.toArray(new ProviderECLibrary[0]);
+ for (ProviderECLibrary lib : libs) {
+ lib.initialize();
+ }
+ }
+
+ @Test
+ public void loaded() {
+ for (ProviderECLibrary lib : libs) {
+ System.err.printf("%s: %b%n", lib.getClass().getSimpleName(), lib.isInitialized());
+ }
+
+ }
+}