Cryptography - ARCAD-Software/AFS GitHub Wiki
The com.arcadsoftware.crypt bundle offer a library with simple cryptographic tools such as the following:
- Some classes to manipulate TLS Certificates:
- CertificateInformation allow to get user friendly information about a X509 Certificate.
- InstallCertificates allow to test a TLS socket connection against the certificates contained into a given TrustStore, retrieve the connection certificate and eventually add it to the TrustStore.
- TrustAnyCertificateManager implement a TrustManager that accept any certificate (use with caution !).
- KeyStoreManager is an utility class to facilitate the manipulation of KeyStore content.
- Some generic utility classes:
- SMAZ and DictionnaryCompression two classes allowing to compress String, based on dictionaries, the first one is dedicated to English text, the second use a given dictionary.
- RandonGenerator an utility class that may help to generate pseudo random numbers and String.
- SignXMLUtils allow to sign XML files. This class is now published by another bundle, com.arcadsoftware.crypt.xml.
- And an utility class, Crypto, that allow to encrypt, hash and test complexity of String (dedicated to the storage of password and critical data).
All of these classes have a Javadoc.
The com.arcadsoftware.crypt.Crypto class allow to encrypt and hash sensitive String with up-to-date cryptographic algorithms. This class is a final static class. The most important methods are the ones related to hashing and encrypting, but there is also some method that provide other cryptographic algorithms, like the methods fog and unfog, or some tools allowing to test password complexity.
The hash method use an algorithm with a ratio of security/performance which can be adjusted by configuration (see below). With the default configuration the hash generation take approximately 50ms and resulting String s a Base64 encoded string of 208 characters long.
As the hash contain a salt (a random part) if the same data is hashed twice the two hash will be different. So to be able to compare a data with a hash you must call the matches method, do not hash the data to compare both hashes ! This imply that if you store hashes in a database you can not use an SQL selection to extract the corresponding row. Calling the matches method take approximately the same time as calling the hash method. If you require an hash implementation for CRC computation, or just to compare two hashes, use one of the methods: md5, sha1 or whirlpool.
To test if an hash have been generated with the current secured hash method, you can call the isHashSecure method. If the result is false then the hash may have been generated with the old "crypt" method, which is equivalent to the whirlpool one. Notes that the matches method can detect this and if the given hash looks like a whirlpool hash then it use it to make the comparison.
The encrypt and decrypt methods use a symmetric key and a assumed secure algorithm. Just like the hash algorithm it may be adjusted by parameters, and it may use a default "master key" to encrypt the data, see the configuration paragraph. With the default parameters the encrypt method generate a Base64 encoded string of at least 62 character (which may go up to 500 chars) in approximately 15ms.
Again the current implementation use a salt (to generate a specific key from the master key) and an initialization vector (iv) so if a same string is encrypted twice it will generate different encode string. So you can not compare two encrypted string, you have to decrypt them first.
The method isCryptSecure allow to detect if the given encrypted string has been generated by the current implementation. The decrypt method also try to identify the original algorithm, for ascendant compatibility, between the previous "encode" or "encodeXE256" methods (it is not possible to differentiate the results of "encodeX64" from the result of "encodeXE256").
The methods encryptA and decryptA use an asymmetric algorithm which require two different keys,; one for encryption and one for decryption only. This algorithm is slower than the symmetric encryption algorithm and is dedicated to small data, like password or other keys...
If you want to use a simple, and fast, encryption algorithm and which, always, generate the same encrypted string for a given data use the fog and unfog methods, but these methods are not secured.
The current implementation of the hashing and encryption algorithm rely on system properties. These property may configured by the user, they will adjust the performances and security level of the application (higher are the parameters values, higher is the security level, and lower are the performances). For more details on these properties take a look the the configuration documentation: Security and cryptography.
The default values of these properties are the following, they ensure an average level of security with good performances :
com.arcadsoftware.salt.min.size = 8
com.arcadsoftware.salt.size.variation = 16
com.arcadsoftware.iv.min.size = 10
com.arcadsoftware.iv.size.variation = 6
com.arcadsoftware.hash.min.iterations = 8675
com.arcadsoftware.hash.iterations.variation = 1892
com.arcadsoftware.cypher.min.iterations = 8000
com.arcadsoftware.cypher.iterations.variation = 1607
com.arcadsoftware.masterkey = complexScrambledString!
The munical values are defined by a minimal value and variation, each time the corresponding parameter is used a speific value is ramdonly generated from theses values. The values of salt properties must be between 4 and 128 bytes, the values of the IV must between 4 and 16 and the values of hash and cipher iterations must be between 1 and 10000000. Any other values are ignored.
Note that salt and iv value change the size of the generated hashed and encrypted strings and the iterations values change the duration of the corresponding operations. As the iv, slat and iteration count are included in the hash or encrypted string any modification of these value do not compromise any data generated with previous values. But any modification of the masterkey property does compromise any data which have been previously encrypted with the default encrypt(String) method.
The masterkey property is only used by the encrypt(String) and it should set to a value during the product installation, once for all. It must not be changed during the whole lifecycle of the installed program. The default value of the masterkey is built from the current values of the following system properties:
- the os.name system property.
- If available the hostname of the loop-back ethernet interface or, if not, the user.name system property.
- and java.home system property.
The concatenation of these properties is scramble to give a quite complex string, like this kind of string: jkxrdvimet1u/=081_.n/l/l7icĂhjbLƇ%1s/uh©jµuu./sr
But as these properties may change at any moment the program may be unable the decrypt any string that was previously encrypted by the default method.
So you must either:
- only use the encrypt(string, key) method with your own master key. Never call the the encrypt(string) method.
- Set during the installation a unique, and really complex, value to the com.arcadsoftware.masterkey value.
There is three properties allowing to define the master key:
- com.arcadsoftware.masterkey : define the master key in clear. Note that this master key is not the "real" one as the real key is scrambled from this one.
- com.arcadsoftware.masterkey.fog : present the master key as returned by the fog encrypt method.
- com.arcadsoftware.masterkey.path : define the path of a file containing an UTF-8 encoded text used as the master key.
Only one of the three definition is used, in priority the file of the "path" property is checked if the file does not exists, or if the property is not set, the "fog" one used, and this property is not defined either then the "clear master key" is used. only is non of theses properties is defined, the default master key is generated. In that last case, the program will try to write the default generated key into the config.ini file so that at the next server startup the same value is used.
⚠️ Note that AFS currently use the default encrypt(string) method... so for this release setting a value to com.arcadsoftware.masterkey is required anyway ! Next releases of AFS will propose a way to configure each module with an independent master key.
The two methods EncryptA and DecryptA, respectively, require an RSA private and public keys. These key should be separated and stored into a secure container. The class KeyStoreManager can help to manage this storage.
To generate the key pair and store the keys into a keystore:
try (KeyStoreManager km = new KeyStoreManager("./ks.p12", "kspass".toCharArray())) {
km.generateNewKeyPair("alias", "kpass".toCharArray());
}
To export the public key from this KeyStore and provide another keystore to store it:
try (KeyStoreManager km = new KeyStoreManager("./ks.p12", "kspass".toCharArray())) {
km.exportPublicKey("alias", "./ts.p12", "tspass".toCharArray());
}
and then, to retrieve the private key (used to encrypt data):
try (KeyStoreManager km = new KeyStoreManager("./ks.p12", "kspass".toCharArray())) {
byte[] key = km.getPrivateKey("alias", "kpass".toCharArray());
}
to retrieve the public key (used to decrypt data):
try (KeyStoreManager km = new KeyStoreManager("./ts.p12", "tspass".toCharArray())) {
byte[] key = km.getPublicKey("alias");
}
The current algorithm used by the secured hash and encrypt methods are:
- Hash: use multiples iteration (from a randomly chosen value between 8675 and 10566 by default) of PBKDF2 With Hmac SHA256 algorithm to generate a 1024 bits long hash, including a random salt (of 8 to 24 bytes by default) generated by a SHA1PRNG random number generator.
- Encrypt: use a counter based cypher using AES-256 (i.e. AES/CTR/NOPADDING) with a random (SHA1PRNG) IV (10 to 16 byte long by default). This cipher use a key of 256 bit long generated from the "masterkey" plus a random salt (from 8 to 24 bytes), using the PBKDF2 With Hmac SHA1 algorithm (with same default as Hash). Note that the usage of AES-256 is conditioned to the legally acceptable AES algorithm usable locally.
- EncryptA : use the RSA algorithm with OAER padding (i.e. RSA/ECB/OAEPWithSHA256AndMGF1Padding).
All implementation of these algorithm are those of the Bouncy Castle library, and so, are independent from the used JVM.