title: How to convert AES_encrypt in counter mode to EVP interfaces?
body: <p>I'm in the process of coding some stuff around common-encryption which require AES Ctr 128. So I'm digging a bit with crypto stuff.</p>
  
  <p>Currently I test a code (find here) which work (encrypt/decrypt a file):</p>
  
  <pre class="lang-c prettyprint-override"><code>#include &lt;openssl/aes.h&gt;
  #include &lt;openssl/rand.h&gt;
  #include &lt;openssl/hmac.h&gt;
  #include &lt;openssl/buffer.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;math.h&gt;
  
  
  struct ctr_state {
    unsigned char ivec[AES_BLOCK_SIZE];
    unsigned int num;
    unsigned char ecount[AES_BLOCK_SIZE];
  };
  
  void print_hex(unsigned char *c) {
    for(int i = 0; i &lt; 16; i++) {
      printf("%02X.", c[i]);
    }
    printf("\n");
  }
  
  
  void init_ctr(struct ctr_state *state, const unsigned char iv[16]) {
    state-&gt;num = 0;
    memset(state-&gt;ecount, 0, 16);
    memset(state-&gt;ivec + 8, 0, 8);
    memcpy(state-&gt;ivec, iv, 8);
  }
  
  void fencrypt(char* read, char* write, const unsigned char* enc_key) {
  
    FILE *readFile;
    FILE *writeFile;
    AES_KEY key;
  
    int bytes_read;
    unsigned char indata[AES_BLOCK_SIZE];
    unsigned char outdata[AES_BLOCK_SIZE];
    unsigned char iv[AES_BLOCK_SIZE];
  
    struct ctr_state state;
  
  
    RAND_bytes(iv, AES_BLOCK_SIZE);
  
    print_hex(iv);
    readFile = fopen(read,"rb");
    writeFile = fopen(write,"wb");
  
  
    AES_set_encrypt_key(enc_key, 128, &amp;key);
  
    init_ctr(&amp;state, iv);
  
    fwrite(state.ivec, 1, AES_BLOCK_SIZE, writeFile);
  
    print_hex(state.ivec);
  
    while(1) {
      bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile);
      AES_ctr128_encrypt(indata, outdata, bytes_read, &amp;key, state.ivec, state.ecount, &amp;state.num);
  
      print_hex(state.ivec);
      fwrite(outdata, 1, bytes_read, writeFile);
      if (bytes_read &lt; AES_BLOCK_SIZE) {
        break;
      }
    }
  
    fclose(writeFile);
    fclose(readFile);
  }
  
  void fdecrypt(char* read, char* write, const unsigned char* enc_key) {
  
    FILE *readFile;
    FILE *writeFile;
    AES_KEY key;
  
    int bytes_read;
    unsigned char indata[AES_BLOCK_SIZE];
    unsigned char outdata[AES_BLOCK_SIZE];
    unsigned char iv[AES_BLOCK_SIZE];
  
    struct ctr_state state;
  
    readFile=fopen(read,"rb");
    writeFile=fopen(write,"wb");
  
    fread(iv, 1, AES_BLOCK_SIZE, readFile);
  
    AES_set_encrypt_key(enc_key, 128, &amp;key);
  
    init_ctr(&amp;state, iv);
  
    while(1) {
      bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile);
      AES_ctr128_encrypt(indata, outdata, bytes_read, &amp;key, state.ivec, state.ecount, &amp;state.num);
  
      print_hex(state.ivec);
      fwrite(outdata, 1, bytes_read, writeFile);
      if (bytes_read &lt; AES_BLOCK_SIZE) {
              break;
      }
    }
    fclose(writeFile);
    fclose(readFile);
  }
  
  int main(int argc, char *argv[]) {
   char* secret = "supersecret";
  
   fencrypt("encme.txt", "enced.enc", (const unsigned char*)secret);
   fdecrypt("enced.enc", "unenced.txt", (const unsigned char*)secret);
  }
  </code></pre>
  
  <p>This work well. But It seems that the standard is to to use EVP functions now with openssl. So I try to adapt my code but something is clearly wrong with my implementations. I don't understand on how properly update/increment the IV vector.</p>
  
  <p>Here my new code with EVP (work but not increment/counter):</p>
  
  <pre class="lang-c prettyprint-override"><code>#include &lt;openssl/aes.h&gt;
  #include &lt;openssl/rand.h&gt;
  #include &lt;openssl/evp.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  
  
  struct ctr_state {
    EVP_CIPHER_CTX* cipher;
    int num;
  };
  
  void print_hex(unsigned char *c) {
    for(int i = 0; i &lt; 16; i++) {
      printf("%02X.", c[i]);
    }
    printf("\n");
  }
  
  void init_ctr(struct ctr_state *state, unsigned char iv[16], unsigned char* key) {
      state-&gt;num = 0;
      state-&gt;cipher = EVP_CIPHER_CTX_new();
      EVP_EncryptInit_ex(state-&gt;cipher, EVP_aes_128_ctr(), NULL, key, iv);
  }
  
  void fencrypt(char* read, char* write, unsigned char* enc_key) {
  
    FILE *readFile;
    FILE *writeFile;
  
    int bytes_read;
    unsigned char indata[AES_BLOCK_SIZE];
    unsigned char outdata[AES_BLOCK_SIZE];
    unsigned char iv[AES_BLOCK_SIZE];
  
    struct ctr_state state;
  
    RAND_bytes(iv, AES_BLOCK_SIZE);
  
    readFile = fopen(read,"rb");
    writeFile = fopen(write,"wb");
  
    fwrite(iv, 1, AES_BLOCK_SIZE, writeFile);
    init_ctr(&amp;state, iv, enc_key);
    print_hex(iv);
  
    while(1) {
      bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile);
  
      EVP_EncryptUpdate(state.cipher, outdata, &amp;state.num, indata, bytes_read);
  
      EVP_EncryptUpdate(state.cipher, outdata, &amp;state.num, indata, bytes_read);
  
      fwrite(outdata, 1, bytes_read, writeFile);
      if (bytes_read &lt; AES_BLOCK_SIZE) {
        break;
      }
    }
  
    fclose(writeFile);
    fclose(readFile);
  }
  
  void fdecrypt(char* read, char* write, unsigned char* enc_key) {
  
    FILE *readFile;
    FILE *writeFile;
  
    int bytes_read;
    unsigned char indata[AES_BLOCK_SIZE];
    unsigned char outdata[AES_BLOCK_SIZE];
    unsigned char iv[AES_BLOCK_SIZE];
  
    struct ctr_state state;
  
    readFile = fopen(read,"rb");
    writeFile = fopen(write,"wb");
  
    fread(iv, 1, AES_BLOCK_SIZE, readFile);
    init_ctr(&amp;state, iv, enc_key);
  
    print_hex(iv);
  
    while(1) {
      bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile);
  
      EVP_EncryptUpdate(state.cipher, outdata, &amp;state.num, indata, bytes_read);
      printf("Pass %d ",state.num);
  
      fwrite(outdata, 1, bytes_read, writeFile);
      if (bytes_read &lt; AES_BLOCK_SIZE) {
        break;
      }
    }
  
    fclose(writeFile);
    fclose(readFile);
  }
  
  int main(int argc, char *argv[]) {
   char* secret = "supersecret";
  
   fencrypt("encme.txt", "enced.enc", (unsigned char*)secret);
   fdecrypt("enced.enc", "unenced.txt", (unsigned char*)secret);
  }
  </code></pre>
  
  <p>Any help appreciated. Thank you.</p>