導航:首頁 > 編程語言 > phpaespkcs7

phpaespkcs7

發布時間:2023-03-07 05:36:05

php 加密:AES & RSA

最近兩年一直從事與金融相關項目的開發與維護。但是,關於 PHP 加密解密的最佳實踐,網上沒有人給出一個完美的總結。恰逢最近看了《圖解密碼技術》一書,對 PHP 加解密有了更深刻的認識。

為了避免各位看枯燥的文字理論,開篇我就把總結給出:

一、對稱加密
對稱加密的特點是加解密速度快,加密後的密文強度目前還沒有硬解的可能性。但是,在未來隨著計算機性能的提升有可能會出現被破解的可能性。

對稱加密的缺點也很明顯。對稱加密的加密過程與解密過程使用的是同一把密鑰。一旦泄漏密鑰,加密就失去了任何意義。

根據《圖解密碼技術》一書的推薦,對稱加密目前推薦使用 AES。在 PHP 當中要實現 AES 加解密,是使用 openssl 擴展來實現。所以,請確保你的 PHP 已經開啟了 openssl 擴展。

可以通過如下方式檢測:

或者如下方式檢測:

AES 的加密模式屬於分組密碼模式。所謂分組密碼,是加密時把明文按照固定的長度分組,然後再進行加密。當然,細節之處很很多不同。AES 分組模式有多種:ECB、CBC、CFB、OFB、CTR 五種分組模式。目前優先推薦使用 CBC 模式。

如果使用 CBC 模式,那麼在加密的時候,就需要一個前置的加密向量 IV。當初博主在使用 AES 來加密的時候,就很奇怪一個對稱加密為何要這個向量。因為,在博主寒冰的潛意識里,對稱加密只需要一個密鑰就 Ok 了。沒想到 AES 加密還有多種模式,而這個 CBC 模式恰恰就需要一個這樣的向量值。關於這個向量大家可以在網上查閱相關的資料。這個東西非常重要,也非常好理解。

關於 PHP AES 加解密會用到的相關方法:

AES 支持三種強度:128、192、256。128 位的強度最低,但是,加密解密速度較快。256 位強度最高,但是,加密解密速度最低。所以,大家根據自己系統的重要程度選擇使用對應強度。通常普通的金融項目使用 192 位完整夠用了。頂級的就用 256 位。其他的就用 128 位吧。

二、非對稱加密
非對稱加密是指公鑰加密私鑰解密,私鑰加密公鑰解密的演算法。非對稱加密的演算法有很多。《圖解密碼技術》一書推薦使用 RSA 演算法。它使用起來也非常簡單。

要使用 RSA 演算法。首先,我們必須生成一對公鑰私鑰。其實生成公鑰私鑰很簡單。

在 Linux 系統,直接使用如下命令生成:

此命令會生 ~/.ssh/ 目錄下生成兩個文件:

id_rsa 是私鑰, is_rsa.pub 是公鑰。

關於 PHP RSA 加解密會用到的相關方法:

以上就是關於在 PHP 項目開發中,我們使用的加密解密演算法的一個總結。博主寒冰在總結過程中難免會有不足之處,還請大家指正!謝謝!

㈡ PHP對稱加密-AES

對稱加解密演算法中,當前最為安全的是 AES 加密演算法(以前應該是是 DES 加密演算法),PHP 提供了兩個可以用於 AES 加密演算法的函數簇: Mcrypt OpenSSL

其中 Mcrypt 在 PHP 7.1.0 中被棄用(The Function Mycrypt is Deprecated),在 PHP 7.2.0 中被移除,所以即可起你應該使用 OpenSSL 來實現 AES 的數據加解密。

在一些場景下,我們不能保證兩套通信系統都使用了相函數簇去實現加密演算法,可能 siteA 使用了最新的 OpenSSL 來實現了 AES 加密,但作為第三方服務的 siteB 可能仍在使用 Mcrypt 演算法,這就要求我們必須清楚 Mcrypt 同 OpenSSL 之間的差異,以便保證數據加解密的一致性。

下文中我們將分別使用 Mcrypt 和 OpenSSL 來實現 AES-128/192/256-CBC 加解密,二者同步加解密的要點為:

協同好以上兩點,就可以讓 Mcrypt 和 OpenSSL 之間一致性的對數據進行加解密。

AES 是當前最為常用的安全對稱加密演算法,關於對稱加密這里就不在闡述了。

AES 有三種演算法,主要是對數據塊的大小存在區別:

AES-128:需要提供 16 位的密鑰 key
AES-192:需要提供 24 位的密鑰 key
AES-256:需要提供 32 位的密鑰 key

AES 是按數據塊大小(128/192/256)對待加密內容進行分塊處理的,會經常出現最後一段數據長度不足的場景,這時就需要填充數據長度到加密演算法對應的數據塊大小。

主要的填充演算法有填充 NUL("0") 和 PKCS7,Mcrypt 默認使用的 NUL("0") 填充演算法,當前已不被推薦,OpenSSL 則默認模式使用 PKCS7 對數據進行填充並對加密後的數據進行了 base64encode 編碼,所以建議開發中使用 PKCS7 對待加密數據進行填充,已保證通用性(alipay sdk 中雖然使用了 Mcrypt 加密簇,但使用 PKCS7 演算法對數據進行了填充,這樣在一定程度上親和了 OpenSSL 加密演算法)。

Mcrypt 的默認填充演算法。NUL 即為 Ascii 表的編號為 0 的元素,即空元素,轉移字元是 "",PHP 的 pack 打包函數在 'a' 模式下就是以 NUL 字元對內容進行填充的,當然,使用 "" 手動拼接也是可以的。

OpenSSL的默認填充演算法。下面我們給出 PKCS7 填充演算法 PHP 的實現:

默認使用 NUL("") 自動對待加密數據進行填充以對齊加密演算法數據塊長度。

獲取 mcrypt 支持的演算法,這里我們只關注 AES 演算法。

注意:mcrypt 雖然支持 AES 三種演算法,但除 MCRYPT_RIJNDAEL_128 外, MCRYPT_RIJNDAEL_192/256 並未遵循 AES-192/256 標准進行加解密的演算法,即如果你同其他系統通信(java/.net),使用 MCRYPT_RIJNDAEL_192/256 可能無法被其他嚴格按照 AES-192/256 標準的系統正確的數據解密。官方文檔頁面中也有人在 User Contributed Notes 中提及。這里給出如何使用 mcrpyt 做標注的 AES-128/192/256 加解密

即演算法統一使用 MCRYPT_RIJNDAEL_128 ,並通過 key 的位數 來選定是以何種 AES 標准做的加密,iv 是建議添加且建議固定為16位(OpenSSL的 AES加密 iv 始終為 16 位,便於統一對齊),mode 選用的 CBC 模式。

mcrypt 在對數據進行加密處理時,如果發現數據長度與使用的加密演算法的數據塊長度未對齊,則會自動使用 "" 對待加密數據進行填充,但 "" 填充模式已不再被推薦,為了與其他系統有更好的兼容性,建議大家手動對數據進行 PKCS7 填充。

openssl 簇加密方法更為簡單明確,mcrypt 還要將加密演算法分為 cipher + mode 去指定,openssl 則只需要直接指定 method 為 AES-128-CBC,AES-192-CBC,AES-256-CBC 即可。且提供了三種數據處理模式,即 默認模式 0 / OPENSSL_RAW_DATA / OPENSSL_ZERO_PADDING 。

openssl 默認的數據填充方式是 PKCS7,為兼容 mcrpty 也提供處理 "0" 填充的數據的模式,具體為下:

options 參數即為重要,它是兼容 mcrpty 演算法的關鍵:

options = 0 : 默認模式,自動對明文進行 pkcs7 padding,且數據做 base64 編碼處理。
options = 1 : OPENSSL_RAW_DATA,自動對明文進行 pkcs7 padding, 且數據未經 base64 編碼處理。
options = 2 : OPENSSL_ZERO_PADDING,要求待加密的數據長度已按 "0" 填充與加密演算法數據塊長度對齊,即同 mcrpty 默認填充的方式一致,且對數據做 base64 編碼處理。注意,此模式下 openssl 要求待加密數據已按 "0" 填充好,其並不會自動幫你填充數據,如果未填充對齊,則會報錯。

故可以得出 mcrpty簇 與 openssl簇 的兼容條件如下:

建議將源碼復制到本地運行,根據運行結果更好理解。

1.二者使用的何種填充演算法。

2.二者對數據是否有 base64 編碼要求。

3.mcrypt 需固定使用 MCRYPT_RIJNDAEL_128,並通過調整 key 的長度 16, 24,32 來實現 ase-128/192/256 加密演算法。

㈢ 前端JS AES加密 後端PHP AES加解密

<!DOCTYPEhtml>

<html>

<head>

    <title>aes demo</title>

</head>

<body>

    <script type="text/javascript" src="./CryptoJS/aes.js"></script>

    <script type="text/javascript" src="./CryptoJS/pad-zeropadding.js"></script>

    <script type="text/javascript">

    text = 'did=12345dg&version=1';

    var key = '';

    key = CryptoJS.enc.Utf8.parse(key);

    var iv = "";

    iv = CryptoJS.enc.Utf8.parse(iv);

    var encrypted = CryptoJS.AES.encrypt(text, key, {

        iv: iv,

        mode: CryptoJS.mode.CBC,

        padding: CryptoJS.pad.ZeroPadding

    }).toString()

    document.write(encrypted);

    </script>

</body>

</html>

後端

public function encrypt2($input = ''){

        $pk = "";

        $iv = substr("", 0, 16);

        // $t = 'T10515';

        $encrypted = ( mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pk, $input, MCRYPT_MODE_CBC,$iv) );

        return base64_encode($encrypted);

    } 

    public function decrypt2($encrypted){

        $pk = "";

        $iv = substr("", 0, 16);

        // $t = 'T10515';

        // $encrypted = "b7y/JPJFNTfxNVR8H4NNtw==";

        return  mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pk, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv);

    }

可以推斷, js 部分實際只使用了 iv 的 16 位長度

ps:

js加密後默認會base64_encode

使用php解密需要base64_decode後才一致

所以使用js加密和php解密時候需要注意,php端要先base64_decode再解密,例:

js加密的串是$t=b7y/JPJFNTfxNVR8H4NNtw==

php需要

$password= trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pk,base64_decode( $t), MCRYPT_MODE_CBC, $iv));

則$password才能正確解析出來

需要引入的兩個js文件

ase.js

[javascript] view plain

/*

CryptoJS v3.1.2

code.google.com/p/crypto-js

(c) 2009-2013 by Jeff Mott. All rights reserved.

code.google.com/p/crypto-js/wiki/License

*/

var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},

r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<

32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,

2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},

q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);

a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,

e)).finalize(b)}}});var n=d.algo={};return d}(Math);

(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<

l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"+/="}})();

(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},

_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),

f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,

m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,

E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/

4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);

(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,

l)}})();

CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},

finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=

c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,

e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,

this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,

1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},

decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,

b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();

(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,

16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchele=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchele=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>

8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchele,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchele,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=

d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();

pad-zeropadding.js

/*

CryptoJS v3.1.2

code.google.com/p/crypto-js

(c) 2009-2013 by Jeff Mott. All rights reserved.

code.google.com/p/crypto-js/wiki/License

*/

/**

* Zero padding strategy.

*/

CryptoJS.pad.ZeroPadding = {

    pad: function (data, blockSize) {

        // Shortcut

        var blockSizeBytes = blockSize * 4; 

        // Pad

        data.clamp();

        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);

    }, 

    unpad: function (data) {

        // Shortcut

        var dataWords = data.words; 

        // Unpad

        var i = data.sigBytes - 1;

        while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {

            i--;

        }

        data.sigBytes = i + 1;

    }

}; 

㈣ Android在用AES加密字元串之後再用base64加密,加密的結果跟ios端不一樣,

之前在項目上用到AES256加密解密演算法,剛開始在java端加密解密都沒有問題,在iOS端加密解密也沒有問題。但是奇怪的是在java端加密後的文件在iOS端無法正確解密打開,然後簡單測試了一下,發現在java端和iOS端採用相同明文,相同密鑰加密後的密文不一樣!上網查了資料後發現iOS中AES加密演算法採用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我們知道加密演算法由演算法+模式+填充組成,所以這兩者不同的填充演算法導致相同明文相同密鑰加密後出現密文不一致的情況。那麼我們需要在java中用PKCS7Padding來填充,這樣就可以和iOS端填充演算法一致了。
要實現在java端用PKCS7Padding填充,需要用到bouncycastle組件來實現,下面我會提供該包的下載。啰嗦了一大堆,下面是一個簡單的測試,上代碼!
001 package com.encrypt.file;
002
003
004 import java.io.UnsupportedEncodingException;
005 importjava.security.Key;
006 import java.security.Security;
007
008 importjavax.crypto.Cipher;
009 importjavax.crypto.SecretKey;
010 importjavax.crypto.spec.SecretKeySpec;
011
012 public classAES256Encryption{
013
014 /**
015 * 密鑰演算法
016 * java6支持56位密鑰,bouncycastle支持64位
017 * */
018 public static finalString KEY_ALGORITHM="AES";
019
020 /**
021 * 加密/解密演算法/工作模式/填充方式
022 *
023 * JAVA6 支持PKCS5PADDING填充方式
024 * Bouncy castle支持PKCS7Padding填充方式
025 * */
026 public static finalString CIPHER_ALGORITHM="AES/ECB/PKCS7Padding";
027
028 /**
029 *
030 * 生成密鑰,java6隻支持56位密鑰,bouncycastle支持64位密鑰
031 * @return byte[] 二進制密鑰
032 * */
033 public static byte[] initkey() throwsException{
034
035 // //實例化密鑰生成器
036 // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
037 // KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC");
038 // //初始化密鑰生成器,AES要求密鑰長度為128位、192位、256位
039 //// kg.init(256);
040 // kg.init(128);
041 // //生成密鑰
042 // SecretKey secretKey=kg.generateKey();
043 // //獲取二進制密鑰編碼形式
044 // return secretKey.getEncoded();
045 //為了便於測試,這里我把key寫死了,如果大家需要自動生成,可用上面注釋掉的代碼
046 return new byte[] { 0x08, 0x08, 0x04, 0x0b, 0x02, 0x0f, 0x0b, 0x0c,
047 0x01, 0x03, 0x09, 0x07, 0x0c, 0x03, 0x07, 0x0a, 0x04, 0x0f,
048 0x06, 0x0f, 0x0e, 0x09, 0x05, 0x01, 0x0a, 0x0a, 0x01, 0x09,
049 0x06, 0x07, 0x09, 0x0d };
050 }
051
052 /**
053 * 轉換密鑰
054 * @param key 二進制密鑰
055 * @return Key 密鑰
056 * */
057 public static Key toKey(byte[] key) throwsException{
058 //實例化DES密鑰
059 //生成密鑰
060 SecretKey secretKey=newSecretKeySpec(key,KEY_ALGORITHM);
061 returnsecretKey;
062 }
063
064 /**
065 * 加密數據
066 * @param data 待加密數據
067 * @param key 密鑰
068 * @return byte[] 加密後的數據
069 * */
070 public static byte[] encrypt(byte[] data,byte[] key) throwsException{
071 //還原密鑰
072 Key k=toKey(key);
073 /**
074 * 實例化
075 * 使用 PKCS7PADDING 填充方式,按如下方式實現,就是調用bouncycastle組件實現
076 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
077 */
078 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
079 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");
080 //初始化,設置為加密模式
081 cipher.init(Cipher.ENCRYPT_MODE, k);
082 //執行操作
083 returncipher.doFinal(data);
084 }
085 /**
086 * 解密數據
087 * @param data 待解密數據
088 * @param key 密鑰
089 * @return byte[] 解密後的數據
090 * */
091 public static byte[] decrypt(byte[] data,byte[] key) throwsException{
092 //歡迎密鑰
093 Key k =toKey(key);
094 /**
095 * 實例化
096 * 使用 PKCS7PADDING 填充方式,按如下方式實現,就是調用bouncycastle組件實現
097 * Cipher.getInstance(CIPHER_ALGORITHM,"BC")
098 */
099 Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
100 //初始化,設置為解密模式
101 cipher.init(Cipher.DECRYPT_MODE, k);
102 //執行操作
103 returncipher.doFinal(data);
104 }
105 /**
106 * @param args
107 * @throws UnsupportedEncodingException
108 * @throws Exception
109 */
110 public static void main(String[] args) {
111
112 String str="AES";
113 System.out.println("原文:"+str);
114
115 //初始化密鑰
116 byte[] key;
117 try {
118 key = AES256Encryption.initkey();
119 System.out.print("密鑰:");
120 for(int i = 0;i<key.length;i++){
121 System.out.printf("%x", key[i]);
122 }
123 System.out.print("\n");
124 //加密數據
125 byte[] data=AES256Encryption.encrypt(str.getBytes(), key);
126 System.out.print("加密後:");
127 for(int i = 0;i<data.length;i++){
128 System.out.printf("%x", data[i]);
129 }
130 System.out.print("\n");
131
132 //解密數據
133 data=AES256Encryption.decrypt(data, key);
134 System.out.println("解密後:"+newString(data));
135 } catch (Exception e) {
136 // TODO Auto-generated catch block
137 e.printStackTrace();
138 }
139
140 }
141 }
運行程序後的結果截圖:

ViewController.m文件

01 //
02 // ViewController.m
03 // AES256EncryptionDemo
04 //
05 // Created by 孫 裔 on 12-12-13.
06 // Copyright (c) 2012年 rich sun. All rights reserved.
07 //
08
09 #import "ViewController.h"
10 #import "EncryptAndDecrypt.h"
11
12 @interface ViewController ()
13
14 @end
15
16 @implementation ViewController
17 @synthesize plainTextField;
18 - (void)viewDidLoad
19 {
20 [super viewDidLoad];
21 // Do any additional setup after loading the view, typically from a nib.
22 }
23
24 - (void)didReceiveMemoryWarning
25 {
26 [super didReceiveMemoryWarning];
27 // Dispose of any resources that can be recreated.
28 }
29 //這個函數實現了用戶輸入完後點擊視圖背景,關閉鍵盤
30 - (IBAction)backgroundTap:(id)sender{
31 [plainTextField resignFirstResponder];
32 }
33
34 - (IBAction)encrypt:(id)sender {
35
36 NSString *plainText = plainTextField.text;//明文
37 NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
38
39 //為了測試,這里先把密鑰寫死
40 Byte keyByte[] = {0x08,0x08,0x04,0x0b,0x02,0x0f,0x0b,0x0c,0x01,0x03,0x09,0x07,0x0c,0x03,
41 0x07,0x0a,0x04,0x0f,0x06,0x0f,0x0e,0x09,0x05,0x01,0x0a,0x0a,0x01,0x09,
42 0x06,0x07,0x09,0x0d};
43 //byte轉換為NSData類型,以便下邊加密方法的調用
44 NSData *keyData = [[NSData alloc] initWithBytes:keyByte length:32];
45 //
46 NSData *cipherTextData = [plainTextData AES256EncryptWithKey:keyData];
47 Byte *plainTextByte = (Byte *)[cipherTextData bytes];
48 for(int i=0;i<[cipherTextData length];i++){
49 printf("%x",plainTextByte[i]);
50 }
51
52 }
53 @end

㈤ 對於加密的總結(AES,RSA)

跟第三方聯調的時候會碰到各種加密演算法,所以總結一下。

AES不是將拿到的明文一次性加密,而是分組加密,就是先將明文切分成長度相等的塊,每塊大小128bit,再對每一小塊進行加密。那麼問題就來了,並不是所有的原始明文串能被等分成128bit,例如原串大小200bit,那麼第二個塊只有72bit,所以就需要對第二個塊進行填充處理,讓第二個塊的大小達到128bit。常見的填充模式有

不進行填充,要求原始加密串大小必須是128bit的整數倍;

假設塊大小8位元組,如果這個塊跟8位元組還差n個位元組,那麼就在原始塊填充n,直到滿8位元組。例:塊{1,2,3},跟8位元組差了5個位元組,那麼補全後的結果{1,2,3,5,5,5,5,5}後面是五個5,塊{1,2,3,..7}跟8位元組差了1個位元組,那麼補全後就是{1,2,3,...,7,1},就是補了一個1。

如果恰好8位元組又選擇了PKCS5Padding填充方式呢?塊{1,2,3...8}填充後變成{1,2,3...8,8...8},原串後面被補了8個8,這樣做的原因是方便解密,只需要看最後一位就能算出原塊的大小是多少。

跟PKCS5Padding的填充方式一樣,不同的是,PKCS5Padding只是對8位元組的進行填充,PKCS7Padding可以對1~256位元組大小的block進行填充。openssl里aes的默認填充方式就是PKCS7Padding

AES有多種加密模式,包括:ECB,CBC,CTR,OCF,CFB,最常見的還是ECB和CBC模式。

最簡單的一種加密模式,每個塊進行獨立加密,塊與塊之間加密互不影響,這樣就能並行,效率高。
雖然這樣加密很簡單,但是不安全,如果兩個塊的明文一模一樣,那麼加密出來的東西也一模一樣。

openssl的相關函數:

CBC模式中引入了一個新的概念,初始向量iv。iv的作用就是為了防止同樣的明文塊被加密成同樣的內容。原理是第一個明文塊跟初始向量做異或後加密,第二個塊跟第一個密文塊做異或再加密,依次類推,避免了同樣的塊被加密成同樣的內容。

openssl相關函數:

敲黑板!! 所以跟第三方對接的時候,如果對面說他們用aes加密,務必對他們發起靈魂三問:

簽名的作用是讓接受方驗證你傳過去的數據沒有被篡改;加密的作用是保證數據不被竊取。

原理:你有一個需要被驗簽的原串A。

步驟一:選擇hash演算法將A進行hash得到hash_a;

步驟二:將hash_a進行加密,得到加密值encrypt_a;

步驟三:將原串A和加密的encrypt_a發給第三方,第三方進行驗簽。第三方先解密encrypt_a,得到一個hash值hash_a1,然後對原串A使用同樣的hash演算法進行hash,得到的即為加密前的hash_a,如果hash_a = hash_a1, 那麼驗簽成功。

rsa使用私鑰對信息加密來做簽名,使用公鑰解密去驗簽。
openssl相關函數:

注意:兩個函數中的m,是原串hash後的值,type表示生成m的演算法,例如NID_sha256表示使用sha256對原串進行的hash,返回1為簽名成功或者驗簽成功,-1位為失敗。

再次敲黑板!! 所以如果第三方說使用rsa驗簽,要讓對方告知他們的hash演算法。

首先明確,私鑰加密不等於簽名。加密的時候,使用使用公鑰加密,第三方使用你的私鑰進行解密。
openssl里公鑰加密函數為RSA_public_encrypt,私鑰解密函數為RSA_private_decrypt,具體的可以自己去查看下官方文檔。

rsa也涉及到了填充方式,所以對接的時候也要問清楚

在使用公鑰進行加密時,會發現每次加密出的結果都不一樣,但使用私鑰加密時,每次的結果都一樣,網上查了一圈,說是因為填充方式的原因。

官方文檔說明:

那麼為什麼一定要使用私鑰做簽名,公鑰做加密,而不是公鑰做簽名,私鑰做加密呢?
舉個栗子:

㈥ 面向對象基礎知識之文件加密解密

文件加密解密是開發中經常用到的一個功能點,常見於客戶端項目,需要對配置數據、參數設置、數據字典等需要隱匿,來增強客戶端的安全性。

本章我們介紹兩種常見文件加密解密方法

1.自定義加密解密函數,思路是文件轉成Byte[],對byte元素使用對稱加密演算法對齊加密。加密後的byte[]轉成base64。解密文件使用base64加密的byte[]解密即可生成原文件。

2.使用 System.Security.Cryptography. RijndaelManaged,這種加密需要提供32位密碼和16位向量密碼

//加密

string pwd = "" ; //32位,密碼

string ivpwd = "gjhdjfhdjdkdssad" ; //16位,向量密碼

RijndaelManaged aes = new RijndaelManaged();

byte [] pwdBytes = System.Text.Encoding.UTF8.GetBytes(pwd);

aes.Key = pwdBytes;

aes.IV = Encoding.UTF8.GetBytes(ivpwd);

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

byte [] readFileByte = ReadByte(filePath);

ICryptoTransform transform = aes.CreateEncryptor();

byte [] fielBuffer = transform.TransformFinalBlock(readFileByte, 0, readFileByte.Length); //注意這里返回的是加密後的byte[]

//解密

RijndaelManaged aes = new RijndaelManaged();

byte [] pwdBytes = System.Text.Encoding.UTF8.GetBytes(pwd);

aes.Key = pwdBytes;

aes.IV = Encoding.UTF8.GetBytes(ivpwd);

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

byte [] readFileByte = ReadByte(filePath);

ICryptoTransform transform = aes.CreateDecryptor();

//注意這里返回的是解密後的byte[]

byte [] fielBuffer = transform.TransformFinalBlock(readFileByte, 0, readFileByte.Length);

加密方式越復雜需要的計算量越大,速度相應會變慢;加密方式需要結合項目來做選擇。客戶端項目對於數據保密性較強建議使用RSA和 RijndaelManaged 混合加密。

python進行 AES CBC-128bit PKCS7/PKCS5 填充加密解密

你看一下這個例子吧。可以參考下面的地址:前面加上http,把句號改成點。


likang。me/blog/2013/06/05/python-pycrypto-aes-ecb-pkcs-5/


#-*-coding:utf-8-*-
fromCrypto.CipherimportAES
importos

BS=AES.block_size
pad=lambdas:s+(BS-len(s)%BS)*chr(BS-len(s)%BS)
unpad=lambdas:s[0:-ord(s[-1])]

key=os.urandom(16)#thelengthcanbe(16,24,32)
text='tobeencrypted'

cipher=AES.new(key)

encrypted=cipher.encrypt(pad(text)).encode('hex')
printencrypted#willbesomethinglike''

decrypted=unpad(cipher.decrypt(encrypted.decode('hex')))
printdecrypted#willbe'tobeencrypted'

㈧ AES加解密使用總結

AES, 高級加密標准, 是採用區塊加密的一種標准, 又稱Rijndael加密法. 嚴格上來講, AES和Rijndael又不是完全一樣, AES的區塊長度固定為128比特, 秘鑰長度可以是128, 192或者256. Rijndael加密法可以支持更大范圍的區塊和密鑰長度, Rijndael使用的密鑰和區塊長度均可以是128,192或256比特. AES是對稱加密最流行的演算法之一.

我們不去討論具體的AES的實現, 因為其中要運用到大量的高等數學知識, 單純的了解AES流程其實也沒什麼意義(沒有數學基礎難以理解), 所以我們今天著重來總結一些使用過程中的小點.

當然了分組密碼的加密模式不僅僅是ECB和CBC這兩種, 其他的我們暫不涉及.

上面說的AES是一種區塊加密的標准, 那加密模式其實可以理解為處理不同區塊的方式和聯系.

ECB可以看做最簡單的模式, 需要加密的數據按照區塊的大小分為N個塊, 並對每個塊獨立的進行加密

此種方法的缺點在於同樣的明文塊會被加密成相同的密文塊, 因此, 在某些場合, 這種方法不能提供嚴格的數據保密性. 通過下面圖示例子大家就很容易明白了

我們的項目中使用的就是這種模式, 在CBC模式中, 每個明文塊與前一個塊的加密結果進行異或後, 在進行加密, 所以每個塊的加密都依賴前面塊的加密結果的, 同時為了保證第一個塊的加密, 在第一個塊中需要引入初始化向量iv.

CBC是最常用的模式. 他的缺點是加密過程只能是串列的, 無法並行, 因為每個塊的加密要依賴到前一個塊的加密結果, 同時在加密的時候明文中的細微改變, 會導致後面所有的密文塊都發生變化. 但此種模式也是有優點的, 在解密的過程中, 每個塊的解密依賴上一個塊的加密結果, 所以我們要解密一個塊的時候, 只需要把他前面一個塊也一起讀取, 就可以完成本塊的解密, 所以這個過程是可以並行操作的.

AES加密每個塊blockSize是128比特, 那如果我們要加密的數據不是128比特的倍數, 就會存在最後一個分塊不足128比特, 那這個塊怎麼處理, 就用到了填充模式. 下面是常用的填充模式.

PKCS7可用於填充的塊大小為1-255比特, 填充方式也很容易理解, 使用需填充長度的數值paddingSize 所表示的ASCII碼 paddingChar = chr(paddingSize)對數據進行冗餘填充. (後面有解釋)

PKCS5隻能用來填充8位元組的塊

我們以AES(128)為例, 數據塊長度為128比特, 16位元組, 使用PKCS7填充時, 填充長度為1-16. 注意, 當加密長度是16整數倍時, 反而填充長度是最大的, 要填充16位元組. 原因是 "PKCS7" 拆包時會按協議取最後一個位元組所表徵的數值長度作為數據填充長度, 如果因真實數據長度恰好為16的整數倍而不進行填充, 則拆包時會導致真實數據丟失.

舉一個blockSize為8位元組的例子

第二個塊中不足8位元組, 差4個位元組, 所以用4個4來填充

嚴格來講 PKCS5不能用於AES, 因為AES最小是128比特(16位元組), 只有在使用DES此類blockSize為64比特演算法時, 考慮使用PKCS5

我們的項目最開始加解密庫使用了CryptoSwift, 後來發現有性能問題, 就改為使用IDZSwiftCommonCrypto.

這里咱們結合項目中邊下邊播邊解密來提一個點, 具體的可以參考之前寫的 邊下邊播的總結 . 因為播放器支持拖動, 所以我們在拖拽到一個點, 去網路拉取對應數據時, 應做好range的修正, 一般我們都會以range的start和end為基準, 向前後找到包含這個range的所有塊范圍. 打比方說我們需要的range時10-20, 這是我們應該修正range為0-31, 因為起點10在0-15中, 20 在16-31中. 這是常規的range修正.(第一步 找16倍數點).

但是在實際中, 我們請求一段數據時, 還涉及到解密器的初始化問題, 如果我們是請求的0-31的數據, 因為是從0開始, 所以我們的解密器只需要用key和初始的iv來進行初始化, 那如果經過了第一步的基本range修正後, 我們請求的數據不是從0開始, 那我們則還需要繼續往前讀取16個位元組的數據, 舉個例子, 經過第一步修正後的range為16-31, 那我們應該再往前讀取16位元組, 應該是要0-31 這32個位元組數據, 拿到數據後,使用前16個位元組(上一個塊的密文)當做iv來初始化解密器.

還有一個要注意的點是, 數據解密的過程中, 還有可能會吞掉後面16個位元組的數據, 我暫時沒看源碼, 不知道具體因為什麼, 所以保險起見, 我們的range最好是再向後讀取6個位元組.

感謝閱讀

參考資料

https://zh.wikipedia.org/zh-cn/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86
https://segmentfault.com/a/1190000019793040
https://ithelp.ithome.com.tw/articles/10250386

閱讀全文

與phpaespkcs7相關的資料

熱點內容
手機文檔解壓之後解壓包去哪兒了 瀏覽:921
java中網路編程重要嗎 瀏覽:683
如何登錄別人的伺服器 瀏覽:626
調度系統軟體python 瀏覽:205
微信大轉盤抽獎源碼 瀏覽:497
壓縮機損壞的表現 瀏覽:862
同步數據伺服器怎麼用 瀏覽:634
163郵箱伺服器的ip地址 瀏覽:50
伺服器跟域是什麼 瀏覽:128
rails啟動命令 瀏覽:465
logistic命令怎麼用 瀏覽:738
c語言點滴pdf 瀏覽:747
linuxrtc編程 瀏覽:258
linux打包並壓縮命令 瀏覽:644
aes加密的證書格式 瀏覽:99
oracledbcalinux 瀏覽:844
酬勤任務app怎麼被特邀 瀏覽:199
android應用文件夾 瀏覽:1002
平面設計法則pdf 瀏覽:339
3d圓角命令怎麼用 瀏覽:569