1

We are planning on implementing encryption or digital signatures using any of the available classes provided by the Java Cryptography Architecture (e.g. KeyPair, MessageDigest, Cipher, KeyStore, Certificate, and Signature JCA APIs.).

We have a system made up of different components are services written not only in Java but other languages as well (nodeJS, .net , flutter SDK etc.). My question is if we are to use these classes, will in work with other languages?

What do I mean? For example, encryption (using public key) is to be done using another language, then the encrypted payload is to be saved in the database, picked up by a program or service written in Java, then using any of those JCA classes mentioned above, decrypt the payload using a private key.

Or does the usage of these classes require that encryption is done using the same classes in Java? like if I use Cipher to encryption, I should use the same for decryption. Tried researching about this but couldn't find any. Maybe anyone here can shed light on this?

3
  • 1
    Encryption, digital signatures and hash algorithms are independent from the programming langage used, e.g. encrypting a payload using RSA/EC/AES with a private key/passphrase using nodeJS, Java or .net should give the same result as long as the same algorithm AND the same private key/passphrase are used.
    – St0rm
    Mar 16 at 9:17
  • 1
    Note that especially in untyped languages cryptographic function often automatically apply key derivation functions on the key if it is not in the expected format. Thus you have to carefully read the documentation and sometimes even the source code to make sure a cryptographic function only use the algorithm(s) you expect it to use.
    – Robert
    Mar 16 at 9:21
  • 1
    @St0rm: any encryption considered secure must be randomized, so encrypting the same value with the same key multiple times gives different results, either in the same language/library or different ones; these are interoperable, but not the same. For signature, ECDSA or DSA standards require randomization, although a deterministic method is known and some people use it; RSA-PSS is randomized, but original RSASSA-PKCS1-v1_5 is not. Hashing or HMAC is deterministic, unless explicitly salted. There are also superficial differences like DER vs 'plain' format of [EC]DSA. Mar 17 at 0:15

1 Answer 1

1

Standard support

In general the JCA implements well specified algorithms. The trick is to use those algorithms both for your Java and for the other languages. You may want to map specific algorithms to the specifications and then take a look at those. Fortunately, Java is relatively well behaved and has a specific document that lists all the algorithms.

For instance the signature scheme "SHA256withRSA" is defined as "The RSA signature algorithm that uses the SHA-* digest with the RSASSA-PKCS1-v1_5 signature scheme as defined in PKCS #1 v2.2." So that way you know that you're dealing with a PKCS#1 v1.5 signature. If you want to maintain compatibility you should make sure that the referenced standards are part of modern, mainstream cryptography.

As long as you can find implementations of the same standard that are binary compatible then you can implement the scheme in any language. Beware though that many languages / runtimes are documented very poorly; many do not even link to the standards that are implemented.

Beware that the algorithm string is just one way to configure the algorithm. The algorithm can often be tweaked using instances of AlgorithmParameterSpec, for instance GCMParameterSpec can be used to set the tag size for GCM.

Existing protocols

In general, using the cryptography classes does require significant knowledge about cryptography and secure development. As such, the JCA is more of a toolbox for professionals. The countless insecure constructions that get posted to StackOverflow shows what happens if you use a powertool without any instructions.

Quite often it is better to keep to higher level standards such as the CMS (i.e. PKCS#7) or PGP "container formats" or of course transport protocols such as TLS and SSH. Those need to be configured correctly, but that's often easier than protocol design.

Pitfalls

Of course, all that doesn't mean that there aren't any other pitfalls; for instance:

  • Most modern cryptography is described as binary, and most of the JCA classes of Java operate on bytes or, more specifically byte arrays (or a wrapper class called ByteBuffer). Some languages automatically perform some kind of encoding / decoding and that may make interop harder to handle. Actually, the highest percentage of cryptographic questions on StackOverflow are related to encoding issues.
  • "SHA256withECDSA" is using the "The ECDSA signature algorithms as defined in ANSI X9.62." which delivers an output of ASN.1 / DER encoded values of r and s as binary signature. ANSI X9.62 is a "payware" standard, and other libraries may just output a "flat" signature consisting of a static sized r and s. This is supported in the Oracle provider as "SHA256withECDSAinP1363Format".
  • Key Derivation Functions are a general issue, and there isn't a specific KDF class in Java 17. Key Derivation Functions are generally also part of key agreement, and it is often hard to create a compatible implementation of key agreement across platforms. These are badly standardized as well.
  • Sometimes the standards themselves are not very clear; e.g. the PSS and OAEP protocols do not define a specific hash as standard for the internal MGF1 mask generation function. In other implementations usually it is the same as the hash used for the message, but Oracles provider always uses SHA-1 as default.
  • RSA encryption does not actually use ECB mode even if it is specified as "RSA/ECB/PKCS1Padding" or similar; RSA doesn't use any block mode of operation (i.e. "ECB" should be absent or read "None").

Recommendations

Some generic recommendations:

  • For ciphers I'd stick to AES in CBC + PKCS#5/7 padding or, preferably, authenticated GCM mode.
  • Always assume that a random number generator does just that: generate random numbers. Finding a compatible RNG is likely to result in failures. For Java I'd mostly just use new SecureRandom().
2
  • Nit: X9.62 has been withdrawn and is no longer officially available even with pay -- and ECDSA is now fully specified (including RFC6979) in FIPS 186-5 for free (but from the Great Satan). 186-5 doesn't specify the signature format as ASN.1/DER, and to my understanding X9.62 didn't either -- certainly RFC3279, where I first saw both DSA-Sig and ECDSA-Sig, does not cite X9.62 for it, while it does cite X9.62 for the encoding of ECPoint in key (also in explicit parameters, but no one used explicit parameters and 5480 dropped them). ... Mar 21 at 1:08
  • More substantively, (SunEC in) Java 9 up supports the 'flat' format under names like SHA256withECDSAinP1363Format -- as shown at your link. Mar 21 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.