Beispiel #1
0
/**
  * Compare one cipher_ctx to another.
  *
  * returns 0 if all the parameters (except the derived key data) are the same
  * returns 1 otherwise
  */
static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
  int are_equal = (
    c1->iv_sz == c2->iv_sz
    && c1->kdf_iter == c2->kdf_iter
    && c1->fast_kdf_iter == c2->fast_kdf_iter
    && c1->key_sz == c2->key_sz
    && c1->pass_sz == c2->pass_sz
    && c1->flags == c2->flags
    && c1->hmac_sz == c2->hmac_sz
    && c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx) 
    && (
      c1->pass == c2->pass
      || !sqlcipher_memcmp((const unsigned char*)c1->pass,
                           (const unsigned char*)c2->pass,
                           c1->pass_sz)
    ));

  CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered \
                  c1=%p c2=%p \
                  c1->iv_sz=%d c2->iv_sz=%d \
                  c1->kdf_iter=%d c2->kdf_iter=%d \
                  c1->fast_kdf_iter=%d c2->fast_kdf_iter=%d \
                  c1->key_sz=%d c2->key_sz=%d \
                  c1->pass_sz=%d c2->pass_sz=%d \
                  c1->flags=%d c2->flags=%d \
                  c1->hmac_sz=%d c2->hmac_sz=%d \
                  c1->provider_ctx=%p c2->provider_ctx=%p \
                  c1->pass=%p c2->pass=%p \
                  c1->pass=%s c2->pass=%s \
                  provider->ctx_cmp=%d \
                  sqlcipher_memcmp=%d \
                  are_equal=%d \
                   \n", 
                  c1, c2,
                  c1->iv_sz, c2->iv_sz,
                  c1->kdf_iter, c2->kdf_iter,
                  c1->fast_kdf_iter, c2->fast_kdf_iter,
                  c1->key_sz, c2->key_sz,
                  c1->pass_sz, c2->pass_sz,
                  c1->flags, c2->flags,
                  c1->hmac_sz, c2->hmac_sz,
                  c1->provider_ctx, c2->provider_ctx,
                  c1->pass, c2->pass,
                  c1->pass, c2->pass,
                  c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx),
                  sqlcipher_memcmp((const unsigned char*)c1->pass,
                           (const unsigned char*)c2->pass,
                           c1->pass_sz),
                  are_equal
                  ));

  return !are_equal; /* return 0 if they are the same, 1 otherwise */
}
/**
  * Compare one cipher_ctx to another.
  *
  * returns 0 if all the parameters (except the derived key data) are the same
  * returns 1 otherwise
  */
static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
  CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2));

  if(
    c1->iv_sz == c2->iv_sz
    && c1->kdf_iter == c2->kdf_iter
    && c1->fast_kdf_iter == c2->fast_kdf_iter
    && c1->key_sz == c2->key_sz
    && c1->pass_sz == c2->pass_sz
    && c1->flags == c2->flags
    && c1->hmac_sz == c2->hmac_sz
    && c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx) 
    && (
      c1->pass == c2->pass
      || !sqlcipher_memcmp((const unsigned char*)c1->pass,
                           (const unsigned char*)c2->pass,
                           c1->pass_sz)
    ) 
  ) return 0;
  return 1;
}
Beispiel #3
0
/*
 * ctx - codec context
 * pgno - page number in database
 * size - size in bytes of input and output buffers
 * mode - 1 to encrypt, 0 to decrypt
 * in - pointer to input bytes
 * out - pouter to output bytes
 */
int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
  unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
  int size;

  /* calculate some required positions into various buffers */
  size = page_sz - c_ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
  iv_out = out + size;
  iv_in = in + size;

  /* hmac will be written immediately after the initialization vector. the remainder of the page reserve will contain
     random bytes. note, these pointers are only valid when using hmac */
  hmac_in = in + size + c_ctx->iv_sz; 
  hmac_out = out + size + c_ctx->iv_sz;
  out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */

  CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
  CODEC_HEXDUMP("codec_cipher: input page data", in, page_sz);

  /* the key size should never be zero. If it is, error out. */
  if(c_ctx->key_sz == 0) {
    CODEC_TRACE(("codec_cipher: error possible context corruption, key_sz is zero for pgno=%d\n", pgno));
    sqlcipher_memset(out, 0, page_sz); 
    return SQLITE_ERROR;
  } 

  if(mode == CIPHER_ENCRYPT) {
    /* start at front of the reserve block, write random data to the end */
    if(c_ctx->provider->random(c_ctx->provider_ctx, iv_out, c_ctx->reserve_sz) != SQLITE_OK) return SQLITE_ERROR; 
  } else { /* CIPHER_DECRYPT */
    memcpy(iv_out, iv_in, c_ctx->iv_sz); /* copy the iv from the input to output buffer */
  } 

  if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT) && !ctx->skip_read_hmac) {
    if(sqlcipher_page_hmac(c_ctx, pgno, in, size + c_ctx->iv_sz, hmac_out) != SQLITE_OK) {
      sqlcipher_memset(out, 0, page_sz); 
      CODEC_TRACE(("codec_cipher: hmac operations failed for pgno=%d\n", pgno));
      return SQLITE_ERROR;
    }

    CODEC_TRACE(("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz));
    if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { /* the hmac check failed */ 
      if(sqlcipher_ismemset(in, 0, page_sz) == 0) {
        /* first check if the entire contents of the page is zeros. If so, this page 
           resulted from a short read (i.e. sqlite attempted to pull a page after the end of the file. these 
           short read failures must be ignored for autovaccum mode to work so wipe the output buffer 
           and return SQLITE_OK to skip the decryption step. */
        CODEC_TRACE(("codec_cipher: zeroed page (short read) for pgno %d, encryption but returning SQLITE_OK\n", pgno));
        sqlcipher_memset(out, 0, page_sz); 
  	return SQLITE_OK;
      } else {
	/* if the page memory is not all zeros, it means the there was data and a hmac on the page. 
           since the check failed, the page was either tampered with or corrupted. wipe the output buffer,
           and return SQLITE_ERROR to the caller */
      	CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno));
        sqlcipher_memset(out, 0, page_sz); 
      	return SQLITE_ERROR;
      }
    }
  } 
  
  c_ctx->provider->cipher(c_ctx->provider_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out);

  if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
    sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out); 
  }

  CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz);

  return SQLITE_OK;
}