Class Crypto

java.lang.Object
com.codename1.backend.Crypto

public final class Crypto extends Object
The crypto a server needs to authenticate a request. Every primitive comes from OpenSSL, which the backend already links for outbound TLS - none of it is implemented here, because hand-rolled HMAC and hand-rolled password hashing are the two most reliable ways to ship an authentication system that looks correct and is not.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
    ECDSA over P-256 with SHA-256, and over P-384 with SHA-384.
    static final String
     
    static final int
    PBKDF2 iterations for a stored password.
    static final String
    RSASSA-PSS over SHA-256 with MGF1-SHA-256 and a 32 byte salt.
    static final String
    RSASSA-PKCS1-v1_5 over SHA-256, SHA-384 and SHA-512: the same bytes for the same key and message, every time.
    static final String
     
    static final String
     
    static final String
    static final String
     
    static final String
     
    static final String
     
  • Method Summary

    Modifier and Type
    Method
    Description
    static byte[]
    aesGcmDecrypt(byte[] key, byte[] iv, byte[] aad, byte[] sealed)
    static byte[]
    aesGcmEncrypt(byte[] key, byte[] iv, byte[] aad, byte[] plaintext)
    AES-GCM.
    static boolean
    equalsConstantTime(byte[] a, byte[] b)
    Compares without leaking where two values first differ.
    static byte[]
    generateRsaKey(int bits)
    A new RSA private key as PKCS#8 DER, with the public exponent 65537.
    static String
    hashPassword(String password)
    Hashes a password for storage.
    static byte[]
    hmac(String digest, byte[] key, byte[] data)
    HMAC over one of SHA1, SHA256, SHA384 and SHA512.
    static byte[]
    hmacSha256(byte[] key, byte[] data)
     
    static byte[]
    md5(byte[] data)
    MD5, for PostgreSQL's md5 authentication method.
    static byte[]
    pbkdf2(String digest, byte[] password, byte[] salt, int iterations, int length)
    PBKDF2 over HMAC with one of SHA1, SHA256, SHA384 and SHA512, on the password's bytes as they are given.
    static byte[]
    pbkdf2Sha256(byte[] password, byte[] salt, int iterations, int length)
    PBKDF2-HMAC-SHA-256.
    static byte[]
    randomBytes(int length)
    Cryptographically secure bytes.
    static byte[]
    sha1(byte[] data)
    SHA-1, for the wire protocols that specify it by name: MySQL's mysql_native_password, and the RFC 6455 4.2.2 websocket handshake, where the digest of the client key and a fixed GUID becomes Sec-WebSocket-Accept.
    static byte[]
    sha256(byte[] data)
     
    static byte[]
    sha384(byte[] data)
    SHA-384; null for null.
    static byte[]
    sha512(byte[] data)
    SHA-512; null for null.
    static byte[]
    sign(String algorithm, byte[] privateKey, byte[] data)
    Signs data with a private key in PKCS#8 DER, under one of RS256, RS384, RS512, PS256, ES256 and ES384.
    static boolean
    verify(String algorithm, byte[] publicKey, byte[] data, byte[] signature)
    Checks a signature against a public key in SubjectPublicKeyInfo DER.
    static boolean
    verifyPassword(String password, String stored)
    False for any malformed stored value rather than throwing.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Method Details

    • sha256

      public static byte[] sha256(byte[] data)
    • sha1

      public static byte[] sha1(byte[] data)

      SHA-1, for the wire protocols that specify it by name: MySQL's mysql_native_password, and the RFC 6455 4.2.2 websocket handshake, where the digest of the client key and a fixed GUID becomes Sec-WebSocket-Accept.

      Never for anything this code CHOOSES: passwords go through hashPassword(String) and tokens through hmacSha256(byte[], byte[]). Both callers here are standards quoting the algorithm, and in neither is the result standing in for a signature -- the handshake value is a replay guard against caches and proxies, not an authenticator.

    • md5

      public static byte[] md5(byte[] data)
      MD5, for PostgreSQL's md5 authentication method. See sha1(byte[]).
    • pbkdf2Sha256

      public static byte[] pbkdf2Sha256(byte[] password, byte[] salt, int iterations, int length) throws IOException
      PBKDF2-HMAC-SHA-256. Exposed because SCRAM-SHA-256 -- how PostgreSQL authenticates by default -- is defined in terms of it with the server's iteration count, which hashPassword(String) does not let a caller choose.
      Throws:
      IOException
    • hmacSha256

      public static byte[] hmacSha256(byte[] key, byte[] data)
    • randomBytes

      public static byte[] randomBytes(int length) throws IOException
      Cryptographically secure bytes. Throws rather than returning weak ones.
      Throws:
      IOException
    • equalsConstantTime

      public static boolean equalsConstantTime(byte[] a, byte[] b)
      Compares without leaking where two values first differ. An early exit on the first differing byte lets a MAC be forged one byte at a time.
    • hashPassword

      public static String hashPassword(String password) throws IOException
      Hashes a password for storage. Returns "pbkdf2$iterations$salt$hash" with both binary parts base64url-encoded, so the iteration count travels with the hash and can be raised later without invalidating existing rows.
      Throws:
      IOException
    • verifyPassword

      public static boolean verifyPassword(String password, String stored)
      False for any malformed stored value rather than throwing.
    • sha384

      public static byte[] sha384(byte[] data)
      SHA-384; null for null.
    • sha512

      public static byte[] sha512(byte[] data)
      SHA-512; null for null.
    • hmac

      public static byte[] hmac(String digest, byte[] key, byte[] data)
      HMAC over one of SHA1, SHA256, SHA384 and SHA512. SHA-1 is here for what specifies it by name -- a TOTP secret an authenticator application already holds, Spring's oldest password format -- and not for anything new.
      Returns:
      the tag, or null when key or data is null
      Throws:
      IllegalArgumentException - for a digest that is not one of the four
    • pbkdf2

      public static byte[] pbkdf2(String digest, byte[] password, byte[] salt, int iterations, int length) throws IOException
      PBKDF2 over HMAC with one of SHA1, SHA256, SHA384 and SHA512, on the password's bytes as they are given.
      Throws:
      IOException - when a count is not positive or derivation fails
    • sign

      public static byte[] sign(String algorithm, byte[] privateKey, byte[] data) throws IOException

      Signs data with a private key in PKCS#8 DER, under one of RS256, RS384, RS512, PS256, ES256 and ES384.

      The key has to be of the kind the algorithm is defined over: an RSA key for the first four, a P-256 key for ES256, a P-384 key for ES384. Any other pairing is refused rather than adapted to.

      An ECDSA signature is returned as ASN.1 DER, the SEQUENCE of r and s both OpenSSL and the JDK produce. JOSE wants the two numbers side by side instead; com.codename1.backend.security.crypto.Der converts.

      Throws:
      IOException - when the key cannot be read, does not fit the algorithm, or signing fails
    • verify

      public static boolean verify(String algorithm, byte[] publicKey, byte[] data, byte[] signature) throws IOException
      Checks a signature against a public key in SubjectPublicKeyInfo DER. The algorithms and the pairing of key and algorithm are those of sign(String, byte[], byte[]), and an ECDSA signature is given as ASN.1 DER.
      Returns:
      true when signature is that key's signature of data; false when it is not, whatever is wrong with it
      Throws:
      IOException - when the question could not be asked: the key cannot be read or does not fit the algorithm. A key that is broken is never reported as a signature that is forged.
    • generateRsaKey

      public static byte[] generateRsaKey(int bits) throws IOException

      A new RSA private key as PKCS#8 DER, with the public exponent 65537.

      For a development profile, so a server that signs tokens starts without a key file. A key made at start-up is gone at the next one, and every token signed with it stops verifying: a deployed server loads its key.

      Parameters:
      bits - 2048 to 8192
      Throws:
      IOException
    • aesGcmEncrypt

      public static byte[] aesGcmEncrypt(byte[] key, byte[] iv, byte[] aad, byte[] plaintext) throws IOException

      AES-GCM. The result is the ciphertext followed by the 16 byte tag.

      The nonce must never repeat under one key: 12 bytes from randomBytes(int) for each call is the ordinary way, stored beside the result.

      Parameters:
      key - 16, 24 or 32 bytes
      iv - the nonce; 12 bytes unless a protocol says otherwise
      aad - data that is authenticated and not encrypted; null for none
      Throws:
      IOException
    • aesGcmDecrypt

      public static byte[] aesGcmDecrypt(byte[] key, byte[] iv, byte[] aad, byte[] sealed) throws IOException
      Returns:
      the plaintext, or null when the tag does not match: the key, the nonce, the associated data or the sealed bytes are not the ones it was made with
      Throws:
      IOException - when the sizes are not ones AES-GCM has