/* * Camellia Cipher Algorithm (x86_64) * * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include <linux/linkage.h> .file "camellia-x86_64-asm_64.S" .text .extern camellia_sp10011110; .extern camellia_sp22000222; .extern camellia_sp03303033; .extern camellia_sp00444404; .extern camellia_sp02220222; .extern camellia_sp30333033; .extern camellia_sp44044404; .extern camellia_sp11101110; #define sp10011110 camellia_sp10011110 #define sp22000222 camellia_sp22000222 #define sp03303033 camellia_sp03303033 #define sp00444404 camellia_sp00444404 #define sp02220222 camellia_sp02220222 #define sp30333033 camellia_sp30333033 #define sp44044404 camellia_sp44044404 #define sp11101110 camellia_sp11101110 #define CAMELLIA_TABLE_BYTE_LEN 272 /* struct camellia_ctx: */ #define key_table 0 #define key_length CAMELLIA_TABLE_BYTE_LEN /* register macros */ #define CTX %rdi #define RIO %rsi #define RIOd %esi #define RAB0 %rax #define RCD0 %rcx #define RAB1 %rbx #define RCD1 %rdx #define RAB0d %eax #define RCD0d %ecx #define RAB1d %ebx #define RCD1d %edx #define RAB0bl %al #define RCD0bl %cl #define RAB1bl %bl #define RCD1bl %dl #define RAB0bh %ah #define RCD0bh %ch #define RAB1bh %bh #define RCD1bh %dh #define RT0 %rsi #define RT1 %rbp #define RT2 %r8 #define RT0d %esi #define RT1d %ebp #define RT2d %r8d #define RT2bl %r8b #define RXOR %r9 #define RRBP %r10 #define RDST %r11 #define RXORd %r9d #define RXORbl %r9b #define xor2ror16(T0, T1, tmp1, tmp2, ab, dst) \ movzbl ab ## bl, tmp2 ## d; \ movzbl ab ## bh, tmp1 ## d; \ rorq $16, ab; \ xorq T0(, tmp2, 8), dst; \ xorq T1(, tmp1, 8), dst; /********************************************************************** 1-way camellia **********************************************************************/ #define roundsm(ab, subkey, cd) \ movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ \ xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ \ xorq RT2, cd ## 0; #define fls(l, r, kl, kr) \ movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ andl l ## 0d, RT0d; \ roll $1, RT0d; \ shlq $32, RT0; \ xorq RT0, l ## 0; \ movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ orq r ## 0, RT1; \ shrq $32, RT1; \ xorq RT1, r ## 0; \ \ movq (key_table + ((kl) * 2) * 4)(CTX), RT2; \ orq l ## 0, RT2; \ shrq $32, RT2; \ xorq RT2, l ## 0; \ movl (key_table + ((kr) * 2) * 4)(CTX), RT0d; \ andl r ## 0d, RT0d; \ roll $1, RT0d; \ shlq $32, RT0; \ xorq RT0, r ## 0; #define enc_rounds(i) \ roundsm(RAB, i + 2, RCD); \ roundsm(RCD, i + 3, RAB); \ roundsm(RAB, i + 4, RCD); \ roundsm(RCD, i + 5, RAB); \ roundsm(RAB, i + 6, RCD); \ roundsm(RCD, i + 7, RAB); #define enc_fls(i) \ fls(RAB, RCD, i + 0, i + 1); #define enc_inpack() \ movq (RIO), RAB0; \ bswapq RAB0; \ rolq $32, RAB0; \ movq 4*2(RIO), RCD0; \ bswapq RCD0; \ rorq $32, RCD0; \ xorq key_table(CTX), RAB0; #define enc_outunpack(op, max) \ xorq key_table(CTX, max, 8), RCD0; \ rorq $32, RCD0; \ bswapq RCD0; \ op ## q RCD0, (RIO); \ rolq $32, RAB0; \ bswapq RAB0; \ op ## q RAB0, 4*2(RIO); #define dec_rounds(i) \ roundsm(RAB, i + 7, RCD); \ roundsm(RCD, i + 6, RAB); \ roundsm(RAB, i + 5, RCD); \ roundsm(RCD, i + 4, RAB); \ roundsm(RAB, i + 3, RCD); \ roundsm(RCD, i + 2, RAB); #define dec_fls(i) \ fls(RAB, RCD, i + 1, i + 0); #define dec_inpack(max) \ movq (RIO), RAB0; \ bswapq RAB0; \ rolq $32, RAB0; \ movq 4*2(RIO), RCD0; \ bswapq RCD0; \ rorq $32, RCD0; \ xorq key_table(CTX, max, 8), RAB0; #define dec_outunpack() \ xorq key_table(CTX), RCD0; \ rorq $32, RCD0; \ bswapq RCD0; \ movq RCD0, (RIO); \ rolq $32, RAB0; \ bswapq RAB0; \ movq RAB0, 4*2(RIO); ENTRY(__camellia_enc_blk) /* input: * %rdi: ctx, CTX * %rsi: dst * %rdx: src * %rcx: bool xor */ movq %rbp, RRBP; movq %rcx, RXOR; movq %rsi, RDST; movq %rdx, RIO; enc_inpack(); enc_rounds(0); enc_fls(8); enc_rounds(8); enc_fls(16); enc_rounds(16); movl $24, RT1d; /* max */ cmpb $16, key_length(CTX); je .L__enc_done; enc_fls(24); enc_rounds(24); movl $32, RT1d; /* max */ .L__enc_done: testb RXORbl, RXORbl; movq RDST, RIO; jnz .L__enc_xor; enc_outunpack(mov, RT1); movq RRBP, %rbp; ret; .L__enc_xor: enc_outunpack(xor, RT1); movq RRBP, %rbp; ret; ENDPROC(__camellia_enc_blk) ENTRY(camellia_dec_blk) /* input: * %rdi: ctx, CTX * %rsi: dst * %rdx: src */ cmpl $16, key_length(CTX); movl $32, RT2d; movl $24, RXORd; cmovel RXORd, RT2d; /* max */ movq %rbp, RRBP; movq %rsi, RDST; movq %rdx, RIO; dec_inpack(RT2); cmpb $24, RT2bl; je .L__dec_rounds16; dec_rounds(24); dec_fls(24); .L__dec_rounds16: dec_rounds(16); dec_fls(16); dec_rounds(8); dec_fls(8); dec_rounds(0); movq RDST, RIO; dec_outunpack(); movq RRBP, %rbp; ret; ENDPROC(camellia_dec_blk) /********************************************************************** 2-way camellia **********************************************************************/ #define roundsm2(ab, subkey, cd) \ movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ xorq RT2, cd ## 1; \ \ xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ \ xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 1, cd ## 1); \ xorq RT2, cd ## 0; \ xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 1, cd ## 1); \ xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 1, cd ## 1); \ xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 1, cd ## 1); #define fls2(l, r, kl, kr) \ movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ andl l ## 0d, RT0d; \ roll $1, RT0d; \ shlq $32, RT0; \ xorq RT0, l ## 0; \ movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ orq r ## 0, RT1; \ shrq $32, RT1; \ xorq RT1, r ## 0; \ \ movl (key_table + ((kl) * 2) * 4)(CTX), RT2d; \ andl l ## 1d, RT2d; \ roll $1, RT2d; \ shlq $32, RT2; \ xorq RT2, l ## 1; \ movq (key_table + ((kr) * 2) * 4)(CTX), RT0; \ orq r ## 1, RT0; \ shrq $32, RT0; \ xorq RT0, r ## 1; \ \ movq (key_table + ((kl) * 2) * 4)(CTX), RT1; \ orq l ## 0, RT1; \ shrq $32, RT1; \ xorq RT1, l ## 0; \ movl (key_table + ((kr) * 2) * 4)(CTX), RT2d; \ andl r ## 0d, RT2d; \ roll $1, RT2d; \ shlq $32, RT2; \ xorq RT2, r ## 0; \ \ movq (key_table + ((kl) * 2) * 4)(CTX), RT0; \ orq l ## 1, RT0; \ shrq $32, RT0; \ xorq RT0, l ## 1; \ movl (key_table + ((kr) * 2) * 4)(CTX), RT1d; \ andl r ## 1d, RT1d; \ roll $1, RT1d; \ shlq $32, RT1; \ xorq RT1, r ## 1; #define enc_rounds2(i) \ roundsm2(RAB, i + 2, RCD); \ roundsm2(RCD, i + 3, RAB); \ roundsm2(RAB, i + 4, RCD); \ roundsm2(RCD, i + 5, RAB); \ roundsm2(RAB, i + 6, RCD); \ roundsm2(RCD, i + 7, RAB); #define enc_fls2(i) \ fls2(RAB, RCD, i + 0, i + 1); #define enc_inpack2() \ movq (RIO), RAB0; \ bswapq RAB0; \ rorq $32, RAB0; \ movq 4*2(RIO), RCD0; \ bswapq RCD0; \ rolq $32, RCD0; \ xorq key_table(CTX), RAB0; \ \ movq 8*2(RIO), RAB1; \ bswapq RAB1; \ rorq $32, RAB1; \ movq 12*2(RIO), RCD1; \ bswapq RCD1; \ rolq $32, RCD1; \ xorq key_table(CTX), RAB1; #define enc_outunpack2(op, max) \ xorq key_table(CTX, max, 8), RCD0; \ rolq $32, RCD0; \ bswapq RCD0; \ op ## q RCD0, (RIO); \ rorq $32, RAB0; \ bswapq RAB0; \ op ## q RAB0, 4*2(RIO); \ \ xorq key_table(CTX, max, 8), RCD1; \ rolq $32, RCD1; \ bswapq RCD1; \ op ## q RCD1, 8*2(RIO); \ rorq $32, RAB1; \ bswapq RAB1; \ op ## q RAB1, 12*2(RIO); #define dec_rounds2(i) \ roundsm2(RAB, i + 7, RCD); \ roundsm2(RCD, i + 6, RAB); \ roundsm2(RAB, i + 5, RCD); \ roundsm2(RCD, i + 4, RAB); \ roundsm2(RAB, i + 3, RCD); \ roundsm2(RCD, i + 2, RAB); #define dec_fls2(i) \ fls2(RAB, RCD, i + 1, i + 0); #define dec_inpack2(max) \ movq (RIO), RAB0; \ bswapq RAB0; \ rorq $32, RAB0; \ movq 4*2(RIO), RCD0; \ bswapq RCD0; \ rolq $32, RCD0; \ xorq key_table(CTX, max, 8), RAB0; \ \ movq 8*2(RIO), RAB1; \ bswapq RAB1; \ rorq $32, RAB1; \ movq 12*2(RIO), RCD1; \ bswapq RCD1; \ rolq $32, RCD1; \ xorq key_table(CTX, max, 8), RAB1; #define dec_outunpack2() \ xorq key_table(CTX), RCD0; \ rolq $32, RCD0; \ bswapq RCD0; \ movq RCD0, (RIO); \ rorq $32, RAB0; \ bswapq RAB0; \ movq RAB0, 4*2(RIO); \ \ xorq key_table(CTX), RCD1; \ rolq $32, RCD1; \ bswapq RCD1; \ movq RCD1, 8*2(RIO); \ rorq $32, RAB1; \ bswapq RAB1; \ movq RAB1, 12*2(RIO); ENTRY(__camellia_enc_blk_2way) /* input: * %rdi: ctx, CTX * %rsi: dst * %rdx: src * %rcx: bool xor */ pushq %rbx; movq %rbp, RRBP; movq %rcx, RXOR; movq %rsi, RDST; movq %rdx, RIO; enc_inpack2(); enc_rounds2(0); enc_fls2(8); enc_rounds2(8); enc_fls2(16); enc_rounds2(16); movl $24, RT2d; /* max */ cmpb $16, key_length(CTX); je .L__enc2_done; enc_fls2(24); enc_rounds2(24); movl $32, RT2d; /* max */ .L__enc2_done: test RXORbl, RXORbl; movq RDST, RIO; jnz .L__enc2_xor; enc_outunpack2(mov, RT2); movq RRBP, %rbp; popq %rbx; ret; .L__enc2_xor: enc_outunpack2(xor, RT2); movq RRBP, %rbp; popq %rbx; ret; ENDPROC(__camellia_enc_blk_2way) ENTRY(camellia_dec_blk_2way) /* input: * %rdi: ctx, CTX * %rsi: dst * %rdx: src */ cmpl $16, key_length(CTX); movl $32, RT2d; movl $24, RXORd; cmovel RXORd, RT2d; /* max */ movq %rbx, RXOR; movq %rbp, RRBP; movq %rsi, RDST; movq %rdx, RIO; dec_inpack2(RT2); cmpb $24, RT2bl; je .L__dec2_rounds16; dec_rounds2(24); dec_fls2(24); .L__dec2_rounds16: dec_rounds2(16); dec_fls2(16); dec_rounds2(8); dec_fls2(8); dec_rounds2(0); movq RDST, RIO; dec_outunpack2(); movq RRBP, %rbp; movq RXOR, %rbx; ret; ENDPROC(camellia_dec_blk_2way)