Итак, у меня есть школьный проект, с которым у меня проблемы. Нам дается метод шифрования, а затем предлагается создать для него метод дешифрования.Crypttext кража в Java
public static byte[] encrypt(byte[] plaintext, BlockCipher64 cipher, long IV) {
if(plaintext.length <= 8)
throw new IllegalArgumentException("plaintext must be longer than 8 bytes!");
byte[] ciphertext = new byte[plaintext.length];
int blocks = plaintext.length/8;
if(plaintext.length % 8 != 0) ++blocks;
long prev = IV;
for(int block = 0; block < blocks; ++block) {
prev = cipher.encrypt(prev^longAt(plaintext, block * 8));
storeLongAt(ciphertext, prev, block * 8);
}
// copy penultimate to last, then prev to penultimate (ciphertext stealing)
int lastBlock = (blocks - 1) * 8;
int secondLastBlock = (blocks - 2) * 8;
storeLongAt(ciphertext, longAt(ciphertext, secondLastBlock), lastBlock);
storeLongAt(ciphertext, prev, secondLastBlock);
return ciphertext;
}
Таким образом, я получил метод дешифрования для работы, когда длина строки равна ровно 16 (2 блока). Другие строки с четными блоками (кратные 8) не работают, 24, 32 ... и т. Д. Также частичные блоки не работают; если я зашифрую строку длиной 18 и снова расшифрую ее, последние два символа всегда ошибочны. Любая помощь высоко ценится! Вот мой метод расшифровки:
public static byte[] decrypt(byte[] ciphertext, BlockCipher64 cipher, long IV) {
// code here
// check for an illegal argument
if(ciphertext.length <= 8)
throw new IllegalArgumentException("ciphertext must be longer than 8 bytes!");
// create a byte[] for the plaintext
byte[] plaintext = new byte[ciphertext.length];
// calculate how many blocks there are
int blocks = plaintext.length/8;
if(plaintext.length % 8 != 0) ++blocks;
// handle the last two blocks (which are special because of ciphertext stealing)
int lastBlock = (blocks - 1) * 8;
int secondLastBlock = (blocks - 2) * 8;
long lBlock = longAt(ciphertext, lastBlock);
int lBlockSize = ciphertext.length % 8;
// if block sizes are even; swap, if block size is partial;
if (lBlockSize != 0) {
//get blocks to switch
byte[] NLB = new byte[lBlockSize];
for (int i=secondLastBlock, j=0; i<secondLastBlock + lBlockSize; i++, j++) {
NLB[j] = ciphertext[i];
}
byte[] NSLB = new byte[lBlockSize];
for (int i=lastBlock, j=0; i<lastBlock + lBlockSize; i++, j++) {
NSLB[j] = ciphertext[i];
}
//build ciphertext
for (int i=secondLastBlock, j=0; i<secondLastBlock + lBlockSize; i++, j++) {
ciphertext[i] = NSLB[j];
}
for (int i=lastBlock, j=0; i<lastBlock + lBlockSize; i++, j++) {
ciphertext[i] = NLB[j];
}
} else {
storeLongAt(ciphertext, longAt(ciphertext, secondLastBlock), lastBlock);
storeLongAt(ciphertext, lBlock, secondLastBlock);
}
// loop over all other blocks, decrypting and xor'ing, and saving the results
long prev = IV;
for(int block = 0; block < blocks; ++block) {
prev = cipher.decrypt(prev^longAt(ciphertext, block * 8));
storeLongAt(plaintext, prev, block * 8);
}
return plaintext;
}
Если какая-либо другая информация необходима, дайте мне знать ... Я реальный тупик на этом.
EDIT: Дополнительные методы и классы storeLongAt() и longAt():
public static void storeLongAt(byte[] b, long x, int pos) {
byte[] c = BlockCipher64.longToBytes(x);
for(int i = 0; i < 8 && (pos + i) < b.length; ++i) {
b[pos + i] = c[i];
}
}
public static long longAt(byte[] b, int pos) {
return BlockCipher64.bytesToLong(Arrays.copyOfRange(b, pos, pos + 8));
}
И класс BlockCipher64:
public interface BlockCipher64 {
long encrypt(long block);
long decrypt(long block);
public static byte[] longToBytes(long l) {
byte[] result = new byte[8];
for (int i = 7; i >= 0; i--) {
result[i] = (byte) l;
l >>= 8;
}
return result;
}
public static long bytesToLong(byte[] b) {
long result = 0;
for (int i = 0; i < 8; i++) {
result <<= 8;
result |= ((long) b[i]) & 0xffL; // notice the L
}
return result;
}
}
Было бы полезно, если вы отредактируете свой вопрос и включите метод 'storeLongAt (...)', а также метод 'longAt (...)'. –
Добавлено вместе с сопроводительным блоком BlockCipher64 – isaac6