HeavyThing - aesxts.inc

Jeff Marrison

Table of functions

	; ------------------------------------------------------------------------
	; HeavyThing x86_64 assembly language library and showcase programs
	; Copyright © 2015-2018 2 Ton Digital 
	; Homepage: https://2ton.com.au/
	; Author: Jeff Marrison <jeff@2ton.com.au>
	;       
	; This file is part of the HeavyThing library.
	;       
	; HeavyThing is free software: you can redistribute it and/or modify
	; it under the terms of the GNU General Public License, or
	; (at your option) any later version.
	;       
	; HeavyThing 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 the HeavyThing library. If not, see <http://www.gnu.org/licenses/>.
	; ------------------------------------------------------------------------
	;       
	; aesxts.inc: AES-256/XTS encryption/decryption
	; 
	; this is by the AESXTS standard, except we use two full sets of 32 byte keys
	; instead of half each
	;

if used aesxts$encrypt | used aesxts$decrypt | defined include_everything


; NOTE: this _must_ be a power of 2 >= 16
aesxts_blocksize = 4096

; 1 << this needs to equal the above
aesxts_blocksize_bits = 12

aesxts_blocks = aesxts_blocksize shr 4



; the size of our allocated structure requires three AES256 contexts:
aesxts_size = aes_size * 3


end if


if used aesxts$new | defined include_everything
	; two arguments: rdi == ptr to 32 byte key, rsi == ptr to 32 byte tweak key
falign
aesxts$new:
	prolog	aesxts$new
	push	rdi rsi
	mov	edi, aesxts_size
	call	heap$alloc
	pop	rdx rsi
	mov	rdi, rax
	push	rax
	call	aesxts$keys
	pop	rax
	epilog

end if


if used aesxts$keys | defined include_everything
	; three arguments: rdi == aesxts object, rsi == ptr to 32 byte key, rdx == ptr to 32 byte tweak key
falign
aesxts$keys:
	prolog	aesxts$keys
	push	rbx r12 r13
	mov	rbx, rdi
	mov	r12, rsi
	mov	r13, rdx
	mov	edx, 32
	call	aes$init_encrypt
	lea	rdi, [rbx+aes_size]
	mov	rsi, r13
	mov	edx, 32
	call	aes$init_encrypt
	lea	rdi, [rbx+(aes_size*2)]
	mov	rsi, r12
	mov	edx, 32
	call	aes$init_decrypt
	pop	r13 r12 rbx
	epilog

end if


if used aesxts$destroy | defined include_everything
	; single argument in rdi: aesxts object
falign
aesxts$destroy:
	prolog	aesxts$destroy
	push	rdi
	xor	esi, esi
	mov	edx, aesxts_size
	call	memset32
	pop	rdi
	call	heap$free
	epilog

end if



if used aesxts$encrypt | defined include_everything
	; three arguments: rdi == aesxts object, rsi == ptr to aesxts_blocksize worth of plaintext, rdx == ptr to encryption tweak (e.g. blocknum) (must be 16 bytes in length)
falign
aesxts$encrypt:
	prolog	aesxts$encrypt
	push	rbx r12 r13 r14 r15
	mov	rbx, rdi
	mov	r12, rsi
	mov	r13, rdx
	; first order of business: encrypt the tweak using the tweak encrypt aes context:
	lea	rdi, [rdi+aes_size]
	mov	rsi, rdx
	call	aes$encrypt
	; now, for aesxts_blocks, do our tweaked encrypt
	mov	r14d, aesxts_blocks
calign
.tweaked:
	; xor our block with the tweak
	mov	rax, [r13]
	mov	rcx, [r13+8]
	xor	[r12], rax
	xor	[r12+8], rcx
	; encrypt the block
	mov	rdi, rbx
	mov	rsi, r12
	call	aes$encrypt
	; xor with the tweak again
	mov	rax, [r13]
	mov	rcx, [r13+8]
	xor	[r12], rax
	xor	[r12+8], rcx
	; LSFR the tweak
	shl	rcx, 1
	jc	.lsfr_carry
	shl	rax, 1
	adc	rcx, 0
	mov	[r13], rax
	mov	[r13+8], rcx

	; proceed to next block or done
	add	r12, 16
	sub	r14d, 1
	jnz	.tweaked
	pop	r15 r14 r13 r12 rbx
	epilog
calign
.lsfr_carry:
	shl	rax, 1
	adc	rcx, 0
	xor	rax, 0x87
	mov	[r13], rax
	mov	[r13+8], rcx
	
	; proceed to next block or done
	add	r12, 16
	sub	r14d, 1
	jnz	.tweaked
	pop	r15 r14 r13 r12 rbx
	epilog


end if


if used aesxts$decrypt | defined include_everything
	; three arguments: rdi == aesxts object, rsi == ptr to aesxts_blocksize worth of ciphertext, rdx == ptr to encryption tweak (e.g. blocknum)
falign
aesxts$decrypt:
	prolog	aesxts$decrypt
	push	rbx r12 r13 r14 r15
	mov	rbx, rdi
	mov	r12, rsi
	mov	r13, rdx
	; first order of business: encrypt the tweak using the tweak encrypt aes context:
	lea	rdi, [rdi+aes_size]
	mov	rsi, rdx
	call	aes$encrypt
	; now, for aesxts_blocks, do our tweaked encrypt
	mov	r14d, aesxts_blocks
calign
.tweaked:
	; xor our block with the tweak
	mov	rax, [r13]
	mov	rcx, [r13+8]
	xor	[r12], rax
	xor	[r12+8], rcx
	; decrypt the block
	lea	rdi, [rbx+(aes_size*2)]
	mov	rsi, r12
	call	aes$decrypt
	; xor with the tweak again
	mov	rax, [r13]
	mov	rcx, [r13+8]
	xor	[r12], rax
	xor	[r12+8], rcx
	; LSFR the tweak
	shl	rcx, 1
	jc	.lsfr_carry
	shl	rax, 1
	adc	rcx, 0
	mov	[r13], rax
	mov	[r13+8], rcx

	; proceed to next block or done
	add	r12, 16
	sub	r14d, 1
	jnz	.tweaked
	pop	r15 r14 r13 r12 rbx
	epilog
calign
.lsfr_carry:
	shl	rax, 1
	adc	rcx, 0
	xor	rax, 0x87
	mov	[r13], rax
	mov	[r13+8], rcx
	
	; proceed to next block or done
	add	r12, 16
	sub	r14d, 1
	jnz	.tweaked

	pop	r15 r14 r13 r12 rbx
	epilog

end if