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
4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ dependencies {

// all walt.id dependencies (not required for this project)
implementation(libs.bundles.waltidNotNeeded)

// crypto2 (new library)
implementation(libs.waltid.crypto2)
implementation(libs.waltid.crypto2.java)
}

// Configure run task to allow dynamic main class selection
Expand Down
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[versions]
kotlin = "2.4.0"
waltid = "0.22.0"
waltid-crypto2 = "1.0.0-SNAPSHOT-crypto2"

[libraries]
# walt.id
Expand All @@ -17,6 +18,10 @@ waltid-dif-definitions-parser = { module = "id.walt.dif-definitions-parser:walti
waltid-mdoc-credentials = { module = "id.walt.mdoc-credentials:waltid-mdoc-credentials", version.ref = "waltid" }
waltid-service-commons = { module = "id.walt:waltid-service-commons", version.ref = "waltid" }

# crypto2 libraries
waltid-crypto2 = { module = "id.walt.crypto2:waltid-crypto2", version.ref = "waltid-crypto2" }
waltid-crypto2-java = { module = "id.walt.crypto2:waltid-crypto2-java", version.ref = "waltid-crypto2" }

[bundles]
waltid = ["waltid-crypto", "waltid-digital-credentials", "waltid-did", "waltid-sdjwt",
"waltid-openid4vc", "waltid-verification-policies", "waltid-dif-definitions-parser"]
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/waltid/crypto2/key/create/Ed25519.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package waltid.crypto2.key.create;

import id.walt.crypto2.CryptoRuntime;
import id.walt.crypto2.keys.*;
import id.walt.crypto2.providers.GenerateSoftwareKeyRequest;
import id.walt.crypto2.providers.cryptography.CryptographySoftwareKeyProvider;
import kotlin.collections.CollectionsKt;
import kotlinx.coroutines.future.FutureKt;
import kotlinx.serialization.json.Json;

import java.util.concurrent.CompletableFuture;

/**
* Java example: Generate an Ed25519 key using crypto2 library.
*
* This demonstrates:
* - Creating CryptoRuntime from Java
* - Using Kotlin suspend functions via CompletableFuture
* - Generating Edwards curve keys
* - Serializing keys to JSON
*/
public class Ed25519 {
public static void main(String[] args) {
try {
createEd25519().get();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}

public static CompletableFuture<Void> createEd25519() {
// Initialize CryptoRuntime with software provider
CryptoRuntime runtime = new CryptoRuntime(
CollectionsKt.listOf(CryptographySoftwareKeyProvider.Companion.invoke()),
CollectionsKt.emptyList(),
null
);

// Generate Ed25519 key (using CompletableFuture for Kotlin suspend function)
return FutureKt.asCompletableFuture(
runtime.generateSoftwareKey(
new GenerateSoftwareKeyRequest(
KeyId.Companion.invoke("ed25519-key"),
new KeySpec.Edwards(EdwardsCurve.Companion.getED25519()),
CollectionsKt.setOf(KeyUsage.SIGN, KeyUsage.VERIFY),
null
),
null,
null
)
).thenAccept(key -> {
// Get the stored key
StoredKey.Software storedKey = key.getStoredKey();

// Serialize to JSON
Json json = Json.Default;

String serialized = json.encodeToString(
StoredKey.Software.Companion.serializer(),
storedKey
);

System.out.println("Generated Ed25519 key:");
System.out.println(serialized);

// Close runtime
FutureKt.asCompletableFuture(runtime.close(null)).join();
});
}
}
58 changes: 58 additions & 0 deletions src/main/java/waltid/crypto2/key/create/Secp256r1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package waltid.crypto2.key.create;

import id.walt.crypto2.CryptoRuntime;
import id.walt.crypto2.keys.*;
import id.walt.crypto2.providers.GenerateSoftwareKeyRequest;
import id.walt.crypto2.providers.cryptography.CryptographySoftwareKeyProvider;
import kotlin.collections.CollectionsKt;
import kotlinx.coroutines.future.FutureKt;
import kotlinx.serialization.json.Json;

import java.util.concurrent.CompletableFuture;

/**
* Java example: Generate a secp256r1 (P-256) ECDSA key using crypto2 library.
*/
public class Secp256r1 {
public static void main(String[] args) {
try {
createSecp256r1().get();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}

public static CompletableFuture<Void> createSecp256r1() {
CryptoRuntime runtime = new CryptoRuntime(
CollectionsKt.listOf(CryptographySoftwareKeyProvider.Companion.invoke()),
CollectionsKt.emptyList(),
null
);

return FutureKt.asCompletableFuture(
runtime.generateSoftwareKey(
new GenerateSoftwareKeyRequest(
KeyId.Companion.invoke("secp256r1-key"),
new KeySpec.Ec(EcCurve.Companion.getP256()),
CollectionsKt.setOf(KeyUsage.SIGN, KeyUsage.VERIFY),
null
),
null,
null
)
).thenAccept(key -> {
Json json = Json.Default;

String serialized = json.encodeToString(
StoredKey.Software.Companion.serializer(),
key.getStoredKey()
);

System.out.println("Generated secp256r1 (P-256) key:");
System.out.println(serialized);

FutureKt.asCompletableFuture(runtime.close(null)).join();
});
}
}
104 changes: 104 additions & 0 deletions src/main/java/waltid/crypto2/signatures/Secp256r1Sign.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package waltid.crypto2.signatures;

import id.walt.crypto2.CryptoRuntime;
import id.walt.crypto2.algorithms.DigestAlgorithm;
import id.walt.crypto2.algorithms.SignatureAlgorithm;
import id.walt.crypto2.keys.*;
import id.walt.crypto2.providers.GenerateSoftwareKeyRequest;
import id.walt.crypto2.providers.cryptography.CryptographySoftwareKeyProvider;
import kotlin.collections.CollectionsKt;
import kotlinx.coroutines.future.FutureKt;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;

/**
* Java example: Sign and verify messages with ECDSA-SHA256 using crypto2 library.
*
* This demonstrates:
* - Signing data with ECDSA
* - Verifying signatures
* - Detecting tampered messages
* - Using capabilities pattern
*/
public class Secp256r1Sign {
public static void main(String[] args) {
try {
signAndVerify().get();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}

public static CompletableFuture<Void> signAndVerify() {
CryptoRuntime runtime = new CryptoRuntime(
CollectionsKt.listOf(CryptographySoftwareKeyProvider.Companion.invoke()),
CollectionsKt.emptyList(),
null
);

// Generate key
return FutureKt.asCompletableFuture(
runtime.generateSoftwareKey(
new GenerateSoftwareKeyRequest(
KeyId.Companion.invoke("secp256r1-signing-key"),
new KeySpec.Ec(EcCurve.Companion.getP256()),
CollectionsKt.setOf(KeyUsage.SIGN, KeyUsage.VERIFY),
null
),
null,
null
)
).thenCompose(key -> {
// Message to sign
byte[] message = "Hello from Java with Crypto2!".getBytes(StandardCharsets.UTF_8);
System.out.println("Message: " + new String(message, StandardCharsets.UTF_8));

// Get signing capability
Signer signer = key.getCapabilities().getSigner();
if (signer == null) {
throw new IllegalStateException("Key does not support signing");
}

// Sign with ECDSA-SHA256
SignatureAlgorithm algorithm = new SignatureAlgorithm.Ecdsa(
DigestAlgorithm.Companion.getSHA_256(),
null
);

return FutureKt.asCompletableFuture(signer.sign(message, algorithm, null))
.thenCompose(signature -> {
System.out.println("Signature (" + signature.length + " bytes): " +
Base64.getEncoder().encodeToString(signature));

// Get verification capability
Verifier verifier = key.getCapabilities().getVerifier();
if (verifier == null) {
throw new IllegalStateException("Key does not support verification");
}

// Verify signature
return FutureKt.asCompletableFuture(
verifier.verify(message, signature, algorithm, null)
).thenCompose(isValid -> {
System.out.println("Signature valid: " + isValid);

// Test with tampered message
byte[] tamperedMessage = "Hello from Java with Crypto3!".getBytes(StandardCharsets.UTF_8);
return FutureKt.asCompletableFuture(
verifier.verify(tamperedMessage, signature, algorithm, null)
).thenAccept(isTamperedValid -> {
System.out.println("Tampered message valid: " + isTamperedValid);
System.out.println();
System.out.println("✅ Java crypto2 signing and verification successful!");

// Close runtime
FutureKt.asCompletableFuture(runtime.close(null)).join();
});
});
});
});
}
}
98 changes: 98 additions & 0 deletions src/main/java/waltid/crypto2/simple/SimpleSigningExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package waltid.crypto2.simple;

import id.walt.crypto2.CryptoRuntime;
import id.walt.crypto2.algorithms.SignatureAlgorithm;
import id.walt.crypto2.keys.*;
import id.walt.crypto2.providers.GenerateSoftwareKeyRequest;
import id.walt.crypto2.providers.cryptography.CryptographySoftwareKeyProvider;
import kotlin.collections.CollectionsKt;
import kotlinx.coroutines.future.FutureKt;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.ExecutionException;

/**
* Simplified Java example with blocking calls.
*
* This shows a more idiomatic Java approach to using crypto2:
* - Using .get() to block on CompletableFuture
* - Focus on the crypto operations rather than coroutine mechanics
* - Exception handling with try-catch
*/
public class SimpleSigningExample {
public static void main(String[] args) {
try {
simpleSignAndVerify();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}

public static void simpleSignAndVerify() throws ExecutionException, InterruptedException {
// 1. Create runtime
CryptoRuntime runtime = new CryptoRuntime(
CollectionsKt.listOf(CryptographySoftwareKeyProvider.Companion.invoke()),
CollectionsKt.emptyList(),
null
);

try {
// 2. Generate Ed25519 key (blocking)
System.out.println("Generating Ed25519 key...");
SoftwareKey key = FutureKt.asCompletableFuture(
runtime.generateSoftwareKey(
new GenerateSoftwareKeyRequest(
KeyId.Companion.invoke("simple-key"),
new KeySpec.Edwards(EdwardsCurve.Companion.getED25519()),
CollectionsKt.setOf(KeyUsage.SIGN, KeyUsage.VERIFY),
null
),
null,
null
)
).get();
System.out.println("✓ Key generated: " + key.getId().getValue());

// 3. Sign a message (blocking)
byte[] message = "Simple Java example!".getBytes(StandardCharsets.UTF_8);
System.out.println("\nSigning message: " + new String(message, StandardCharsets.UTF_8));

Signer signer = key.getCapabilities().getSigner();
if (signer == null) {
throw new IllegalStateException("Key does not support signing");
}

byte[] signature = FutureKt.asCompletableFuture(
signer.sign(message, SignatureAlgorithm.EdDsa, null)
).get();
System.out.println("✓ Signature: " + Base64.getEncoder().encodeToString(signature));

// 4. Verify signature (blocking)
System.out.println("\nVerifying signature...");
Verifier verifier = key.getCapabilities().getVerifier();
if (verifier == null) {
throw new IllegalStateException("Key does not support verification");
}

boolean isValid = FutureKt.asCompletableFuture(
verifier.verify(message, signature, SignatureAlgorithm.EdDsa, null)
).get();
System.out.println("✓ Signature valid: " + isValid);

// 5. Test with wrong message
byte[] wrongMessage = "Different message!".getBytes(StandardCharsets.UTF_8);
boolean isWrongValid = FutureKt.asCompletableFuture(
verifier.verify(wrongMessage, signature, SignatureAlgorithm.EdDsa, null)
).get();
System.out.println("✓ Wrong message valid: " + isWrongValid);

System.out.println("\n✅ Simple Java example completed successfully!");

} finally {
// 6. Clean up
FutureKt.asCompletableFuture(runtime.close(null)).get();
}
}
}
Loading