public static String SCryptHash(String p, int cost, int BSize, int par, int len, int s) throws NoSuchAlgorithmException { String salt = ""; if (s==1) { salt = KeyGenerators.string().generateKey(); } else { salt = "0621f185e1ba732d"; } byte[] resBytes = SCrypt.generate(p.getBytes(), salt.getBytes(), cost, BSize, par, len);; String res = new String(Hex.encodeHex(resBytes)); return res; }
/** * Encrypt this key with AES/CBC/PKCS5Padding. Useful if you decide to store it. * * @param passphrase - passphrase * @param production - determines the Base58 serialization that will then be encrypted. * @return ciphertext * @throws HyperLedgerException for any error in the used libraries */ public byte[] encrypt(String passphrase, boolean production) throws HyperLedgerException { try { byte[] key = SCrypt.generate(passphrase.getBytes("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keyspec); byte[] iv = cipher.getIV(); byte[] c = cipher.doFinal(serialize(production).getBytes()); byte[] result = new byte[iv.length + c.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(c, 0, result, iv.length, c.length); return result; } catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new HyperLedgerException(e); } }
/** * Encrypt this key with AES/CBC/PKCS5Padding. Useful if you decide to store it. * * @param passphrase - passphrase * @param production - determines the Base58 serialization that will then be encrypted. * @return cipher text * @throws HyperLedgerException for any error in the used libraries */ public byte[] encrypt(String passphrase, boolean production) throws HyperLedgerException { try { byte[] key = SCrypt.generate(passphrase.getBytes("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keyspec); byte[] iv = cipher.getIV(); byte[] c = cipher.doFinal(serialize(production).getBytes()); byte[] result = new byte[iv.length + c.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(c, 0, result, iv.length, c.length); return result; } catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new HyperLedgerException(e); } }
/** * sets the password * * This method sets the password of the user. The password is hashed with * SCrypt. The hashed password will be stored with the salt in the format of * the {@link PasswordFile} in the password file. A successful invocation of * the method prepares the authenticator for * {@link SCryptAuthManager#verify(String)} and * {@link SCryptAuthManager#getPassword()}. * * @param pass * the password to set * * @throws FailToStoreCredentialException * if cannot write the generated hash to password file */ @Override public synchronized void setPassword(String pass) { byte[] salt = new byte[8]; rand.nextBytes(salt); byte[] crypt = SCrypt.generate(pass.getBytes(StandardCharsets.UTF_16), salt, 262144, 10, 3, 256); passCont = new PasswordFile(crypt, salt); try { passwdFile.write(passCont.toString(), StandardCharsets.US_ASCII); } catch (IOException e) { FailToStoreCredentialException fs = new FailToStoreCredentialException( "Cannot store password to passwd file:" + e.getMessage()); fs.initCause(e); passCont = null; throw new RuntimeException(fs); } this.password = pass; }
/** * Hash function with SHA256 applied on the input. * * @param input * @param salt * @param size size of the output * @param n_bc work load for bcrypt - for now not used * @param n_sha number of sha256 applications * @return */ private byte[] hashFunction(byte[] input, byte[] salt, int size, int sc_N, int sc_r, int sc_p, int n_sha) { int i; byte[] tmpInput = new byte[input.length]; System.arraycopy(input, 0, tmpInput, 0, input.length); for(i = 0; i < n_sha; i++) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(tmpInput); tmpInput = md.digest(); } catch(Exception e) { //NoSuchAlgorithmException System.out.println("Problem with SHA256 in hashFunction (used in hashChain)."); } } return SCrypt.generate(tmpInput, salt, sc_N, sc_r, sc_p, size); }
public byte[] encrypt (String passphrase, boolean production) throws ValidationException { try { byte[] key = SCrypt.generate (passphrase.getBytes ("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec (key, "AES"); Cipher cipher = Cipher.getInstance ("AES/CBC/PKCS5Padding", "BC"); cipher.init (Cipher.ENCRYPT_MODE, keyspec); byte[] iv = cipher.getIV (); byte[] c = cipher.doFinal (serialize (production).getBytes ()); byte[] result = new byte[iv.length + c.length]; System.arraycopy (iv, 0, result, 0, iv.length); System.arraycopy (c, 0, result, iv.length, c.length); return result; } catch ( UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e ) { throw new ValidationException (e); } }
/** * Create a MasterPrivateKey from a seed, that is assumed to be encrypted. In practice often simply random. * * @param passphrase - passphrase for decryption * @param encryptedSeed the seed * @return (re-)created MasterPrivateKey * @throws HyperLedgerException for any error in used libraries */ public static MasterPrivateKey createFromEncryptedSeed(String passphrase, byte[] encryptedSeed) throws HyperLedgerException { try { byte[] key = SCrypt.generate(passphrase.getBytes("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); if (encryptedSeed.length != 32) { throw new HyperLedgerException("Incorrect encrypted seed length"); } Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); cipher.init(Cipher.DECRYPT_MODE, keyspec); return create(cipher.doFinal(encryptedSeed)); } catch (UnsupportedEncodingException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { throw new HyperLedgerException(e); } }
/** * Re-create a MasterPrivateKey from encrypted serialization * * @param passphrase passphrase * @param encrypted cipher text from encrypt * @return * @throws HyperLedgerException error in used libraries or wrong format */ public static MasterPrivateKey decrypt(String passphrase, byte[] encrypted) throws HyperLedgerException { try { byte[] key = SCrypt.generate(passphrase.getBytes("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC"); byte[] iv = Arrays.copyOfRange(encrypted, 0, 16); byte[] data = Arrays.copyOfRange(encrypted, 16, encrypted.length); cipher.init(Cipher.DECRYPT_MODE, keyspec, new IvParameterSpec(iv)); return MasterPrivateKey.parse(new String(cipher.doFinal(data))); } catch (UnsupportedEncodingException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { throw new HyperLedgerException(e); } }
/** * Re-create a MasterPublicKey from encrypted serialization. * * @param passphrase - passphrase * @param encrypted - the cipher text returned by encrypt * @return * @throws HyperLedgerException error in used libraries or wrong format */ public static MasterPublicKey decrypt(String passphrase, byte[] encrypted) throws HyperLedgerException { try { byte[] key = SCrypt.generate(passphrase.getBytes("UTF-8"), BITCOIN_SEED, 16384, 8, 8, 32); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC"); byte[] iv = Arrays.copyOfRange(encrypted, 0, 16); byte[] data = Arrays.copyOfRange(encrypted, 16, encrypted.length); cipher.init(Cipher.DECRYPT_MODE, keyspec, new IvParameterSpec(iv)); return MasterPublicKey.parse(new String(cipher.doFinal(data))); } catch (UnsupportedEncodingException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { throw new HyperLedgerException(e); } }
private byte[] generateHash(String password, byte[] salt) { try { byte[] pw = password.getBytes("UTF-8"); return SCrypt.generate(pw, salt, SCRYPT_N, SCRYPT_R, SCRYPT_P, HASH_BYTES); } catch (UnsupportedEncodingException e) { // UTF-8 must be supported throw new RuntimeException("UTF-8 not supported.", e); } }
@Override public Inventory readInventoryFromBytes(byte[] source, UserSecurityProvider usp) throws BaseBunkrException { try { // generate the encryption key and iv using scrypt byte[] data = SCrypt.generate( usp.getHashedPassword(), this.scryptSalt, this.scryptN, this.scryptR, this.scryptP, this.encryptionAlgorithm.keyByteLength + this.encryptionAlgorithm.ivByteLength ); // pull key and iv out of the data byte[] key = Arrays.copyOfRange(data, 0, this.encryptionAlgorithm.keyByteLength); byte[] iv = Arrays.copyOfRange(data, this.encryptionAlgorithm.keyByteLength, data.length); byte[] decryptedInv = SimpleBlockCipher.decrypt(this.encryptionAlgorithm, source, key, iv); Arrays.fill(data, (byte) 0); Arrays.fill(key, (byte) 0); Arrays.fill(iv, (byte) 0); return InventoryJSON.decode(new String(decryptedInv)); } catch (CryptoException e) { throw new BaseBunkrException(e); } }
@Override public byte[] writeInventoryToBytes(Inventory source, UserSecurityProvider usp) throws BaseBunkrException { try { byte[] inventoryJsonBytes = InventoryJSON.encode(source).getBytes(); // first refresh the salt RandomMaker.fill(this.scryptSalt); if (this.encryptionAlgorithm == Encryption.NONE) throw new IllegalArgumentException("ScryptDescriptor requires an active encryption mode"); // generate the encryption key and iv using scrypt byte[] data = SCrypt.generate( usp.getHashedPassword(), this.scryptSalt, this.scryptN, this.scryptR, this.scryptP, this.encryptionAlgorithm.keyByteLength + this.encryptionAlgorithm.ivByteLength ); // pull key and iv out of the data byte[] key = Arrays.copyOfRange(data, 0, this.encryptionAlgorithm.keyByteLength); byte[] iv = Arrays.copyOfRange(data, this.encryptionAlgorithm.keyByteLength, data.length); byte[] encryptedInv = SimpleBlockCipher.encrypt(this.encryptionAlgorithm, inventoryJsonBytes, key, iv); Arrays.fill(inventoryJsonBytes, (byte) 0); Arrays.fill(data, (byte) 0); Arrays.fill(key, (byte) 0); Arrays.fill(iv, (byte) 0); return encryptedInv; } catch (IllegalPasswordException | CryptoException e) { throw new BaseBunkrException(e); } }
@Override public byte[] deriveKey(byte[] pswMaterial) { /* System.out.println("=== ScryptKDF deriveKey:"); System.out.println("memoryFactor: " + memoryFactor + ", cpuFactor: " + cPUFactor + ", parallelFactor: " + parallelFactor); Help.printBytes("Salt", KeyDerivation.getSalt()); Help.printBytes("pswMaterial", pswMaterial); */ if (KeyDerivation.getSalt().length < 16) { System.err.println("Warning: Scrypt: short salt."); } if(KeyDerivation.getSalt().length < 8) { System.err.println("Srypt: salt too short"); throw new IllegalArgumentException("Scrypt - invalid salt size"); } //long start = System.currentTimeMillis(); // Startpunkt byte[] keyMaterial = null; try { keyMaterial = SCrypt.generate(pswMaterial, KeyDerivation.getSalt(), cPUFactor, memoryFactor, parallelFactor, 64); } catch (Exception e) { System.err.println("ScryptKDF Exception."); e.printStackTrace(); } //System.out.println("Scrypt: " + cPUFactor + " iterations, " + memoryFactor + " memory factor" ); printInfos(true); keyMaterial = adjustKeyMaterial(keyMaterial); //Help.printBytes("keyMaterial", keyMaterial); return keyMaterial; }
private static byte[] generateDerivedScryptKey( byte[] password, byte[] salt, int n, int r, int p, int dkLen) throws CipherException { return SCrypt.generate(password, salt, n, r, p, dkLen); }
/** * Encrypts payload byte array with a key derived from the supplied password. * Returns the byte array formatted according to the specification. */ public final byte[] encrypt(byte[] payload, OpaqueChars pass, SecureRandom random) throws Exception { int n = SCRYPT_N; int r = SCRYPT_R; int p = SCRYPT_P; ByteArrayOutputStream out = new ByteArrayOutputStream(); try { // header DataTools.writeLong(out, SIGNATURE_V2); DataTools.writeInt(out, n); DataTools.writeInt(out, r); DataTools.writeInt(out, p); // the same nonce is being used for both scrypt and EAX encryption byte[] nonce = new byte[NONCE_SIZE_BYTES]; random.nextBytes(nonce); out.write(nonce); byte[] pw = null; byte[] salt = nonce; // reuse nonce as salt try { // generate key with scrypt // P - passphrase // S - salt // N - cpu/memory cost // r - block mix size parameter // p - parallelization parameter pw = pass.getBytes(); byte[] key = SCrypt.generate(pw, salt, n, r, p, KEY_SIZE_BYTES); try { EAXEncryptStream es = new EAXEncryptStream(key, nonce, null, out); try { DataTools.writeInt(es, payload.length); es.write(payload); } finally { CKit.close(es); } } finally { Crypto.zero(key); } } finally { Crypto.zero(pw); } } finally { CKit.close(out); } return out.toByteArray(); }
/** * Attempts to decrypt the supplied byte array using the specified passphrase. * Returns the decrypted data or throws an exception. */ public final byte[] decrypt(byte[] encrypted, OpaqueChars pass) throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(encrypted); try { // header long ver = DataTools.readLong(in); if(ver != SIGNATURE_V2) { throw new Exception(ERROR_WRONG_SIGNATURE); } int n = DataTools.readInt(in); DataTools.check(n, 1, Integer.MAX_VALUE, ERROR_INVALID_FORMAT); int r = DataTools.readInt(in); DataTools.check(r, 1, Integer.MAX_VALUE, ERROR_INVALID_FORMAT); int p = DataTools.readInt(in); DataTools.check(p, 1, Integer.MAX_VALUE, ERROR_INVALID_FORMAT); byte[] nonce = new byte[NONCE_SIZE_BYTES]; CKit.readFully(in, nonce); byte[] pw = null; byte[] salt = nonce; // reuse nonce as salt try { // generate key with scrypt // P - passphrase // S - salt // N - cpu/memory cost // r - block mix size parameter // p - parallelization parameter pw = pass.getBytes(); byte[] key = SCrypt.generate(pw, salt, n, r, p, KEY_SIZE_BYTES); try { EAXDecryptStream ds = new EAXDecryptStream(key, nonce, null, in); try { int len = DataTools.readInt(ds); DataTools.check(len, 0, Integer.MAX_VALUE, ERROR_INVALID_FORMAT); byte[] decrypted = new byte[len]; CKit.readFully(ds, decrypted); return decrypted; } finally { CKit.close(ds); } } finally { Crypto.zero(key); } } finally { Crypto.zero(pw); } } finally { CKit.close(in); } }
private static String hash(String str, byte[] salt) { byte[] dk = SCrypt.generate(str.getBytes(UTF_8), salt, COST, 8, 8, KEY_LENGTH); return Base64.encodeBase64String(dk); }
public void performTest() throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader( getClass().getResourceAsStream("SCryptTestVectors.txt"))); int count = 0; String line = br.readLine(); while (line != null) { ++count; String header = line; StringBuffer data = new StringBuffer(); while (!isEndData(line = br.readLine())) { for (int i = 0; i != line.length(); i++) { if (line.charAt(i) != ' ') { data.append(line.charAt(i)); } } } int start = header.indexOf('(') + 1; int limit = header.lastIndexOf(')'); String argStr = header.substring(start, limit); String[] args = Strings.split(argStr, ','); byte[] P = extractQuotedString(args[0]); byte[] S = extractQuotedString(args[1]); int N = extractInteger(args[2]); int r = extractInteger(args[3]); int p = extractInteger(args[4]); int dkLen = extractInteger(args[5]); byte[] expected = Hex.decode(data.toString()); // This skips very expensive test case(s), remove check to re-enable if (N <= 16384) { byte[] result = SCrypt.generate(P, S, N, r, p, dkLen); if (!areEqual(expected, result)) { fail("Result does not match expected value in test case " + count); } } } br.close(); }
/** * verifies a password * * This method verifies if a given password is the valid password. This must * be called after a {@link SCryptAuthManager#load()} with valid non empty * password file or a {@link SCryptAuthManager#setPassword(String)} is * called. If the given password is valid, the plain text password will be * stored and ready to be accessed via the * {@link SCryptAuthManager#getPassword()}. * * @param pass * the password to verify * @return true if valid, false otherwise * * @throws NullPointerException * if hashed password not in buffer */ @Override public synchronized boolean verify(String pass) { byte[] crypt = SCrypt.generate(pass.getBytes(StandardCharsets.UTF_16), passCont.getSalt(), 262144, 10, 3, 256); boolean match = Arrays.equals(crypt, passCont.getCredentialInfo()); if (match) { this.password = pass; } return match; }