如何使用C中的crypt库进行DES加密? (设置密钥、加密、加密等)

发布于 2024-08-04 19:57:47 字数 804 浏览 1 评论 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;
}

I need to do some simple DES encryption in C to interface with some old code. From what I understand you can use the "crypt" library for this, with the functions setkey, encrypt, crypt, etc. I have been messing with it and can't get it right. The example on the man page for setkey/encrypt is lacking.

I want to get the same output as I would be able to get with some java code (see below).

So let's say I have two character arrays in C.

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

Can someone give an example of how to encrypt these with setkey/encrypt and get the same result as I would from the java code? I realize you have to put message and key into a 64-byte array where each char represents a bit, but some of that is confusing too. Apparently you have to get the bit parity right on that too or something?

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

逆蝶 2024-08-11 19:57:47

由于您仅使用字符串 "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;
}

Because you're calling Cipher.getInstance with just the string "DES", you're not specifying a cipher mode or padding method. This means you get the defaults, which depends on what Java cryptography provider you're using - you need to know exactly what they are to write compatible C. (You really should be specifying them rather than relying on defaults).

If you're using the SunJCE provider, then the defaults for DES are ECB mode and PKCS #5 padding. The best way to do this is probably to use OpenSSL or another meaty crypto library - but if you want to use functions that are usually found in the standard C library on UNIX-type platforms, the ecb_crypt family of functions is going to be a lot easier to work with than the setkey / encrypt family.

You will need to add PKCS#5 padding when encrypting, and check it (and discard it) when decrypting). The following ecb_pkcs5_encrypt function should do the rough equivalent of the above Java code using those functions.

/* 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;
}
剩一世无双 2024-08-11 19:57:47

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

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

如果你确实必须使用 crypt,Sun 的 JRE 附带了一个类来处理 crypt,

   com.sun.security.auth.module.Crypt

这是内部类,因此没有文档。只需阅读源代码即可。

Don't use crypt(). It uses some non-standard algorithm so it will be very difficult to interoperate with other systems. Besides, DES is not secure anyway.

I suggest you use OpenSSL in C. Most of its ciphers are compatible with JCE.

If you really have to use crypt, Sun's JRE comes with a class to handle crypt,

   com.sun.security.auth.module.Crypt

This is internal class so the documentation isn't there. Just read the source code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文