pkixops-crypto
pkixops-crypto provides cryptographic utilities used by PKIXOps projects. It is designed to be lightweight, easy to embed, and friendly for Java/Spring services.
Features
- Base64 utilities
- Base58 encoding/decoding
- Hash utilities (SHA-512)
- AES encryption/decryption (128/256 depending on policy)
- ECDSA key generation + sign/verify (P-256)
- RSA key generation + Base58 key transport + OAEP encrypt/decrypt
- Hybrid encryption pattern (RSA + AES)
Installation (Maven)
<dependency>
<groupId>com.pkixops</groupId>
<artifactId>pkixops-crypto</artifactId>
<version>1.2.1</version>
</dependency>
(Adjust the version to your latest release.)
Examples
The following examples are based on a single flow (similar to your MobileIdMain) to demonstrate how each primitive is used.
Base64
String plainText = "This is a Java example.";
String base64Encoding = Base64Util.encode(plainText);
System.out.println("base 64 encoding : " + base64Encoding);
String base64Decoding = Base64Util.decode(base64Encoding);
System.out.println("base 64 decoding : " + base64Decoding);
Quick Start: Base58
byte[] dataBytes = plainText.getBytes(StandardCharsets.UTF_8);
String base58Encoding = BASE58.encode(dataBytes);
System.out.println("base 58 encoding : " + base58Encoding);
byte[] decodedBytes = BASE58.decode(base58Encoding);
String base58Decoding = new String(decodedBytes, StandardCharsets.UTF_8);
System.out.println("base 58 decoding : " + base58Decoding);
HASH (SHA-512)
String nonce = Generator.genNonce();
byte[] hash = HASH.SHA512(nonce);
String hexString = HASH.toHex(hash);
System.out.println("SHA 512 : " + hexString);
AES AES-128 / AES-256
AES support depends on your runtime policy and JCE restrictions. You can check the maximum allowed key length:
int max = Cipher.getMaxAllowedKeyLength("AES");
if (max >= 256) {
System.out.println("AES 256 Enable");
} else {
System.out.println("AES 128 Enable");
}
AES with String key/IV
String aesKey = "1234567890ABCDEF1234567890ABCDEF"; // 32 chars = 256-bit
String aesIv = "1234567890ABCDEF"; // 16 chars = 128-bit IV
String encText = AES.encrypt(aesKey, aesIv, plainText);
String decText = AES.decrypt(aesKey, aesIv, encText);
AES with byte[] key/IV (recommended for hybrid flows)
// randomData -> SHA512 -> sKey(32 bytes), iV(16 bytes)
byte[] sKey = Arrays.copyOfRange(HASH.SHA512(randomData), 0, 32);
byte[] iV = Arrays.copyOfRange(HASH.SHA512(randomData), 32, 48);
String encData = AES.encrypt(sKey, iV, plainText);
String decData = AES.decrypt(sKey, iV, encData);
ECDSA P-256 / secp256r1
The example below generates a P-256 keypair, exports to PEM, signs using SHA-256 with ECDSA,
and verifies the signature.
// 1) Generate EC P-256 keypair (secp256r1 / prime256v1)
KeyPair keyPair = ECDSA.generateP256KeyPair();
// 2) Export to PEM
String pubPem = PemUtil.toPem(keyPair.getPublic());
String priPem = PemUtil.toPem(keyPair.getPrivate());
System.out.println(pubPem);
System.out.println(priPem);
// 3) Sign (SHA-256 + ECDSA)
byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
PrivateKey privateKey = PemUtil.fromSec1EcPrivateKeyPem(priPem, "secp256r1");
byte[] signature = ECDSA.signSha256Ecdsa(privateKey, data);
String sigB64 = Base64.getEncoder().encodeToString(signature);
System.out.println("Signature(Base64): " + sigB64);
// 4) Verify
PublicKey publicKey = PemUtil.fromEcPublicKeyPem(pubPem);
boolean ok = ECDSA.verifySha256Ecdsa(publicKey, data, signature);
System.out.println("Verify result: " + ok);
// 5) Tamper check (expected false)
boolean fail = ECDSA.verifySha256Ecdsa(publicKey, "tampered".getBytes(StandardCharsets.UTF_8), signature);
System.out.println("Verify tampered: " + fail);
RSA 2048
RSA utilities include keypair generation, Base58 transport of keys, and OAEP encryption/decryption.
KeyPair + Base58 transport
int keySize = 2048;
// 1) Generate RSA keypair
KeyPair keyPair = RSA.generateRsaKeyPair(keySize);
// 2) Export public/private to Base58 (compact string transport)
String publicKey58 = PemUtil.publicKeyToBase58(keyPair.getPublic());
String privateKey58 = PemUtil.privateKeyToBase58(keyPair.getPrivate());
System.out.println("PublicKey(Base58) = " + publicKey58);
System.out.println("PrivateKey(Base58) = " + privateKey58);
// 3) Restore and compare
PublicKey restoredPublicKey = PemUtil.publicKeyFromBase58(publicKey58);
PrivateKey restoredPrivateKey = PemUtil.privateKeyFromBase58(privateKey58);
System.out.println("Restored equals original? " +
Arrays.equals(keyPair.getPublic().getEncoded(), restoredPublicKey.getEncoded()));
System.out.println("Restored equals original? " +
Arrays.equals(keyPair.getPrivate().getEncoded(), restoredPrivateKey.getEncoded()));
RSA-OAEP encrypt/decrypt
// Encrypt with Base58 public key
byte[] encrypted = RSA.encryptOaepFromBase58PublicKey(publicKey58, plainText.getBytes(StandardCharsets.UTF_8));
String enc58 = BASE58.encode(encrypted);
System.out.println("encrypted rsa : " + enc58);
// Decrypt with Base58 private key
byte[] cipherText = BASE58.decode(enc58);
byte[] decrypted = RSA.decryptOaepFromBase58PrivateKey(privateKey58, cipherText);
System.out.println("decrypted rsa : " + new String(decrypted, StandardCharsets.UTF_8));
Hybrid Encryption (RSA + AES)
A common pattern: RSA encrypts a random secret, and AES encrypts the real payload.
Encrypt
// 1) randomData -> RSA (public) -> Base58
String randomData = Generator.genNonce48();
byte[] rsaEncrypted = RSA.encryptOaepFromBase58PublicKey(publicKey58, randomData.getBytes(StandardCharsets.UTF_8));
String enc58 = BASE58.encode(rsaEncrypted);
// 2) randomData -> SHA-512 -> sKey(32 bytes), iV(16 bytes)
byte[] sKey = Arrays.copyOfRange(HASH.SHA512(randomData), 0, 32);
byte[] iV = Arrays.copyOfRange(HASH.SHA512(randomData), 32, 48);
// 3) AES encrypt payload
String encData = AES.encrypt(sKey, iV, plainText);
System.out.println("[AES] AES 256 Encrypt : " + encData);
Decrypt
// 1) Base58 -> RSA (private) -> randomData
byte[] encrypted = BASE58.decode(enc58);
byte[] decrypted = RSA.decryptOaepFromBase58PrivateKey(privateKey58, encrypted);
String randomData = new String(decrypted, StandardCharsets.UTF_8);
// 2) randomData -> SHA-512 -> sKey, iV
byte[] sKey = Arrays.copyOfRange(HASH.SHA512(randomData), 0, 32);
byte[] iV = Arrays.copyOfRange(HASH.SHA512(randomData), 32, 48);
// 3) AES decrypt payload
String decText = AES.decrypt(sKey, iV, encData);
System.out.println("[AES] AES 256 Decrypt : " + decText);
Notes on Security
- Keep Intermediate/Root private keys in secure storage (HSM or equivalent)
- Do not embed production private keys inside application artifacts
- Use environment secrets / vault / HSM-backed PKCS#11 where possible
License
The Apache License, Version 2.0