Created
February 15, 2018 02:37
-
-
Save juusechec/701ea268dfad1d24c4e7b05f24631851 to your computer and use it in GitHub Desktop.
Class to encrypt and decrypt values in AES algorithm with rando IV saved in convenient BASE64 format.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package co.edu.udistrital.glud.services; | |
import javax.crypto.spec.SecretKeySpec; | |
import javax.crypto.spec.IvParameterSpec; | |
import javax.crypto.Cipher; | |
import java.util.Base64; | |
import java.util.Random; | |
import java.util.Scanner; | |
/** | |
* Based on https://gist.github.com/bricef/2436364#file-aes-java | |
* @author juusechec | |
* This class encrypt and decrypt paramns | |
* You can execute making "Run AS" -> "Java Application" over the File | |
* | |
* Example: | |
* | |
* import co.edu.udistrital.glud.services.EncryptService; | |
* | |
* ... | |
* String secret = "I'm a secret"; | |
* String encryptedSecret = EncryptService.ecryptSecret(secret); | |
* System.out.println("encryptedSecret: " + encryptedSecret); | |
* String recoveredSecret = EncryptService.decryptSecret(encryptedSecret); | |
* System.out.println("recoveredSecret: " + recoveredSecret); | |
* ... | |
*/ | |
public class EncryptService { | |
static int blockSize = 16; | |
static byte[] IV = new byte[16]; // needed 16 bytes | |
static String encryptionKey = "0123456789abcdef0123456789abcdef"; // 16, 24, 32 bytes optionally | |
static String splitter = "$"; | |
public static void main(String[] args) { | |
// link: https://stackoverflow.com/questions/5287538/how-can-i-get-the-user-input-in-java | |
Scanner scan = new Scanner(System.in); | |
System.out.println("You want con encrypt (e) or decrypt(d) (enter to submit): "); | |
String option = scan.nextLine(); | |
if (option.toLowerCase().startsWith("d")) { // decrypt | |
System.out.println("Enter a string to decrypt (enter to jump): "); | |
String encryptedSecret = scan.nextLine(); | |
String recoveredSecret = decryptSecret(encryptedSecret); | |
System.out.println("recoveredSecret (between quotation marks): '" + recoveredSecret + "'"); | |
scan.close(); | |
return; | |
} | |
System.out.println("Enter a string to encrypt (enter to jump): "); | |
String plaintext = scan.nextLine(); | |
//String s = scan.next(); // only first word (separated with space \s) | |
//int n = scan.nextInt(); // Scans the next token of the input as an int. | |
scan.close(); //once finished | |
if (!plaintext.equals("")) { | |
System.out.println("\n=== Starting step by step ===\n"); | |
int longitud = plaintext.length(); | |
int veces = (int) Math.ceil((double) longitud / blockSize); // double for precision Beginig | |
int faltan = (blockSize * veces) - longitud; | |
String faltante = new String(new char[faltan]); | |
String newplaintext = plaintext + faltante; | |
try { | |
System.out.println("plain: " + newplaintext); | |
System.out.println("plain length: " + newplaintext.length()); | |
IV = randomIV(); | |
System.out.println("randomIV: " + new String(IV)); | |
byte[] cipher = encrypt(newplaintext, encryptionKey); | |
System.out.println("encrypt: " + new String(cipher)); | |
byte[] encodedBytes = Base64.getEncoder().encode(cipher); | |
System.out.println("encodedEncryptBase64Bytes: " + new String(encodedBytes)); | |
byte[] encodedIVBytes = Base64.getEncoder().encode(IV); | |
System.out.println("encodedIVBase64Bytes: " + new String(encodedIVBytes)); | |
System.out.println("\n=== Recovering ===\n"); | |
byte[] decodedBytes = Base64.getDecoder().decode(encodedBytes); | |
System.out.println("decodedEncryptBase64Bytes: " + new String(decodedBytes)); | |
byte[] decodedIVBytes = Base64.getDecoder().decode(encodedIVBytes); | |
System.out.println("decodedIVBase64Bytes: " + new String(decodedIVBytes)); | |
IV = decodedIVBytes; | |
String decrypted = decrypt(decodedBytes, encryptionKey); | |
decrypted = decrypted.replace("\0", ""); // replacing null chars with no chars | |
System.out.println("decrypt: " + decrypted); | |
System.out.println("decrypt length: " + decrypted.length()); | |
System.out.println("\n=== Final Result ===\n"); | |
String encryptedSecret = ecryptSecret(plaintext); | |
System.out.println("secureSecret: " + encryptedSecret); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return; | |
} | |
// example with 16 bytes string | |
try { | |
System.out.println("\n=== Example ===\n"); | |
plaintext = "test text 123\0\0\0"; // obligatory 16 length! | |
System.out.println("plain: " + plaintext); | |
IV = "AAAAAAAAAAAAAAAA".getBytes("UTF-8"); // example IV | |
byte[] cipher = encrypt(plaintext, encryptionKey); | |
System.out.print("cipher: "); | |
for (int i = 0; i < cipher.length; i++) | |
System.out.print(new Integer(cipher[i]) + " "); | |
//System.out.print((char)(cipher[i])); | |
System.out.println(""); | |
String decrypted = decrypt(cipher, encryptionKey); | |
System.out.println("decrypt: " + decrypted); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
public static String decryptSecret(String encryptedSecret) { | |
// text = "$id_algorithm$salt$hashed" | |
// text = "$1$saltbase64$encryptedbase64text" | |
// https://www.cyberciti.biz/faq/understanding-etcshadow-file/ | |
try { | |
String[] parts = encryptedSecret.split("\\" + splitter, 4); | |
String id = parts[1]; | |
String salt = parts[2]; | |
String hashed = parts[3]; | |
if (id.equals("1")) { // RSA | |
byte[] decodedIVBytes = Base64.getDecoder().decode(salt); | |
byte[] decodedEncryptBytes = Base64.getDecoder().decode(hashed); | |
IV = decodedIVBytes; | |
String decrypted = decrypt(decodedEncryptBytes, encryptionKey); | |
decrypted = decrypted.replace("\0", ""); | |
return decrypted; | |
} | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return ""; | |
} | |
public static String ecryptSecret(String plainSecret) { | |
try { | |
if (plainSecret.equals("")) { | |
return ""; | |
} | |
int lengthSecret = plainSecret.length(); | |
int timesInSizeKey = (int) Math.ceil((double) lengthSecret / blockSize); // double for precision | |
int remainingNullChars = (blockSize * timesInSizeKey) - lengthSecret; | |
String remainingString = new String(new char[remainingNullChars]); | |
plainSecret = plainSecret + remainingString; | |
IV = randomIV(); | |
byte[] cipher = encrypt(plainSecret, encryptionKey); | |
byte[] encodedEncryptBytes = Base64.getEncoder().encode(cipher); | |
byte[] encodedIVBytes = Base64.getEncoder().encode(IV); | |
// text = "$id_algorithm$salt$hashed" | |
// text = "$1$saltbase64$encryptedbase64text" | |
// https://www.cyberciti.biz/faq/understanding-etcshadow-file/ | |
return splitter + "1" + splitter + new String(encodedIVBytes) + splitter + new String(encodedEncryptBytes); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return ""; | |
} | |
public static byte[] encrypt(String plainText, String encryptionKey) throws Exception { | |
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE"); | |
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES"); | |
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV)); | |
return cipher.doFinal(plainText.getBytes("UTF-8")); | |
} | |
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception { | |
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE"); | |
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES"); | |
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV)); | |
return new String(cipher.doFinal(cipherText), "UTF-8"); | |
} | |
public static byte[] randomIV() { | |
byte[] b = new byte[16]; // 16 length | |
new Random().nextBytes(b); | |
return b; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment