使用 libTomCrypt 实现 AES、HMAC、HKDF 运算

56 篇文章 5 订阅
42 篇文章 2 订阅
使用 libTomCrypt 实现 AES、HMAC、HKDF 运算

Qidi 2017.11.06 (Markdown & Haroopad)


1、libTomCrypt 简介

libTomCrypt 是一个使用 C 语言编写的开源加解密算法库,使用 WTF 协议进行授权,支持 AES、HMAC、HKDF、RSA、PRNG、BASE64 等常用加解密算法。


2、基础文件

我们在使用 libTomCrypt 时会发现,调用某一类算法时总是要依赖几个特定头文件和源文件。我称这些头文件/源文件为该类算法的基础文件。
  对于 AES 算法来说,这些基础文件是:

tomcrypt.h    tomcrypt_argchk.h    tomcrypt_cipher.h
aes.c    aes_tab.c    compare_testvector.c
crypt_argchk.c    crypt_cipher_descriptor.c    crypt_cipher_is_valid.c
crypt_find_cipher.c    crypt_register_cipher.c    crypt_unregister_cipher.c
zeromem.c

对于 HMAC 和 HKDF 算法来说,这些基础文件是:

tomcrypt.h    tomcrypt_argchk.h    tomcrypt_cipher.h
aes.c    aes_tab.c    compare_testvector.c
crypt_argchk.c    crypt_hash_descriptor.c   crypt_hash_is_valid.c
crypt_find_hash.c    crypt_register_hash.c    crypt_unregister_hash.c
zeromem.c

3、AES 算法调用流程

使用 AES 算法时一般可以分为以下几个步骤:

  • 注册算法描述符:
 register_cipher(&aes_desc);
  • 获取算法描述符:
 idx = find_cipher("aes");
  • 初始化算法结构体:
 XXX_start(idx, IV,
            key, key_len,
            num_rounds,
            symmetric_XXX *XXX);
  • 加密:
 XXX_encrypt(*plain_text, *crypted_text,
              len, symmetric_XXX *XXX);
  • 解密:
 XXX_decrypt(*crypted_text, *plain_text,
              len, symmetric_XXX *XXX);
  • 结束运算:
 XXX_done(symmetric_XXX *XXX);
  • 释放资源:
 zeromem(key, sizeof(key));
 zeromem(XXX, sizeof(XXX));

3.1、实现 AES-128-ECB 加解密

要实现 aes-128-ecb 加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个 ecb 相关的源文件,如下:

ecb_decrypt.c    ecb_done.c
ecb_encrypt.c    ecb_start.c

工程中截取的代码片段如下:

    ...
    symmetric_ECB ecb;
    unsigned char key[MAXBLOCKSIZE] = "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcdef" \
                             "1234567890abcde";
    unsigned char pt[4096] = "Keep it simple and stupid.";    // plain text for encrypting, place your own content here
    unsigned char ct[4096];
    if (register_cipher(&aes_desc) < 0) {
        ALOGE("register_cipher() failed!\n");
        goto exit1;
    }
    int idx = find_cipher("aes");
    if (idx == -1) {
        ALOGE("find_cipher() failed!\n");
        goto exit1;
    }
    if (CRYPT_OK != ecb_start(idx, key, cipher_descriptor[idx].min_key_length, 0, &ecb)) {
        ALOGE("ecb_start() failed!\n");
        goto exit1;
    }
    if (CRYPT_OK != ecb_encrypt(pt, ct, sizeof(pt), &ecb)) {
        ALOGE("ecb_encrypt() failed!\n");
        goto exit1;
    }
#if SHOW_DECRYPT
    if (CRYPT_OK != ecb_decrypt(ct, at, sizeof(at), &ecb)) {
        LOG("ecb_decrypt() failed!\n");
        goto exit1;
    }
#endif
    if (CRYPT_OK != ecb_done(&ecb)) {
        LOG("ecb_done() failed!\n");
        goto exit1;
    }
    ...
exit1:
    ...

3.2、实现 AES-128-CTR 加解密

要实现 aes-128-ctr 加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个 ctr 相关的源文件,如下:

ctr_decrypt.c    ctr_done.c
ctr_encrypt.c    ctr_start.c

工程中截取的代码片段如下:

    ...
    if (register_cipher(&aes_desc) < 0) {
        ALOGE("Qidi - aes-128-ctr register_cipher() failed!\n");
        goto error;
    }
    idx = find_cipher("aes");
    if (idx == -1) {
        ALOGE("Qidi - aes-128-ctr find_cipher() failed!\n");
        goto error;
    }
    err = ctr_start(idx, session_iv, session_key, 16, 0, CTR_COUNTER_BIG_ENDIAN, &ctr);
    if (err != CRYPT_OK) {
        ALOGE("Qidi - ctr_start() failed!\n");
        goto error;
    }
    err = ctr_encrypt((unsigned char*)input_raw, buf, 16, &ctr);
    if (err != CRYPT_OK) {
        ALOGE("Qidi - ctr_encrypt() failed!\n");
        goto error;
    }
    // ctr 解密前需要再 start 初始化一次
    err = ctr_start(idx, session_iv, session_key, 16, 0, CTR_COUNTER_BIG_ENDIAN, &ctr);
    if (err != CRYPT_OK) {
        ALOGE("Qidi - ctr_start() failed!\n");
        goto error;
    }
    memset(input_raw, 0, 16);
    err = ctr_decrypt((unsigned char *)output_raw, (unsigned char *)input_raw, 16, &ctr);
    if (err != CRYPT_OK) {
        ALOGE("Qidi - ERROR: ctr_decrypt() failed!\n");
        goto error;
    }
    ctr_done(&ctr);
    ...
error:
    ...

4、HASH 算法一般调用流程

使用 HASH 算法时,一般可以分为以下几个步骤:

  • 注册算法描述符:
 register_hash(&aes_desc);
  • 获取算法描述符:
 idx = find_hash("aes");
  • 初始化算法结构体:
 XXX_start(idx, IV,
            key, key_len,
            num_rounds,
            symmetric_XXX *XXX);
  • 加密:
 XXX_encrypt(*plain_text, *crypted_text,
              len, symmetric_XXX *XXX);
  • 解密:
 XXX_decrypt(*crypted_text, *plain_text,
              len, symmetric_XXX *XXX);
  • 结束运算:
 XXX_done(symmetric_XXX *XXX);
  • 释放资源:
 zeromem(key, sizeof(key));
 zeromem(XXX, sizeof(XXX));

4.1、实现 HMAC 运算

要实现 hmac 加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个 hmac 相关的源文件,如下:

hmac_init.c    hmac_process.c
hmac_memory.c  hash_memory.c
hmac_done.c    sha256.c

工程中截取的代码片段如下:

    ...
    if (register_hash(&sha256_desc) < 0) {
        ALOGE("Qidi - ERROR: verify fw_resp register_hash(&sha256_desc) failed!\n");
        goto error;
    }
    int idx = find_hash("sha256");
    if (idx < 0) {
        ALOGE("Qidi - ERROR: verify fw_resp find_hash(sha256) failed!\n");
        goto error;
    }

    if (CRYPT_OK != hmac_memory(idx, (unsigned char*)pre_key, 32,
                               (unsigned char*)in_data, 36,
                                (unsigned char*)fw_resp, &fw_resp_len)) {
        ALOGE("ERROR: verify fw_resp hmac_memory() failed!\n");
        goto error;
    }
    ...
error:
    ...

其中 hmac_memory() 函数实际上是对 hmac_init()hmac_processhmac_done() 的封装。


4.2、实现 HKDF 运算

要实现 hkdf 加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个 hkdf 相关的源文件,如下:

hkdf.c    sha256.c

工程中截取的代码片段如下:

    ...
    register_hash(&sha256_desc);
    int idx = find_hash("sha256");
    ret = hkdf(idx, (unsigned char*)salt, 20,
         (unsigned char*)info, 20, (unsigned char*)in_data, 18, session_key_iv, 32);
    ...

其中 hkdf() 函数实际上是对 hkdf_extract()hkdf_expand() 的封装。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LibTomCrypt is a fairly comprehensive, modular and portable cryptographic toolkit that provides developers with a vast array of well known published block ciphers, one-way hash functions, chaining modes, pseudo-random number generators, public key cryptography and a plethora of other routines. LibTomCrypt has been designed from the ground up to be very simple to use. It has a modular and standard API that allows new ciphers, hashes and PRNGs to be added or removed without change to the overall end application. It features easy to use functions and a complete user manual which has many source snippet examples. LibTomCrypt is free for all purposes under the public domain. This includes commercial use, redistribution and even branching. Sports the following Public domain and open source. Written entirely in portable ISO C source (except for things like RNGs for natural reasons) Builds out of the box on virtually every box. All that is required is GCC for the source to build. Includes a 180+ page user manual in PDF format (with working examples in it) Block Ciphers Ciphers come with an ECB encrypt/decrypt, setkey and self-test interfaces. All ciphers have the same prototype which facilitates using multiple ciphers at runtime. Some of the ciphers are flexible in terms of code size and memory usage. Ciphers Supported. Blowfish XTEA RC5 RC6 SAFER+ Rijndael (aka AES) Twofish SAFER (K64, SK64, K128, SK128) RC2 DES, 3DES CAST5 Noekeon Skipjack Anubis (with optional tweak as proposed by the developers) Khazad KASUMI SEED Chaining Modes Modes come with a start, encrypt/decrypt and set/get IV interfaces. Mode supported. ECB CBC OFB CFB CTR IEEE LRW mode F8 Chaining Mode One-Way Hash Functions Hashes come with init, process, done and self-test interfaces. All hashes use the same prototypes for the interfaces. Hashes supported. MD2 MD4 MD5 SHA-1 SHA-224/256/384/512 TIGER-192 RIPE-MD 128/160/256/320 WHIRLPOOL Message Authenticat
好的,下面是一个 Java 实现的示例,可以用于在 HTTP 请求头部中使用 HMAC-SHA256 加密: ```java import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; public class HmacSha256Example { public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException { String secretKey = "your_secret_key"; // 你的密钥 String message = "your_message_to_sign"; // 要签名的消息 String signature = generateHmacSha256Signature(secretKey, message); System.out.println("HMAC-SHA256 signature: " + signature); } private static String generateHmacSha256Signature(String secretKey, String message) throws NoSuchAlgorithmException, InvalidKeyException { String algorithm = "HmacSHA256"; Mac mac = Mac.getInstance(algorithm); SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), algorithm); mac.init(signingKey); byte[] signatureBytes = mac.doFinal(message.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(signatureBytes); } } ``` 在上述示例中,我们首先定义了一个 `secretKey` 和一个 `message`。然后通过 `generateHmacSha256Signature` 方法,使用 `Mac` 类来实现 HMAC-SHA256 加密。最终,我们通过 Base64 编码将签名结果转换成字符串并返回。 注意,这里的 `secretKey` 和 `message` 都是示例数据,你需要将其替换成你自己的数据。另外,这里使用的是 Java 标准库中的 `javax.crypto` 包,你需要确保你的代码中已经引入了这个包。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值