// File: wangyu-[P]pwdgen/lib/pbkdf2-sha1.cpp
// Function: PKCS5_PBKDF2_HMAC_SHA1(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned char*)
void PKCS5_PBKDF2_HMAC_SHA1(const unsigned char *password, size_t plen,
    const unsigned char *salt, size_t slen,
    const unsigned long iteration_count, const unsigned long key_length,
    unsigned char *output)
{
	sha1_context ctx;
	sha1_starts(&ctx);

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

	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;

		sha1_hmac_starts(&ctx, password, plen);
		sha1_hmac_update(&ctx, salt, slen);
		sha1_hmac_update(&ctx, c, 4);
		sha1_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
			sha1_hmac_starts(&ctx, password, plen);
			sha1_hmac_update(&ctx, md1, md_size);
			sha1_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 $0x1a8, %rsp            # imm = 0x1A8
movq 0x1b0(%rsp), %rax
movq %rdi, 0x1a0(%rsp)
movq %rsi, 0x198(%rsp)
movq %rdx, 0x190(%rsp)
movq %rcx, 0x188(%rsp)
movq %r8, 0x180(%rsp)
movq %r9, 0x178(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x4043b0
movb $0x14, 0x7f(%rsp)
movq $0x1, 0x38(%rsp)
movq $0x0, 0x30(%rsp)
movq 0x30(%rsp), %rax
cmpq 0x178(%rsp), %rax
jae 0x4084e9
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 0x1a0(%rsp), %rsi
movq 0x198(%rsp), %rax
movl %eax, %edx
leaq 0x80(%rsp), %rdi
callq 0x407ff0
movq 0x190(%rsp), %rsi
movq 0x188(%rsp), %rax
movl %eax, %edx
leaq 0x80(%rsp), %rdi
callq 0x408110
leaq 0x2c(%rsp), %rsi
leaq 0x80(%rsp), %rdi
movl $0x4, %edx
callq 0x408110
leaq 0x60(%rsp), %rsi
leaq 0x80(%rsp), %rdi
callq 0x408140
leaq 0x40(%rsp), %rdi
leaq 0x60(%rsp), %rsi
movzbl 0x7f(%rsp), %eax
movl %eax, %edx
callq 0x401040
movq $0x1, 0x20(%rsp)
movq $0x1, 0x20(%rsp)
movq 0x20(%rsp), %rax
cmpq 0x180(%rsp), %rax
jae 0x40846c
movq 0x1a0(%rsp), %rsi
movq 0x198(%rsp), %rax
movl %eax, %edx
leaq 0x80(%rsp), %rdi
callq 0x407ff0
leaq 0x60(%rsp), %rsi
movzbl 0x7f(%rsp), %edx
leaq 0x80(%rsp), %rdi
callq 0x408110
leaq 0x60(%rsp), %rsi
leaq 0x80(%rsp), %rdi
callq 0x408140
movq $0x0, 0x18(%rsp)
movq $0x0, 0x18(%rsp)
movq 0x18(%rsp), %rax
movzbl 0x7f(%rsp), %ecx
cmpq %rcx, %rax
jae 0x408457
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 0x40841e
jmp 0x408459
movq 0x20(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x20(%rsp)
jmp 0x4083b1
movq 0x178(%rsp), %rax
subq 0x30(%rsp), %rax
movzbl 0x7f(%rsp), %ecx
cmpq %rcx, %rax
jae 0x408497
movq 0x178(%rsp), %rax
subq 0x30(%rsp), %rax
movq %rax, 0x8(%rsp)
jmp 0x4084a1
movzbl 0x7f(%rsp), %eax
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x1b0(%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 0x4082c3
addq $0x1a8, %rsp            # imm = 0x1A8
retq
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)