mbedtls學習筆記 AES GCM
標簽: mbedtls
AES-GCM算法簡介
AES是一種對稱加密算法,GCM是對該對稱加密采用Counter模式,并帶有GMAC消息認證碼。
AES-GCM算法是帶認證和加密的算法,同時可以對給定的原文,生成加密數據和認證碼。參數如下:
1)帶加密的原文、2)存儲加密后密文、3)IV向量、4)生成的消息驗證碼tag、5)額外的消息認證數據aad,通信雙方需要共享。
Ek | 使用**k對輸入做對稱加密運算 |
---|---|
XOR | 異或運算 |
Mh | 將輸入與**h在有限域GF(2^128)上做乘法 |
分組密碼模式
-
ECB(Electronic Codebook)電子密碼本模式
將明文進行分組,分組長度可為128,256,或512bits。采用ECB模式的分組密碼算法加密過程如下圖:
-
CBC(cipher block chaining)密碼分組鏈接模式
每一組明文在加密前都與前面的密文分組進行異或操作,由于第一個明文分組前面沒有密文分組所以需要準備一個與密文分組長度相同的比特序列來代替密文分組,這個比特序列被稱作初始化向量IV。
-
PKCS7填充方案
ECB、CBC模式中需要進行填充,常用的是PKCS7填充方案,以AES-CBC為例,分組長度16字節,若明文28字節,則需要在明文末尾填充4字節的04,若待明文明文長度是16字節,則需要額外填充16字節的16,解密后取最后一個明文字節的值,比如是x,則要去掉尾部x字節后才是真正明文消息。
-
CTR ( CounTeR 計數器模式)
CTR模式使用與明文長度相同的計數值參與運算,通過加密計數值來產生**流,然后讓**流與明文進行異或操作來加密明文。加入最后一個明文長度不是分組長度整數被,則對**流截取明文長度后異或加密,所以這種方式不需要對明文分組進行填充。(ECB、CBC需要填充)
計數器模式下,每次與明文分組進行XOR的比特序列是不同的,因此,計數器模式解決了ECB模式中,相同的明文會得到相同的密文的問題。CBC,CFB,OFB模式都能解決這個問題,但CTR的另兩個優點是:1)支持加解密并行計算,可事先進行加解密準備;2)錯誤密文中的對應比特只會影響明文中的對應比特等優點。
但CTR仍然不能提供密文消息完整性校驗的功能。 -
MAC ( Message Authentication Code, 消息驗證碼)
想要校驗消息的完整性,必須引入另一個概念:消息驗證碼。消息驗證碼是一種與秘鑰相關的單項散列函數。
密文的收發雙發需要提前共享一個秘鑰。密文發送者將密文的MAC值隨密文一起發送,密文接收者通過共享秘鑰計算收到密文的MAC值,這樣就可以對收到的密文做完整性校驗。當篡改者篡改密文后,沒有共享秘鑰,就無法計算出篡改后的密文的MAC值。
如果生成密文的加密模式是CTR,或者是其他有初始IV的加密模式,別忘了將初始的計時器或初始向量的值作為附加消息與密文一起計算MAC。 -
GMAC ( Galois message authentication code mode, 伽羅瓦消息驗證碼 )
對應到上圖中的消息認證碼,GMAC就是利用伽羅華域(Galois Field,GF,有限域)乘法運算來計算消息的MAC值。假設秘鑰長度為128bits, 當密文大于128bits時,需要將密文按128bits進行分組。應用流程如下圖:
-
GCM( Galois/Counter Mode )
GCM中的G就是指GMAC,C就是指CTR。
GCM可以提供對消息的加密和完整性校驗,另外,它還可以提供附加消息的完整性校驗。在實際應用場景中,有些信息是我們不需要保密,但信息的接收者需要確認它的真實性的,例如源IP,源端口,目的IP,IV,等等。因此,我們可以將這一部分作為附加消息加入到MAC值的計算當中。下圖的Ek表示用對稱秘鑰k對輸入做AES運算。最后,密文接收者會收到密文、IV(計數器CTR的初始值)、MAC值。
AES-128-GCM的例子
#define MBEDTLS_CONFIG_H
/* System support */
#define MBEDTLS_HAVE_ASM
/* mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_GCM_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_PKCS5_C
/* Save RAM at the expense of ROM */
#define MBEDTLS_AES_ROM_TABLES
#include "link_key.h"
#include <stdio.h>
#include <string.h>
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform.h"
#include "mbedtls/md.h"
#include "mbedtls/pkcs5.h"
#include "mbedtls/gcm.h"
#include "mbedtls/pk.h"
#include "mbedtls/timing.h"
#define LINK_KEY_RANDOM_LEN 16
#define IV_LEN 12
#define TAG_LEN 16
#define ADD_LEN 4
uint8_t keyFactor1[LINK_KEY_RANDOM_LEN];
uint8_t keyFactor2[LINK_KEY_RANDOM_LEN];
uint8_t rootKey[LINK_KEY_RANDOM_LEN];
uint8_t tagBuf[TAG_LEN];
uint8_t IV[IV_LEN];
static const uint8_t addition[ADD_LEN] = {0xfe, 0xa5, 0x5a, 0xef};
static void dump_buf(char *info, uint8_t *buf, uint32_t len)
{
mbedtls_printf("%s", info);
for (int i = 0; i < len; i++) {
mbedtls_printf("%s%02X%s", i % 16 == 0 ? "\n ":" ",
buf[i], i == len - 1 ? "\n":"");
}
}
static int timer_entropy_poll(void *data, uint8_t *output, size_t len, size_t *olen)
{
unsigned long timer = mbedtls_timing_hardclock();
((void) data);
*olen = 0;
if( len < sizeof(unsigned long) )
return( 0 );
memcpy( output, &timer, sizeof(unsigned long) );
*olen = sizeof(unsigned long);
return( 0 );
}
static int GenRandom(const uint8_t *custom, uint8_t * out, size_t out_len)
{
int ret = 0;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_add_source(&entropy, timer_entropy_poll, NULL,
MBEDTLS_ENTROPY_MAX_GATHER,
MBEDTLS_ENTROPY_SOURCE_STRONG);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, custom, strlen(custom));
if (ret != 0)
goto cleanup;
ret = mbedtls_ctr_drbg_random(&ctr_drbg, out, out_len);
cleanup:
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return ret;
}
int GenKeyComponent(void)
{
int ret;
const uint8_t *factor1 = "keyFactor1";
const uint8_t *factor2 = "keyFactor2";
ret = GenRandom(factor1, keyFactor1, LINK_KEY_RANDOM_LEN);
if (ret != 0)
goto exit;
ret = GenRandom(factor2, keyFactor2, LINK_KEY_RANDOM_LEN);
if (ret != 0)
goto exit;
exit:
return ret;
}
void GenRootAesKey(void)
{
mbedtls_md_context_t md_ctx;
const mbedtls_md_info_t *info_sha256;
const uint8_t *randomkey = "rootkey";
uint8_t password[LINK_KEY_RANDOM_LEN] = {0};
uint8_t salt[LINK_KEY_RANDOM_LEN];
mbedtls_md_init(&md_ctx);
info_sha256 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
if( info_sha256 == NULL )
{
return;
}
if(mbedtls_md_setup( &md_ctx, info_sha256, 1 )!= 0)
{
return;
}
GenRandom(randomkey, password, LINK_KEY_RANDOM_LEN);
for (int i = 0; i < LINK_KEY_RANDOM_LEN; i++)
{
salt[i] = keyFactor1[i]^keyFactor2[i];
}
mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, salt, LINK_KEY_RANDOM_LEN, salt, LINK_KEY_RANDOM_LEN, 1, LINK_KEY_RANDOM_LEN, rootKey);
mbedtls_md_free(&md_ctx);
}
void AesGcmEncryptFunction(uint8_t *out, const uint8_t *in, uint32_t len)
{
mbedtls_gcm_context ctx;
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
uint32_t keybit = LINK_KEY_RANDOM_LEN * 8;
mbedtls_gcm_init(&ctx);
mbedtls_gcm_setkey(&ctx, cipher, rootKey, keybit);
GenRandom("mbedtls_IV", IV, IV_LEN);
mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT, len, IV, IV_LEN, addition, ADD_LEN, in, out, TAG_LEN, tagBuf);
mbedtls_gcm_free(&ctx);
}
void AesGcmDecryptFunction(uint8_t *out, const uint8_t *in, uint32_t len)
{
mbedtls_gcm_context ctx;
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
uint32_t keybit = LINK_KEY_RANDOM_LEN * 8;
mbedtls_gcm_init(&ctx);
mbedtls_gcm_setkey(&ctx, cipher, rootKey, keybit);
int ret = mbedtls_gcm_auth_decrypt(&ctx, len, IV, IV_LEN, addition, ADD_LEN, tagBuf, TAG_LEN, in, out);
mbedtls_gcm_free(&ctx);
}
int main(void)
{
uint8_t out[32];
uint8_t deout[32];
uint8_t rsaEn[512] = {0};
uint8_t rsaDe[32] = {0};
//uint8_t randomOut[16];
const uint8_t *buff = "CXF123CAIXUEFNEG4561lj398709f03caix3245-0i@(@()%*U13456454D5234@¥%%g";
int j = 0;
for (int i = 0; i < 10; i++)
{
uint8_t in[32];
memcpy(in, buff+2*j, 31);
GenKeyComponent();
GenRootAesKey();
AesGcmEncryptFunction(out, in, 31);
AesGcmDecryptFunction(deout, out, 31);
mbedtls_printf("%d:%s\n", i, deout);
}
return 0;
}
智能推薦
STM32使用mbedtls的AES加密
Author:果果小師弟 電子信息專業在讀研究生 有一點思考,有一點想法,有一點理性! 定個小小目標,努力成為習慣!在最美的年華遇見更好的自己! CSDN@果果小師弟,CSDN首發,果果原創 唯一博客更新的地址為: 果果小師弟的博客 一、安裝mbedtls 轉到keil官網http://www.keil.com/dd2/pack/ 找到ARM mbed Cryptographic and SSL/...
python關于AES加密學習
一、什么是AES加密 https://blog.csdn.net/weixin_40117614/article/details/93018940 一、定義 密碼學中的高級加密標準(Advanced Encryption Standard,AES),又稱Rijndael加密法,是美國聯邦政府采用的一種區塊加密標準。 二、加密方式及參數 1、** **是AES算法實現加密和解密的根本。對稱加密算法之...
AutoJs學習-AES加解密
往期文章分享 點擊跳轉=>《導航貼》- Unity手冊,系統實戰學習 點擊跳轉=>《導航貼》- Android手冊,重溫移動開發 ??關于作者 眾所周知,人生是一個漫長的流程,不斷克服困難,不斷反思前進的過程。在這個過程中會產生很多對于人生的質疑和思考,于是我決定將自己的思考,經驗和故事全部分享出來,以此尋找共鳴 !!! 專注于Android/Unity和各種游戲開發技巧,以及各種資源...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...