Bagsværd Crypto RSA API implements a subset of IETF RFC 8017 "PKCS #1: RSA Cryptography Specifications Version 2.2".
- Implement encryption and signing features of IETF RFC 8017 with OAEP and PSS padding.
- Sourcecode speaks the "language" of RFC 8017 when possible to make assessment of correctness easier.
- Lightweight with few or no dependencies other than the Java Standard API.
- Is not a JCA provider and does not publish security primitives from JCA through its own public API.
- Limited support for PKCS1 and PKCS8 ASN.1 key schemas and X.690 DER encoding and decoding of keys.
- Limited to two prime factors P and Q.
- Legacy crypto schemes using EME-PKCS1-v1_5 and EMSA-PKCS1-v1_5 padding are not supported.
- Imposes additional constraints on generated public and private keys.
- Implements blinding of private exponent d.
Bagsværd Crypto RSA API is subject to the terms of the GNU General Public License Version 2 with "Classpath" exception. The terms are listed in the LICENSE file that accompanies this work. You may not distribute and/or use this code except in compliance with the license.
Requires Java 11 and Maven 3.
mvn package
mvn javadoc:javadoc
The default key factory uses Carmichael's Lambda Function as prescribed by RFC 8017.
KeyPair keyPair = KeyFactory.getInstance().generateKeyPair(2048);
PublicKey publicKey = keyPair.getPublicKey();
PrivateKey privateKey = keyPair.getPrivateKey();
Euler's Phi Function can be used alternatively by specifying the KeyFactoryAlgorithm.
KeyPair keyPair = KeyFactory.getInstance(KeyFactoryAlgorithm.EULER).generateKeyPair(2048);
The following snippet shows how to encrypt a message M with a public key to produce a ciphertext C.
byte[] M = "secret message".getBytes(UTF_8);
Crypt crypt = Crypt.getInstance(HashAlgorithm.SHA256);
byte[] C = crypt.encrypt(publicKey, M);
Encryption uses OAEP padding with one of the RFC 8017 approved hash function such as SHA256 and the default mask generating function MGF1-SHA1.
This snippet shows how to decrypt a ciphertext C with a private key to produce a plaintext m.
byte[] m = crypt.decrypt(privateKey, C);
String M = new String(m, UTF_8);
The default Crypt implementation uses the Chinese Remainder Theorem when decrypting for speed and blinds the private exponent with a method based on Paul C. Kocher's "Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems"
This snippet shows how to sign a message M with a private key to produce a signature S.
byte[] M = "message to be signed".getBytes(UTF_8);
Signature signature = Signature.getInstance(new SignatureParameterPssImpl(HashAlgorithm.SHA256, HashAlgorithm.SHA256, 20));
signature.update(M);
byte[] S = signature.sign(privateKey);
The signature implementation uses PSS padding with one of the RFC 8017 approved hash functions and the mask generating function MGF1 with another of the approved hash functions and a salt length.
It implements the Chinese Remainder Theorem for speed and blinds the private exponent with a method based on Paul C. Kocher's "Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems"
The following snippet verifies the signature S of message M with a public key.
Signature signature = Signature.getInstance(new SignatureParameterPssImpl(HashAlgorithm.SHA256, HashAlgorithm.SHA256, 20));
signature.update(M);
boolean verified = signature.verify(publicKey, S);
This snippet shows how to structure a private key according to the ASN.1 schema in PKCS #8 "Private-Key Information Syntax Specification Version 1.2" and encode it with X.690 DER.
byte[] encodedPrivateKey = privateKey.encode(PrivateKeyEncodingScheme.DER_PKCS8);
The following snippet shows how to decode a private key that has been structured according the ASN.1 schema in PKCS #8 "Private-Key Information Syntax Specification Version 1.2" and encoded with X.690 DER.
KeyFactory keyFactory = KeyFactory.getInstance();
KeyPair keyPair = keyFactory.decodePrivateKey(encodedPrivateKey, PrivateKeyEncodingScheme.DER_PKCS8);
PrivateKey privateKey = keyPair.getPrivateKey();
Despite its title, PKCS #8 also holds the public key, which is why a KeyPair is returned.
Public keys can be structured according to the ASN.1 schema in PKCS #1 and X.690 DER encoded.
byte[] encodedPublicKey = publicKey.encode(PublicKeyEncodingScheme.DER_PKCS1);
This snippet shows how to decode a public key that was structured according to the ASN.1 schema in PKCS #1 and encoded with X.690 DER.
KeyFactory keyFactory = KeyFactory.getInstance();
PublicKey publicKey = keyFactory.decodePublicKey(encodedPublicKey, PublicKeyEncodingScheme.DER_PKCS1);