int mbedtls_pkcs5_pbkdf2_hmac(
mbedtls_md_context_t* context,
const unsigned char* password,
size_t passwordLength,
const unsigned char* salt,
size_t saltLength,
unsigned int iterationCount,
uint32_t outputLength,
unsigned char* output
)
PBKDF2算法
mbedtls_md_context_t
的定义:
typedef enum {
MBEDTLS_MD_NONE=0, /**< None. */
MBEDTLS_MD_MD2, /**< The MD2 message digest. */
MBEDTLS_MD_MD4, /**< The MD4 message digest. */
MBEDTLS_MD_MD5, /**< The MD5 message digest. */
MBEDTLS_MD_SHA1, /**< The SHA-1 message digest. */
MBEDTLS_MD_SHA224, /**< The SHA-224 message digest. */
MBEDTLS_MD_SHA256, /**< The SHA-256 message digest. */
MBEDTLS_MD_SHA384, /**< The SHA-384 message digest. */
MBEDTLS_MD_SHA512, /**< The SHA-512 message digest. */
MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */
} mbedtls_md_type_t;
typedef struct {
const char* name; /** Name of the message digest */
mbedtls_md_type_t type; /** Digest identifier */
unsigned char size; /** Output length of the digest function in bytes */
unsigned char block_size; /** Block length of the digest function in bytes */
} mbedtls_md_info_t;
typedef struct mbedtls_md_context_t {
/** Information about the associated message digest. */
const mbedtls_md_info_t *md_info;
void *md_ctx; /** The digest-specific context. */
void *hmac_ctx; /** The HMAC part of the context. */
} mbedtls_md_context_t;
const unsigned char *password
是密码
的字节数据
。C语言中没有其他语言中的byte
类型,C语言中表达byte
类型就是用unsigned char
,unsigned char
的意思就是告诉编译器, 不要把我的最高位当成符号位,这样这8bit
就都表示真实的数据了。
size_t
的定义:
typedef long unsigned int __darwin_size_t;
typedef __darwin_size_t size_t;
size_t passwordLength
是const unsigned char* password
的大小,单位是字节
。
const unsigned char* salt
是盐
的字节数据
。
size_t saltLength
是const unsigned char* salt
的大小,单位是字节
。
unsigned int iterationCount
是迭代次数。迭代次数越多,产生输出的速度越慢,破解的难度也越大。
unsigned char* output
是输出
的字节数据
。 其长度是uint32_t outputLength
,它的最大值为0xFFFFFFFF
。
0
表示成功。
非0
表示失败。错误码定义如下:
#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /** The selected feature is not available. */
#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /** Bad input parameters to function. */
#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /** Failed to allocate memory. */
#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /** Opening or reading of file failed. */
#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA -0x2f80 /** Bad input parameters to function. */
#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 /** Unexpected ASN.1 data. */
#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 /** Requested encryption or digest alg not available. */
#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 /** Given private key password does not allow for correct decryption. */
step1、创建一个项目目录和存放源码的目录PBKDF2/mbedtls
,并进入该目录
mkdir -p PBKDF2/mbedtls && cd PBKDF2/mbedtls
step2、使用curl命令下载代码
BRANCH=development
BASE_URL_H=https://raw.githubusercontent.com/ARMmbed/mbedtls/$BRANCH/include/mbedtls
BASE_URL_C=https://raw.githubusercontent.com/ARMmbed/mbedtls/$BRANCH/library
for item in pkcs5.h sha256.h md.h md_internal.h platform_util.h platform.h threading.h error.h
do
curl -LO "$BASE_URL_H/$item"
done
for item in pkcs5.c sha256.c md.c platform_util.c platform.c threading.c error.c
do
curl -LO "$BASE_URL_C/$item"
done
step3、编写一个config.h
文件,其内容如下
#define MBEDTLS_PKCS5_C
#define MBEDTLS_MD_C
#define MBEDTLS_SHA256_C
注意:此例中,我们只与SHA-256联合使用。要与其他哈希函数联合使用的话,定义对应的宏
,并下载对应的代码。
| md5.h |
| ripemd160.h |
| sha1.h |
| sha256.h |
| sha512.h |
step4、将代码中的mbedtls/
字符串去掉
sed -i 's@mbedtls/@@g' * 2> /dev/null ||
sed -i "" 's@mbedtls/@@g' *
step5、进入目录PBKDF2
cd ..
step6、编写一个C语言源程序hamcTest.c
,其内容如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "mbedtls/pkcs5.h"
#define OUTPUT_LENGTH_IN_BYTES 32
#define BASE_16_OUTPUT_LENGTH_IN_BYTES 32 * 2 + 1
#define ITERATION_COUNT 1000
void showHelp() {
printf("usage: pbkdf2 <option> <PASSWORD> <SALT>\n");
printf("option: -x lower case, default true\n");
printf(" -X upper case\n");
printf("example:pbkdf2 -X 123456 abcdefg\n");
exit(1);
}
void base16(unsigned char input[OUTPUT_LENGTH_IN_BYTES], char* output, bool isToUpper) {
const char* format = isToUpper ? "%02X" : "%02x";
char tmp[3] = {0};
for(int i = 0; i < OUTPUT_LENGTH_IN_BYTES; i++) {
sprintf(tmp, format, input[i]);
strcat(output, tmp);
}
}
void performPBKDF2_HMAC_SHA256(char* password, char* salt, bool isToUpper) {
unsigned char output[OUTPUT_LENGTH_IN_BYTES] = {0};
mbedtls_md_context_t md_context;
mbedtls_md_init(&md_context);
extern const mbedtls_md_info_t mbedtls_sha256_info;
int resultCode = mbedtls_md_setup(&md_context, &mbedtls_sha256_info, 1);
if (0 == resultCode) {
resultCode = mbedtls_pkcs5_pbkdf2_hmac(&md_context, (unsigned char*)password, strlen(password), (unsigned char*)salt, strlen(salt), ITERATION_COUNT, OUTPUT_LENGTH_IN_BYTES, output);
if (0 == resultCode) {
mbedtls_md_free(&md_context);
//为了便于比较,通常会把字节数据用base16编码
char base16Encoded[BASE_16_OUTPUT_LENGTH_IN_BYTES] = {0};
base16(output, base16Encoded, isToUpper);
printf("pbkdf2_hmac_sha256(password=%s,salt=%s)=%s\n", password, salt, base16Encoded);
return;
}
}
printf("occrued error, code is %d\n", resultCode);
}
int main(int argc, char* argv[]) {
if (4 == argc) {
if (strcmp("-x", argv[1]) == 0) {
performPBKDF2_HMAC_SHA256(argv[2], argv[3], false);
} else if (strcmp("-X", argv[1]) == 0) {
performPBKDF2_HMAC_SHA256(argv[2], argv[3], true);
} else {
showHelp();
}
}
return 0;
}
step7、使用cc命令进行编译
cc -o pbkdf2Test pbkdf2Test.c mbedtls/*.c
step8、运行pbkdf2Test
./pbkdf2Test -x 123456 abc
pbkdf2_hmac_sha256(password=123456,salt=abc)=d4c3fa431418d704a43b48f699c6ee0eecf55754891455d95500a69aa1228efa
./pbkdf2Test -X 123456 abc
pbkdf2_hmac_sha256(password=123456,salt=abc)=D4C3FA431418D704A43B48F699C6EE0EECF55754891455D95500A69AA1228EFA
step9、在浏览器中运行下面的HTML代码,看看结果是否一样:
<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
<script>
var password = '123456';
var salt = 'abc';
var iterations = 1000;
var dklength = 256;
var key = CryptoJS.PBKDF2(password, salt, {hasher:CryptoJS.algo.SHA256, iterations: iterations, keySize: dklength/32}).toString(CryptoJS.enc.Hex);
document.write("pbkdf2_hmac_sha256(password=123456,salt=abc)=" + key);
</script>
source code on GitHub