【问题标题】:How do you use the crypt library in C for DES encryption? (setkey, encrypt, crypt, etc.)您如何使用 C 中的 crypt 库进行 DES 加密? (setkey、encrypt、crypt 等)
【发布时间】:2009-09-14 14:08:22
【问题描述】:

我需要在 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;
}

【问题讨论】:

    标签: java c encryption des


    【解决方案1】:

    因为您只使用字符串"DES" 调用Cipher.getInstance,所以您没有指定密码模式或填充方法。这意味着您获得默认值,这取决于您使用的 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;
    }
    

    【讨论】:

    • 感谢您的详细回答,这正是我想要的。
    【解决方案2】:

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

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

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

       com.sun.security.auth.module.Crypt
    

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

    【讨论】:

    • crypt() 不是libcrypt,这就是问题所在。
    • 通常 libcrypt 指的是带有 encrypt()/setkey() 的 DES crypt() 实现。该库由 David Burren 编写。你在说另一个吗?
    最近更新 更多