劉 聰
(德州學(xué)院 信息管理學(xué)院,山東 德州 253000)
分組密碼“Kuznyechik”是俄羅斯密碼標(biāo)準(zhǔn)算法集合(稱為GOST算法)之一。該算法能夠保證信息在傳輸過程中的機(jī)密性和完整性,它符合現(xiàn)代密碼的要求,具有安全、高效率、易用和靈活等優(yōu)點(diǎn)。適用于開發(fā)、運(yùn)用到各種用途的現(xiàn)代信息系統(tǒng)中,保護(hù)數(shù)據(jù)的安全。為了提高Kuznyechik算法在實(shí)際應(yīng)用中的加密速度,本文根據(jù)Kuznyechik算法的特點(diǎn),與Java線程池技術(shù)結(jié)合,提出采用線程池技術(shù)并行加密Kuznyechik的方法。
通常情況下,加密程序都是單線程運(yùn)行的。為了提高程序的加密速度,可以設(shè)置多個線程去運(yùn)行。Java語言對多線程提供了非常優(yōu)秀的支持,基本的Java線程模型有Thread類、Runnable接口、Callable接口、Future接口等。
線程池就是在程序運(yùn)行時創(chuàng)建一定數(shù)量的線程保存起來,當(dāng)需要時,從線程池中取出一個線程。完成相應(yīng)任務(wù)后再放回到線程池中。通過線程池,可以有效降低資源消耗、提高程序響應(yīng)速度、提高線程的可管理性。根據(jù)線程池的工作原理,算法程序需要線程池管理器、工作線程、任務(wù)隊(duì)列、數(shù)據(jù)加密實(shí)體幾個部分。
Kuznyechik在俄羅斯聯(lián)邦GOST R 34.12-2015的國家標(biāo)準(zhǔn)中定義,它有128比特的塊大小和256比特的密鑰長度。該算法是俄羅斯密碼標(biāo)準(zhǔn)算法集合(稱為GOST算法)之一。該算法可以在硬件和軟件中實(shí)現(xiàn),能夠保證信息在傳輸過程中的機(jī)密性和完整性,它符合現(xiàn)代密碼的要求。該標(biāo)準(zhǔn)適用于開發(fā),運(yùn)用到各種用途的現(xiàn)代信息系統(tǒng)。
該算法包括密鑰編排和加密兩部分,密鑰編排算法是Feistel結(jié)構(gòu)的,有左右兩支,在密鑰編排算法中,主密鑰k為256比特,分為k1和k2,各128比特。首先k1與常數(shù)c1相加,將得到的結(jié)果經(jīng)過s盒,L置換,然后與k2相加,得左支到k1′,之前k1的值變成k2′。密鑰編排流程如圖1所示:
圖1 密鑰編排流程圖
經(jīng)過8輪相同的運(yùn)算,最后得到編排后的密鑰k3和k4,然后以同樣的方式生成k5和k6、k7和k8、k9和k10。其中L置換經(jīng)過下面公式得到:
其中a是128位的,經(jīng)過線性反饋移位寄存器轉(zhuǎn)16拍,其中轉(zhuǎn)換的定義如下:
其中ai是8位,a16是經(jīng)過Ⅰ運(yùn)算得到的,Ⅰ運(yùn)算的定義如下:
I(a15,…,a0)=?(148·Δ(a15)+32·Δ(a14)
+133·Δ(a13)+16·Δ(a12)+194·Δ(a11)
+192·Δ(a10)+1·Δ(a9)+251·Δ(a8)
+1·Δ(a7)+192·Δ(a6)+194·Δ(a5)+16·Δ(a4))
+133·Δ(a3)+32·Δ(a2)+148·Δ(a1)+1·Δ(a0))
I運(yùn)算的輸入是16個8位二進(jìn)制數(shù),輸出為1個8位二進(jìn)制數(shù)。表示將8位二進(jìn)制數(shù)轉(zhuǎn)換成有限域內(nèi)的元素,▽是它的逆運(yùn)算。經(jīng)過有限域內(nèi)的乘法運(yùn)算,然后相加,最后轉(zhuǎn)換成1個8位二進(jìn)制輸出。計(jì)算有限域乘法,首先要確定GF(2)上的8次不可約多項(xiàng)式。在該算法中,這個不可約多項(xiàng)式為
在加密算法中,明文塊a為128比特,密鑰k1,…,k10分別為128位,經(jīng)過10輪運(yùn)算,分別使用密鑰k1,…,k10。加密算法定義如下:
具體加密流程如圖2所示:
圖2 加密流程圖
Kuznyechik要進(jìn)行10輪循環(huán)加密,因?yàn)楦鶕?jù)算法的特點(diǎn),事先進(jìn)行密鑰編排,得到10個輪密鑰進(jìn)行循環(huán)加密。根據(jù)加密算法的特點(diǎn),本文設(shè)計(jì)了適用于Kuznyechik算法加密的線程池。首先創(chuàng)建任務(wù)實(shí)體,要加密數(shù)據(jù)的輸入和輸出保存到任務(wù)實(shí)體的屬性中。
public class encryptionData{
public String inputData;
public String outputData;
public String getInputData(){
return inputData;
}
public String getOutputData(){
return outputData;
}
public void setInputData(String inputData) {
this.inputData=inputData;
}
public void setOutputData(String outputData) {
this.outputData=outputData;
}
在主線程中,首先創(chuàng)建隊(duì)列和工作線程,然后創(chuàng)建任務(wù)實(shí)體,通過set方法給實(shí)體的屬性賦值,然后將加密數(shù)據(jù)對象實(shí)體加入到任務(wù)隊(duì)列中,最后不斷循環(huán)檢測工作線程的隊(duì)列是否為空,如果為空,說明數(shù)據(jù)已經(jīng)加密完成,線程池銷毀[3-4]。在主線程工作的同時,工作線程不斷從任務(wù)隊(duì)列中取出任務(wù)實(shí)體,獲取要加密的內(nèi)容,不斷進(jìn)行加密,加密結(jié)束存儲密文,當(dāng)工作線程將所有任務(wù)實(shí)體處理完后,隊(duì)列為空,線程池銷毀。具體運(yùn)行流程如圖3所示。
圖3 Java線程池的kuznyechik算法流程圖
根據(jù)算法原理和加密流程,本文采用128bit的密鑰,需要加密10輪。首先需要設(shè)計(jì)線程池管理類,該類內(nèi)部成員包括線程池實(shí)體、任務(wù)隊(duì)列和工作線程實(shí)體,線程池實(shí)體使用單例模式來設(shè)計(jì),并加入同步鎖保證線程池對象的唯一[5]。任務(wù)隊(duì)列用來存放加密實(shí)體對象,工作線程不斷從任務(wù)隊(duì)列中取出任務(wù)實(shí)體,從任務(wù)實(shí)體中獲取需要加密的明文,然后調(diào)用加密方法進(jìn)行輪加密運(yùn)算。以下是線程池管理類的主要代碼:
public class ThreadPool{
private static ThreadPool instance=null;
public List<encryptionData> taskQueue = Collections.synchronizedList (new LinkedList<encryptionData>());//任務(wù)隊(duì)列
//工作線程(真正執(zhí)行任務(wù)的線程)
private WorkThread workQueue;
private ThreadPool(){
workQueue=new WorkThread();
}
public static synchronized ThreadPool getInstance(){
if(instance==null)
instance=new ThreadPool();
return instance;
}
public void addTask(encryptionData task){
//對任務(wù)隊(duì)列的操作上鎖
synchronized(taskQueue){
if(task!=null){
taskQueue.add(task);
taskQueue.notifyAll();
}
}
}
public void destory(){
workQueue.stopThread();
workQueue=null;
//對任務(wù)隊(duì)列的操作上鎖
synchronized(taskQueue){
taskQueue.clear();
}
}
工作線程的主要代碼如下:
public void run(){
while(isRuning){
encryptionData temp=null;
//對任務(wù)隊(duì)列的操作要上鎖
synchronized(taskQueue){
//任務(wù)隊(duì)列為空,等待新的任務(wù)加入
while(isRuning&&taskQueue.isEmpty()){
try{
taskQueue.wait(10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
i( fisRuning)
temp=taskQueue.remove(0);
}
i(ftemp!=null){
isWaiting=false;
//執(zhí)行加密函數(shù)
Encryption.encresult(temp.getInputData());
isWaiting=true;
}
}
在加密函數(shù)中,主要通過明文與密鑰相加運(yùn)算,然后通過S盒和L運(yùn)算,得到密文,其中,S盒和L運(yùn)算的主要代碼如下:
進(jìn)s盒運(yùn)算,使用以下方法來實(shí)現(xiàn),其中s盒的長度為256,返回的結(jié)果是s盒的輸出。
public static char[] sbox(char x[]){
for(int i=0;i<16;i++){
a[i]=(char)x[i];
c[i]= (char) s[a[i]];
}
return c;
}
L運(yùn)算主要進(jìn)行了16次R運(yùn)算,主要代碼如下:
for(int i=0;i<16;i++){
char e= ltrans(k11);
for(int j=0;j<15;j++){
k11[j]=k11[j+1];
}
k11[15] =e;
}
其中,ltrans表示l運(yùn)算。在l運(yùn)算中,主要用到的是GF(2^8)有限域內(nèi)乘法,這個域的最大值為256。有限域內(nèi)的乘法使用以下的方法實(shí)現(xiàn):
public static char multiply(char a, char b){
char temp[]={a,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
char tempmultiply=0x00;
int i=0;
for(i=1;i< 8;i++){
temp[i] =XTIME(temp[i-1]);
}
tempmultiply=(char)((b&0x01)*a);
for(i=1;i<=7;i++){
tempmultiply^=(((b >> i)&0x01)*temp[i]);
}
return tempmultiply;
}
在二進(jìn)制中,所有的數(shù)都能用0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80異或得到,任何一個數(shù)b和a進(jìn)行相乘,都可以表示為b和0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80分別相乘,然后異或得到。只要計(jì)算出b和這幾個數(shù)的乘積,一切結(jié)果都可以得到。XTIME方法的含義是求一個數(shù)與0x02的乘積,如果求一個數(shù)乘以2,一般是左移一位,本算法中,不可約多項(xiàng)式為p(x)=x8+x7+x6+x+1,如果最高位為1,再繼續(xù)左移會超出最大值,這時,左移1位的同時要異或0xc3。XTIME的具體實(shí)現(xiàn)代碼如下:
public static char XTIME(char x) {
int k=0x00;
if((x&0x80)!=0)
k=0xc3;
return(char)((((x << 1)^k))&0xff);
}
經(jīng)過8次temp[i]=XTIME(temp[i-1])運(yùn)算,temp數(shù)組中包含8個字符,分別為:a*0x01,a*0x02,a*0x04,a*0x08,a*0x10,a*0x20,a*0x40,a*0x80。然后經(jīng)過8次tempmulti?ply^=(((b >> i)&0x01)*temp[i])運(yùn)算,另一個乘數(shù)b首先進(jìn)行1位右移,再和0x01與運(yùn)算,然后分別和這8個字符相乘,把相乘的結(jié)果進(jìn)行相加,得到a和b的乘積。
本文使用Java語句,在eclipse平臺進(jìn)行測試,硬件采用Intel(R)CoreI-5(TM)i5-8400(主頻2.8GHZ,6核)32G內(nèi)存的臺式機(jī)作為平臺進(jìn)行測試。測試用到了加速比,未采用線程池和采用線程池程序加密算法的運(yùn)行時間分別記為τa和τb,經(jīng)過測試,結(jié)果如下表1所示:
表1 加密驗(yàn)證結(jié)果
測試表明,在數(shù)據(jù)量比較少時,采用線程池比未采用線程池加密效率略高,但是隨著數(shù)據(jù)量的增大,采用線程池明顯比不采用線程池加密效率明顯增高。隨著數(shù)據(jù)量的增加,加速比逐漸變陡。下面是原始的測試數(shù)據(jù),圖4-圖7:
圖4 1k數(shù)據(jù)加密示意圖
圖5 10k數(shù)據(jù)加密示意圖
圖6 100k數(shù)據(jù)加密示意圖
圖7 1000k數(shù)據(jù)加密示意圖
本文通過設(shè)計(jì)線程池,基于Java線程池技術(shù),對Kuznyechik算法進(jìn)行了改進(jìn),通過eclipse平臺進(jìn)行測試,測試結(jié)果表明,隨著數(shù)據(jù)量的增大,能夠明顯增加加密的效率,縮短加密時間,為大數(shù)據(jù)環(huán)境下的加密奠定了基礎(chǔ)。在未來的研究中,將通過GPU的并行計(jì)算,來進(jìn)一步提高加密效率。