A 5/1暗号化アルゴリズムの紹介と実現


1.アルゴリズムの概要
A 5/1暗号化アルゴリズムは、GSMにおけるデータ機密暗号化に用いられる.このアルゴリズムは,X,Y,Zの3つの線形フィードバックシフトレジスタを用いて記述した.このうちX(x 0,x 1,...,x 18)レジスタは19ビット,Yレジスタは22ビット,Zレジスタは23ビットである.以下では原理を言わず,鍵ストリーム生成アルゴリズムのみを述べる.
  • 定義Xアクション:temp=x 13^x 16^x 17^x 18 xi=xi-1 for i=18,17,16,...,1 x 0=temp;(簡単に言えば左シフト1位、そして1位は左シフト前のx 13^x 16^x 17^x 18で埋め込まれ、以下同様)Y操作を定義する:temp=y 20^y 21 yi=yi-1 for i=21,20,19,...,1 y 0=temp;Z操作の定義:temp=z 7^z 20^z 21^z 22 zi=zi-1 for i=22,21,20,...,1 z 0=temp;
  • 多数投票関数maj(x,y,z):x,y,zの0の個数が比較的多い場合、0を返す.そうでなければ1を返します.
  • はm=maj(x 8,y 10,z 10)を命令し、x 8=mであればX操作を実行する.y 10=mの場合、Y操作を実行する.z 10=mの場合、Z操作を実行します.
  • 鍵ストリームビットs=x 18^y 21^z 22.
  • 上記の手順を繰り返して鍵ストリームを生成する.

  • 2.簡単な実現
    C++で簡単に実現したので、簡単にはあまり話さない.
    #include 
    #include 
    #include 
    #define _for(i,a,b) for(int i=(a); i
    #define setbit(x,y)  x|=(1<
    #define clrbit(x,y)  x&=~(1<
    #define reversebit(x,y)  x^=(1<
    #define getbit(x,y)   (x&=(1<
    using namespace std;
    typedef unsigned char uc;
    bool x[19] = {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1};
    bool y[22] = {1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1};
    bool z[23] = {1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0};
    int maj(bool x, bool y, bool z) {
    	return x + y + z >= 2;
    }
    void X(bool x[]) {
    	bool temp = x[13] ^ x[16] ^ x[17] ^ x[18];
    	for(int i = 18; i >= 1; i--) {
    		x[i] = x[i-1];
    	}
    	x[0] = temp;
    }
    void Y(bool y[]) {
    	bool temp = y[20] ^ y[21];
    	for(int i = 21; i >= 1; i--) {
    		y[i] = y[i-1];
    	}
    	y[0] = temp;
    }
    void Z(bool z[]) {
    	bool temp = z[7] ^ z[20] ^ z[21] ^ z[22];
    	for(int i = 22; i >= 1; i--) {
    		z[i] = z[i-1];
    	}
    	z[0] = temp;
    }
    uc* generateSecretKeyStream(int n) {
    	bool temp[8]; 
    	uc* secretKeyStream = (uc*)malloc(n/8 + 1);
    	int cnt = 0, cnt1 = 0;
    	_for(i, 0, n) {
    		bool m = maj(x[8], y[10], z[10]);
    		if(x[8] == m) {
    			X(x);
    		}
    		if(y[10] == m) {
    			Y(y);
    		}
    		if(z[10] == m) {
    			Z(z);
    		}
    		bool s = x[18] ^ y[21] ^ z[22];
    		temp[cnt++] = s;
    		if(cnt == 8) {
    			_for(j, 0, cnt) {
    				if(temp[j] == 0) {
    					clrbit(secretKeyStream[cnt1], j);
    				} else {
    					setbit(secretKeyStream[cnt1], j);
    				}
    			}
    			cnt1++;
    			cnt = 0;
    		}
    	}
    	_for(j, 0, cnt) {
    		if(temp[j] == 0) {
    			clrbit(secretKeyStream[cnt1], j);
    		} else {
    			setbit(secretKeyStream[cnt1], j);
    		}
    	}
    	return secretKeyStream;
    }
    int getFileSize(FILE *fp) {
    	fseek(fp, 0L, SEEK_END);
        int size = ftell(fp);
        fseek(fp, 0L, 0);
        return size;
    } 
    uc* readFromFile(FILE *fp, int size) {
    	uc *buffer = (uc *)malloc(sizeof(uc) * size);
    	fread(buffer, size, 1, fp);
    	return buffer;
    }
    void  encrypt(char* fileName) {
    	FILE* fp = fopen(fileName, "rb");
    	int fileSize = getFileSize(fp);
        uc *buffer = readFromFile(fp, fileSize);
        uc* secretKeyStream = generateSecretKeyStream(fileSize * 8);
        _for(i, 0, fileSize) {
        	buffer[i] ^= secretKeyStream[i];
    	}
    	FILE* fp1 = fopen("secret.a51", "wb");
    	fwrite(buffer, fileSize, 1, fp1);
    	_for(i, 0, fileSize) {
        	buffer[i] ^= secretKeyStream[i];
    	}
    	FILE* fp2 = fopen("_secret.a51", "wb");
    	fwrite(buffer, fileSize, 1, fp2);
    	fclose(fp);
    	fclose(fp1);
    	fclose(fp2);
    	free(buffer);
    }
    int main(int argc, char const **argv) {
    	char fileName[50] = "lenna.bmp";
    	encrypt(fileName);
    	return 0;
    }