柚子快報(bào)邀請碼778899分享:算法 關(guān)于openssl的BN
柚子快報(bào)邀請碼778899分享:算法 關(guān)于openssl的BN
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret) //將 s 數(shù)據(jù)轉(zhuǎn)為小端存入 BIGNUM int BN_bn2bin(const BIGNUM *a, unsigned char *to) //將 BIGNUM 數(shù)據(jù)轉(zhuǎn)為大端存入to
unsigned char buf[8]={0x00,0x00,0x10,0x20,0x30,0x40,0x00,0x10}; // 緩沖區(qū)大小
int len =8;
BIGNUM *bn = BN_new();
BN_bin2bn(buf, len, bn); //此刻 BIGNUM 數(shù)據(jù)為 0x10 0x00 0x40 0x30 0x20 0x10 0x00 0x00 ,并不忽略buf的頭部00進(jìn)行轉(zhuǎn)換,也就是不忽略高位0
printf("bn_len:%d\n",BN_num_bytes(bn)); //6 ,但算出實(shí)際字節(jié)數(shù)為 6,此刻計(jì)算忽略了高位0
char * bn_buf = ((char*)(*((long int *)bn))); //在64位平臺(tái)測試 此處為long int 取 8字節(jié)值
bn_buf [0]=0; //讓低位為0
//此刻BIGNUM 數(shù)據(jù)為 0x00 0x00 0x40 0x30 0x20 0x10 0x00 0x00
unsigned char buf_2[8]={0};
buf_2[2]=0x99; //調(diào)用BN_bn2bin預(yù)計(jì)會(huì)改為0x01,但實(shí)際上是0x30
int buf2_len = BN_bn2bin(bn,buf_2); //buf2_len 為6
/*
預(yù)計(jì)buf2應(yīng)該為 0x00 0x00 0x10 0x20 0x30 0x40 0x00 0x00
但實(shí)際為 0x10 0x20 0x30 0x40 0x00 0x00
對于 BIGNUM 來說數(shù)據(jù)為小端字節(jié)序,調(diào)用BN_bn2bin時(shí),會(huì)把高位的00去掉轉(zhuǎn)換為大端存入第二參數(shù)的buf,以至于返回的 buf_len 不正確
但是低位的00 不會(huì)被忽略
*/
1. BN_bin2bn 函數(shù)的行為
BN_bin2bn 函數(shù)會(huì)將輸入的字節(jié)數(shù)組 s 按 小端字節(jié)序 解釋并存入 BIGNUM 結(jié)構(gòu)中。也就是說,數(shù)組中的低位字節(jié)會(huì)在 BIGNUM 的低內(nèi)存地址中,而高位字節(jié)會(huì)在 BIGNUM 的高內(nèi)存地址中。這符合小端字節(jié)序的存儲(chǔ)方式,因?yàn)?BIGNUM 的內(nèi)部存儲(chǔ)是小端的。 輸入數(shù)組 buf 是: unsigned char buf[8] = {0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x00, 0x10};
調(diào)用 BN_bin2bn(buf, len, bn) 后,BIGNUM 結(jié)構(gòu)中存儲(chǔ)的數(shù)據(jù)按小端序存儲(chǔ),即: 0x10 0x00 0x40 0x30 0x20 0x10 0x00 0x00
注意:雖然字節(jié)數(shù)組的高位(前兩個(gè) 0x00)沒有被丟棄,但由于它們是高位的零,它們不會(huì)對 BIGNUM 的值產(chǎn)生實(shí)際影響。
2. BN_num_bytes 計(jì)算字節(jié)數(shù)
當(dāng)調(diào)用 BN_num_bytes(bn) 時(shí),返回值為 6,因?yàn)樵摵瘮?shù)計(jì)算的是 BIGNUM 的 有效字節(jié)數(shù)。這意味著它忽略了高位的零(0x00),從而得出實(shí)際有用的字節(jié)數(shù)為 6。有效值為:0x10 0x20 0x30 0x40 0x00 0x00
3. BN_bn2bin 的行為
當(dāng)調(diào)用 BN_bn2bin(bn, buf_2) 時(shí),它會(huì)將 BIGNUM 中的值按 大端字節(jié)序 存入目標(biāo)緩沖區(qū) buf_2。這意味著它會(huì)將最高有效字節(jié)(MSB)放在 buf_2 的起始位置。 由于 BN_bn2bin 只轉(zhuǎn)換 BIGNUM 的有效字節(jié)(忽略高位的零字節(jié)),因此目標(biāo)緩沖區(qū) buf_2 最終是: 0x10 0x20 0x30 0x40 0x00 0x00
高位的零字節(jié)被忽略,因此預(yù)期的 buf_2 的結(jié)果(包含所有字節(jié))沒有發(fā)生。
4. 為什么低位零不被忽略
當(dāng) BN_bn2bin 進(jìn)行大端轉(zhuǎn)換時(shí),它只忽略高位的零字節(jié),而不會(huì)忽略 低位的零字節(jié)。這是因?yàn)榈臀坏牧阕止?jié)對數(shù)值有實(shí)際影響,而高位的零字節(jié)在大多數(shù)情況下是無關(guān)緊要的。 因此,觀察到的 buf_2 是: 0x10 0x20 0x30 0x40 0x00 0x00
高位的零被忽略,但低位的零沒有被去掉。
為何低位零字節(jié)有實(shí)際影響,而高位零字節(jié)在大多數(shù)情況下無關(guān)緊要
1. 數(shù)值表示 vs. 存儲(chǔ)方式
數(shù)值表示:表示一個(gè)整數(shù)時(shí),它的數(shù)值只依賴于有效位數(shù)(即從非零位開始的部分),高位的零不影響數(shù)值大小,而低位的零則直接影響數(shù)值。
例如:0x0010 和 0x10 是相同的數(shù)值,因?yàn)闊o論在左側(cè)添加多少個(gè)零,這都不會(huì)改變它的實(shí)際數(shù)值。高位的零可以被忽略,因?yàn)樗粫?huì)影響數(shù)值大小。但是 0x10 和 0x100 是不同的數(shù)值,低位的零不能被忽略,因?yàn)樗鼈冎苯佑绊懥藬?shù)值的大小。
2. 存儲(chǔ)方式
在存儲(chǔ)時(shí),尤其是在使用大端或小端字節(jié)序的場合,高位零和低位零的處理方式不同:
高位的零字節(jié):在許多場景下可以被忽略,因?yàn)樗鼈儾挥绊憯?shù)值的大小。例如,在進(jìn)行大數(shù)運(yùn)算時(shí),系統(tǒng)可能會(huì)忽略那些存儲(chǔ)在高位的零字節(jié),以減少不必要的存儲(chǔ)開銷。低位的零字節(jié):它們會(huì)影響數(shù)值大小。比如 0x0010 和 0x1000 是完全不同的數(shù)值,低位的零不能被忽略。
3. 為什么高位的零字節(jié)可以忽略
當(dāng)一個(gè)數(shù)被表示為 0x0010 和 0x10,它們的數(shù)值是相同的。高位的零只是用來占位的,不影響數(shù)值。因此,在高位有零字節(jié)的情況下,可以在某些操作中安全地忽略這些零字節(jié)。在某些場合(如 BN_bn2bin 和 BN_bin2bn 的轉(zhuǎn)換中),為了優(yōu)化存儲(chǔ)空間和減少不必要的運(yùn)算,系統(tǒng)會(huì)忽略高位零字節(jié)。而低位零字節(jié)則會(huì)被保留,因?yàn)樗鼈冎苯佑绊憯?shù)值的大小。
4. 例子
高位零字節(jié)無關(guān)緊要:0x0010 和 0x10 表示相同的數(shù)值,所以 0x0010 的高位零可以被忽略。低位零字節(jié)不能忽略:0x10 和 0x100 表示不同的數(shù)值,低位零表示數(shù)值乘以 16,不能被忽略。
總結(jié)
在大數(shù)運(yùn)算中,高位的零字節(jié)在數(shù)值表示中不影響結(jié)果,因此通常被忽略。而低位零字節(jié)則是數(shù)值的一部分,不能被忽略。
但是由于BN_bn2bin忽略了高位0,如果這個(gè)BIGNUM 是代表的密鑰對計(jì)算無影響,但是如果是簽名體的一部分,這樣按照數(shù)值解釋忽略了高位0,實(shí)則忽略了一部分簽名體數(shù)據(jù),如sm2的簽名體的r或s,則會(huì)導(dǎo)致拿到的簽名體不正確,導(dǎo)致驗(yàn)簽錯(cuò)誤
在涉及到數(shù)字簽名時(shí),簽名體的每個(gè)字節(jié)都至關(guān)重要,包括高位的零字節(jié)。 在大數(shù)運(yùn)算中,比如用于密鑰或數(shù)值計(jì)算的 BIGNUM 對象,忽略高位的零字節(jié)通常不會(huì)對數(shù)值產(chǎn)生影響。但當(dāng) BIGNUM 被用于表示簽名體的一部分(如 SM2 簽名的 r 或 s 值)時(shí),高位的零字節(jié)也是簽名體的一部分,不能被忽略。否則,簽名的完整性會(huì)受到影響,導(dǎo)致簽名驗(yàn)證失敗。
原因分析:
數(shù)字簽名的完整性:簽名體(如 SM2 的 r 和 s)是對消息哈希值的精確加密表示,簽名的每一個(gè)字節(jié)都包含了加密后的重要信息。即使是高位的零字節(jié),它也代表了原始數(shù)據(jù)的一部分。如果在處理 BIGNUM 時(shí)高位零字節(jié)被忽略,實(shí)際上相當(dāng)于刪除了簽名的一部分信息,這將導(dǎo)致簽名不再與原始消息的哈希值匹配,驗(yàn)證自然會(huì)失敗。 BN_bn2bin 忽略高位零字節(jié)的影響:當(dāng) BN_bn2bin 將 BIGNUM 轉(zhuǎn)換為字節(jié)數(shù)組時(shí),它確實(shí)會(huì)忽略高位零字節(jié),認(rèn)為這些零對數(shù)值無影響。然而,在簽名體這種場景中,每個(gè)字節(jié)都是有意義的。忽略高位零字節(jié)意味著丟失了一部分簽名信息,驗(yàn)證時(shí)會(huì)認(rèn)為簽名不完整或錯(cuò)誤。 簽名驗(yàn)證過程依賴精確的簽名體:簽名驗(yàn)證的過程通常是將接收到的簽名體(如 SM2 的 r 和 s)與根據(jù)消息和公鑰計(jì)算出的簽名進(jìn)行比對。如果簽名體中的高位零字節(jié)被忽略,簽名驗(yàn)證算法接收到的簽名體和實(shí)際簽名體就會(huì)不一致,導(dǎo)致驗(yàn)證失敗。
解決方案:
為了避免這個(gè)問題,在簽名體處理中,不能依賴 BN_bn2bin 自動(dòng)忽略高位零字節(jié)??梢钥紤]以下方法:
使用更低級(jí)的字節(jié)處理函數(shù),確保簽名體的高位零字節(jié)不會(huì)被忽略。在調(diào)用 BN_bn2bin 時(shí),手動(dòng)處理高位零字節(jié),確保其正確轉(zhuǎn)換并保留。
結(jié)論:
在大數(shù)運(yùn)算中忽略高位零字節(jié)可能不會(huì)影響數(shù)值計(jì)算,但在處理簽名體時(shí),忽略高位零字節(jié)會(huì)導(dǎo)致簽名信息丟失,從而導(dǎo)致驗(yàn)證失敗。對于 SM2 簽名或其他類似場景,確保簽名體的完整性(包括高位零字節(jié))非常重要,否則簽名驗(yàn)證將無法成功。
以上結(jié)論全靠意淫加胡亂測試,不一定正確,如有錯(cuò)誤求大佬指教
柚子快報(bào)邀請碼778899分享:算法 關(guān)于openssl的BN
好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。