HSM simulator in Java — Eliptic Curve Cryptography

Jan Rock
6 min readSep 29, 2023

--

Please, take this article as simplified explanation of ECC with little bit of code and research around this topic.

Eliptic Curve Cryptography

The requirement to comply with standards related to data privacy is proposed to be supported by Elliptic Curve Cryptography (ECC) which is based on modern algebraic structures of the elliptic curves over finite fields and on the difficulty of the Elliptic Curve Discrete Logarithm Problem [1]. ECC implements all major capabilities of asymmetric crypto systems: encryption, signatures, and key exchange.

The ECC cryptography is considered a natural modern successor [2] of the RSA crypto system. The reason is the ECC uses smaller keys and signatures than RSA for the same level of security and provides very fast key generation, fast key agreement and fast signatures.

The private keys in the ECC are integers (in the range of the curve’s field size, typically 256-bit integers). An example of a 256-bit ECC private key (hex encoded, 32 bytes, 64 hex digits) is:

0x51897b64e85c3f714bba707e867914295a1377a7463a9dae8ea6a8b914246319

The key generation in ECC cryptography is as simple as securely generating a random integer in a certain range, so it is extremely fast. Any number within the range is a valid ECC private key.

The public keys in the ECC are EC points — pairs of integer coordinates {x, y}, laying on the curve. Due to their special properties, EC points can be compressed to just one coordinate + 1 bit (odd or even). The compressed public key, corresponding to a 256-bit ECC private key, is a 257-bit integer. An example of an ECC public key (corresponding to the above private key, encoded in the Ethereum format, as hex with prefix 02 or 03) is:

0x02f54ba86dc1ccb5bed0224d23f01ed87e4a443c47fc690d7797a13d41d2340e1a

In this format, the public key takes 33 bytes (66 hex digits), which can be optimised to exactly 257 bits.

ECC crypto algorithms can use different underlying elliptic curves. Different curves provide different levels of security (cryptographic strength), different performance(speed) and different key lengths and may involve different algorithms. ECC curves, adopted in the popular cryptographic libraries and security standards, have a name (named curves, e.g., secp256k1 or Curve25519), field size (which defines the key length, e.g., 256-bit), security strength (usually the field size / 2 or less), performance (operations/sec) and many other parameters.

ECC keys have length, which directly depends on the underlying curve. In most applications (like OpenSSL, OpenSSH and Bitcoin) the default key length for the ECC private keys is 256 bits, but depending on the curve many different ECC key sizes are possible: 192-bit (curve secp192r1), 233-bit (curve sect233k1), 224-bit (curve secp224k1), 256-bit (curves secp256k1 and Curve25519), 283-bit (curve sect283k1), 384-bit (curves p384 and secp384r1), 409-bit (curve sect409r1), 414-bit (curve Curve41417), 448-bit (curve Curve448-Goldilocks), 511-bit (curve M-511), 521-bit (curve P-521), 571-bit (curve sect571k1) and many others.

Elliptic-curve cryptography (ECC) provides several groups of algorithms based on the math of the elliptic curves over finite fields:

1) ECC digital signature algorithms like ECDSA (for classical curves) and EdDSA (for twisted Edwards curves).

2) ECC encryption algorithms and hybrid encryption schemes like the ECIES integrated encryption scheme and EEECC (EC-based ElGamal).

3) ECC key agreement algorithms like ECDH, X25519 and FHMQV.

All these algorithms use a curve behind (like secp256k1, curve25519 or p521) for the calculations and rely on the difficulty of the ECDLP (elliptic curve discrete logarithm problem). All these algorithms use public/private key pairs, where the private key is an integer, and the public key is a point on the elliptic curve (EC point). Let’s get into details about the elliptic curves over finite fields.

In mathematics, elliptic curves are plane algebraic curves consisting of all points {x, y}, described by the equation:

Cryptography uses elliptic curves in a simplified form (Weierstras form), which is defined as:

For example, the NIST curve secp256k1 (used in Bitcoin) is based on an elliptic curve in the form:

Figure 1: Visualization of an elliptic curve where a=2 and b=2

Since each bit can either be zero or one, we can represent 2²⁵⁶ unique numbers. If we were to convert that into our base-10 number system:

2²⁵⁶=115792089237316195423570985008687907853269984665640564039457584007913129639936

The current total hash power of Bitcoin is approximately 370 million tera hashes per second (May 2023, Blockchain.com), which is 3.7 * 10¹⁸ hashes/second:

10⁷⁷ total keys / (3.7*10¹⁸ keys/second) = 2.7*10⁵⁸ seconds = 8.7*10⁵⁴ years

The fundamental operation in ECC is point addition, which defines the addition of two points on the curve to obtain a third point. This operation is associative and commutative, forming an abelian group structure. ECC also involves scalar multiplication, where a point on the curve is multiplied by an integer scalar to obtain another point. The security of ECC relies on the difficulty of the already mentioned Elliptic Curve Discrete Logarithm Problem (ECDLP), which states that finding the scalar given a point and the curve parameters is computationally infeasible.

One significant application of ECC recommended to use before UI sends a file and metadata to API is to sign the payload adding authentication and integrity to transactions. Signer uses private keys to create unique signatures for specific transactions, while the corresponding public keys are used to verify the signatures. ECC’s efficient computation and robust security make it a widely adopted method for signing transactions in various domains, including blockchain networks, where transaction integrity and non-repudiation are essential.

The specifics of the ECDSA algorithm determine the exact calculations involved.

Example of sign and verification in Java:

//example to sign a message using the private key
String message = "This is a message to be signed";
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(privateKey);
signature.update(message.getBytes());
byte[] digitalSignature = signature.sign();

//example to verify the signature using the public key
Signature verifier = Signature.getInstance("SHA256withECDSA");
verifier.initVerify(publicKey);
verifier.update(message.getBytes());
boolean isSignatureValid = verifier.verify(digitalSignature);
System.out.println("Is Signature Valid? " + isSignatureValid);

// Verify the signature again using the imported keys
verifier.initVerify(importedPublicKey);
verifier.update(message.getBytes());
isSignatureValid = verifier.verify(digitalSignature);
System.out.println("Is Signature Valid? " + isSignatureValid);

The critical decision is related to the level of identifiable information stored in the database and blockchain. The decision to store hashes only simplifies the process of encryption and decryption, and keys store and burn if data must be deleted. The delete operation on the immutable system is provided by deleting — “burning” of private keys in combination with previous strong encryption.

Important: In the real world the implementation of file-based pair of keys requires HSM (Hardware Security Module).

Example of an HSM simulator in Java:

import java.security.*;
import java.util.Base64;

public class Main {
private KeyPair keyPair;

public Main() throws NoSuchAlgorithmException {
// Generate a key pair for demonstration purposes
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(2048, secureRandom);
this.keyPair = keyPairGenerator.generateKeyPair();
}

public byte[] signData(byte[] data) {
// Simulate signing the data using the private key stored
in the HSM
// In a real HSM, this operation would be performed by
the actual hardware
// Here, we simply use the private key of the generated
key pair to sign the data
// In practice, a secure and dedicated mechanism is
required for key storage and signing operations
// For demonstration purposes only, do not use it in
Production!
try {
// Simulate signing by using the private key
PrivateKey privateKey = keyPair.getPrivate();
Signature signature =
Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);

return signature.sign();

} catch (Exception e) {
e.printStackTrace();
}

return null;
}

public static void main(String[] args) {
try {
Main hsm = new Main();

// Simulate signing some data
byte[] dataToSign = "Hello, HSM!".getBytes();
byte[] signature = hsm.signData(dataToSign);

if (signature != null) {
System.out.println("Data signed successfully! " +
Base64.getEncoder().encodeToString(signature));
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

Bibliography and Web Sources

[1] Sia, G. (2011). A Brief Survey of the Discrete Logarithm Problem. https://core.ac.uk/download/pdf/10599546.pdf
[Online, accessed: 20/05/2023]

[2] Menezes, A. (2008). The Elliptic Curve Discrete Logarithm Problem: State of the Art. DOI:10.1007/978–3–540–89598–5_14

Thank you!

If you like the article, please, click on the applause icon below. Please, add comments and ideas for the next DLT-related content.

--

--