在不知道密钥的情况下对秘密后缀进行加密解密

时间:2017-03-09 14:42:19

标签: java encryption cryptography

我在密码学中遇到了这个问题。问题是我必须通过在不知道加密密钥的情况下从Oracle查询来找到秘密后缀,k。

我对如何进行加密的信息是在DES下使用ECB模式完成的,使用56位密钥,输入块大小为64位。

所以我的问题是,鉴于上述所有信息,解密的步骤是什么。根据我的研究,我发现攻击者不会只使用给定的密文。所以我想知道在这种情况下是否有可能攻击它?

我给出的主要功能如下:

 public static void main(String[] args) {
    String key = "3%ac^`+=";  // a different key
    String ciphertext = "a(19q-j*"; // a different suffix
    Oracle1 oracle = new Oracle1(key.getBytes(), ciphertext.getBytes());
    Attacker1 attacker = new Attacker1(oracle);
    byte[] res = attacker.decryptCiphertext();
    // should be true
    System.out.println(isConsistent(ciphertext, res));
}

我应该在decryptCiphertext()中执行攻击并将结果作为字节数组返回,然后与给定的密文进行比较。如果比较结果为真,那么它是正确的。

Oracle.java

public class Oracle1 {

private static Logger logger = LoggerFactory.getLogger(Oracle1.class);

final private byte[] SuffixBytes;

private Cipher cipher;
private static String ALGO = Config.ALGO;
private static int BlockSize = getAlgoBlockSize(ALGO);

public Oracle1() {
    this(Config.p1Key, Config.p1Suffix);
}

private void init(byte[] keyBytes) {
    Security.addProvider(new BouncyCastleProvider());
    SecretKey KEY;
    try {
        if (isSizeLegal(keyBytes, ALGO)) {
            KEY = new SecretKeySpec(keyBytes, ALGO);
        } else {
            throw new RuntimeException(String.format("illegal ALGO %s with key length %d", ALGO, keyBytes.length));
        }
        cipher = Cipher.getInstance(String.format("%s/ECB/NoPadding", ALGO));
        cipher.init(Cipher.ENCRYPT_MODE, KEY);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
        System.exit(1);
    }
}

public Oracle1(byte[] keyBytes, byte[] suffixBytes) {
    SuffixBytes = suffixBytes;
    init(keyBytes);
}

public Oracle1(String keyString, String suffixString) {
    byte[] keyBytes = keyString.getBytes();
    SuffixBytes = suffixString.getBytes();
    init(keyBytes);
}

public byte[] compose(String plainText) {
    return compose(plainText.getBytes());
}

public byte[] compose(byte[] bytes) {
    int byteLength = bytes.length;
    if (byteLength > BlockSize) {
        logger.info("input length {} > {}", byteLength, BlockSize);
    }

    byte[] inputBytes = concat(bytes, SuffixBytes);
    byte[] finalBytes = paddingBytes(inputBytes, BlockSize);
    byte[] cipherBytes = new byte[0];
    try {
        cipherBytes = cipher.doFinal(finalBytes);
        logger.info("input:{}\tcipher:{}", finalBytes, cipherBytes);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
        System.exit(1);
    }
    return cipherBytes;
}

}

提前致谢。

1 个答案:

答案 0 :(得分:2)

我们有一个加密Oracle,允许我们发送消息M并返回E(M|S)(意味着加密M + S,其中是后缀)。挑战在于确定S。我假设给出的密钥和后缀是测试数据,以便在尝试“真实”之前测试代码(因为如果我们知道密钥,我们可以自己解密结果)。

由于加密使用的是ECB,因此每个块都是独立加密的。我们可以使用它来确定S

DES的块大小为8个字节。如果我们创建一个7字节长的输入(例如7 0x00字节),那么Oracle将追加S然后加密结果。这意味着生成的密文的第一个块将是

的加密
0x00 0x00 0x00 0x00 0x00 0x00 0x00 X

其中XS的第一个字节。我们记下了这个密文。

如果我们然后发送一系列8字节块,我们改变最终字节,如下所示:

0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x03
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x04
...
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xff

并将它们与未知的密文进行比较,我们将找到匹配的密文。只有256个这样的块,所以这不会花很长时间。然后我们知道后缀的第一个字节。

然后我们可以为下一个字节重复此过程,但是首先我们发送一个6字节的消息,而不是7字节的消息,然后我们使用现在已知的第一个字节构造我们的(最多)256个测试消息,所以如果第一个字节例如是0x55,它们看起来像

0x00 0x00 0x00 0x00 0x00 0x00 0x55 0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x55 0x02
...

重复这一点,我们可以一次确定S个字节。

查看您提供的代码,我认为这个想法可能是您实施Attacker1类,在{{oracle.compose()内多次调用decryptSuffix() 1}}方法。然后,您拥有的main方法将用于测试您的代码。然后,您将提交此类,并将使用“真正的”oracle进行测试。