// File: shanet[P]Crypto-Example/Crypto.cpp
// Function: Crypto::rsaEncrypt(unsigned char const*, unsigned long, unsigned char**, unsigned char**, unsigned long*, unsigned char**, unsigned long*)
int Crypto::rsaEncrypt(const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage, unsigned char **encryptedKey,
  size_t *encryptedKeyLength, unsigned char **iv, size_t *ivLength) {

  // Allocate memory for everything
  size_t encryptedMessageLength = 0;
  size_t blockLength = 0;

  *encryptedKey = (unsigned char*)malloc(EVP_PKEY_size(remotePublicKey));
  *iv = (unsigned char*)malloc(EVP_MAX_IV_LENGTH);
  *ivLength = EVP_MAX_IV_LENGTH;

  if(*encryptedKey == NULL || *iv == NULL) {
    return FAILURE;
  }

  *encryptedMessage = (unsigned char*)malloc(messageLength + EVP_MAX_IV_LENGTH);
  if(encryptedMessage == NULL) {
    return FAILURE;
  }

  // Encrypt it!
  if(!EVP_SealInit(rsaEncryptContext, EVP_aes_256_cbc(), encryptedKey, (int*)encryptedKeyLength, *iv, &remotePublicKey, 1)) {
    return FAILURE;
  }

  if(!EVP_SealUpdate(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength, (const unsigned char*)message, (int)messageLength)) {
    return FAILURE;
  }
  encryptedMessageLength += blockLength;

  if(!EVP_SealFinal(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength)) {
    return FAILURE;
  }
  encryptedMessageLength += blockLength;

  return (int)encryptedMessageLength;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq 0x18(%rbp), %rax
movq 0x10(%rbp), %rax
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movq %r8, -0x30(%rbp)
movq %r9, -0x38(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x50(%rbp)
movq $0x0, -0x40(%rbp)
movq $0x0, -0x48(%rbp)
movq (%rax), %rdi
callq 0x2390
movslq %eax, %rdi
callq 0x22d0
movq %rax, %rcx
movq -0x30(%rbp), %rax
movq %rcx, (%rax)
movl $0x10, %edi
callq 0x22d0
movq %rax, %rcx
movq 0x10(%rbp), %rax
movq %rcx, (%rax)
movq 0x18(%rbp), %rax
movq $0x10, (%rax)
movq -0x30(%rbp), %rax
cmpq $0x0, (%rax)
je 0x2d3d
movq 0x10(%rbp), %rax
cmpq $0x0, (%rax)
jne 0x2d49
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x2e36
movq -0x20(%rbp), %rdi
addq $0x10, %rdi
callq 0x22d0
movq %rax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, (%rax)
cmpq $0x0, -0x28(%rbp)
jne 0x2d73
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x2e36
movq -0x50(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x58(%rbp)
callq 0x2160
movq -0x58(%rbp), %rdi
movq -0x50(%rbp), %r9
movq %rax, %rsi
movq -0x30(%rbp), %rdx
movq -0x38(%rbp), %rcx
movq 0x10(%rbp), %rax
movq (%rax), %r8
movl $0x1, (%rsp)
callq 0x23d0
cmpl $0x0, %eax
jne 0x2db8
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x2e36
movq -0x50(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x28(%rbp), %rax
movq (%rax), %rsi
addq -0x40(%rbp), %rsi
movq -0x18(%rbp), %rcx
movq -0x20(%rbp), %rax
movl %eax, %r8d
leaq -0x48(%rbp), %rdx
callq 0x2050
cmpl $0x0, %eax
jne 0x2ded
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x2e36
movq -0x50(%rbp), %rax
movq -0x48(%rbp), %rcx
addq -0x40(%rbp), %rcx
movq %rcx, -0x40(%rbp)
movq 0x8(%rax), %rdi
movq -0x28(%rbp), %rax
movq (%rax), %rsi
addq -0x40(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0x2260
cmpl $0x0, %eax
jne 0x2e23
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x2e36
movq -0x48(%rbp), %rax
addq -0x40(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x60, %rsp
popq %rbp
retq
nop