Как реализовать двойное шифрование для шифрования / дешифрования строк в Java?
Я недавно скачал twofish-java.zip с https://www.schneier.com/academic/twofish/download.html. В нем есть файл jar twofish.jar. Кто-то объяснил мне, как реализовать шифрование twofish в Java для шифрования / дешифрования строк в Java с использованием этого файла JAR
1 ответ
Вам нужно реализовать функции
blockEncrypt()
а также
blockDecrypt()
и построить режим работы вокруг них. Ключи создаются с помощью
makeKey()
функция, для которой требуется длина ключа 8, 16, 24 или 32 байта. Убедитесь, что открытый текст дополнен кратным 16 байтам. Я приложил свой код для режимов ECB и CBC с Twofish. Я бы порекомендовал вам реализовать собственную функцию заполнения и функцию расширения ключа, если вы хотите обеспечить максимальную безопасность. В моем примере один и тот же ключ используется для каждого блока, а открытый текст дополняется только 0 в конце.
static byte[] ecbEncrypt(byte[] plaintext, byte[] key) throws InvalidKeyException {
byte[] pt = pad(plaintext, 16);
byte[] ciphertext = new byte[pt.length];
for (int i = 0; i < pt.length; i += 16) {
byte[] t = Twofish_Algorithm.blockEncrypt(pt, i, Twofish_Algorithm.makeKey(key));
for (int j = i; j < i + 16; j++)
ciphertext[j] = t[j % 16];
}
return ciphertext;
}
static byte[] ecbDecrypt(byte[] ciphertext, byte[] key) throws InvalidKeyException {
byte[] plaintext = new byte[ciphertext.length];
for (int i = 0; i < ciphertext.length; i += 16) {
byte[] t = Twofish_Algorithm.blockDecrypt(ciphertext, i, Twofish_Algorithm.makeKey(key));
for (int j = i; j < i + 16; j++)
plaintext[j] = t[j % 16];
}
return unpad(plaintext);
}
static byte[] cbcEncrypt(byte[] plaintext, byte[] key, byte[] iv) throws InvalidKeyException {
byte[] pt = pad(plaintext, 16);
byte[] ciphertext = new byte[pt.length];
for (int i = 0; i < 16; i++)
pt[i] ^= iv[i];
byte[] t = Twofish_Algorithm.blockEncrypt(pt, 0, Twofish_Algorithm.makeKey(key));
for (int i = 0; i < 16; i++)
ciphertext[i] = t[i];
for (int i = 16; i < pt.length; i += 16) {
for (int j = 0; j < 16; j++)
pt[i + j] ^= ciphertext[i - 16 + j];
byte[] t2 = Twofish_Algorithm.blockEncrypt(pt, i, Twofish_Algorithm.makeKey(key));
for (int j = 0; j < 16; j++)
ciphertext[i + j] = t2[j];
}
return ciphertext;
}
static byte[] cbcDecrypt(byte[] ciphertext, byte[] key, byte[] iv) throws InvalidKeyException {
byte[] plaintext = new byte[ciphertext.length];
byte[] t = Twofish_Algorithm.blockDecrypt(ciphertext, 0, Twofish_Algorithm.makeKey(key));
for (int i = 0; i < 16; i++)
plaintext[i] = (byte) (t[i] ^ iv[i]);
for (int i = 16; i < ciphertext.length; i += 16) {
byte[] t2 = Twofish_Algorithm.blockDecrypt(ciphertext, i, Twofish_Algorithm.makeKey(key));
for (int j = 0; j < 16; j++)
plaintext[i + j] = (byte) (t2[j] ^ ciphertext[i - 16 + j]);
}
return unpad(plaintext);
}
static byte[] pad(byte[] in, int blockSize) {
byte[] ret = new byte[in.length + blockSize - in.length % blockSize];
for (int i = 0; i < in.length; i++)
ret[i] = in[i];
byte paddedBytes = 0;
for (int i = in.length; i < ret.length - 1; i++) {
ret[i] = 0;
paddedBytes++;
}
ret[ret.length - 1] = paddedBytes;
return ret;
}
static byte[] unpad(byte[] in) {
byte[] ret = new byte[in.length - in[in.length - 1] - 1];
for (int i = 0; i < ret.length; i++)
ret[i] = in[i];
return ret;
}
Эта реализация, вероятно, не будет идеальной, поэтому не стесняйтесь писать мне об улучшениях, чтобы я мог отредактировать свой ответ.
Вы можете вызывать функции следующим образом:
SecureRandom sr = new SecureRandom();
byte[] plaintext = "This is secret plaintext".getBytes();
byte[] key = new byte[16];
byte[] iv = new byte[16];
sr.nextBytes(key);
sr.nextBytes(iv);
System.out.println("Plaintext: " + new String(plaintext));
byte[] ecbCiphertext = ecbEncrypt(plaintext, key);
System.out.println("ECB-Ciphertext: " + new String(ecbCiphertext));
byte[] ecbPlaintext = ecbDecrypt(ecbCiphertext, key);
System.out.println("ECB-Plaintext: " + new String(ecbPlaintext));
byte[] cbcCiphertext = cbcEncrypt(plaintext, key, iv);
System.out.println("CBC-Ciphertext: " + new String(cbcCiphertext));
byte[] cbcPlaintext = cbcDecrypt(cbcCiphertext, key, iv);
System.out.println("CBC-Plaintext: " + new String(cbcPlaintext));
Plaintext: This is secret plaintext
ECB-Ciphertext: ÑìÔõ¬ŽÁ@γ÷ÊÑ–1—N,/ )ë+$
ECB-Plaintext: This is secret plaintext
CBC-Ciphertext: JÉÌÙ•=Hæí_•¤iÔ[%˜Å?ÆÍæ“!Ø?%
CBC-Plaintext: This is secret plaintext
Если вам нужен способ шифрования/дешифрования с использованием режима счетчика, я также добавил свою реализацию для этого.
static byte[] ctrEncrypt(byte[] plaintext, byte[] key, byte[] iv) throws InvalidKeyException {
byte[] initializationVector = Arrays.copyOf(iv, iv.length);
byte[] counter = { -128, -128, -128, -128, -128, -128, -128, -128 };
byte[] ciphertext = new byte[plaintext.length];
for (int i = 0; i < plaintext.length / 16 + 1; i++) {
for (int j = 0; j < 8; j++) {
if (counter[j] == 127 && j != 7) { counter[j] = -128;
counter[j + 1]++;
}
if (counter[j] != -128)
initializationVector[15 - j] = counter[j];
else
initializationVector[15-j] = iv[15-j];
}
byte[] t = Twofish_Algorithm.blockEncrypt(initializationVector, 0, Twofish_Algorithm.makeKey(key));
for (int j = 0; i < plaintext.length / 16 ? j < 16 : j < plaintext.length % 16; j++)
ciphertext[i * 16 + j] = (byte) (plaintext[i * 16 + j] ^ t[j]);
counter[0]++;
}
return ciphertext;
}
static byte[] ctrDecrypt(byte[] ciphertext, byte[] key, byte[] iv) throws InvalidKeyException {
return ctrEncrypt(ciphertext, key, iv);
}