// File: wangyu-[P]pwdgen/lib/pbkdf2-sha256.cpp
// Function: PKCS5_PBKDF2_HMAC_SHA256(unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long, unsigned long, unsigned char*)
void PKCS5_PBKDF2_HMAC_SHA256(unsigned char *password, size_t plen,
    unsigned char *salt, size_t slen,
    const unsigned long iteration_count, const unsigned long key_length,
    unsigned char *output)
{
	sha2_context ctx;
	sha2_starts(&ctx, 0);

	// Size of the generated digest
	unsigned char md_size = 32;
	unsigned char md1[32];
	unsigned char work[32];

	unsigned long counter = 1;
	unsigned long generated_key_length = 0;
	while (generated_key_length < key_length) {
		// U1 ends up in md1 and work
		unsigned char c[4];
		c[0] = (counter >> 24) & 0xff;
		c[1] = (counter >> 16) & 0xff;
		c[2] = (counter >> 8) & 0xff;
		c[3] = (counter >> 0) & 0xff;

		sha2_hmac_starts(&ctx, password, plen, 0);
		sha2_hmac_update(&ctx, salt, slen);
		sha2_hmac_update(&ctx, c, 4);
		sha2_hmac_finish(&ctx, md1);
		memcpy(work, md1, md_size);

		unsigned long ic = 1;
		for (ic = 1; ic < iteration_count; ic++) {
			// U2 ends up in md1
			sha2_hmac_starts(&ctx, password, plen, 0);
			sha2_hmac_update(&ctx, md1, md_size);
			sha2_hmac_finish(&ctx, md1);
			// U1 xor U2
			unsigned long i = 0;
			for (i = 0; i < md_size; i++) {
				work[i] ^= md1[i];
			}
			// and so on until iteration_count
		}

		// Copy the generated bytes to the key
		unsigned long bytes_to_write =
		    min((key_length - generated_key_length), md_size);
		memcpy(output + generated_key_length, work, bytes_to_write);
		generated_key_length += bytes_to_write;
		++counter;
	}
}

// Assembly:
subq $0x1d8, %rsp            # imm = 0x1D8
movq 0x1e0(%rsp), %rax
movq %rdi, 0x1d0(%rsp)
movq %rsi, 0x1c8(%rsp)
movq %rdx, 0x1c0(%rsp)
movq %rcx, 0x1b8(%rsp)
movq %r8, 0x1b0(%rsp)
movq %r9, 0x1a8(%rsp)
leaq 0x90(%rsp), %rdi
xorl %esi, %esi
callq 0x408500
movb $0x20, 0x8f(%rsp)
movq $0x1, 0x38(%rsp)
movq $0x0, 0x30(%rsp)
movq 0x30(%rsp), %rax
cmpq 0x1a8(%rsp), %rax
jae 0x41147d
movq 0x38(%rsp), %rax
shrq $0x18, %rax
andq $0xff, %rax
movb %al, 0x2c(%rsp)
movq 0x38(%rsp), %rax
shrq $0x10, %rax
andq $0xff, %rax
movb %al, 0x2d(%rsp)
movq 0x38(%rsp), %rax
shrq $0x8, %rax
andq $0xff, %rax
movb %al, 0x2e(%rsp)
movq 0x38(%rsp), %rax
shrq $0x0, %rax
andq $0xff, %rax
movb %al, 0x2f(%rsp)
movq 0x1d0(%rsp), %rsi
movq 0x1c8(%rsp), %rdx
leaq 0x90(%rsp), %rdi
xorl %ecx, %ecx
callq 0x410ed0
movq 0x1c0(%rsp), %rsi
movq 0x1b8(%rsp), %rdx
leaq 0x90(%rsp), %rdi
callq 0x411030
leaq 0x2c(%rsp), %rsi
leaq 0x90(%rsp), %rdi
movl $0x4, %edx
callq 0x411030
leaq 0x60(%rsp), %rsi
leaq 0x90(%rsp), %rdi
callq 0x411060
leaq 0x40(%rsp), %rdi
leaq 0x60(%rsp), %rsi
movzbl 0x8f(%rsp), %eax
movl %eax, %edx
callq 0x401040
movq $0x1, 0x20(%rsp)
movq $0x1, 0x20(%rsp)
movq 0x20(%rsp), %rax
cmpq 0x1b0(%rsp), %rax
jae 0x4113fa
movq 0x1d0(%rsp), %rsi
movq 0x1c8(%rsp), %rdx
leaq 0x90(%rsp), %rdi
xorl %ecx, %ecx
callq 0x410ed0
leaq 0x60(%rsp), %rsi
movzbl 0x8f(%rsp), %eax
movl %eax, %edx
leaq 0x90(%rsp), %rdi
callq 0x411030
leaq 0x60(%rsp), %rsi
leaq 0x90(%rsp), %rdi
callq 0x411060
movq $0x0, 0x18(%rsp)
movq $0x0, 0x18(%rsp)
movq 0x18(%rsp), %rax
movzbl 0x8f(%rsp), %ecx
cmpq %rcx, %rax
jae 0x4113e5
movq 0x18(%rsp), %rax
movzbl 0x60(%rsp,%rax), %edx
movq 0x18(%rsp), %rax
movzbl 0x40(%rsp,%rax), %ecx
xorl %edx, %ecx
movb %cl, 0x40(%rsp,%rax)
movq 0x18(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x18(%rsp)
jmp 0x4113a9
jmp 0x4113e7
movq 0x20(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x20(%rsp)
jmp 0x411337
movq 0x1a8(%rsp), %rax
subq 0x30(%rsp), %rax
movzbl 0x8f(%rsp), %ecx
cmpq %rcx, %rax
jae 0x411428
movq 0x1a8(%rsp), %rax
subq 0x30(%rsp), %rax
movq %rax, 0x8(%rsp)
jmp 0x411435
movzbl 0x8f(%rsp), %eax
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x1e0(%rsp), %rdi
addq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rsi
movq 0x10(%rsp), %rdx
callq 0x401040
movq 0x10(%rsp), %rax
addq 0x30(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x38(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x38(%rsp)
jmp 0x411248
addq $0x1d8, %rsp            # imm = 0x1D8
retq
nopw %cs:(%rax,%rax)