在密碼學中經常用到有限域的乘法,一般在AES中用到的是GF(2^8)有限域內乘法。什麼是有限域呢?有限域通俗的講就是函數的運算結果全都包含在一個域中,不同於實數域,有限域有一個最大值,所有超過這個最大值的數都會經過一定的方法使他回到這個域中,在密碼學中應用很廣泛,2^8意味着這個域的最大值是256.
以下代碼是GF(2^8)有限域內乘法的C代碼實現:
- unsigned char XTIME(unsigned char x) {
- return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
- }
- unsigned char multiply(unsigned char a, unsigned char b) {
- unsigned char temp[8] = { a };
- unsigned char tempmultiply = 0x00;
- int i = 0;
- for (i = 1; i < 8; i++) {
- temp[i] = XTIME(temp[i - 1]);
- }
- tempmultiply = (b & 0x01) * a;
- for (i = 1; i <= 7; i++) {
- tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
- }
- return tempmultiply;
- }
以下講一下乘法的原理:
在二進制中,所有的數都能用0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80異或得到,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80的二進制表示如下:
後一個分別是前一個的2倍。假設任意一個數a,他的二進制表示爲10101101,可以由以下組合組成:
而任何一個數x和a相乘都可以表示爲
所以只要計算出
一切乘法的結果都可以得到。
XTIME函數的含義是求一個數x與0x02的乘積,一般求一個數的2倍,都是作移一位,在有限域內,要計算有限域的乘法,必須先確定一個GF上的8次不可約多項式,Rijndael密碼中,這個多項式確定爲x^8+x^4+x^3+x+1,如果最高位是1的話,左移一位的同時要異或0x1B,是因爲最高位是1的話,再繼續左移會超出域的最大值,這個時候需要取除以同餘式,也就是異或0x1B。
- for (i = 1; i < 8; i++) {
- temp[i] = XTIME(temp[i - 1]);
- }
- for (i = 1; i <= 7; i++) {
- tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
- }
另一個乘數b右移一位和0x01與運算,分別和這8個字符相乘,再把相乘的結果異或。就得到了a和b相乘的結果。
接下來舉個例子:
求0x3a*0x24?首先0x3a=00111010,分別求
是正確結果。
如果要提高算法的計算效率,還可以這麼做。
如果一個乘數的二進制可以表示爲
一個乘數表示爲
那麼a的倍數關係可表示爲:
那麼他的乘積可以表示爲
其中
所以乘法可以表示爲
所以還有一種計算方法,那就是按照上面這個矩陣乘法。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- void print_bit(bool *hexbit, int len) {
- int i = 0;
- for (i = 0; i < len; i++) {
- printf("%x ", hexbit[i]);
- }
- }
- void print_matrix(bool matrix[8][8]) {
- int i = 0;
- for (i = 0; i < 8; i++) {
- print_bit(matrix[i], 8);
- printf("\n");
- }
- }
- void convertto_bit(unsigned char cipher, bool *hexbit, int len) {
- len = 8;
- int i = 0;
- for (i = 0; i < 8; i++) {
- if (cipher & 0x80) {
- hexbit[i] = true;
- }
- cipher = cipher << 1;
- }
- }
- void convertto_matrix(bool hexbit[8], bool matrix[8][8]) {
- matrix[0][0] = hexbit[0];
- matrix[0][1] = hexbit[1];
- matrix[0][2] = hexbit[2];
- matrix[0][3] = hexbit[3];
- matrix[0][4] = hexbit[0] ^ hexbit[4];
- matrix[0][5] = hexbit[0] ^ hexbit[1] ^ hexbit[5];
- matrix[0][6] = hexbit[1] ^ hexbit[2] ^ hexbit[6];
- matrix[0][7] = hexbit[0] ^ hexbit[2] ^ hexbit[3] ^ hexbit[7];
- matrix[1][0] = hexbit[1];
- matrix[1][1] = hexbit[2];
- matrix[1][2] = hexbit[3];
- matrix[1][3] = matrix[0][4];
- matrix[1][4] = matrix[0][5];
- matrix[1][5] = matrix[0][6];
- matrix[1][6] = hexbit[0] ^ hexbit[2] ^ hexbit[3] ^ hexbit[7];
- matrix[1][7] = hexbit[1] ^ hexbit[3] ^ hexbit[4];
- matrix[2][0] = hexbit[2];
- matrix[2][1] = hexbit[3];
- matrix[2][2] = matrix[1][3];
- matrix[2][3] = matrix[1][4];
- matrix[2][4] = matrix[1][5];
- matrix[2][5] = matrix[1][6];
- matrix[2][6] = matrix[1][7];
- matrix[2][7] = hexbit[2] ^ hexbit[4] ^ hexbit[5];
- matrix[3][0] = hexbit[3];
- matrix[3][1] = matrix[2][2];
- matrix[3][2] = matrix[2][3];
- matrix[3][3] = matrix[2][4];
- matrix[3][4] = matrix[2][5];
- matrix[3][5] = matrix[2][6];
- matrix[3][6] = matrix[2][7];
- matrix[3][7] = hexbit[0] ^ hexbit[3] ^ hexbit[5] ^ hexbit[6];
- matrix[4][0] = hexbit[4];
- matrix[4][1] = hexbit[0] ^ hexbit[5];
- matrix[4][2] = hexbit[1] ^ hexbit[6];
- matrix[4][3] = hexbit[0] ^ hexbit[2] ^ hexbit[7];
- matrix[4][4] = hexbit[0] ^ hexbit[1] ^ hexbit[3];
- matrix[4][5] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[4];
- matrix[4][6] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[3] ^ hexbit[5];
- matrix[4][7] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[3] ^ hexbit[4]
- ^ hexbit[6];
- matrix[5][0] = hexbit[5];
- matrix[5][1] = hexbit[6];
- matrix[5][2] = hexbit[0] ^ hexbit[7];
- matrix[5][3] = hexbit[0] ^ hexbit[1];
- matrix[5][4] = hexbit[1] ^ hexbit[2];
- matrix[5][5] = hexbit[2] ^ hexbit[3];
- matrix[5][6] = hexbit[0] ^ hexbit[3] ^ hexbit[4];
- matrix[5][7] = hexbit[1] ^ hexbit[4] ^ hexbit[5];
- matrix[6][0] = hexbit[6];
- matrix[6][1] = matrix[5][2];
- matrix[6][2] = matrix[5][3];
- matrix[6][3] = matrix[5][4];
- matrix[6][4] = matrix[5][5];
- matrix[6][5] = matrix[5][6];
- matrix[6][6] = matrix[5][7];
- matrix[6][7] = hexbit[0] ^ hexbit[2] ^ hexbit[5] ^ hexbit[6];
- matrix[7][0] = hexbit[7];
- matrix[7][1] = hexbit[0];
- matrix[7][2] = hexbit[1];
- matrix[7][3] = hexbit[2];
- matrix[7][4] = hexbit[3];
- matrix[7][5] = matrix[2][2];
- matrix[7][6] = matrix[2][3];
- matrix[7][7] = matrix[2][4];
- return;
- }
- unsigned char XTIME(unsigned char x) {
- return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
- }
- unsigned char multiply(unsigned char a, unsigned char b) {
- unsigned char temp[8] = { a };
- unsigned char tempmultiply = 0x00;
- int i = 0;
- for (i = 1; i < 8; i++) {
- temp[i] = XTIME(temp[i - 1]);
- }
- tempmultiply = (b & 0x01) * a;
- for (i = 1; i <= 7; i++) {
- tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
- }
- return tempmultiply;
- }
- unsigned char multiply_bit(unsigned char plaintext, unsigned char key) {
- int ret_len = 0;
- bool plaintext_hexbit[8] = { false, false, false, false, false, false,
- false, false };
- bool key_hexbit[8] = { false, false, false, false, false, false, false,
- false };
- bool cipher_hexbit[8] = { false, false, false, false, false, false, false,
- false };
- //把plaintext轉換成二進制
- convertto_bit(plaintext, plaintext_hexbit, ret_len);
- bool matrix[8][8] = { };
- convertto_matrix(plaintext_hexbit, matrix);
- //把key轉換成二進制
- convertto_bit(key, key_hexbit, ret_len);
- //print_matrix(matrix);
- //printf("\n");
- //print_bit(key_hexbit, sizeof(key_hexbit));
- //printf("\n");
- int i = 0;
- int j = 0;
- for (i = 0; i < 8; i++) {
- cipher_hexbit[i] = false;
- for(j = 0;j < 8;j++) {
- if(key_hexbit[j]){
- cipher_hexbit[i] ^=matrix[i][7-j];
- }
- }
- }
- //print_bit(cipher_hexbit, sizeof(cipher_hexbit));
- unsigned char outcome = 0;
- for (i = 0; i < 8; i++) {
- if (cipher_hexbit[i]) {
- outcome ^= 0x01 << (7 - i);
- }
- }
- return outcome;
- }
- int main(int argc, char * argv[]) {
- unsigned char plaintext = 0x49;
- unsigned char key = 0x24;
- printf("%#x", multiply_bit(plaintext, key));
- printf("\n");
- // unsigned char plaintext1 = 0x01;
- // unsigned char key1 = 0x21;
- printf("%#x", multiply(plaintext, key));
- return 0;
- }
輸出結果是
- 0xdc
- 0xdc
經過測試,後一種方法比第一種方法效率慢很多,原因是其中代碼計算矩陣和矩陣乘法比第一種方法複雜。但是第二種提供另外一種思路。
轉載出處:http://blog.csdn.net/bupt073114/article/details/27382533