0

我需要在 C 中做一些简单的 DES 加密来与一些旧代码交互。据我了解,您可以为此使用“crypt”库,以及 setkey、encrypt、crypt 等功能。我一直在弄乱它,无法正确处理。缺少 setkey/encrypt 手册页上的示例。

我想获得与使用一些 java 代码所能获得的相同的输出(见下文)。

所以假设我在 C 中有两个字符数组。

char *message = "hellothe";
char *key = "iamakey0";

有人可以举例说明如何使用 setkey/encrypt 加密这些并获得与 java 代码相同的结果吗?我意识到您必须将消息和密钥放入一个 64 字节的数组中,其中每个字符代表一个位,但其中一些也令人困惑。显然你也必须得到比特奇偶校验或其他什么?

public static byte[] encryptDES(byte[] message, byte[] key) {
    byte[] encrypted = new byte[0];
    try{
        Cipher c = Cipher.getInstance("DES");
        c.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(key,"DES"));
        encrypted = c.doFinal(message);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return encrypted;
}
4

2 回答 2

2

因为您Cipher.getInstance只使用 string 调用,所以"DES"您没有指定密码模式或填充方法。这意味着您获得默认值,这取决于您使用的 Java 加密提供程序 - 您需要确切知道它们是什么才能编写兼容的 C。(您确实应该指定它们而不是依赖默认值)。

如果您使用 SunJCE 提供程序,则 DES 的默认值是 ECB 模式和 PKCS #5 填充。做到这一点的最好方法可能是使用 OpenSSL 或其他丰富的加密库 - 但如果您想使用通常在 UNIX 类型平台上的标准 C 库中找到的函数,那么ecb_crypt函数系列将会容易得多与比setkey/encrypt家人一起工作。

您需要在加密时添加 PKCS#5 填充,并在解密时检查它(并丢弃它)。下面的ecb_pkcs5_encrypt函数应该使用这些函数大致等效于上述 Java 代码。

/* Returns a newly-allocated buffer containing the contents of `data',
 * padded out to a multiple of 8 bytes using PKCS #5 style padding.
 *
 * If `padded_len` is non-NULL, the value it points to is updated to
 * the size of the padded output data.
 *
 * Returns NULL on error.
 */
char *pad_pkcs5(const char *data, size_t data_len, size_t *padded_len)
{
    char *padded_data;
    unsigned padding_len = 8 - (data_len % 8);
    const char padding = padding_len;
    char *pad_ptr;

    /* check for length overflow */
    if (data_len + padding_len < data_len)
        return NULL;

    /* Copy data into a new buffer and pad it out */
    padded_data = malloc(data_len + padding_len);

    if (!padded_data)
        return NULL;

    memcpy(padded_data, data, data_len);

    if (*padded_len)
    {
        *padded_len = data_len + padding_len;
    }

    /* Add the padding bytes */
    pad_ptr = padded_data + data_len;
    while (padding_len--)
    {
        *pad_ptr++ = padding;
    }

    return padded_data;
}

/* Returns a newly-allocated buffer containing the contents of `data',
 * encrypted with `key' using DES/ECB/PKCS5.
 *
 * If `out_len` is non-NULL, the value it points to is updated to
 * the size of the encrypted output data (which will always be a
 * multiple of 8).
 *
 * Returns NULL on error.
 */
char *ecb_pkcs5_encrypt(const char *key, const char *data, size_t data_len, size_t *out_len)
{
    char des_key[8];
    char *padded_data;
    size_t padded_len;
    int status;

    /* One of the few cases where strncpy() is exactly what we want! */
    strncpy(des_key, key, sizeof des_key);
    des_setparity(des_key);

    padded_data = pad_pkcs5(data, data_len, &padded_len);

    if (!padded_data)
        return NULL;

    status = ecb_crypt(des_key, padded_data, padded_len, DES_ENCRYPT);

    if (DES_FAILED(status))
        return NULL;

    if (out_len)
        *out_len = padded_len;

    return padded_data;
}
于 2009-09-14T02:11:46.853 回答
1

不要使用 crypt()。它使用了一些非标准的算法,因此很难与其他系统进行互操作。此外,DES 无论如何也不安全。

我建议您在 C 中使用 OpenSSL。它的大多数密码都与 JCE 兼容。

如果你真的要使用 crypt,Sun 的 JRE 自带了一个类来处理 crypt,

   com.sun.security.auth.module.Crypt

这是内部类,因此文档不存在。只需阅读源代码。

于 2009-09-13T23:14:29.813 回答