1. 程式人生 > >openssl學習之ccm,gcm 模式

openssl學習之ccm,gcm 模式

openssl中添加了對AES ccm 和gcm模式的支援。下面的內容主要是對這兩個模式相關資料的收集以及整理。

一,CCM

CCM (counter with CBC-MAC)定義在分組長度為128位的加密演算法中,如,AES 的分組長度為128。組成AES-CCM演算法的關鍵組成是CTR工作模式以及CMAC認證演算法。Wifi 的WPE協議中使用了AES-CCM。在HMAC中我們介紹CCM是屬於一種E&M(認證並且加密),首先我們來看一下AES-CCM模式的輸入輸出。

首先介紹兩個引數設定:

L:長度域,取值為2~8 ,openssl中預設的為8。

M:tag的長度,合法的值為:4,6,8,10,12,14 和16。openssl中預設的為12

key 16,24,32
None 15-L
Message to authenticate and encrypt len(Msg)
Additional authenticated data len(AAD)
其中對訊息長度有:0<= len(Msg)<= 2^(8L);

對附加資料長度有:0<= len(AAD)< 2^64;

/* Simple AES CCM test program, uses the same NIST data used for the FIPS
 * self test but uses the application level EVP APIs.
 */
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/evp.h>

/* AES-CCM test data from NIST public test vectors */

static const unsigned char ccm_key[] = {
	0xce,0xb0,0x09,0xae,0xa4,0x45,0x44,0x51,0xfe,0xad,0xf0,0xe6,
	0xb3,0x6f,0x45,0x55,0x5d,0xd0,0x47,0x23,0xba,0xa4,0x48,0xe8
};
// 隨機數,每次加密針對相同的KEY使用不同的NONCE。否則會破壞CCM模式的安全性(RFC3610)
static const unsigned char ccm_nonce[] = {
	0x76,0x40,0x43,0xc4,0x94,0x60,0xb7
};
//附加資料
static const unsigned char ccm_adata[] = {
	0x6e,0x80,0xdd,0x7f,0x1b,0xad,0xf3,0xa1,0xc9,0xab,0x25,0xc7,
	0x5f,0x10,0xbd,0xe7,0x8c,0x23,0xfa,0x0e,0xb8,0xf9,0xaa,0xa5,
	0x3a,0xde,0xfb,0xf4,0xcb,0xf7,0x8f,0xe4
};
//plaintext 表示明文
static const unsigned char ccm_pt[] = {
	0xc8,0xd2,0x75,0xf9,0x19,0xe1,0x7d,0x7f,0xe6,0x9c,0x2a,0x1f,
	0x58,0x93,0x9d,0xfe,0x4d,0x40,0x37,0x91,0xb5,0xdf,0x13,0x10
};
//ciphertext 表示密文
static const unsigned char ccm_ct[] = {
	0x8a,0x0f,0x3d,0x82,0x29,0xe4,0x8e,0x74,0x87,0xfd,0x95,0xa2,
	0x8a,0xd3,0x92,0xc8,0x0b,0x36,0x81,0xd4,0xfb,0xc7,0xbb,0xfd
};
//tag 表示tag資料
static const unsigned char ccm_tag[] = {
	0x2d,0xd6,0xef,0x1c,0x45,0xd4,0xcc,0xb7,0x23,0xdc,0x07,0x44,
	0x14,0xdb,0x50,0x6d
};

void aes_ccm_encrypt(void)
{
	EVP_CIPHER_CTX *ctx;
	int outlen, tmplen;
	unsigned char outbuf[1024];
	printf("AES CCM Encrypt:\n");
	printf("Plaintext:\n");
	BIO_dump_fp(stdout, ccm_pt, sizeof(ccm_pt));
	ctx = EVP_CIPHER_CTX_new();
	/* Set cipher type and mode */
	EVP_EncryptInit_ex(ctx, EVP_aes_192_ccm(), NULL, NULL, NULL);
	/* Set nonce length if default 96 bits is not appropriate */
	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, sizeof(ccm_nonce), NULL);
	/* Set tag length */
	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, sizeof(ccm_tag), NULL);
	/* Initialise key and IV */
	EVP_EncryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce);
	/* Set plaintext length: only needed if AAD is used*/
        //輸入輸出需設定為NULL
	EVP_EncryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_pt));
	/* Zero or one call to specify any AAD */
        //設定AAD,out引數需設定為NULL
	EVP_EncryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata));
	/* Encrypt plaintext: can only be called once */
	EVP_EncryptUpdate(ctx, outbuf, &outlen, ccm_pt, sizeof(ccm_pt));
	/* Output encrypted block */
	printf("Ciphertext:\n");
	BIO_dump_fp(stdout, outbuf, outlen);
	/* Finalise: note get no output for CCM */
	EVP_EncryptFinal_ex(ctx, outbuf, &outlen);
	/* Get tag */
	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 16, outbuf);
	/* Output tag */
	printf("Tag:\n");
	BIO_dump_fp(stdout, outbuf, 16);
	EVP_CIPHER_CTX_free(ctx);
}

void aes_ccm_decrypt(void)
{
	EVP_CIPHER_CTX *ctx;
	int outlen, tmplen, rv;
	unsigned char outbuf[1024];
	printf("AES CCM Derypt:\n");
	printf("Ciphertext:\n");
	BIO_dump_fp(stdout, ccm_ct, sizeof(ccm_ct));
	ctx = EVP_CIPHER_CTX_new();
	/* Select cipher */
	EVP_DecryptInit_ex(ctx, EVP_aes_192_ccm(), NULL, NULL, NULL);
	/* Set nonce length, omit for 96 bits */
	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, sizeof(ccm_nonce), NULL);
	/* Set expected tag value */
	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG,
					sizeof(ccm_tag), (void *)ccm_tag);
	/* Specify key and IV */
	EVP_DecryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce);
	/* Set ciphertext length: only needed if we have AAD */
	EVP_DecryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_ct));
	/* Zero or one call to specify any AAD */
	EVP_DecryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata));
	/* Decrypt plaintext, verify tag: can only be called once */
	rv = EVP_DecryptUpdate(ctx, outbuf, &outlen, ccm_ct, sizeof(ccm_ct));
	/* Output decrypted block: if tag verify failed we get nothing */
	if (rv > 0)
	{
		printf("Plaintext:\n");
		BIO_dump_fp(stdout, outbuf, outlen);
	}
	else
		printf("Plaintext not available: tag verify failed.\n");
	EVP_CIPHER_CTX_free(ctx);
}

int main(int argc, char **argv)
{
	aes_ccm_encrypt();
	aes_ccm_decrypt();
}
2,GCM 

GCM基於並行化設計,因此可以提供高效的吞吐率和低成本、低時延。本質是訊息在變形的CTR模式下加密,密文結果與金鑰以及訊息長度在GF(2^128)域上相乘,計算流程如下所示。其輸入輸出和CCM基本一致。CCM和GCM的具體計算過程可以參看《密碼學與網路安全》第五版,書中有詳細的介紹。FRC5288 中介紹了TLS1.2 中的GCM應用。下面貼出openssl中AES-GCM的例項。


/* Simple AES GCM test program, uses the same NIST data used for the FIPS
 * self test but uses the application level EVP APIs.
 */
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/evp.h>

/* AES-GCM test data from NIST public test vectors */

static const unsigned char gcm_key[] = {
        0xee,0xbc,0x1f,0x57,0x48,0x7f,0x51,0x92,0x1c,0x04,0x65,0x66,
        0x5f,0x8a,0xe6,0xd1,0x65,0x8b,0xb2,0x6d,0xe6,0xf8,0xa0,0x69,
        0xa3,0x52,0x02,0x93,0xa5,0x72,0x07,0x8f
};

static const unsigned char gcm_iv[] = {
        0x99,0xaa,0x3e,0x68,0xed,0x81,0x73,0xa0,0xee,0xd0,0x66,0x84
};

static const unsigned char gcm_pt[] = {
        0xf5,0x6e,0x87,0x05,0x5b,0xc3,0x2d,0x0e,0xeb,0x31,0xb2,0xea,
        0xcc,0x2b,0xf2,0xa5
};

static const unsigned char gcm_aad[] = {
        0x4d,0x23,0xc3,0xce,0xc3,0x34,0xb4,0x9b,0xdb,0x37,0x0c,0x43,
        0x7f,0xec,0x78,0xde
};

static const unsigned char gcm_ct[] = {
        0xf7,0x26,0x44,0x13,0xa8,0x4c,0x0e,0x7c,0xd5,0x36,0x86,0x7e,
        0xb9,0xf2,0x17,0x36
};

static const unsigned char gcm_tag[] = {
        0x67,0xba,0x05,0x10,0x26,0x2a,0xe4,0x87,0xd7,0x37,0xee,0x62,
        0x98,0xf7,0x7e,0x0c
};

void aes_gcm_encrypt(void)
{
        EVP_CIPHER_CTX *ctx;
        int outlen, tmplen;
        unsigned char outbuf[1024];
        printf("AES GCM Encrypt:\n");
        printf("Plaintext:\n");
        BIO_dump_fp(stdout, gcm_pt, sizeof(gcm_pt));
        ctx = EVP_CIPHER_CTX_new();
        /* Set cipher type and mode */
        EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
        /* Set IV length if default 96 bits is not appropriate */
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
        /* Initialise key and IV */
        EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv);
        /* Zero or more calls to specify any AAD */
        EVP_EncryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad));
        /* Encrypt plaintext */
        EVP_EncryptUpdate(ctx, outbuf, &outlen, gcm_pt, sizeof(gcm_pt));
        /* Output encrypted block */
        printf("Ciphertext:\n");
        BIO_dump_fp(stdout, outbuf, outlen);
        /* Finalise: note get no output for GCM */
        EVP_EncryptFinal_ex(ctx, outbuf, &outlen);
        /* Get tag */
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, outbuf);
        /* Output tag */
        printf("Tag:\n");
        BIO_dump_fp(stdout, outbuf, 16);
        EVP_CIPHER_CTX_free(ctx);
}

void aes_gcm_decrypt(void)
{
        EVP_CIPHER_CTX *ctx;
        int outlen, tmplen, rv;
        unsigned char outbuf[1024];
        printf("AES GCM Derypt:\n");
        printf("Ciphertext:\n");
        BIO_dump_fp(stdout, gcm_ct, sizeof(gcm_ct));
        ctx = EVP_CIPHER_CTX_new();
        /* Select cipher */
        EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
        /* Set IV length, omit for 96 bits */
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
        /* Specify key and IV */
        EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv);
#if 0
        /* Set expected tag value. A restriction in OpenSSL 1.0.1c and earlier
         * required the tag before any AAD or ciphertext */
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, sizeof(gcm_tag), gcm_tag);
#endif
        /* Zero or more calls to specify any AAD */
        EVP_DecryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad));
        /* Decrypt plaintext */
        EVP_DecryptUpdate(ctx, outbuf, &outlen, gcm_ct, sizeof(gcm_ct));
        /* Output decrypted block */
        printf("Plaintext:\n");
        BIO_dump_fp(stdout, outbuf, outlen);
        /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, sizeof(gcm_tag), gcm_tag);
        /* Finalise: note get no output for GCM */
        rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen);
        /* Print out return value. If this is not successful authentication
         * failed and plaintext is not trustworthy.
         */
        printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!");
        EVP_CIPHER_CTX_free(ctx);
 }

int main(int argc, char **argv)
{
        aes_gcm_encrypt();
        aes_gcm_decrypt();
 }


相關推薦

openssl學習ccmgcm 模式

openssl中添加了對AES ccm 和gcm模式的支援。下面的內容主要是對這兩個模式相關資料的收集以及整理。 一,CCM CCM (counter with CBC-MAC)定義在分組長度為128位的加密演算法中,如,AES 的分組長度為128。組成AES-CCM演算法

python學習pycpyopyd文件

加載 -s 提高 font ont mic 優化 ros 學習 pyc:二進制文件,python文件經過編譯器編譯之後的文件。可以提高文件加載速度。 pyo:二進制文件,優化編譯後的文件。可以通過`python -O file.py`生成。 pyd:python的動態鏈接庫

Python學習Day1 – Python基礎1

inf avr jet 源代碼 pre 創始人 UC 修改 學習python 寫在前面的話:   大學畢業之後沒有從事自己專業方面的工作,期間也做了很多工作,現在來到了一家物流公司,但是每天日復一日的工作,枯燥,乏味,發現這並不是自己想要的,自己也有自己的夢想,也有自己的追

自動傳輸軟件(學習給自己弄得一個學習小結)

完成 ima 頁面 code 使用 不能 else str2 查詢系統 學習了一段時間後,總覺得有些地方不能融會貫通,因此給自己定了一個小的學習總結目標,自動傳輸軟件 項目要求:需要擁有首頁、傳輸界面、接收界面及尾頁,實現自動跳轉功能 1 #include<st

小白學習基礎三(函數)

但是 iter 使用 問題 個數 函數作為參數 無限 中間 ble 一,函數的基本介紹 首先談到函數,相信大家都不陌生,不管是其他語言都會用到,可能就是叫法不一樣。就我知道的跟python中函數類似的,在C中只有function,在Java裏面叫做method,在js中也是

小白學習基礎四(函數的進階)

strong 部分 iter 讀者 結果 http 內部 mod 取數 一,內置函數 前面已經認識了函數,對函數都有所了解了,其實呢,在Python中提供了很多內置的函數方便給我們調用。下面會給大家提到一些常用的常用內置函數的用法,當然還有一些其他沒講到的,你也可以看參考文

小白學習初識面向對象

指針 -i 路徑 語句 程序 eat -- 不可 不用 一,編程範式 所謂編程範式(programming paradigm),指的是計算機編程的基本風格或典範模式。怎麽說呢,每個人都有自己不同的習慣,當然編程也是一樣的,每個程序組員根據自己不同的習慣會寫出不同的代碼。當然

小白學習網絡編程(下)

多人 困難 get err lose imp 出現 popen one 一,socket進階 在前面的博客中講到了一些基本的計算機網絡知識,有一點也是為我在要考傳輸與交換看到一個題,然後就看到說ARP屬於網絡層,因為ARP協議跟網絡相關,但是我前面的博客說的是ARP協議屬於

模擬電路學習-電容電感重新認識

呵呵 由於 img 哈哈 實驗 觀察 效果 圖片 重新 一、電容 電容是構成基礎電路的原件,它的重要性就不多說了,下面是關於電容的一些特性: 【1】線性電容端電壓和積聚的電荷量的關系是:q=Cu(其中C就是電容,單位法拉,u是電壓,單位福特,q單位庫倫) 【2】電容伏安特

整合學習boostingAdaboost、GBDT 和 xgboost(二)

AdaBoost 演算法的訓練誤差分析 AdaBoost最基本的性質是它能在學習過程中不斷減少訓練誤差,即在訓練資料集上的分類誤差率。 定理:AdaBoost的訓練誤差界: 1

整合學習boostingAdaboost、GBDT 和 xgboost(一)

在前面的部落格(https://blog.csdn.net/qq_16608563/article/details/82878127) 介紹了整合學習的bagging方法及其代表性的隨機森林。此次接著介紹整合學習的另一個方法boosting以及boosting系列的一些演算法,具體包括 Ad

整合學習boostingAdaboost、GBDT 和 xgboost(三)

AdaBoost演算法的解釋——前向分步法與提升樹(GBDT) 可以認為AdaBoost演算法是模型為加法模型,損失函式為指數函式、學習演算法為前向分步演算法時的二類分類學習方法。 前向分步演算法: 考慮加法模型

python學習scipymatplotlibpandas解讀

scipy可參考:https://www.jianshu.com/p/6c742912047f matplotlib可參考:https://www.jianshu.com/p/250eaa709b73 pandas可參考:https://www.jianshu.com/p/8b6137b1f

2018年11月4日java學習關鍵字識別符號命名規範

1關鍵字 java 語言中的關鍵字都是小寫的,java嚴格區分大小寫 藍色的都是關鍵字,紅色的是類 還有一些保留字比如goto 2.識別符號 -》自己可以起名字的叫識別符號:類名,方法,變數,介面名 數字不可以開頭 由26個大小寫字母,數字

openssl 學習證書中提取N 和 E

通常數字證書包含很多資訊,其中N和E值即我們稱為的公鑰。如何從PEM 或者DER格式的證書中提出證書呢?下面給出程式碼實現從PEM和DER編碼的證書中提出N、E。 #include <openssl/evp.h> #include <openssl/x

nio學習channel基於流的方式獲取channel

package nio; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileCh

mongoDB學習安裝、配置、啟動、命令、應用(一)

mongoDB初學 mongoDB學習了一段時間,今天整理一下,以便自己回顧,加深印象,同時讓更多mongo初學者有個好的資料。真好 在學習mongoDB之前,我們先了解什麼是mongoDB,以及相關概念 MongoDB 是一個基於分散式檔案儲存的資料庫。由 C++

mongoDB學習安裝、配置、啟動、命令、應用(五)-

上篇說了java連線mongo,並進行增刪改查 這篇說一下spring整合mongo github上也有小demo,很簡單,適合初學者,地址:點選跳轉 1、首先建立maven專案,新增依賴 <!-- mongo驅動 --> <dependen

C++PrimerPlus學習輸入輸出和檔案

流和緩衝區 C++程式把輸入和輸出看作位元組流。輸入時,程式從輸入流中抽取位元組;輸出時,程式將位元組插入到輸出流中。 流充當了程式和流源或流目標之間的橋樑。C++程式只是檢查位元組流,而不需要知道位

Web 基礎學習 JS 迴圈練習

1.判斷閏年  var i; for(i=1980;i<=2016;i++) { if( i % 4 == 0 && i % 100 != 0 || i % 400 == 0) document.write( i + " "); } 2.九