public static SaltedSecretKey createMasterKey(String password, byte[] salt) throws CipherException { try { logger.log(Level.FINE, "- Creating secret key using {0} with {1} rounds, key size {2} bit ...", new Object[] { MASTER_KEY_DERIVATION_FUNCTION, MASTER_KEY_DERIVATION_ROUNDS, MASTER_KEY_SIZE }); SecretKeyFactory factory = SecretKeyFactory.getInstance(MASTER_KEY_DERIVATION_FUNCTION); KeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, MASTER_KEY_DERIVATION_ROUNDS, MASTER_KEY_SIZE); SecretKey masterKey = factory.generateSecret(pbeKeySpec); return new SaltedSecretKey(masterKey, salt); } catch (Exception e) { throw new CipherException(e); } }
@Override public String toString() { return "[secretKey={algorithm=" + getAlgorithm() + ", format=" + getFormat() + ", encoded=" + StringUtil.toHex(getEncoded()) + "}, salt=" + StringUtil.toHex(getSalt()) + "]"; }
public void write(OutputNode node, SaltedSecretKey saltedSecretKey) { node.setAttribute("salt", StringUtil.toHex(saltedSecretKey.getSalt())); node.setAttribute("key", StringUtil.toHex(saltedSecretKey.getEncoded())); } }
secretKeyCacheEntry.increaseUseCount(); logger.log(Level.FINE, "- Using CACHED WRITE secret key " + secretKeyCacheEntry.getSaltedSecretKey().getAlgorithm() + ", with salt " + StringUtil.toHex(secretKeyCacheEntry.getSaltedSecretKey().getSalt())); return secretKeyCacheEntry.getSaltedSecretKey(); secretKeyWriteCache.put(cipherSpec, secretKeyCacheEntry); logger.log(Level.FINE, "- Created NEW WRITE secret key " + secretKeyCacheEntry.getSaltedSecretKey().getAlgorithm() + ", and added to cache, with salt " + StringUtil.toHex(saltedSecretKey.getSalt())); return saltedSecretKey;
public String createEncryptedLink(SaltedSecretKey masterKey) throws Exception { byte[] plaintextStorageXml = getPlaintextStorageXml(); List<CipherSpec> cipherSpecs = CipherSpecs.getDefaultCipherSpecs(); // TODO [low] Shouldn't this be the same as the application?! byte[] masterKeySalt = masterKey.getSalt(); byte[] encryptedPluginBytes = CipherUtil.encrypt(new ByteArrayInputStream(plaintextStorageXml), cipherSpecs, masterKey); String masterKeySaltEncodedStr = Base58.encode(masterKeySalt); String encryptedEncodedPlugin = Base58.encode(encryptedPluginBytes); String applicationLink = String.format(LINK_FORMAT_ENCRYPTED, masterKeySaltEncodedStr, encryptedEncodedPlugin); if (shortUrl) { return shortenLink(applicationLink); } else { return applicationLink; } }
logger.log(Level.FINE, "- Using CACHED READ secret key " + secretKeyCacheEntry.getSaltedSecretKey().getAlgorithm() + ", with salt " + StringUtil.toHex(salt)); return secretKeyCacheEntry.getSaltedSecretKey(); logger.log(Level.FINE, "- Created NEW READ secret key " + secretKeyCacheEntry.getSaltedSecretKey().getAlgorithm() + ", and added to cache, with salt " + StringUtil.toHex(salt)); return saltedSecretKey;
@Test public void testCreateMasterKeyNoSalt() throws CipherException { SaltedSecretKey masterKeyForPasswordTestNoSalt1 = CipherUtil.createMasterKey("Test"); SaltedSecretKey masterKeyForPasswordTestNoSalt2 = CipherUtil.createMasterKey("Test"); logger.log(Level.INFO, "Key comparison for password 'Test':"); logger.log(Level.INFO, "- Master key 1: "+StringUtil.toHex(masterKeyForPasswordTestNoSalt1.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(masterKeyForPasswordTestNoSalt1.getSalt())); logger.log(Level.INFO, "- Master key 2: "+StringUtil.toHex(masterKeyForPasswordTestNoSalt2.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(masterKeyForPasswordTestNoSalt2.getSalt())); assertFalse(Arrays.equals(masterKeyForPasswordTestNoSalt1.getSalt(), masterKeyForPasswordTestNoSalt2.getSalt())); assertFalse(Arrays.equals(masterKeyForPasswordTestNoSalt1.getEncoded(), masterKeyForPasswordTestNoSalt2.getEncoded())); } }
new MasterTO(configTO.getMasterKey().getSalt()).save(masterFile);
@Test public void testCreateMasterKeyWithSalt() throws CipherException { long timeStart = System.currentTimeMillis(); SaltedSecretKey masterKeyForPasswordTestAndSalt123 = CipherUtil.createMasterKey("Test", new byte[] { 1, 2, 3 }); long timeEnd = System.currentTimeMillis(); long timeDuration = timeEnd - timeStart; logger.log(Level.INFO, "Creating master key took "+timeDuration+"ms:"); logger.log(Level.INFO, " - Key: "+StringUtil.toHex(masterKeyForPasswordTestAndSalt123.getEncoded())); logger.log(Level.INFO, " - Salt: "+StringUtil.toHex(masterKeyForPasswordTestAndSalt123.getSalt())); assertEquals("010203", StringUtil.toHex(masterKeyForPasswordTestAndSalt123.getSalt())); assertEquals("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0", StringUtil.toHex(masterKeyForPasswordTestAndSalt123.getEncoded())); assertEquals(CipherParams.MASTER_KEY_SIZE/8, masterKeyForPasswordTestAndSalt123.getEncoded().length); assertEquals("PBKDF2WithHmacSHA1", masterKeyForPasswordTestAndSalt123.getAlgorithm()); assertEquals("RAW", masterKeyForPasswordTestAndSalt123.getFormat()); assertTrue(timeDuration > 3000); }
@Test public void testCreateDerivedKeys() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { SaltedSecretKey masterKey = createDummyMasterKey(); CipherSpec cipherSpec = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM); byte[] derivedKeySalt1 = new byte[] { 1, 2, 3 }; byte[] derivedKeySalt2 = new byte[] { 1, 2, 3, 4 }; SaltedSecretKey derivedKey1 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt1, cipherSpec); SaltedSecretKey derivedKey2 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt2, cipherSpec); logger.log(Level.INFO, "- Derived key 1: "+StringUtil.toHex(derivedKey1.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(derivedKey1.getSalt())); logger.log(Level.INFO, "- Derived key 2: "+StringUtil.toHex(derivedKey2.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(derivedKey2.getSalt())); assertEquals(128/8, derivedKey1.getEncoded().length); assertEquals(128/8, derivedKey2.getEncoded().length); assertFalse(Arrays.equals(derivedKey1.getSalt(), derivedKey2.getSalt())); assertFalse(Arrays.equals(derivedKey1.getEncoded(), derivedKey2.getEncoded())); }
public static SaltedSecretKey toSaltedSecretKey(byte[] secretKeyBytes, byte[] saltBytes, String algorithm) { return new SaltedSecretKey(toSecretKey(secretKeyBytes, algorithm), saltBytes); }
private void saveLocalConfig(File configFile, File repoFile, File masterFile, String masterKeyPassword) throws Exception { if (options.isEncryptionEnabled()) { SaltedSecretKey masterKey = createMasterKeyFromPassword(masterKeyPassword); // This takes looong! options.getConfigTO().setMasterKey(masterKey); new MasterTO(masterKey.getSalt()).save(masterFile); options.getRepoTO().save(repoFile, options.getCipherSpecs(), masterKey); } else { options.getRepoTO().save(repoFile); } options.getConfigTO().save(configFile); }
private void writeHeader() throws IOException { if (!headerWritten) { try { // Initialize header HMAC SaltedSecretKey hmacSecretKey = cipherSession.getWriteSecretKey(HMAC_SPEC); headerHmac = Mac.getInstance(HMAC_SPEC.getAlgorithm(), CRYPTO_PROVIDER_ID); headerHmac.init(hmacSecretKey); // Write header writeNoHmac(underlyingOutputStream, STREAM_MAGIC); writeNoHmac(underlyingOutputStream, STREAM_VERSION); writeNoHmac(underlyingOutputStream, hmacSecretKey.getSalt()); writeAndUpdateHmac(underlyingOutputStream, cipherSpecs.size()); cipherOutputStream = underlyingOutputStream; for (CipherSpec cipherSpec : cipherSpecs) { SaltedSecretKey saltedSecretKey = cipherSession.getWriteSecretKey(cipherSpec); byte[] iv = CipherUtil.createRandomArray(cipherSpec.getIvSize()/8); writeAndUpdateHmac(underlyingOutputStream, cipherSpec.getId()); writeAndUpdateHmac(underlyingOutputStream, saltedSecretKey.getSalt()); writeAndUpdateHmac(underlyingOutputStream, iv); cipherOutputStream = cipherSpec.newCipherOutputStream(cipherOutputStream, saltedSecretKey.getEncoded(), iv); } writeNoHmac(underlyingOutputStream, headerHmac.doFinal()); } catch (Exception e) { throw new IOException(e); } headerWritten = true; } }
private void initCipherSession(String masterKeyStr, String masterKeySaltStr) { byte[] masterKeySalt = StringUtil.fromHex(masterKeySaltStr); byte[] masterKeyBytes = StringUtil.fromHex(masterKeyStr); SaltedSecretKey masterKey = new SaltedSecretKey(new SecretKeySpec(masterKeyBytes, "RAW"), masterKeySalt); cipherSession = new CipherSession(masterKey); }
private void initTransformers(RepoTO repoTO) throws Exception { if (repoTO.getTransformers() == null || repoTO.getTransformers().size() == 0) { transformer = new NoTransformer(); } else { List<TransformerTO> transformerTOs = new ArrayList<TransformerTO>(repoTO.getTransformers()); Transformer lastTransformer = null; for (int i = transformerTOs.size() - 1; i >= 0; i--) { TransformerTO transformerTO = transformerTOs.get(i); Transformer transformer = Transformer.getInstance(transformerTO.getType()); if (transformer == null) { throw new ConfigException("Cannot find transformer '" + transformerTO.getType() + "'"); } if (transformer instanceof CipherTransformer) { // Dirty workaround transformerTO.getSettings().put(CipherTransformer.PROPERTY_MASTER_KEY, StringUtil.toHex(getMasterKey().getEncoded())); transformerTO.getSettings().put(CipherTransformer.PROPERTY_MASTER_KEY_SALT, StringUtil.toHex(getMasterKey().getSalt())); } transformer.init(transformerTO.getSettings()); if (lastTransformer != null) { transformer.setNextTransformer(lastTransformer); } lastTransformer = transformer; } transformer = lastTransformer; } }
public SaltedSecretKey read(InputNode node) throws Exception { byte[] saltBytes = StringUtil.fromHex(node.getAttribute("salt").getValue()); byte[] keyBytes = StringUtil.fromHex(node.getAttribute("key").getValue()); return new SaltedSecretKey(new SecretKeySpec(keyBytes, CipherParams.MASTER_KEY_DERIVATION_FUNCTION), saltBytes); }
private SaltedSecretKey createDummyMasterKey() { return new SaltedSecretKey( new SecretKeySpec( StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"), "AnyAlgorithm" ), StringUtil.fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc") ); } }
private SaltedSecretKey createDummyMasterKey() { return new SaltedSecretKey( new SecretKeySpec( StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"), "AnyAlgorithm" ), StringUtil .fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc")); } }
private SaltedSecretKey createDummyMasterKey() { return new SaltedSecretKey( new SecretKeySpec( StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"), "AnyAlgorithm" ), StringUtil.fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc") ); } }
private SaltedSecretKey createDummyMasterKey() { return new SaltedSecretKey( new SecretKeySpec( StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"), "AnyAlgorithm" ), StringUtil.fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc") ); } }