Created
March 16, 2023 04:45
-
-
Save MrCoder/1ba65f111636d806b83561bc9fbb4f20 to your computer and use it in GitHub Desktop.
FPE in Java with BouncyCastle
This file contains 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 org.example; | |
import org.bouncycastle.crypto.AlphabetMapper; | |
import org.bouncycastle.crypto.util.BasicAlphabetMapper; | |
import org.bouncycastle.jcajce.spec.FPEParameterSpec; | |
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |
import javax.crypto.Cipher; | |
import javax.crypto.KeyGenerator; | |
import javax.crypto.NoSuchPaddingException; | |
import javax.crypto.SecretKey; | |
import javax.crypto.spec.SecretKeySpec; | |
import java.security.MessageDigest; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.SecureRandom; | |
import java.security.spec.AlgorithmParameterSpec; | |
import java.text.SimpleDateFormat; | |
import java.util.Arrays; | |
/** | |
* Hello world! | |
* | |
*/ | |
public class App | |
{ | |
// explain the following code | |
public static void main( String[] args ) throws Exception { | |
SecretKey key = generateAESKey("12345678901234567890123456789012"); | |
byte[] tweak = getTweak(); | |
AlphabetMapper alphabetMapper = new BasicAlphabetMapper("0123456789"); | |
int radix = alphabetMapper.getRadix(); | |
char[] plaintext = "123456788".toCharArray(); | |
byte[] plain_bytes = alphabetMapper.convertToIndexes(plaintext); | |
Cipher cipher = Cipher.getInstance("AES/FF3-1/NoPadding", new BouncyCastleProvider()); | |
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); | |
System.out.println(sdf.format(System.currentTimeMillis())); | |
byte[] cipher_bytes = null; | |
for(int i = 0; i < 100000; i++) { | |
cipher_bytes = encrypt(cipher, key, tweak, radix, plain_bytes); | |
} | |
System.out.println(sdf.format(System.currentTimeMillis())); | |
byte[] decrypted = null;Fo | |
for(int i = 0; i < 100000; i++) { | |
decrypted = decrypt(cipher, key, tweak, radix, cipher_bytes); | |
} | |
System.out.println(sdf.format(System.currentTimeMillis())); | |
char[] cipher_chars = alphabetMapper.convertToChars(cipher_bytes); | |
System.out.println(new String(cipher_chars)); | |
char[] plain_chars = alphabetMapper.convertToChars(decrypted); | |
System.out.println(new String(plain_chars)); | |
System.out.println( "Hello World!" ); | |
} | |
public static SecretKeySpec generateAESKey(String password) throws Exception { | |
// Convert password to bytes | |
byte[] passwordBytes = password.getBytes("UTF-8"); | |
System.out.println("passwordBytes: " + passwordBytes.length); | |
// Generate 256-bit key from password bytes using SHA-256 hash function | |
MessageDigest sha = MessageDigest.getInstance("SHA-256"); | |
byte[] keyBytes = sha.digest(passwordBytes); // will create a 32-byte key | |
// Truncate key to 128 bits (16 bytes) for use with AES | |
keyBytes = Arrays.copyOf(keyBytes, 32); | |
// Create secret key spec from AES key bytes | |
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); | |
return keySpec; | |
} | |
public static byte[] encrypt(Cipher cipher, SecretKey key, byte[] tweak, int radix, byte[] plaintext) throws Exception { | |
AlgorithmParameterSpec fpeParameterSpec = new FPEParameterSpec(radix, tweak); | |
cipher.init(Cipher.ENCRYPT_MODE, key, fpeParameterSpec); | |
return cipher.doFinal(plaintext); | |
} | |
public static byte[] decrypt(Cipher cipher, SecretKey key, byte[] tweak, int radix, byte[] ciphertext) throws Exception { | |
AlgorithmParameterSpec fpeParameterSpec = new FPEParameterSpec(radix, tweak); | |
cipher.init(Cipher.DECRYPT_MODE, key, fpeParameterSpec); | |
return cipher.doFinal(ciphertext); | |
} | |
private static SecretKey generateKey() throws NoSuchAlgorithmException { | |
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); | |
int keyLength = 256; | |
keyGenerator.init(keyLength); | |
return keyGenerator.generateKey(); | |
} | |
private static byte[] getTweak() { | |
byte[] byteArray = new byte[7]; | |
for (int i = 0; i < 7; i++) { | |
byteArray[i] = 0; | |
} | |
return byteArray; | |
} | |
private int getRadix(String alphabet) { | |
AlphabetMapper alphabetMapper = new BasicAlphabetMapper(alphabet); | |
int radix = alphabetMapper.getRadix(); | |
return radix; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment