├── How_to_use_java_crypto_api_securely.key ├── README.md ├── cipher ├── SecurePBKDFUsage.java ├── SecuredGCMUsage.java └── SecuredRSAUsage.java ├── crypto_applications ├── mac │ └── MacComputation.java ├── password_management │ ├── Authentication.java │ ├── PasswordManagementUtils.java │ └── PasswordStorage.java └── signature │ ├── DigitalSignature.java │ └── SignatureUtils.java ├── message_digest └── CalculateChecksum.java └── securerandom └── CheckSecureRandomConfig.java /How_to_use_java_crypto_api_securely.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/java_crypto/6ad566b58f5e91b75552223b357dda7ef0315a65/How_to_use_java_crypto_api_securely.key -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED - Shinier, microserviced, dockerized more real worldy version maintained at https://gitlab.com/1MansiS/JavaCrypto 2 | 3 | This repository 4 | - Complimenting code repo for [Java Crypto blog series](https://www.veracode.com/blog/research/how-get-started-using-java-cryptography-securely) 5 | - Working Examples presented in Conference Talks at JavaOne & JavaZone : [How To Use Java Cryptography API Securely?](https://2017.javazone.no/program/c305c46014624f02b86a8864b54555b3) 6 | -------------------------------------------------------------------------------- /cipher/SecurePBKDFUsage.java: -------------------------------------------------------------------------------- 1 | import java.security.SecureRandom ; 2 | import javax.crypto.spec.PBEKeySpec ; 3 | import javax.crypto.SecretKeyFactory ; 4 | 5 | import java.util.Base64 ; 6 | 7 | 8 | import java.security.spec.InvalidKeySpecException ; 9 | import java.lang.NullPointerException ; 10 | import java.security.spec.InvalidKeySpecException ; 11 | import java.lang.NullPointerException ; 12 | import java.security.NoSuchAlgorithmException ; 13 | import java.lang.IllegalArgumentException ; 14 | import java.security.GeneralSecurityException ; 15 | 16 | /* 17 | This class shows how to use PBKDF2 based password generation. 18 | Recommended way of storing passwords in databases. Also called as password stretching 19 | */ 20 | public class SecurePBKDFUsage { 21 | 22 | public static String PDKDF_ALGORITHM = "PBKDF2WithHmacSHA512" ; 23 | public static int ITERATION_COUNT = 12288 ; 24 | public static int SALT_LENGTH = 128 ; 25 | public static int DERIVED_KEY_LENGTH = 256 ; 26 | 27 | public static void main(String args[]) { 28 | 29 | // Strings are immutatable, so there is no way to change/nullify/modify its content after use. So always, collect and store security sensitive information in a char array instead. 30 | char[] PASSWORD = args[0].toCharArray() ; 31 | 32 | String hashedPassword = null ; 33 | try { 34 | hashedPassword = computePBKDF(PASSWORD) ; 35 | } catch(GeneralSecurityException genSecExc) {System.out.println(genSecExc.getMessage() + " " + genSecExc.getCause() ) ; System.exit(1) ; } 36 | 37 | System.out.println("PDKDF2 = " + hashedPassword) ; 38 | } 39 | 40 | public static String computePBKDF(char[] password) throws GeneralSecurityException { 41 | byte[] salt = new byte[SALT_LENGTH] ; 42 | 43 | SecureRandom secRandom = new SecureRandom() ; 44 | secRandom.nextBytes(salt) ; 45 | 46 | PBEKeySpec keySpec = null ; 47 | try { 48 | keySpec = new PBEKeySpec(password, salt, ITERATION_COUNT , DERIVED_KEY_LENGTH * 8); 49 | } catch(NullPointerException nullPointerExc){throw new GeneralSecurityException("Salt " + salt + "is null") ;} 50 | catch(IllegalArgumentException illegalArgumentExc){throw new GeneralSecurityException("One of the argument is illegal. Salt " + salt + " is of 0 length, iteration count " + ITERATION_COUNT + " is not positive or derived key length " + DERIVED_KEY_LENGTH + " is not positive." ) ;} 51 | 52 | SecretKeyFactory pbkdfKeyFactory = null ; 53 | 54 | try { 55 | pbkdfKeyFactory = SecretKeyFactory.getInstance(PDKDF_ALGORITHM) ; 56 | } catch(NullPointerException nullPointExc) {throw new GeneralSecurityException("Specified algorithm " + PDKDF_ALGORITHM + "is null") ;} 57 | catch(NoSuchAlgorithmException noSuchAlgoExc) {throw new GeneralSecurityException("Specified algorithm " + PDKDF_ALGORITHM + "is not available by the provider " + pbkdfKeyFactory.getProvider().getName()) ;} 58 | 59 | byte[] pbkdfHashedArray = null ; 60 | try { 61 | pbkdfHashedArray = pbkdfKeyFactory.generateSecret(keySpec).getEncoded() ; 62 | } catch(InvalidKeySpecException invalidKeyExc) {throw new GeneralSecurityException("Specified key specification is inappropriate") ; } 63 | 64 | return Base64.getEncoder().encodeToString(pbkdfHashedArray) ; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cipher/SecuredGCMUsage.java: -------------------------------------------------------------------------------- 1 | import javax.crypto.Cipher ; 2 | import java.security.SecureRandom ; 3 | import javax.crypto.spec.GCMParameterSpec ; 4 | import javax.crypto.KeyGenerator; 5 | import javax.crypto.SecretKey; 6 | 7 | import java.util.Base64 ; 8 | 9 | import java.security.NoSuchAlgorithmException ; 10 | import java.security.InvalidKeyException; 11 | import javax.crypto.IllegalBlockSizeException ; 12 | import javax.crypto.NoSuchPaddingException ; 13 | import java.security.InvalidAlgorithmParameterException ; 14 | import javax.crypto.BadPaddingException ; 15 | import javax.crypto.ShortBufferException; 16 | 17 | import java.util.Arrays ; 18 | 19 | /** 20 | This class shows how to securely perform AES encryption in GCM mode, with 256 bits key size. 21 | */ 22 | public class SecuredGCMUsage { 23 | 24 | public static int AES_KEY_SIZE = 256 ; 25 | public static int IV_SIZE = 96 ; 26 | public static int TAG_BIT_LENGTH = 128 ; 27 | public static String ALGO_TRANSFORMATION_STRING = "AES/GCM/PKCS5Padding" ; 28 | 29 | public static void main(String args[]) { 30 | String messageToEncrypt = args[0] ; 31 | 32 | byte[] aadData = "random".getBytes() ; // Any random data can be used as tag. Some common examples could be domain name... 33 | 34 | // Use different key+IV pair for encrypting/decrypting different parameters 35 | 36 | // Generating Key 37 | SecretKey aesKey = null ; 38 | try { 39 | KeyGenerator keygen = KeyGenerator.getInstance("AES") ; // Specifying algorithm key will be used for 40 | keygen.init(AES_KEY_SIZE) ; // Specifying Key size to be used, Note: This would need JCE Unlimited Strength to be installed explicitly 41 | aesKey = keygen.generateKey() ; 42 | } catch(NoSuchAlgorithmException noSuchAlgoExc) { System.out.println("Key being request is for AES algorithm, but this cryptographic algorithm is not available in the environment " + noSuchAlgoExc) ; System.exit(1) ; } 43 | 44 | // Generating IV 45 | byte iv[] = new byte[IV_SIZE]; 46 | SecureRandom secRandom = new SecureRandom() ; 47 | secRandom.nextBytes(iv); // SecureRandom initialized using self-seeding 48 | 49 | 50 | // Initialize GCM Parameters 51 | GCMParameterSpec gcmParamSpec = new GCMParameterSpec(TAG_BIT_LENGTH, iv) ; 52 | 53 | byte[] encryptedText = aesEncrypt(messageToEncrypt, aesKey, gcmParamSpec, aadData) ; 54 | 55 | System.out.println("Encrypted Text = " + Base64.getEncoder().encodeToString(encryptedText) ) ; 56 | 57 | byte[] decryptedText = aesDecrypt(encryptedText, aesKey, gcmParamSpec, aadData) ; // Same key, IV and GCM Specs for decryption as used for encryption. 58 | 59 | System.out.println("Decrypted text " + new String(decryptedText)) ; 60 | 61 | // Make sure not to repeat Key + IV pair, for encrypting more than one plaintext. 62 | secRandom.nextBytes(iv); 63 | } 64 | 65 | 66 | public static byte[] aesEncrypt(String message, SecretKey aesKey, GCMParameterSpec gcmParamSpec, byte[] aadData) { 67 | Cipher c = null ; 68 | 69 | try { 70 | c = Cipher.getInstance(ALGO_TRANSFORMATION_STRING); // Transformation specifies algortihm, mode of operation and padding 71 | }catch(NoSuchAlgorithmException noSuchAlgoExc) {System.out.println("Exception while encrypting. Algorithm being requested is not available in this environment " + noSuchAlgoExc); System.exit(1); } 72 | catch(NoSuchPaddingException noSuchPaddingExc) {System.out.println("Exception while encrypting. Padding Scheme being requested is not available this environment " + noSuchPaddingExc); System.exit(1); } 73 | 74 | 75 | try { 76 | c.init(Cipher.ENCRYPT_MODE, aesKey, gcmParamSpec, new SecureRandom()) ; 77 | } catch(InvalidKeyException invalidKeyExc) {System.out.println("Exception while encrypting. Key being used is not valid. It could be due to invalid encoding, wrong length or uninitialized " + invalidKeyExc) ; System.exit(1); } 78 | catch(InvalidAlgorithmParameterException invalidAlgoParamExc) {System.out.println("Exception while encrypting. Algorithm parameters being specified are not valid " + invalidAlgoParamExc) ; System.exit(1); } 79 | 80 | try { 81 | c.updateAAD(aadData) ; // add AAD tag data before encrypting 82 | }catch(IllegalArgumentException illegalArgumentExc) {System.out.println("Exception thrown while encrypting. Byte array might be null " +illegalArgumentExc ); System.exit(1);} 83 | catch(IllegalStateException illegalStateExc) {System.out.println("Exception thrown while encrypting. CIpher is in an illegal state " +illegalStateExc); System.exit(1);} 84 | catch(UnsupportedOperationException unsupportedExc) {System.out.println("Exception thrown while encrypting. Provider might not be supporting this method " +unsupportedExc); System.exit(1);} 85 | 86 | byte[] cipherTextInByteArr = null ; 87 | try { 88 | cipherTextInByteArr = c.doFinal(message.getBytes()) ; 89 | } catch(IllegalBlockSizeException illegalBlockSizeExc) {System.out.println("Exception while encrypting, due to block size " + illegalBlockSizeExc) ; System.exit(1); } 90 | catch(BadPaddingException badPaddingExc) {System.out.println("Exception while encrypting, due to padding scheme " + badPaddingExc) ; System.exit(1); } 91 | 92 | return cipherTextInByteArr ; 93 | } 94 | 95 | 96 | public static byte[] aesDecrypt(byte[] encryptedMessage, SecretKey aesKey, GCMParameterSpec gcmParamSpec, byte[] aadData) { 97 | Cipher c = null ; 98 | 99 | try { 100 | c = Cipher.getInstance(ALGO_TRANSFORMATION_STRING); // Transformation specifies algortihm, mode of operation and padding 101 | } catch(NoSuchAlgorithmException noSuchAlgoExc) {System.out.println("Exception while decrypting. Algorithm being requested is not available in environment " + noSuchAlgoExc); System.exit(1); } 102 | catch(NoSuchPaddingException noSuchAlgoExc) {System.out.println("Exception while decrypting. Padding scheme being requested is not available in environment " + noSuchAlgoExc); System.exit(1); } 103 | 104 | try { 105 | c.init(Cipher.DECRYPT_MODE, aesKey, gcmParamSpec, new SecureRandom()) ; 106 | } catch(InvalidKeyException invalidKeyExc) {System.out.println("Exception while encrypting. Key being used is not valid. It could be due to invalid encoding, wrong length or uninitialized " + invalidKeyExc) ; System.exit(1); } 107 | catch(InvalidAlgorithmParameterException invalidParamSpecExc) {System.out.println("Exception while encrypting. Algorithm Param being used is not valid. " + invalidParamSpecExc) ; System.exit(1); } 108 | 109 | try { 110 | c.updateAAD(aadData) ; // Add AAD details before decrypting 111 | }catch(IllegalArgumentException illegalArgumentExc) {System.out.println("Exception thrown while encrypting. Byte array might be null " +illegalArgumentExc ); System.exit(1);} 112 | catch(IllegalStateException illegalStateExc) {System.out.println("Exception thrown while encrypting. CIpher is in an illegal state " +illegalStateExc); System.exit(1);} 113 | 114 | byte[] plainTextInByteArr = null ; 115 | try { 116 | plainTextInByteArr = c.doFinal(encryptedMessage) ; 117 | } catch(IllegalBlockSizeException illegalBlockSizeExc) {System.out.println("Exception while decryption, due to block size " + illegalBlockSizeExc) ; System.exit(1); } 118 | catch(BadPaddingException badPaddingExc) {System.out.println("Exception while decryption, due to padding scheme " + badPaddingExc) ; System.exit(1); } 119 | 120 | return plainTextInByteArr ; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /cipher/SecuredRSAUsage.java: -------------------------------------------------------------------------------- 1 | import java.security.KeyPairGenerator; 2 | import java.security.PrivateKey ; 3 | import java.security.PublicKey ; 4 | import java.util.Base64 ;; 5 | import javax.crypto.Cipher ; 6 | import java.lang.Exception ; 7 | import java.security.Key ; 8 | import java.security.KeyPair ; 9 | 10 | public class SecuredRSAUsage { 11 | 12 | static int RSA_KEY_LENGTH = 4096; 13 | static String ALGORITHM_NAME = "RSA" ; 14 | static String PADDING_SCHEME = "OAEPWITHSHA-512ANDMGF1PADDING" ; 15 | static String MODE_OF_OPERATION = "ECB" ; // This essentially means none behind the scene 16 | 17 | public static void main(String args[]) { 18 | String shortMessage = args[0] ; 19 | 20 | 21 | try { 22 | 23 | // Generate Key Pairs 24 | KeyPairGenerator rsaKeyGen = KeyPairGenerator.getInstance(ALGORITHM_NAME) ; 25 | rsaKeyGen.initialize(RSA_KEY_LENGTH) ; 26 | KeyPair rsaKeyPair = rsaKeyGen.generateKeyPair() ; 27 | 28 | 29 | String encryptedText = rsaEncrypt(shortMessage, rsaKeyPair.getPublic()); 30 | 31 | String decryptedText = rsaDecrypt(Base64.getDecoder().decode(encryptedText), rsaKeyPair.getPrivate()) ; 32 | 33 | System.out.println("Encrypted text = " + encryptedText) ; 34 | System.out.println("Decrypted text = " + decryptedText) ; 35 | 36 | } catch(Exception e) {System.out.println("Exception while encryption/decryption") ;e.printStackTrace() ; } 37 | 38 | 39 | } 40 | 41 | public static String rsaEncrypt(String message, Key publicKey) throws Exception { 42 | 43 | Cipher c = Cipher.getInstance(ALGORITHM_NAME + "/" + MODE_OF_OPERATION + "/" + PADDING_SCHEME) ; 44 | 45 | c.init(Cipher.ENCRYPT_MODE, publicKey) ; 46 | 47 | byte[] cipherTextArray = c.doFinal(message.getBytes()) ; 48 | 49 | return Base64.getEncoder().encodeToString(cipherTextArray) ; 50 | 51 | } 52 | 53 | 54 | public static String rsaDecrypt(byte[] encryptedMessage, Key privateKey) throws Exception { 55 | Cipher c = Cipher.getInstance(ALGORITHM_NAME + "/" + MODE_OF_OPERATION + "/" + PADDING_SCHEME) ; 56 | c.init(Cipher.DECRYPT_MODE, privateKey); 57 | byte[] plainText = c.doFinal(encryptedMessage); 58 | 59 | return new String(plainText) ; 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crypto_applications/mac/MacComputation.java: -------------------------------------------------------------------------------- 1 | package crypto_applications.mac; 2 | 3 | 4 | import javax.crypto.KeyGenerator; 5 | import javax.crypto.Mac; 6 | import javax.crypto.SecretKey; 7 | import java.io.IOException; 8 | import java.security.InvalidKeyException; 9 | import java.security.NoSuchAlgorithmException; 10 | 11 | import java.util.Arrays; 12 | 13 | 14 | /** 15 | * This class shows how to use HMAC. Ideally, separate key management systems would be used for storing and retrieving of secret keys. 16 | */ 17 | public class MacComputation { 18 | 19 | private static String HMAC_ALGORITHM = "HmacSHA256" ; 20 | 21 | public static void main(String args[]) throws IOException{ 22 | String fileNameToBeMaced = args[0] ; 23 | 24 | // Some checks for validity of file, existence, null, file extn etc 25 | 26 | MacUtils macUtils = new MacUtils(); 27 | 28 | // generate secret key for MAC computation 29 | KeyGenerator kg = null; 30 | try { 31 | kg = KeyGenerator.getInstance(HMAC_ALGORITHM); 32 | } catch (NoSuchAlgorithmException e) { 33 | System.out.println("Unable to generate key for " + HMAC_ALGORITHM); 34 | System.exit(0); 35 | } 36 | SecretKey secretKey = kg.generateKey() ; 37 | 38 | byte[] macTag = sender(macUtils.readFile(fileNameToBeMaced), secretKey) ; 39 | 40 | System.out.println("Receiver verified integrity and authenticity of message from file " + fileNameToBeMaced + " ? " + macVerifiedByReceiver(macUtils.readFile(fileNameToBeMaced), macTag, secretKey)) ; 41 | 42 | } 43 | 44 | /** 45 | * This method is used on sender side, to compute MacTag and send it across to receiver, alongwith original message content, to verify against recomputed MacTag 46 | * @param content 47 | * @param secretKey 48 | * @return 49 | */ 50 | private static byte[] sender(byte[] content, SecretKey secretKey) { 51 | return computeMac(content, secretKey); 52 | } 53 | 54 | /** 55 | * This method is used on receiver side, to recompute macTag, and verify it with send macTag. This will verify integrity and authenticity of received messages. 56 | * @param content 57 | * @param macTag 58 | * @param secretKey 59 | * @return 60 | */ 61 | private static boolean macVerifiedByReceiver(byte[] content, byte[] macTag, SecretKey secretKey) { 62 | byte[] recomputerMacTags = computeMac(content, secretKey) ; 63 | 64 | boolean isVerified = false ; 65 | 66 | if(Arrays.equals(macTag, recomputerMacTags)) 67 | isVerified = true; 68 | 69 | return isVerified ; 70 | 71 | } 72 | 73 | 74 | /** 75 | * This method, would be available both on sender and receiver side. This will compute macTag of input message, using same SecretKey on both sides. 76 | * @param content 77 | * @param secretKey 78 | * @return 79 | */ 80 | private static byte[] computeMac(byte[] content, SecretKey secretKey) { 81 | 82 | Mac mac = null; 83 | try { 84 | mac = Mac.getInstance(HMAC_ALGORITHM); 85 | } catch (NoSuchAlgorithmException e) { 86 | System.out.println("No algorithm found for MAC using " + HMAC_ALGORITHM) ; 87 | System.exit(0); 88 | } 89 | try { 90 | mac.init(secretKey); 91 | } catch (InvalidKeyException e) { 92 | System.out.println("Generated key is invalid") ; 93 | System.exit(0); 94 | } 95 | 96 | mac.update(content); 97 | 98 | return mac.doFinal() ; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /crypto_applications/password_management/Authentication.java: -------------------------------------------------------------------------------- 1 | package crypto_usecases.password_management ; 2 | 3 | import java.util.Base64 ; 4 | import java.security.GeneralSecurityException; 5 | import java.util.Arrays; 6 | 7 | public class Authentication { 8 | 9 | static PasswordManagementUtils pwdMgmtUtils = new PasswordManagementUtils() ; 10 | 11 | public static void main(String args[]) { 12 | String attemptedPassword = args[0].trim() ; 13 | 14 | String storedEncryptedPassword = getEncryptedStoredPassword(args) ; 15 | String salt = getUserSalt(args) ; 16 | 17 | 18 | byte[] computePBKDF2AttemptedPassword = null ; 19 | try { 20 | computePBKDF2AttemptedPassword = pwdMgmtUtils.generateEncryptedPassword(attemptedPassword, pwdMgmtUtils.returnByteArray(salt)) ; 21 | } catch(GeneralSecurityException genSecExc) {System.out.println(genSecExc.getMessage() + " " + genSecExc.getCause() ) ; System.exit(1) ; } 22 | 23 | boolean successful_authentication = Arrays.equals(computePBKDF2AttemptedPassword, pwdMgmtUtils.returnByteArray(storedEncryptedPassword)) ; 24 | 25 | System.out.println("User authenticated ? " + successful_authentication); 26 | 27 | } 28 | 29 | 30 | 31 | 32 | // For sake of this example, passing it from command line 33 | // Should be retrieved from database, as stored in PasswordStorage class 34 | private static String getEncryptedStoredPassword(String args[]) { 35 | return args[1].trim() ; 36 | } 37 | 38 | // For sake of this example, passing it from command line 39 | // Should be retrieved from database, as stored in PasswordStorage class. 40 | private static String getUserSalt(String args[]) { 41 | return args[2].trim() ; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /crypto_applications/password_management/PasswordManagementUtils.java: -------------------------------------------------------------------------------- 1 | package crypto_usecases.password_management; 2 | 3 | import java.security.GeneralSecurityException; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.spec.InvalidKeySpecException; 6 | import java.util.Base64; 7 | 8 | import javax.crypto.SecretKeyFactory; 9 | import javax.crypto.spec.PBEKeySpec; 10 | 11 | public class PasswordManagementUtils { 12 | 13 | public String PDKDF_ALGORITHM = "PBKDF2WithHmacSHA512" ; 14 | public int ITERATION_COUNT = 12288 ; 15 | public int SALT_LENGTH = 128 ; 16 | public int DERIVED_KEY_LENGTH = 256 ; 17 | 18 | 19 | protected byte[] generateEncryptedPassword(String enteredPassword, byte[] salt) throws GeneralSecurityException { 20 | // Strings are immutatable, so there is no way to change/nullify/modify its content after use. So always, collect and store security sensitive information in a char array instead. 21 | char[] charEnteredPassword = enteredPassword.toCharArray() ; 22 | 23 | PBEKeySpec keySpec = null ; 24 | 25 | try { 26 | keySpec = new PBEKeySpec(charEnteredPassword, salt, ITERATION_COUNT, DERIVED_KEY_LENGTH * 8 ) ; 27 | } catch(NullPointerException npe) {throw new GeneralSecurityException("Salt " + returnStringRep(salt) + "is null") ;} 28 | catch(IllegalArgumentException iae) {throw new GeneralSecurityException("One of the argument is illegal. Salt " + returnStringRep(salt) + " may be of 0 length, iteration count " + ITERATION_COUNT + " is not positive or derived key length " + DERIVED_KEY_LENGTH + " is not positive." ) ;} 29 | 30 | SecretKeyFactory pbkdfKeyFactory = null ; 31 | 32 | try { 33 | pbkdfKeyFactory = SecretKeyFactory.getInstance(PDKDF_ALGORITHM) ; 34 | } catch(NullPointerException nullPointExc) {throw new GeneralSecurityException("Specified algorithm " + PDKDF_ALGORITHM + "is null") ;} 35 | catch(NoSuchAlgorithmException noSuchAlgoExc) {throw new GeneralSecurityException("Specified algorithm " + PDKDF_ALGORITHM + "is not available by the provider " + pbkdfKeyFactory.getProvider().getName()) ;} 36 | 37 | byte[] pbkdfHashedArray = null ; 38 | try { 39 | pbkdfHashedArray = pbkdfKeyFactory.generateSecret(keySpec).getEncoded() ; 40 | }catch(InvalidKeySpecException invalidKeyExc) {throw new GeneralSecurityException("Specified key specification is inappropriate") ; } 41 | 42 | return pbkdfHashedArray; 43 | } 44 | 45 | protected String returnStringRep(byte[] data) { 46 | return Base64.getEncoder().encodeToString(data) ; 47 | } 48 | 49 | protected byte[] returnByteArray(String data) { 50 | return Base64.getDecoder().decode(data) ; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /crypto_applications/password_management/PasswordStorage.java: -------------------------------------------------------------------------------- 1 | package crypto_usecases.password_management ; 2 | 3 | import java.security.GeneralSecurityException; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.SecureRandom; 6 | import java.security.spec.InvalidKeySpecException; 7 | import java.util.Base64 ; 8 | 9 | import javax.crypto.SecretKeyFactory; 10 | import javax.crypto.spec.PBEKeySpec; 11 | 12 | public class PasswordStorage { 13 | 14 | 15 | public static int SALT_SIZE = 20 ; // This would be in bytes 16 | 17 | static PasswordManagementUtils pwdMgmtUtils = new PasswordManagementUtils() ; 18 | 19 | public static void main(String args[]) { 20 | 21 | String enteredPassword = args[0].trim() ; 22 | 23 | byte[] salt = generateSalt() ; 24 | byte[] saltedStretchedPassword = null ; 25 | try { 26 | saltedStretchedPassword = pwdMgmtUtils.generateEncryptedPassword(enteredPassword , salt) ; 27 | } catch(GeneralSecurityException genSecExc) {System.out.println(genSecExc.getMessage() + " " + genSecExc.getCause() ) ; System.exit(1) ; } 28 | 29 | storeSaltAndEncryptedPassword(saltedStretchedPassword, salt ) ; 30 | } 31 | 32 | 33 | private static byte[] generateSalt() { 34 | SecureRandom secRan = new SecureRandom(); 35 | byte[] ranBytes = new byte[SALT_SIZE]; 36 | secRan.nextBytes(ranBytes); 37 | 38 | return ranBytes; 39 | } 40 | 41 | // Dummy function, which is supposed to store encrypted user password and corresponding salt in database. 42 | // Salt would be unique to each user. It can be non-secret value, so can co-exist with encrypted password. 43 | public static boolean storeSaltAndEncryptedPassword(byte[] encryptedPassword, byte[] salt) { 44 | System.out.println("Password = " + pwdMgmtUtils.returnStringRep(encryptedPassword) + " and corresponding salt = " + pwdMgmtUtils.returnStringRep(salt) + " stored in credentials database "); 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crypto_applications/signature/DigitalSignature.java: -------------------------------------------------------------------------------- 1 | package crypto_applications.signature; 2 | 3 | 4 | import java.io.IOException; 5 | import java.security.*; 6 | import java.util.Base64; 7 | import org.bouncycastle.jce.provider.BouncyCastleProvider; 8 | 9 | /** 10 | * This class shows how to use digital signatures. Ideally, key management systems (KMS, JKS etc), should be used to store and retrieve keys. 11 | * Command Line Argument, pass file name whose content needs to be digitally signed. 12 | */ 13 | public class DigitalSignature { 14 | 15 | private static String KEY_ALGO = "RSA" ; 16 | private static String DIGITAL_KEY_ALGO = "SHA1withRSAandMGF1" ; 17 | private static int DIGITAL_ALGO_KEY_LENGTH = 4096 ; 18 | private static final String PROVIDER = BouncyCastleProvider.PROVIDER_NAME; 19 | 20 | 21 | 22 | 23 | public static void main(String[] args) throws IOException { 24 | String impFileName = args[0] ; 25 | SignatureUtils signatureUtils = new SignatureUtils() ; 26 | 27 | /* 28 | Generate public/private key pair 29 | Ideally, keys should be generated onces separately and stored in key management systems, and retrieved from their directly. 30 | */ 31 | KeyPairGenerator keyPairGen = null; 32 | try { 33 | keyPairGen = KeyPairGenerator.getInstance(KEY_ALGO); 34 | } catch (NoSuchAlgorithmException e) { 35 | System.out.println("Algorithm " + KEY_ALGO + " not available to generate keys") ; 36 | } 37 | keyPairGen.initialize(DIGITAL_ALGO_KEY_LENGTH); 38 | 39 | KeyPair pair = keyPairGen.generateKeyPair() ; 40 | PrivateKey privateKey = pair.getPrivate() ; 41 | PublicKey publicKey = pair.getPublic() ; 42 | 43 | 44 | 45 | // Sign message checksum 46 | byte[] signature = new byte[8192] ; 47 | try { 48 | signature = sign(signatureUtils.calculateChecksum(signatureUtils.readFile(impFileName)) , privateKey); 49 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + DIGITAL_KEY_ALGO + " not supported by any installed provider"); System.exit(0);} 50 | catch(InvalidKeyException ike) {System.out.println("Key Generated is not valid"); System.exit(0);} 51 | catch(SignatureException se) {System.out.println("Error while generating signature"); System.exit(0);} 52 | catch(NoSuchProviderException se) {System.out.println("Cannot find provider " + PROVIDER); System.exit(0);} 53 | 54 | // verify signature 55 | boolean verified = false ; 56 | try { 57 | verified = verify(signatureUtils.calculateChecksum(signatureUtils.readFile(impFileName)), signature, publicKey); 58 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + DIGITAL_KEY_ALGO + " not supported by any installed provider"); System.exit(0);} 59 | catch(InvalidKeyException ike) {System.out.println("Key Generated is not valid"); System.exit(0);} 60 | catch(SignatureException se) {System.out.println("Error while generating signature"); System.exit(0);} 61 | catch(NoSuchProviderException se) {System.out.println("Cannot find provider " + PROVIDER); System.exit(0);} 62 | 63 | System.out.println("File checksum = " + Base64.getEncoder().encodeToString(signatureUtils.calculateChecksum(signatureUtils.readFile(impFileName)))) ; 64 | System.out.println("Signature Verified ? " + verified) ; 65 | } 66 | 67 | /** 68 | * This method will return signature of input content (checksum), using privateKey 69 | * @param checksum 70 | * @param privateKey 71 | * @return 72 | * @throws NoSuchAlgorithmException 73 | * @throws InvalidKeyException 74 | * @throws SignatureException 75 | */ 76 | private static byte[] sign(byte[] checksum, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException,NoSuchProviderException { 77 | Signature sign = Signature.getInstance(DIGITAL_KEY_ALGO,PROVIDER) ; 78 | sign.initSign(privateKey); 79 | sign.update(checksum); 80 | 81 | return sign.sign() ; 82 | } 83 | 84 | /** 85 | * This method will verify if generated signature matches with input signature 86 | * @param checksum 87 | * @param signature 88 | * @param publicKey 89 | * @return 90 | * @throws NoSuchAlgorithmException 91 | * @throws InvalidKeyException 92 | * @throws SignatureException 93 | */ 94 | private static boolean verify(byte[] checksum, byte[] signature, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException,NoSuchProviderException { 95 | Signature verify = Signature.getInstance(DIGITAL_KEY_ALGO,PROVIDER) ; 96 | verify.initVerify(publicKey); 97 | verify.update(checksum); 98 | 99 | return verify.verify(signature) ; 100 | } 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /crypto_applications/signature/SignatureUtils.java: -------------------------------------------------------------------------------- 1 | package crypto_applications.signature; 2 | 3 | 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.security.MessageDigest; 9 | import java.security.NoSuchAlgorithmException; 10 | 11 | 12 | public class SignatureUtils { 13 | private static int FILE_READ_BUFF = 8192 ; 14 | private static String SHA512HASH = "SHA-256" ; 15 | 16 | 17 | 18 | 19 | public byte[] readFile(String fileName) throws IOException{ 20 | 21 | Path filePath = Paths.get(fileName); 22 | byte[] data = Files.readAllBytes(filePath); 23 | 24 | return data ; 25 | } 26 | 27 | public byte[] calculateChecksum(byte[] data) { 28 | MessageDigest digest = null ; 29 | 30 | try { 31 | digest = MessageDigest.getInstance(SHA512HASH) ; // Returns instance of SHA-512 implementation, from the first provider configured in java.security config file. 32 | } catch(NoSuchAlgorithmException nsae) {System.out.println(SHA512HASH + " not available" ); } 33 | 34 | digest.update(data) ; 35 | 36 | byte[] hash = digest.digest(); // once you have all content bundled up, than only apply digesting. 37 | 38 | return hash ; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /message_digest/CalculateChecksum.java: -------------------------------------------------------------------------------- 1 | package message_digest; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | import java.security.MessageDigest ; 9 | import java.security.NoSuchAlgorithmException; 10 | import java.util.Base64; 11 | 12 | public class CalculateChecksum { 13 | 14 | public static String SHA512HASH = "SHA-512" ; 15 | 16 | public static int FILE_READ_BUFF = 8192 ; 17 | 18 | public static void main(String args[]) { 19 | 20 | String fileName = args[0] ; 21 | // Should perform some file validation, like length check, null check etc. 22 | System.out.println(SHA512HASH + " checksum = " + getChecksum(fileName)) ; 23 | } 24 | 25 | // Returns Base64 encoded checksum value of input file. 26 | public static String getChecksum(String fileName) { 27 | MessageDigest digest = null ; 28 | byte[] buffer = new byte[8192] ; // read 8192 bytes at a time 29 | BufferedInputStream bis = null ; 30 | int count ; 31 | 32 | try { 33 | digest = MessageDigest.getInstance(SHA512HASH) ; // Returns instance of SHA-512 implementation, from the first provider configured in java.security config file. 34 | } catch(NoSuchAlgorithmException nsae) {System.out.println(SHA512HASH + " not available" ); } 35 | 36 | try { 37 | bis = new BufferedInputStream(new FileInputStream(fileName)) ; 38 | while((count = bis.read()) > 0) { 39 | digest.update(buffer,0,count) ; // repeated apply update method, till all content of this file is bundled up for digesting 40 | } 41 | } catch(IOException io) {System.out.println(io.getMessage());} 42 | 43 | byte[] hash = digest.digest(); // once u have all content bundled up, than only apply digesting. 44 | 45 | return Base64.getEncoder().encodeToString(hash) ; // to return in a human readable format 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /securerandom/CheckSecureRandomConfig.java: -------------------------------------------------------------------------------- 1 | import java.security.SecureRandom; 2 | import java.security.NoSuchAlgorithmException; 3 | import java.security.Security; 4 | 5 | import javax.crypto.KeyGenerator; 6 | 7 | import java.util.Base64 ; 8 | 9 | /* 10 | This class is observing, effect of below different parameters in different combinations. 11 | 12 | 1. algorithm choosen: System defaults, SHA1PRNG and Windows-PRNG. Didn't play around with NativePRNGBlocking and NonBlocking variety, as they are variant of NativePRNG (default on Unix like). 13 | 2. Between Unix like systems and Windows Operating Systems 14 | 3. Configuration of securerandom.source value in java.security file 15 | 4. Initial self-seeded or explicit sedded 16 | 17 | Run below program a few times, and observe Randomizer bytes and Base64 value of Symmetric Key. If SecureRandom is insecure, output would be predictable across different run. 18 | 19 | Conclusion: 20 | 21 | SHA1PRNG algorithm, when explicitly seeded, pseudo-random output generated would be directly proportional to the entropy source provided. We always want entropy source to be provided by underlying OS. 22 | Thus, for Unix/Linux: default implementation selected would be NativePRNG and allow it to be self seeded. However, for windows default implementation selected would be SHA1PRNG, which with explicit seeding might reduce entropy. Thus, always choose an algorithm when running on Windows. 23 | 24 | Unfortunately, explicitly selecting a windows specific algorithm on windows and letting JDK choose algorithm for Unix like systems, makes it less portable across Unix like systems and Windows. But beter safe than sorry. 25 | 26 | Most secure and portable way of using SecureRandom in Unix like OS is: 27 | 28 | SecureRandom secRan = new SecureRandom() ; 29 | byte[] b = new byte[NO_OF_RANDOM_BYTES] ; 30 | secRan.nextBytes(b); 31 | 32 | In Windows: 33 | 34 | secRan = SecureRandom.getInstance("Windows-PRNG") ; 35 | byte[] b = new byte[NO_OF_RANDOM_BYTES] ; 36 | secRan.nextBytes(b); 37 | 38 | */ 39 | public class CheckSecureRandomConfig { 40 | 41 | public static final int NO_OF_RANDOM_BYTES = 20 ; 42 | public static final int KEY_SIZE = 256 ; 43 | public static void main( String args[] ) { 44 | 45 | SecureRandom secRan = null ; 46 | 47 | /* 48 | 1. SecureRandom Configuration: 49 | - Default provider 50 | - Default implementation 51 | - Default securerandom.source property 52 | - self-seeding 53 | 54 | Observations: 55 | - On Unix like systems: Produces cryptographically secure random pseudo-data. Most prefered option. 56 | - Provider: SUN 57 | - Algorithm: NativePRNG 58 | - securerandom.source: file:/dev/random 59 | - seeding: self-seeding 60 | - On Windows systems: Produces cryptographically secure random pseudo-data. Not the most prefered option, since it defaults to SHA1PRNG. 61 | - Provider: SUN 62 | - Algorithm: SHA1PRNG 63 | - securerandom.source: file:/dev/random 64 | - seeding: self-seeding 65 | 66 | */ 67 | try { 68 | secRan = new SecureRandom() ; // SecureRandom default constructor will always use default provider and algorithm. 69 | printRandomnessParameters(secRan, "1. Using default algorithm, securerandom.source and self-seeding " ); 70 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 71 | 72 | /* 73 | 2. SecureRandom Configuration: 74 | - Default provider 75 | - Default implementation 76 | - Default securerandom.source property 77 | - explicit-seeding 78 | 79 | Observations: 80 | - On Unix like systems: Produces cryptographically secure random pseudo-data. 81 | - Provider: SUN 82 | - Algorithm: NativePRNG 83 | - securerandom.source: file:/dev/random 84 | - seeding: explicit seeding 85 | - On Windows systems: DANGEROUS. SHA1PRNG algorithm is directly seeded with user supplied source of entropy. This makes output directly proportional to source of randomness. 86 | - Provider: SUN 87 | - Algorithm: SHA1PRNG 88 | - securerandom.source: file:/dev/random 89 | - seeding: explicit seeding 90 | 91 | */ 92 | try { 93 | secRan = new SecureRandom() ; 94 | secRan.setSeed(12345); // To see effects of using a low entropy source on pseudo random data generated and Key Generation, used such a static value. 95 | printRandomnessParameters(secRan, "2. Using default algorithm, securerandom.source and explicit seeding " ); 96 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 97 | 98 | /* 99 | 3. SecureRandom Configuration: 100 | - Default provider 101 | - Algorithm: SHA1PRNG 102 | - Default securerandom.source property: file:/dev/random 103 | - self-seeding 104 | 105 | Observations: 106 | - On Unix like systems: Produces cryptographically secure random pseudo-data. SHA1PRNG is seeded using file:/dev/random 107 | - Provider: SUN 108 | - Algorithm: SHA1PRNG 109 | - securerandom.source: file:/dev/random 110 | - seeding: self-seeding 111 | - On Windows systems: Produces cryptographically secure random pseudo-data. SHA1PRNG is seeded using file:/dev/random 112 | - Provider: SUN 113 | - Algorithm: SHA1PRNG 114 | - securerandom.source: file:/dev/random 115 | - seeding: self-seeding 116 | 117 | */ 118 | try { 119 | secRan = SecureRandom.getInstance("SHA1PRNG") ; 120 | printRandomnessParameters(secRan, "3. Using SHA1PRNG algorithm, default value of securerandom.source and self-seeding " ); 121 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 122 | 123 | /* 124 | 4. SecureRandom Configuration: 125 | - Default provider 126 | - Default implementation: SHA1PRNG 127 | - Default securerandom.source property: file:/dev/random 128 | - seeding: explicit 129 | 130 | Observations: 131 | - On Unix like systems: DANGEROUS. SHA1PRNG implementation is directly seeded with the explicitly configured source of randomness. This makes output directly proportional to source of randomness. 132 | - Provider: SUN 133 | - Algorithm: SHA1PRNG 134 | - securerandom.source: file:/dev/random 135 | - seeding: explicit 136 | - On Windows systems: DANGEROUS. SHA1PRNG implementation is directly seeded with the explicitly configured source of randomness. This makes output directly proportional to source of randomness. 137 | - Provider: SUN 138 | - Algorithm: SHA1PRNG 139 | - securerandom.source: file:/dev/random 140 | - seeding: explicit 141 | 142 | 143 | 144 | */ 145 | try { 146 | secRan = SecureRandom.getInstance("SHA1PRNG") ; 147 | secRan.setSeed(12345) ; 148 | printRandomnessParameters(secRan, "4. Using SHA1PRNG algorithm, default value of securerandom.source and explicit seeding " ); 149 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 150 | 151 | /* 152 | 5. SecureRandom Configuration: 153 | - Default provider 154 | - Default implementation: SHA1PRNG 155 | - Changed securerandom.source property: file://something-other-than-dev-random 156 | - self-seeding 157 | 158 | Observations: 159 | - On Unix like systems: Produces cryptographically secure random pseudo-data. 160 | - Provider: SUN 161 | - Algorithm: SHA1PRNG 162 | - securerandom.source: file://something-other-than-dev-random 163 | - seeding: self-seeding 164 | - On Windows systems: Produces cryptographically secure random pseudo-data. 165 | - Provider: SUN 166 | - Algorithm: SHA1PRNG 167 | - securerandom.source: file://something-other-than-dev-random 168 | - seeding: self-seeding 169 | 170 | */ 171 | try { 172 | secRan = SecureRandom.getInstance("SHA1PRNG") ; 173 | Security.setProperty("securerandom.source", "file:/something-other-than-dev-random"); 174 | printRandomnessParameters(secRan, "5. Using SHA1PRNG algorithm, changing securerandom.source value and self-seeding " ); 175 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 176 | 177 | /* 178 | 6. SecureRandom Configuration: 179 | - Default provider 180 | - Default implementation: SHA1PRNG 181 | - Default securerandom.source property: file:/something-other-than-dev-random 182 | - seeding: explicit 183 | 184 | Observations: 185 | - On Unix like systems: DANGEROUS. SHA1PRNG implementation is directly seeded with the explicitly configured source of randomness. This makes output directly proportional to source of randomness. 186 | - Provider: SUN 187 | - Algorithm: SHA1PRNG 188 | - securerandom.source: file:/something-other-than-dev-random 189 | - seeding: explicit 190 | - On Windows systems: DANGEROUS. SHA1PRNG implementation is directly seeded with the explicitly configured source of randomness. This makes output directly proportional to source of randomness. 191 | - Provider: SUN 192 | - Algorithm: SHA1PRNG 193 | - securerandom.source: file:/something-other-than-dev-random 194 | - seeding: explicit 195 | */ 196 | try { 197 | secRan = SecureRandom.getInstance("SHA1PRNG") ; 198 | secRan.setSeed(12345) ; 199 | printRandomnessParameters(secRan, "6. Using SHA1PRNG algorithm, changing securerandom.source value and explicit seeding " ); 200 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 201 | 202 | /* 203 | 7. SecureRandom Configuration: 204 | - Default provider 205 | - Default implementation 206 | - securerandom.source property: file:/something-other-than-dev-random 207 | - seeding: self 208 | 209 | Observations: 210 | - On Unix like systems: Produces cryptographically secure random pseudo-data. 211 | - Provider: SUN 212 | - Algorithm: NativePRNG 213 | - securerandom.source: file:/something-other-than-dev-random 214 | - seeding: self 215 | - On Windows systems: Produces cryptographically secure random pseudo-data. 216 | - Provider: SUN 217 | - Algorithm: SHA1PRNG 218 | - securerandom.source: file:/something-other-than-dev-random 219 | - seeding: self 220 | 221 | */ 222 | try { 223 | secRan = new SecureRandom() ; 224 | printRandomnessParameters(secRan, "7. Using default algorithm, changing securerandom.source value and self-seeding " ); 225 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 226 | 227 | /* 228 | 8. SecureRandom Configuration: 229 | - Default provider 230 | - Default implementation 231 | - securerandom.source property: file:/something-other-than-dev-random 232 | - self-seeding 233 | 234 | Observations: 235 | - On Unix like systems: Produces cryptographically secure random pseudo-data. 236 | - Provider: SUN 237 | - Algorithm: NativePRNG 238 | - securerandom.source: file:/something-other-than-dev-random 239 | - seeding: explicit 240 | - On Windows systems: DANGEROUS. SHA1PRNG implementation is directly seeded with the explicitly configured source of randomness. This makes output directly proportional to source of randomness. 241 | - Provider: SUN 242 | - Algorithm: SHA1PRNG 243 | - securerandom.source: file:/something-other-than-dev-random 244 | - seeding: explicit 245 | 246 | */ 247 | try { 248 | secRan = new SecureRandom() ; 249 | secRan.setSeed(12345) ; 250 | printRandomnessParameters(secRan, "8. Using default algorithm, changing securerandom.source value and explicit-seeding " ); 251 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + secRan.getAlgorithm() + " is not available on this system") ;} 252 | 253 | /* 9. SecureRandom Configuration: 254 | - Default provider 255 | - implementation: Windows-PRNG 256 | - securerandom.source property: file:/something-other-than-dev-random 257 | - self-seeding 258 | 259 | Observations: 260 | - On Unix like systems: Throws NoSuchAlgorithmException 261 | 262 | - On Windows systems: Produces cryptographically secure random pseudo-data. 263 | - Provider: SunMSCAPI 264 | - Algorithm: Windows-PRNG 265 | - securerandom.source: file:/something-other-than-dev-random 266 | - seeding: self 267 | 268 | 269 | */ 270 | try { 271 | secRan = SecureRandom.getInstance("Windows-PRNG") ; 272 | printRandomnessParameters(secRan, "9. Using Windows-PRNG algorithm, changing securerandom.source value and self-seeding " ); 273 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + "Windows-PRNG" + " is not available on this system") ;} 274 | 275 | 276 | /* 10. SecureRandom Configuration: 277 | - Default provider 278 | - implementation: Windows-PRNG 279 | - securerandom.source property: file:/something-other-than-dev-random 280 | - self-seeding 281 | 282 | Observations: 283 | - On Unix like systems: Throws NoSuchAlgorithmException 284 | 285 | - On Windows systems: Produces cryptographically secure random pseudo-data. 286 | - Provider: SunMSCAPI 287 | - Algorithm: Windows-PRNG 288 | - securerandom.source: file:/something-other-than-dev-random 289 | - seeding: explicit 290 | 291 | 292 | */ 293 | try { 294 | secRan = SecureRandom.getInstance("Windows-PRNG") ; 295 | secRan.setSeed(12345); 296 | printRandomnessParameters(secRan, "10. Using Windows-PRNG algorithm, changing securerandom.source value and explicit seeding " ); 297 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + "Windows-PRNG" + " is not available on this system") ;} 298 | 299 | /* 11. SecureRandom Configuration: 300 | - Default provider 301 | - implementation: Windows-PRNG 302 | - Default securerandom.source property: file:/dev/random 303 | - self-seeding 304 | 305 | Observations: 306 | - On Unix like systems: Throws NoSuchAlgorithmException 307 | 308 | - On Windows systems: Produces cryptographically secure random pseudo-data. 309 | - Provider: SunMSCAPI 310 | - Algorithm: Windows-PRNG 311 | - securerandom.source: file:/dev/random 312 | - seeding: self 313 | 314 | 315 | */ 316 | try { 317 | secRan = SecureRandom.getInstance("Windows-PRNG") ; 318 | Security.setProperty("securerandom.source", "file:/dev/random"); 319 | printRandomnessParameters(secRan, "11. Using Windows-PRNG algorithm, default securerandom.source value and self-seeding " ); 320 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + "Windows-PRNG" + " is not available on this system") ;} 321 | 322 | /* 323 | 12. SecureRandom Configuration: 324 | - Default provider 325 | - implementation: Windows-PRNG 326 | - Default securerandom.source property: file:/dev/random 327 | - seeding: explicit 328 | 329 | Observations: 330 | - On Unix like systems: Throws NoSuchAlgorithmException 331 | 332 | - On Windows systems: Produces cryptographically secure random pseudo-data. 333 | - Provider: SunMSCAPI 334 | - Algorithm: Windows-PRNG 335 | - securerandom.source: file:/dev/random 336 | - seeding: explicit 337 | 338 | */ 339 | try { 340 | secRan = SecureRandom.getInstance("Windows-PRNG") ; 341 | secRan.setSeed(12345) ; 342 | printRandomnessParameters(secRan, "12. Using Windows-PRNG algorithm, default securerandom.source value and explicit seeding " ); 343 | } catch(NoSuchAlgorithmException nsae) {System.out.println("Algorithm " + "Windows-PRNG" + " is not available on this system") ;} 344 | } 345 | 346 | /* 347 | This method, prints the value of various parameters used like provider, CSPRNG algorithm, randomness source. It also prints effect of using secRan on a Symmetric Key to see if its truly random. 348 | */ 349 | protected static void printRandomnessParameters(SecureRandom secRan, String prefixMessage) throws NoSuchAlgorithmException { 350 | System.out.println(prefixMessage + " : " + "SecureRandom() Provider : " + secRan.getProvider().getName() + " Algorithm " + secRan.getAlgorithm() + " randomness source " + Security.getProperty("securerandom.source")); 351 | 352 | byte[] b = new byte[NO_OF_RANDOM_BYTES]; 353 | secRan.nextBytes(b); 354 | 355 | System.out.println("Randomizer bytes = " + Base64.getEncoder().encodeToString(b) ) ; 356 | 357 | KeyGenerator symmKeyGen = KeyGenerator.getInstance("AES") ; 358 | symmKeyGen.init(KEY_SIZE,secRan) ; 359 | 360 | System.out.println("Key generated = " + Base64.getEncoder().encodeToString(symmKeyGen.generateKey().getEncoded())) ; 361 | 362 | System.out.println("=========================="); 363 | 364 | } 365 | } 366 | --------------------------------------------------------------------------------