OpenSSL常用函数分类索引
内存管理
void *OPENSSL_malloc(size_t num)
void *OPENSSL_zalloc(size_t num)
void *OPENSSL_realloc(void *addr, size_t num)
void *OPENSSL_memdup(void *data, size_t s)
void OPENSSL_free(void *addr)
char *OPENSSL_strdup(const char *str)
char *OPENSSL_strndup(const char *str, size_t s)
size_t OPENSSL_strlcat(char *dst, const char *src, size_t size);
size_t OPENSSL_strlcpy(char *dst, const char *src, size_t size);
void *OPENSSL_clear_realloc(void *p, size_t old_len, size_t num)
void OPENSSL_clear_free(void *str, size_t num)
void OPENSSL_cleanse(void *ptr, size_t len);
抽象IO库BIO
二进制数据与字符串互转
与16进制字符串互转
unsigned char *OPENSSL_hexstr2buf(const char *str, long *len);
char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len);
int OPENSSL_hexchar2int(unsigned char c);
与base64字符串互转
#include <openssl/evp.h>
EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void);
void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx);
int EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX *dctx, EVP_ENCODE_CTX *sctx);
int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx);
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl);
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl);
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
哈希算法
MD5/MD4/MD2
-
一步式操作
unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md);
-
三段式操作
int MD5_Init(MD5_CTX *c); int MD5_Update(MD5_CTX *c, const void *data, unsigned long len); int MD5_Final(unsigned char *md, MD5_CTX *c);
SHA1/SHA224/SHA256/SHA384/SHA512
-
一步式操作
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
-
三段式操作
int SHA1_Init(SHA_CTX *c); int SHA1_Update(SHA_CTX *c, const void *data, size_t len); int SHA1_Final(unsigned char *md, SHA_CTX *c);
对称加密
DES加解密
DES加解密模式参考man des_modes
命令
常用的模式有:
1. ecb
2. cbc
DES加解密相关API参考man DES_random_key
命令
加密过程有:
1. 单次加密:DES_ecb_encrypt 和 DES_xxx_encrypt
2. 双密码三次加密:DES_ecb2_encrypt 和 DES_ede2_xxx_encrypt
3. 三密码三次加密:DES_ecb3_encrypt 和 DES_ede3_xxx_encrypt
其中xxx是加密模式,对于cbc单次加密,应使用DES_ncbc_encrypt
密码每个字节的LSB是校验位,一组密码8个字节除了校验位,有效位只有56位,双密码是112位,三密码就是168位;
使用DES加密需要选择加密模式、加密过程、设置密钥,对使用初始向量的加密模式还需要设置初始向量,加密模式加密过程通常为双方约定,密钥和初始向量则通过握手过程协商获得或通过其他渠道获得。
使用步骤:
生成或者获取密钥:
void DES_random_key(DES_cblock *ret);
需要从密码字符串生成密钥,推荐使用hash算法,而不是用DES_string_to_key或DES_string_to_2key
根据需要对密钥设置奇校验
void DES_set_odd_parity(DES_cblock *key);
根据需要检查密钥强度
int DES_is_weak_key(const_DES_cblock *key);
由密钥生成key_schedule
int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule);
void DES_set_key_unchecked(const_DES_cblock *key, DES_key_schedule *schedule);
对于需要初始向量的加密模式,还需要选择或生成初始向量
执行加解密
void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output,
DES_key_schedule *ks, int enc);
void DES_ecb2_encrypt(const_DES_cblock *input, DES_cblock *output,
DES_key_schedule *ks1, DES_key_schedule *ks2, int enc);
void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
DES_key_schedule *ks1, DES_key_schedule *ks2,
DES_key_schedule *ks3, int enc);
void DES_ncbc_encrypt(const unsigned char *input, unsigned char *output,
long length, DES_key_schedule *schedule, DES_cblock *ivec,
int enc);
void DES_ede2_cbc_encrypt(const unsigned char *input, unsigned char *output,
long length, DES_key_schedule *ks1,
DES_key_schedule *ks2, DES_cblock *ivec, int enc);
void DES_ede3_cbc_encrypt(const unsigned char *input, unsigned char *output,
long length, DES_key_schedule *ks1,
DES_key_schedule *ks2, DES_key_schedule *ks3,
DES_cblock *ivec, int enc);
其他对称加密算法还有AES、Blowfish、CAST、IDEA、RC2、RC5,都支持电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)四种常用的分组密码加密模式。其中,AES使用的加密反馈模式(CFB)和输出反馈模式(OFB)分组长度是128位,其它算法使用的则是64位。
以上都是分组加密算法,分组加密每次计算需要一种数据(64位或128位),对于最后一组数据位数不够时根据约定补padding,中间过程如果数据不够需要等待。下面介绍的是流式加密算法RC4
RC4加解密
生成密钥
void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
数据加解密
void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata,
unsigned char *outdata);
大数操作BN
BN与字符串互转
char *BN_bn2hex(const BIGNUM *a);
char *BN_bn2dec(const BIGNUM *a);
int BN_hex2bn(BIGNUM **a, const char *str);
int BN_dec2bn(BIGNUM **a, const char *str);
BN与二进制内存数据互转
int BN_bn2bin(const BIGNUM *a, unsigned char *to);
int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
BN输出到文件
int BN_print(BIO *fp, const BIGNUM *a);
int BN_print_fp(FILE *fp, const BIGNUM *a);
PEM文件操作
PEM格式密钥保存和读取
int PEM_write_RSAPrivateKey(FILE *fp, RSA *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u);
int PEM_write_bio_RSAPrivateKey(BIO *bp, RSA *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u);
int PEM_write_RSAPublicKey(FILE *fp, RSA *x);
int PEM_write_bio_RSAPublicKey(BIO *bp, RSA *x);
int PEM_write_RSA_PUBKEY(FILE *fp, RSA *x);
int PEM_write_bio_RSA_PUBKEY(BIO *bp, RSA *x);
RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **x,
pem_password_cb *cb, void *u);
RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **x,
pem_password_cb *cb, void *u);
RSA *PEM_read_RSAPublicKey(FILE *fp, RSA **x,
pem_password_cb *cb, void *u);
RSA *PEM_read_bio_RSAPublicKey(BIO *bp, RSA **x,
pem_password_cb *cb, void *u);
RSA *PEM_read_RSA_PUBKEY(FILE *fp, RSA **x,
pem_password_cb *cb, void *u);
RSA *PEM_read_bio_RSA_PUBKEY(BIO *bp, RSA **x,
pem_password_cb *cb, void *u);
EVP接口
int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u);
int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x,
const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u);
int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u);
int PEM_write_bio_PUBKEY(BIO *bp, EVP_PKEY *x);
int PEM_write_PUBKEY(FILE *fp, EVP_PKEY *x);
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x,
pem_password_cb *cb, void *u);
EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x,
pem_password_cb *cb, void *u);
EVP_PKEY *PEM_read_bio_PUBKEY(BIO *bp, EVP_PKEY **x,
pem_password_cb *cb, void *u);
EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
pem_password_cb *cb, void *u);
非对称加密
RSA加解密
生成密钥
int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes, BIGNUM *e, BN_GENCB *cb);
密钥参数打印
int RSA_print(BIO *bp, RSA *x, int offset);
int RSA_print_fp(FILE *fp, RSA *x, int offset);```
密钥的提取和指定
void RSA_get0_key(const RSA *r,
const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
有了公钥和私钥数据n,e,d,就可以结合BN(BIGNUM)相关函数做任意格式的保存;但经常使用的方法是配合使用PEM相关的API来保存和读取公钥与私钥数据
密钥的保存和读取
参考前面PEM格式密钥保存和读取
检测私钥是否正确
#include <openssl/rsa.h>
int RSA_check_key_ex(RSA *rsa, BN_GENCB *cb);
int RSA_check_key(RSA *rsa);
加解密
#include <openssl/rsa.h>
int RSA_public_encrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int RSA_private_decrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
以下私钥加密,公钥解密方法通常用于签名
#include <openssl/rsa.h>
int RSA_private_encrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int RSA_public_decrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
签名和验签
#include <openssl/rsa.h>
int RSA_sign(int type, const unsigned char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
int RSA_verify(int type, const unsigned char *m, unsigned int m_len,
unsigned char *sigbuf, unsigned int siglen, RSA *rsa);