Work in progress ...
This commit is contained in:
@@ -2,20 +2,26 @@ package de.neitzel.encryption;
|
||||
|
||||
import com.idealista.fpe.config.Alphabet;
|
||||
|
||||
public abstract class BaseAlphabet implements Alphabet {
|
||||
/**
|
||||
* Base implementation of the {@link Alphabet} interface providing common helper methods
|
||||
* for working with character sets and validating characters against the alphabet.
|
||||
*/
|
||||
public interface BaseAlphabet extends Alphabet {
|
||||
/**
|
||||
* Replaces illegal characters of a string with a given replacement character
|
||||
* @param text Text to check.
|
||||
* @param replacement Replacement character.
|
||||
* @return String in which all characters was replaced.
|
||||
* Replaces illegal characters of a string with a given replacement character.
|
||||
*
|
||||
* @param text Text to check; may not be null
|
||||
* @param replacement Replacement character to use for characters not present in the alphabet
|
||||
* @return a new string in which every invalid character was replaced with the provided replacement
|
||||
* @throws IllegalArgumentException if {@code replacement} is not a valid character in the alphabet
|
||||
*/
|
||||
public String replaceIllegalCharacters(String text, char replacement) {
|
||||
default String replaceIllegalCharacters(String text, char replacement) {
|
||||
// Validate
|
||||
if (!isValidCharacter(replacement)) throw new IllegalArgumentException("replacement");
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (char ch: text.toCharArray()) {
|
||||
if (isValidCharacter(ch)){
|
||||
for (char ch : text.toCharArray()) {
|
||||
if (isValidCharacter(ch)) {
|
||||
result.append(ch);
|
||||
} else {
|
||||
result.append(replacement);
|
||||
@@ -26,10 +32,11 @@ public abstract class BaseAlphabet implements Alphabet {
|
||||
|
||||
/**
|
||||
* Checks if a given Character is part of the alphabet.
|
||||
*
|
||||
* @param character Character to check.
|
||||
* @return true if character is valid, else false.
|
||||
*/
|
||||
public boolean isValidCharacter(char character) {
|
||||
default boolean isValidCharacter(char character) {
|
||||
// Compare with all characters
|
||||
for (char ch : availableCharacters()) {
|
||||
if (ch == character) return true;
|
||||
|
||||
@@ -7,49 +7,53 @@ import com.idealista.fpe.config.LengthRange;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Random;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* Helper class to deal with FF1Encryption using com.idealista:format-preserving-encryption:1.0.0.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class FF1Encryption {
|
||||
|
||||
/**
|
||||
* Key to use for all encryption / unencryption
|
||||
*/
|
||||
private byte[] key;
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
/**
|
||||
* Should to small strings be ignored?
|
||||
*
|
||||
* If this is set to true, small strings (less than 2 characters) will not be encrypted!
|
||||
* Key to use for all encryption / unencryption.
|
||||
*/
|
||||
private boolean ignoreToShortStrings;
|
||||
private final byte[] key;
|
||||
|
||||
/**
|
||||
* tweak to use for encryption
|
||||
* Should too small strings be ignored?
|
||||
* If this is set to true, small strings (less than {@code minLength} characters)
|
||||
* will not be encrypted or decrypted and will be returned unchanged.
|
||||
*/
|
||||
private byte[] tweak;
|
||||
private final boolean ignoreToShortStrings;
|
||||
|
||||
/**
|
||||
* Domain used for encryption
|
||||
* Tweak to use for encryption.
|
||||
*/
|
||||
private Domain domain;
|
||||
private final byte[] tweak;
|
||||
|
||||
/**
|
||||
* Format preserving encryption to use.
|
||||
* Domain used for encryption.
|
||||
*/
|
||||
private FormatPreservingEncryption encryption;
|
||||
private final Domain domain;
|
||||
|
||||
/**
|
||||
* Minimum length of a string.
|
||||
* Format preserving encryption implementation to use.
|
||||
*/
|
||||
private int minLength;
|
||||
private final FormatPreservingEncryption encryption;
|
||||
|
||||
/**
|
||||
* Minimum length of a string for which encryption/decryption will be applied.
|
||||
*/
|
||||
private final int minLength;
|
||||
|
||||
/**
|
||||
* Creates a new instance of FF1Encryption
|
||||
* @param key AES key to use.
|
||||
* @param tweak tweak to use for encryption / decryption
|
||||
*
|
||||
* @param key AES key to use.
|
||||
* @param tweak tweak to use for encryption / decryption
|
||||
* @param ignoreToShortStrings Ignore strings that are to short.
|
||||
*/
|
||||
public FF1Encryption(byte[] key, byte[] tweak, boolean ignoreToShortStrings) {
|
||||
@@ -58,12 +62,13 @@ public class FF1Encryption {
|
||||
|
||||
/**
|
||||
* Creates a new instance of FF1Encryption
|
||||
* @param key AES key to use.
|
||||
* @param tweak tweak to use for encryption / decryption
|
||||
*
|
||||
* @param key AES key to use.
|
||||
* @param tweak tweak to use for encryption / decryption
|
||||
* @param ignoreToShortStrings Ignore strings that are to short.
|
||||
* @param domain Domain to use for encryption
|
||||
* @param minLength Minimum length of string.
|
||||
* @param maxLength Maximum length of string.
|
||||
* @param domain Domain to use for encryption
|
||||
* @param minLength Minimum length of string.
|
||||
* @param maxLength Maximum length of string.
|
||||
*/
|
||||
public FF1Encryption(byte[] key, byte[] tweak, boolean ignoreToShortStrings, Domain domain, int minLength, int maxLength) {
|
||||
this.key = key;
|
||||
@@ -72,15 +77,45 @@ public class FF1Encryption {
|
||||
this.domain = domain;
|
||||
this.minLength = minLength;
|
||||
|
||||
encryption = FormatPreservingEncryptionBuilder
|
||||
.ff1Implementation().withDomain(domain)
|
||||
this.encryption = FormatPreservingEncryptionBuilder
|
||||
.ff1Implementation()
|
||||
.withDomain(domain)
|
||||
.withDefaultPseudoRandomFunction(key)
|
||||
.withLengthRange(new LengthRange(minLength, maxLength))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AES key woth the given length.
|
||||
*
|
||||
* @param length Length of the key in bits. Must be 128, 192 or 256 bits
|
||||
* @return Byte array of the new key.
|
||||
*/
|
||||
public static byte[] createNewKey(int length) {
|
||||
try {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(length); // for example
|
||||
return keyGen.generateKey().getEncoded();
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tweak of the given length.
|
||||
*
|
||||
* @param length Number of bytes the new teeak should have.
|
||||
* @return byte array with the new tweak.
|
||||
*/
|
||||
public static byte[] createNewTweak(int length) {
|
||||
byte[] key = new byte[length];
|
||||
RANDOM.nextBytes(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a given text.
|
||||
*
|
||||
* @param plainText Unencrypted text.
|
||||
* @return Encrypted text.
|
||||
*/
|
||||
@@ -97,6 +132,7 @@ public class FF1Encryption {
|
||||
|
||||
/**
|
||||
* Decrypt a given text.
|
||||
*
|
||||
* @param cipherText Encrypted text.
|
||||
* @return Decrypted text.
|
||||
*/
|
||||
@@ -110,31 +146,4 @@ public class FF1Encryption {
|
||||
// Return decrypted text.
|
||||
return encryption.decrypt(cipherText, tweak);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AES key woth the given length.
|
||||
* @param length Length of the key in bits. Must be 128, 192 or 256 bits
|
||||
* @return Byte array of the new key.
|
||||
*/
|
||||
public static byte[] createNewKey(int length) {
|
||||
try {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(length); // for example
|
||||
return keyGen.generateKey().getEncoded();
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tweak of the given length.
|
||||
* @param length Number of bytes the new teeak should have.
|
||||
* @return byte array with the new tweak.
|
||||
*/
|
||||
public static byte[] createNewTweak(int length) {
|
||||
Random random = new Random();
|
||||
byte[] key = new byte[length];
|
||||
random.nextBytes(key);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package de.neitzel.encryption;
|
||||
/**
|
||||
* Main characters of the Alphabet.
|
||||
*/
|
||||
public class MainAlphabet extends BaseAlphabet {
|
||||
public class MainAlphabet implements BaseAlphabet {
|
||||
|
||||
/**
|
||||
* All characters we want to use.
|
||||
* All characters that are part of the alphabet used by the MainDomain.
|
||||
* This array includes lowercase letters, uppercase letters, digits, a set of
|
||||
* special characters, and German-specific characters.
|
||||
*/
|
||||
private static final char[] ALL_CHARS = new char[] {
|
||||
private static final char[] ALL_CHARS = new char[]{
|
||||
// lowercase characters
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
|
||||
's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
@@ -21,16 +23,38 @@ public class MainAlphabet extends BaseAlphabet {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
|
||||
// special characters
|
||||
'-', '_', '?', ' ', '#', '+', '/', '*', '!', '\"', '§', '$', '%', '&', '(', ')', '=', '@',
|
||||
'-', '_', '?', ' ', '#', '+', '/', '*', '!', '"', '§', '$', '%', '&', '(', ')', '=', '@',
|
||||
'€', ',', ';', '.', ':', '<', '>', '|', '\'', '\\', '{', '}', '[', ']',
|
||||
|
||||
// german special characters
|
||||
'ä', 'Ä', 'ö', 'Ö', 'ü', 'Ü', 'ß'
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new MainAlphabet instance.
|
||||
*
|
||||
* <p>This constructor performs no runtime initialization because the
|
||||
* alphabet is represented by the static {@code ALL_CHARS} array. Use
|
||||
* {@link #availableCharacters()} to obtain the supported characters and
|
||||
* {@link #radix()} to obtain the alphabet size.</p>
|
||||
*
|
||||
* <p> Important usage notes: </p>
|
||||
* <ul>
|
||||
* <li>The array returned by {@link #availableCharacters()} is the internal
|
||||
* static array; callers must not modify it.</li>
|
||||
* <li>The alphabet intentionally contains letters (lower and upper case),
|
||||
* digits, common punctuation and a set of German-specific characters
|
||||
* to support locale-sensitive operations.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public MainAlphabet() {
|
||||
// default constructor only ...
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available characters.
|
||||
* @return
|
||||
*
|
||||
* @return an array containing all supported characters in the alphabet
|
||||
*/
|
||||
@Override
|
||||
public char[] availableCharacters() {
|
||||
@@ -39,7 +63,8 @@ public class MainAlphabet extends BaseAlphabet {
|
||||
|
||||
/**
|
||||
* Gets the radix of the alphabet.
|
||||
* @return
|
||||
*
|
||||
* @return the number of characters in the alphabet (radix)
|
||||
*/
|
||||
@Override
|
||||
public Integer radix() {
|
||||
|
||||
@@ -4,26 +4,60 @@ import com.idealista.fpe.config.Alphabet;
|
||||
import com.idealista.fpe.config.Domain;
|
||||
import com.idealista.fpe.config.GenericTransformations;
|
||||
|
||||
/**
|
||||
* Domain implementation that provides the alphabet and transformation helpers
|
||||
* used by the format-preserving encryption implementation in this project.
|
||||
* <p>
|
||||
* This class delegates character-to-index and index-to-character transformations
|
||||
* to a {@link GenericTransformations} helper configured with the {@link MainAlphabet}.
|
||||
*/
|
||||
public class MainDomain implements Domain {
|
||||
|
||||
/**
|
||||
* The alphabet used by the domain for encoding/decoding characters.
|
||||
*/
|
||||
private Alphabet _alphabet;
|
||||
|
||||
/**
|
||||
* Helper instance performing actual transformations between characters and indices.
|
||||
*/
|
||||
private GenericTransformations transformations;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code MainDomain} instance and initializes its alphabet and transformation helper.
|
||||
*/
|
||||
public MainDomain() {
|
||||
_alphabet = new MainAlphabet();
|
||||
transformations = new GenericTransformations(_alphabet.availableCharacters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Alphabet} implementation used by this domain.
|
||||
*
|
||||
* @return the alphabet used for transforming values in this domain
|
||||
*/
|
||||
@Override
|
||||
public Alphabet alphabet() {
|
||||
return _alphabet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a string of characters into an array of integer indices according to the configured alphabet.
|
||||
*
|
||||
* @param data the input string to transform; may not be null
|
||||
* @return an integer array representing the indices of the characters in the given string
|
||||
*/
|
||||
@Override
|
||||
public int[] transform(String data) {
|
||||
return transformations.transform(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of integer indices back into a string using the configured alphabet.
|
||||
*
|
||||
* @param data the array of indices to transform back into characters
|
||||
* @return the resulting string produced from the given index array
|
||||
*/
|
||||
@Override
|
||||
public String transform(int[] data) {
|
||||
return transformations.transform(data);
|
||||
|
||||
Reference in New Issue
Block a user