-
Sub-task
-
Resolution: Unresolved
-
Major
-
None
-
None
-
None
-
False
-
None
-
False
-
-
Use the following guidelines to ensure that your application uses algorithms, parameters, and key lengths that adhere to strict standards for encryption:
- Always use well-tested and industry-accepted cryptographic algorithms.
- In case an organization does not have approved cryptographic algorithms or key lengths, check the algorithm against the FIPS 140-3 validation list. Annex A Section 14 provides a list of approved security algorithms applicable to FIPS 140-3.
- For example, Data Encryption Standard (DES) is not considered secure and an alternative such as Advanced Encryption Standard (AES) should be used for symmetric encryption.
- Use any unapproved algorithms only in conjunction with approved algorithms and implement it in a manner that does not reduce the equivalent cryptographic key strength provided by the approved algorithms.
- Do not use encoding and compression algorithms instead of encryption algorithms. For example, a common mistake is using a type of encoding to protect data, such as Base64 encoding. Base64 encoding is not an encryption algorithm and does not protect data. It can be reversed using Base64 decoding without the need for any additional shared knowledge (such as knowledge of a shared key). Techniques such as Base64, ROT13, GZip, LZW, Huffman coding, etc., should not be used for protecting data in place of encryption algorithms.
- Use a key management system that provides features for secure generation, distribution, storage, change, and retirement or revocation of cryptographic keys.
- Always initialize the initialization vectors (IVs) used in the algorithms with secure random values.
- Always use cryptographically secure random IVs when using a block cipher in cipher-block chaining (CBC) mode.
- A predictable IV can cause an affected system to be vulnerable to plaintext attacks. - Use encryption in CBC mode instead of Electronic Codebook (ECB) mode.
- Always incorporate an industry-accepted standard padding method, where padding is used prior to or during encryption.
- Do not reuse the same cryptographic key for multiple purposes.
- Use only approved, collision-resistant hash algorithms and methods with a salt value of appropriate strength that is generated using a secure random number generator.
Imported from SD Elements: https://redhat.sdelements.com/bunits/psse-secure-development/group-2-extended-functionality-offerings/amq-clients/tasks/phase/specifications/141-T60/
How Tos:
ASP.NET Core / C#: Choosing cryptographic algorithms
Description
By default, Microsoft ASP.NET Core uses AES-256-CBC for confidentiality and HMACSHA256 for authenticity. Although it is possible to change the algorithm you use, it is recommended that you use the defaults as the minimum standard because they are known to be strong. In some scenarios, a stronger algorithm, longer key length or shorter key rotation periods may be necessary.
To change the algorithm, you can use the code below. Changing the algorithm will override the one used by the default machine-wide policy and only newly generated keys are affected.
In this example, ASP.NET Core's default algorithms appear as the encryption and validation algorithms. Replace these strings with the name of the algorithms you are switching to.
Code
services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
.NET Core implements algorithms for you, but you can manage the implementation yourself using the code below. This gives you more flexibility in terms of customizing cipher strength, for example:
serviceCollection.AddDataProtection() .UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptionSettings() { // a type that subclasses SymmetricAlgorithm EncryptionAlgorithmType = typeof(Aes),
// specified in bits
EncryptionAlgorithmKeySize = 256,
// a type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
ASP.NET Core / C#: Setting Key Lifetime
Description
When a key is created, it is automatically activated two days after creation, giving other applications time to find the key when they next refresh. It is given a default lifetime of 90 days. At expiry, ASP.NET Core automatically generates a new key and sets it as the active key. This change to the new key is called rolling.
You can change the lifetime using the code below. This example sets the lifetime to 14 days from now, which is the time of creation.
**`
public void ConfigureServices(IServiceCollection services)
**`
Using Correct Cryptographic Algorithms and Parameters in Java
The following provides Java code examples for common security objectives.
1) Protecting shared secrets (Symmetric Cryptography)
Encrypt shared secrets to hide them from adversaries. Consider the following code fragment used to encrypt and decrypt shared secrets.
// Shared secrets only. Passwords are handled differently (see following examples). public static String encrypt(byte[] key, byte[] initVector, String value) throws Exception { IvParameterSpec iv = new IvParameterSpec(initVector); SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(value.getBytes("UTF-8")); String encoded = Base64.getEncoder().encodeToString(encrypted); return encoded; blic static String decrypt(byte[] key, byte[] initVector, String encrypted) throws Exception { IvParameterSpec iv = new IvParameterSpec(initVector); SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted)); return new String(original); ivate static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); } return sb.toString();
2) Send information securely over the Internet (Asymmetric Cryptography)
In this case, we want to open a secure connection to a remote web server and check its X.590 certificate. Once we have the server certificate, we test to ensure it chains back to a root that ships with Java. The following code fragment demonstrates the process.
public static final boolean checkTrustedCertificate( X509Certificate[] certs, URL url) throws KeyStoreException, NoSuchAlgorithmException, UnknownHostException, IOException { boolean valid = false;
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket)factory.createSocket(url.getHost(), url.getDefaultPort());
SSLSession session = socket.getSession();
String keyexchalgo = getKeyExchangeAlgorithm(session);
try { socket.close(); } catch( IOException e ) {}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore)null); // you could use a non-default KeyStore as your truststore too, instead of null. for (TrustManager trustManager: trustManagerFactory.getTrustManagers()) { if (trustManager instanceof X509TrustManager) { X509TrustManager x509TrustManager = (X509TrustManager)trustManager; try { x509TrustManager.checkServerTrusted(certs,keyexchalgo); valid = true; } catch( CertificateException e ) { // Eat the stacktrace logger.error( "url="+url.toString() ); } } } return valid;}
For an idea of the type of metadata included in an X.509 certificate, consider the following dump using the OWASP DeepViolet tool:
[Server certificate information] Trusted State=>>>TRUSTED<<< Validity Check=VALID, certificate valid between Tue Jan 03 12:08:00 PST 2017 and Mon Apr 03 13:08:00 PDT 2017 SubjectDN=CN=securitycurmudgeon.com IssuerDN=CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US Serial Number=284509671358157103109227291976164022995273 Signature Algorithm=SHA256withRSA Signature Algorithm OID=1.2.840.113549.1.1.11 Certificate Version =3 SHA256(Fingerprint)=FD:3A:53:EE:4D:6E:F9:DD:DE:67:7E:E7:76:34:5A:54:CD:87:E6:DA:65:E8:D4:E5:94:4E:AB:D2:03:E4:59:F3 Non-critical OIDs AuthorityInfoAccess=[ocsp=http://ocsp.int-x3.letsencrypt.org/ | caIssuers=http://cert.int-x3.letsencrypt.org/] CertificatePolicies=[2.23.140.1.2.1=1.3.6.1.4.1.44947.1.1.1=qualifierID=http://cps.letsencrypt.orgCPSUserNotice=This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/] AuthorityKeyIdentifier=[A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1] SubjectKeyIdentifier=[3C:82:DA:31:4F:71:00:E2:34:37:ED:9A:CA:CD:7D:B0:88:3E:93:F1] ExtendedKeyUsages=[serverauth clientauth] SubjectAlternativeName=[securitycurmudgeon.com | www.securitycurmudgeon.com] Critical OIDs KeyUsage=[keycertsign] BasicConstraints=[]
3) Secure hash (Message Digests)and passwords
A message digest result is beneficial for identifying modified files. On the Java platform, you can generate a SHA3-256 digest like this:
private void printHash() throws Exception { MessageDigest md = MessageDigest.getInstance("SHA3-256"); byte[] bIn = "test content to hashs".getBytes("UTF-8"); byte[] bOut = md.digest(bIn); for( int i=0; i< bOut.length ; i++) { System.out.print(String.format("%02x", bOut[i])); } System.out.println(); }
Following is an example of a SHA3-256 digest:
5e4e1fab4e1e205b9ecd76064dfb68fce1f517c601dc9dbe7e46f47aaf7335e4
Small changes in a hashed string cause wild fluctuations in the digest results. For example, changing the string slightly to "test content to hashes" produces the following SHA3-256 hash:
efab4425234dad7bfc4fc432f66c3e0f4a8908ba51181081098eeffe01d0d402
Altering the string by even a single character produces an entirely different digest result. Hashes are great for identifying changes in data. This works well to test the integrity of a file or network data.
Passwords are a special case and hashing alone is not enough. An attacker can easily precompute a table based upon common dictionary words, called a Rainbow Table. Rainbow tables are particularly useful when stored password hashes are exfiltrated. If attackers can match rainbow table values against the password values, then the password is identified by the dictionary word. A better solution combines several security measures for strong password defense.
Brief summary of password protection methodology is as follows:
- Step 1) Plan text password. Plain text password UTF-8 encoded.
- Step 2) Output value of step 1 is hashed with SHA512 algorithm. This ensures a consistently high entropy for all passwords regardless of length.
- Step 3) Output value of step 2 is encrypted with an HMAC function. bcrypt is recommended, alternatively PBKDF2 if a Java only solution is required. The HMAC function should use a high iterator and a per user salt value.
- Step 4) Output value of step 3 is encrypted with AES256. A global (application instance hash) pepper is provided to the hash function along with the output of step 3. Output of step 4 is the finished hash suitable for storage or comparison.
PLAIN TEXT PASSWORD --> UTF-8 --> SHA512 --> HMAC(bcrypt) ---> AES256 --> SECURE PASSWORD
Note: The approach is described in detail by DropBox here
4) Secure random numbers (Cryptographically Secure Number Generation)
There are a lot of methods to create random numbers in Java and many are insecure or weak. In Java 9+, you can use the DRBG (Deterministic Random Bit Generator) to generate a secure random number in accordance with NIST specification, "NIST Special Publication 800-90A Revision 1, Recommendation for Random Number Generation Using Deterministic Random Bit Generators (800-90Ar1)". Consider the following code sample.
SecureRandom sr = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation(256, DrbgParameters.Capability.PR_AND_RESEED, "PersonalizeThisString".getBytes())); byte[] key = new byte[32]; // nextBytes() places the result in key, a 256-bit result. sr.nextBytes(key);