加密和解密算法通常带有“基数”值,例如Caesar(N = 26),Elgamal(N是素数)。如果消息值大于N,我们必须将其拆分。
一个简单的例子:
E(m) = m + 1 = c (mod 1009) => D(c) = c - 1 = m (mod 1009)
与
m = `"buazyhv"` = `546999123` (base-26 to base-10)
为避免丢失数据(使用模数),我将拆分为3位数块:
M = (546)(999)(123) = m1m2m3
现在,加密每个块
546 -> E -> 547
999 -> E -> 1000
123 -> E -> 124
然后我们加入它:
C = `5471000124` = "rsmetls"
对于解密,我们也这样做:
5 -> D -> 4
471 -> D -> 470
000 -> D -> 999
124 -> D -> 123
我们有decypt消息M = 4470999123 = "omhwyat"
。因此,我的拆分和加入消息方法不正确。
使用另一个加密函数,如ElGamal(如c = 980*m (mod 1009)
)
139 -> 980 * 139 = 5 (mod 1009) -> 005 (fill to 3 digit)
696 -> 980 * 696 = 1005 (mod 1009) -> 1005
因此,如果我们找到m[i] == "005"
,我们就无法预测它之前的加密块是"005"
还是"1005"
。
我们如何在Java中正确编码/解码密文?
答案 0 :(得分:2)
解决方案是:
加密后:
解密前:
但是通过这个解决方案,它可以获得不必要的' 0'加密消息中的数字,如果所有加密块只有3位数...
答案 1 :(得分:0)
这些基本密码的问题在于它们未定义为处理大量(二进制)数据。现代密码只是存储二进制,它们与modes of operation和填充模式相结合,以处理几乎任意长度的数据。此外,非对称密码几乎总是在hybrid cryptosystem中使用,这使得它们也可以处理任意大小的数据。
凯撒密码是一种在字母表中定义的移位密码。应用它的简单和历史正确的方法是通过在同一字母表中指定密文。你不应该使用数字代表它。
对于ElGamal,可以使用任何编码一组数字的方法,只要该方法能够区分数字即可。使用左边填充的数字as suggested只是一种方式。也可以将它们编码为固定大小的二进制(这是例如RSA使用的,参见PKCS#1 specifications)。
作为文本,可能最简单的方法是简单地使用分隔符和可能的空格以便于阅读。然后,您只需使用String.split(",\\s*")
来检索数字。为了简化生活,您可以使用AbstractCollection.toString()表示列表,或Arrays.toString(int[])表示数组(注意额外的括号)。这可能是这里描述的玩具密码的最佳选择。
编码/解码示例:
public class ToyCiphertextCodec {
private ToyCiphertextCodec() {
// nothin' to do here
}
public static ToyCiphertextCodec getInstance() {
return new ToyCiphertextCodec();
}
public String encode(int[] ciphertext) {
// this is relatively lazy, probably better off creating the
// encoding yourself if you are using this "in the field"
return Arrays.toString(ciphertext);
}
public int[] decode(String encodedCiphertext) {
if (!encodedCiphertext.startsWith("[") || !encodedCiphertext.endsWith("]")) {
throw new IllegalArgumentException("Ciphertext encoding invalid");
}
String encodedCiphertextWithoutBrackets = encodedCiphertext.substring(1, encodedCiphertext.length() - 1);
String[] numbers = encodedCiphertextWithoutBrackets.split(", ");
int[] intermediateResult = new int[numbers.length];
for (int i = 0; i < numbers.length; i++) {
intermediateResult[i] = Integer.parseInt(numbers[i]);
}
return intermediateResult;
}
public static void main(String[] args) {
ToyCiphertextCodec t = ToyCiphertextCodec.getInstance();
int[] ciphertext = { 1, 2, 3 };
String encodedCiphertext = t.encode(ciphertext);
System.out.println(encodedCiphertext);
int[] decodedCiphertext = t.decode(encodedCiphertext);
System.out.println(Arrays.equals(ciphertext, decodedCiphertext));
}
}
只是为了好玩:
import java.util.Arrays;
public class ToyCiphertextCodecWithModulus {
private final int sizeOfNumbers;
private final String staticallySizedNumberFormat;
private ToyCiphertextCodecWithModulus(int sizeOfNumbers) {
this.sizeOfNumbers = sizeOfNumbers;
this.staticallySizedNumberFormat = "%0" + sizeOfNumbers + "d";
}
public static ToyCiphertextCodecWithModulus getInstanceForModulus(int n) {
int largestNumberOfDigits = String.valueOf(n - 1).length();
return new ToyCiphertextCodecWithModulus(largestNumberOfDigits);
}
public String encode(int[] ciphertext) {
StringBuilder sb = new StringBuilder(ciphertext.length * sizeOfNumbers);
for (int i = 0; i < ciphertext.length; i++) {
sb.append(String.format(staticallySizedNumberFormat, ciphertext[i]));
}
return sb.toString();
}
public int[] decode(String encodedCiphertext) {
if (encodedCiphertext.length() % sizeOfNumbers != 0) {
throw new IllegalArgumentException("Ciphertext encoding invalid");
}
int numbers = encodedCiphertext.length() / sizeOfNumbers;
int[] intermediateResult = new int[numbers];
for (int i = 0; i < numbers; i++) {
String number = encodedCiphertext.substring(i * sizeOfNumbers, (i + 1) * sizeOfNumbers);
intermediateResult[i] = Integer.parseInt(number);
}
return intermediateResult;
}
public static void main(String[] args) {
ToyCiphertextCodecWithModulus t = ToyCiphertextCodecWithModulus.getInstanceForModulus(997);
int[] ciphertext = { 1, 2, 3 };
String encodedCiphertext = t.encode(ciphertext);
System.out.println(encodedCiphertext);
int[] decodedCiphertext = t.decode(encodedCiphertext);
System.out.println(Arrays.equals(ciphertext, decodedCiphertext));
}
}