如何分割和加入加密消息?

时间:2014-10-24 05:03:26

标签: java encryption

加密和解密算法通常带有“基数”值,例如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中正确编码/解码密文?

2 个答案:

答案 0 :(得分:2)

解决方案是:

加密后

  1. 将邮件拆分为3(数字)块;
  2. 最多填充4位加密块。
  3. 解密前

    1. 将加密的邮件拆分为4个块;
    2. 填写最多3位数的解密块。
    3. 但是通过这个解决方案,它可以获得不必要的' 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));
    }
}