diff --git a/pom.xml b/pom.xml index fd5dcd0..ae28ba3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,9 +6,14 @@ net.wedjaa.ansible.vault vault-utilities - 1.2.0 + 1.3.0-SNAPSHOT + + org.bouncycastle + bcprov-jdk15to18 + 1.69 + commons-io commons-io diff --git a/src/main/java/net/wedjaa/ansible/vault/crypto/VaultHandler.java b/src/main/java/net/wedjaa/ansible/vault/crypto/VaultHandler.java index 382f05d..a4872e1 100644 --- a/src/main/java/net/wedjaa/ansible/vault/crypto/VaultHandler.java +++ b/src/main/java/net/wedjaa/ansible/vault/crypto/VaultHandler.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.Security; import net.wedjaa.ansible.vault.crypto.data.Util; import net.wedjaa.ansible.vault.crypto.data.VaultInfo; @@ -37,9 +38,15 @@ public class VaultHandler public final static String CHAR_ENCODING = "UTF-8"; + private static synchronized void addBouncyCastleProvider() { + if( Security.getProvider("BC") == null ) { + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + } public static byte [] encrypt(byte [] cleartext, String password, String cypher) throws IOException { + addBouncyCastleProvider(); CypherInterface cypherInstance = CypherFactory.getCypher(cypher); byte [] vaultData = cypherInstance.encrypt(cleartext, password); String vaultDataString = new String(vaultData); @@ -71,7 +78,7 @@ public static void decrypt(InputStream encryptedVault, OutputStream decryptedVau public static byte[] decrypt(byte[] encrypted, String password) throws IOException { - + addBouncyCastleProvider(); VaultInfo vaultInfo = Util.getVaultInfo(encrypted); if ( !vaultInfo.isEncryptedVault() ) { throw new IOException("File is not an Ansible Encrypted Vault"); diff --git a/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultContent.java b/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultContent.java index 5d371b5..3c6fb23 100644 --- a/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultContent.java +++ b/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultContent.java @@ -75,7 +75,7 @@ private int[] getDataLengths(byte[] encodedData) throws IOException int idx = 0; int saltLen = 0; - while (encodedData[idx] != '\n' && idx < encodedData.length) + while (idx < encodedData.length && encodedData[idx] != '\n') { saltLen++; idx++; @@ -89,7 +89,7 @@ private int[] getDataLengths(byte[] encodedData) throws IOException result[0] = saltLen; int hmacLen = 0; - while (encodedData[idx] != '\n' && idx < encodedData.length) + while (idx < encodedData.length && encodedData[idx] != '\n') { hmacLen++; idx++; @@ -121,7 +121,7 @@ private byte[][] splitData(byte[] encodedData) throws IOException int idx = 0; int saltIdx = 0; result[0] = new byte[partsLength[0]]; - while (encodedData[idx] != '\n' && idx < encodedData.length) + while (idx < encodedData.length && encodedData[idx] != '\n') { result[0][saltIdx++] = encodedData[idx++]; } @@ -133,7 +133,7 @@ private byte[][] splitData(byte[] encodedData) throws IOException } int macIdx = 0; result[1] = new byte[partsLength[1]]; - while (encodedData[idx] != '\n' && idx < encodedData.length) + while (idx < encodedData.length && encodedData[idx] != '\n') { result[1][macIdx++] = encodedData[idx++]; } diff --git a/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultInfo.java b/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultInfo.java index 4163432..39ad47a 100644 --- a/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultInfo.java +++ b/src/main/java/net/wedjaa/ansible/vault/crypto/data/VaultInfo.java @@ -54,7 +54,7 @@ public VaultInfo(String infoLine) if ( infoParts[MAGIC_PART].equals(VAULT_MAGIC) ) { validVault = true; vaultVersion = infoParts[VERSION_PART]; - vaultCypher = infoParts[CYPHER_PART]; + vaultCypher = infoParts[CYPHER_PART].trim(); } } } diff --git a/src/main/java/net/wedjaa/ansible/vault/crypto/decoders/implementation/CypherAES256.java b/src/main/java/net/wedjaa/ansible/vault/crypto/decoders/implementation/CypherAES256.java index 733a90f..27284e6 100644 --- a/src/main/java/net/wedjaa/ansible/vault/crypto/decoders/implementation/CypherAES256.java +++ b/src/main/java/net/wedjaa/ansible/vault/crypto/decoders/implementation/CypherAES256.java @@ -40,7 +40,7 @@ public class CypherAES256 implements CypherInterface public final static String CHAR_ENCODING = "UTF-8"; public final static String KEYGEN_ALGO = "HmacSHA256"; public final static String CYPHER_KEY_ALGO = "AES"; - public static final String CYPHER_ALGO = "AES/CTR/NoPadding"; + public static final String CYPHER_ALGO = "AES/CTR/PKCS7Padding"; // handle by BouncyCastle private static final String JDK8_UPF_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html"; private static final int SALT_LENGTH = 32; @@ -122,7 +122,7 @@ public byte[] pad(byte[] cleartext) throws IOException try { - int blockSize = Cipher.getInstance(CYPHER_ALGO).getBlockSize(); + int blockSize = Cipher.getInstance(CYPHER_ALGO, "BC").getBlockSize(); logger.debug("Padding to block size: {}", blockSize); int padding_length = (blockSize - (cleartext.length % blockSize)); if (padding_length == 0) @@ -148,10 +148,9 @@ public byte[] decryptAES(byte[] cypher, byte[] key, byte[] iv) throws IOExceptio IvParameterSpec ivSpec = new IvParameterSpec(iv); try { - Cipher cipher = Cipher.getInstance(CYPHER_ALGO); + Cipher cipher = Cipher.getInstance(CYPHER_ALGO, "BC"); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); - byte[] decrypted = cipher.doFinal(cypher); - return unpad(decrypted); + return cipher.doFinal(cypher); } catch (Exception ex) { @@ -165,7 +164,7 @@ public byte[] encryptAES(byte[] cleartext, byte[] key, byte[] iv) throws IOExcep IvParameterSpec ivSpec = new IvParameterSpec(iv); try { - Cipher cipher = Cipher.getInstance(CYPHER_ALGO); + Cipher cipher = Cipher.getInstance(CYPHER_ALGO, "BC"); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(cleartext); return encrypted; @@ -244,8 +243,6 @@ public byte[] encrypt(byte[] data, String password) throws IOException byte[] iv = keys.getIv(); logger.debug("IV: {} - {}", iv.length, Util.hexit(iv, 100)); logger.debug("Original data length: {}", data.length); - data = pad(data); - logger.debug("Padded data length: {}", data.length); byte[] encrypted = encryptAES(data, keys.getEncryptionKey(), keys.getIv()); byte[] hmacHash = calculateHMAC(keys.getHmacKey(), encrypted); VaultContent vaultContent = new VaultContent(keys.getSalt(), hmacHash, encrypted); diff --git a/src/test/resources/test-vault.yml b/src/test/resources/test-vault.yml index a3ae003..561b7e3 100644 --- a/src/test/resources/test-vault.yml +++ b/src/test/resources/test-vault.yml @@ -1,12 +1,12 @@ $ANSIBLE_VAULT;1.1;AES256 -33643135356137353133373035376564316239633562363430636665373133376131633364633366 -3561306635333832356137313239643335303631323662330a303464373738373932333564353634 -31653666306337356665343736643136656264353534643139626333653630333235306430393832 -3231643966373262650a653664663237616138303932313663643939393539343734366662343365 -63376565643165386538326138396632333566356266333538636335396132316161313538396137 -66623032663537656636373164303763623538333665666466386562343934303735313135663030 -66616130346130303063663636306537613334663661616361636235666361613462373066363565 -34643665663030636333313237613861626665326462313239353532313535303264646361613734 -31333762343638316364363632653861356135336333356662303732633962336133343563396432 -39353065393238666334396232653034613263346566343639333163656633626436636364313932 -313436663431643964396366633264306633 +35313934363637313839333532346163363766626365633865613338386338623264303965613236 +3339323330346632316437396530393439353662376538610a353833323134643538343864306435 +64396461653430353636333763376161363039646662633631363637663131646231643432636531 +3833663937393065380a396331623064663465356138313934326630356465326330393439366563 +33326161643763393561353862626433633833386232363564656330373130613832396232393230 +39303537616366623462353164643063623935653030333061643530396131306561316134353564 +64356662646630623665643831306134653732353935336432333537633538656363653630383061 +61626262383761393236623664393563623561646661636463363466653731366364623462646532 +62666138363938323639356263336132316634626633376461623466643461336535626632356264 +35653834333239386630656236653865653536656132323965386537393337313931333561323131 +666435653932323731646164383065636236 \ No newline at end of file