]> git.saurik.com Git - apple/xnu.git/blobdiff - EXTERNAL_HEADERS/corecrypto/ccmode.h
xnu-7195.60.75.tar.gz
[apple/xnu.git] / EXTERNAL_HEADERS / corecrypto / ccmode.h
index 0c7a19479c5f1e2b1d45ca10a43ee9c5bcf1504b..e01908eb1d0d942cc6f520187be0f972b4b5de76 100644 (file)
@@ -1,10 +1,12 @@
-/*
- *  ccmode.h
- *  corecrypto
- *
- *  Created by Michael Brouwer on 12/6/10.
- *  Copyright 2010,2011 Apple Inc. All rights reserved.
+/* Copyright (c) (2010,2011,2012,2014,2015,2016,2017,2018,2019) Apple Inc. All rights reserved.
  *
+ * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
+ * is contained in the License.txt file distributed with corecrypto) and only to 
+ * people who accept that license. IMPORTANT:  Any license rights granted to you by 
+ * Apple Inc. (if any) are limited to internal use within your organization only on 
+ * devices and computers you own or control, for the sole purpose of verifying the 
+ * security characteristics and correct functioning of the Apple Software.  You may 
+ * not, directly or indirectly, redistribute the Apple Software or any portions thereof.
  */
 
 #ifndef _CORECRYPTO_CCMODE_H_
 
 #include <corecrypto/cc.h>
 #include <corecrypto/ccmode_impl.h>
+#include <corecrypto/ccmode_siv.h>
+#include <corecrypto/ccmode_siv_hmac.h>
 
 /* ECB mode. */
 
 /* Declare a ecb key named _name_.  Pass the size field of a struct ccmode_ecb
    for _size_. */
 #define ccecb_ctx_decl(_size_, _name_) cc_ctx_decl(ccecb_ctx, _size_, _name_)
-#define ccecb_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccecb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t ccecb_context_size(const struct ccmode_ecb *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long ccecb_block_size(const struct ccmode_ecb *mode)
+CC_INLINE size_t ccecb_block_size(const struct ccmode_ecb *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccecb_init(const struct ccmode_ecb *mode, ccecb_ctx *ctx,
-                          size_t key_len, const void *key)
+CC_INLINE int ccecb_init(const struct ccmode_ecb *mode, ccecb_ctx *ctx, size_t key_len, const void *key)
 {
-    mode->init(mode, ctx, key_len, key);
+    return mode->init(mode, ctx, key_len, key);
 }
 
-CC_INLINE void ccecb_update(const struct ccmode_ecb *mode, const ccecb_ctx *ctx,
-                            unsigned long nblocks, const void *in, void *out)
+CC_INLINE int ccecb_update(const struct ccmode_ecb *mode, const ccecb_ctx *ctx, size_t nblocks, const void *in, void *out)
 {
-       mode->ecb(ctx, nblocks, in, out);
+    return mode->ecb(ctx, nblocks, in, out);
 }
 
-CC_INLINE void ccecb_one_shot(const struct ccmode_ecb *mode,
-                              size_t key_len, const void *key,
-                              unsigned long nblocks, const void *in, void *out)
+CC_INLINE int
+ccecb_one_shot(const struct ccmode_ecb *mode, size_t key_len, const void *key, size_t nblocks, const void *in, void *out)
 {
-       ccecb_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key);
-       mode->ecb(ctx, nblocks, in, out);
-       ccecb_ctx_clear(mode->size, ctx);
+    int rc;
+    ccecb_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, key_len, key);
+    if (rc == 0) {
+        rc = mode->ecb(ctx, nblocks, in, out);
+    }
+    ccecb_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
 /* CBC mode. */
 
-/* The CBC interface changed due to rdar://11468135. This macros is to indicate 
-   to client which CBC API is implemented. Clients can support old versions of
-   corecrypto at build time using this.
- */
 #define __CC_HAS_FIX_FOR_11468135__ 1
 
 /* Declare a cbc key named _name_.  Pass the size field of a struct ccmode_cbc
    for _size_. */
 #define cccbc_ctx_decl(_size_, _name_) cc_ctx_decl(cccbc_ctx, _size_, _name_)
-#define cccbc_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define cccbc_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* Declare a cbc iv tweak named _name_.  Pass the blocksize field of a
    struct ccmode_cbc for _size_. */
 #define cccbc_iv_decl(_size_, _name_) cc_ctx_decl(cccbc_iv, _size_, _name_)
-#define cccbc_iv_clear(_size_, _name_) cc_ctx_clear(cccbc_iv, _size_, _name_)
+#define cccbc_iv_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* Actual symmetric algorithm implementation can provide you one of these.
 
@@ -83,87 +84,82 @@ CC_INLINE size_t cccbc_context_size(const struct ccmode_cbc *mode)
     return mode->size;
 }
 
-CC_INLINE unsigned long cccbc_block_size(const struct ccmode_cbc *mode)
+CC_INLINE size_t cccbc_block_size(const struct ccmode_cbc *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void cccbc_init(const struct ccmode_cbc *mode, cccbc_ctx *ctx,
-                          size_t key_len, const void *key)
+CC_INLINE int cccbc_init(const struct ccmode_cbc *mode, cccbc_ctx *ctx, size_t key_len, const void *key)
 {
-    mode->init(mode, ctx, key_len, key);
+    return mode->init(mode, ctx, key_len, key);
 }
 
-CC_INLINE void cccbc_set_iv(const struct ccmode_cbc *mode, cccbc_iv *iv_ctx,
-                            const void *iv)
+CC_INLINE int cccbc_set_iv(const struct ccmode_cbc *mode, cccbc_iv *iv_ctx, const void *iv)
 {
-    if (iv)
+    if (iv) {
         cc_copy(mode->block_size, iv_ctx, iv);
-    else
-        cc_zero(mode->block_size, iv_ctx);
+    } else {
+        cc_clear(mode->block_size, iv_ctx);
+    }
+    return 0;
 }
 
-CC_INLINE void cccbc_update(const struct ccmode_cbc *mode,  cccbc_ctx *ctx,
-                            cccbc_iv *iv, unsigned long nblocks,
-                            const void *in, void *out)
+CC_INLINE int cccbc_update(const struct ccmode_cbc *mode, cccbc_ctx *ctx, cccbc_iv *iv, size_t nblocks, const void *in, void *out)
 {
-       mode->cbc(ctx, iv, nblocks, in, out);
+    return mode->cbc(ctx, iv, nblocks, in, out);
 }
 
-CC_INLINE void cccbc_one_shot(const struct ccmode_cbc *mode,
-                              unsigned long key_len, const void *key,
-                              const void *iv, unsigned long nblocks,
-                              const void *in, void *out)
-{
-       cccbc_ctx_decl(mode->size, ctx);
-       cccbc_iv_decl(mode->block_size, iv_ctx);
-       mode->init(mode, ctx, key_len, key);
-    if (iv)
-        cccbc_set_iv(mode, iv_ctx, iv);
-    else
-        cc_zero(mode->block_size, iv_ctx);
-    mode->cbc(ctx, iv_ctx, nblocks, in, out);
-       cccbc_ctx_clear(mode->size, ctx);
-}
+int cccbc_one_shot(const struct ccmode_cbc *mode,
+                   size_t key_len,
+                   const void *key,
+                   const void *iv,
+                   size_t nblocks,
+                   const void *in,
+                   void *out);
 
 /* CFB mode. */
 
 /* Declare a cfb key named _name_.  Pass the size field of a struct ccmode_cfb
    for _size_. */
 #define cccfb_ctx_decl(_size_, _name_) cc_ctx_decl(cccfb_ctx, _size_, _name_)
-#define cccfb_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define cccfb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t cccfb_context_size(const struct ccmode_cfb *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long cccfb_block_size(const struct ccmode_cfb *mode)
+CC_INLINE size_t cccfb_block_size(const struct ccmode_cfb *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void cccfb_init(const struct ccmode_cfb *mode, cccfb_ctx *ctx,
-                          size_t key_len, const void *key,
-                          const void *iv)
+CC_INLINE int cccfb_init(const struct ccmode_cfb *mode, cccfb_ctx *ctx, size_t key_len, const void *key, const void *iv)
 {
-    mode->init(mode, ctx, key_len, key, iv);
+    return mode->init(mode, ctx, key_len, key, iv);
 }
 
-CC_INLINE void cccfb_update(const struct ccmode_cfb *mode, cccfb_ctx *ctx,
-                            size_t nbytes, const void *in, void *out)
+CC_INLINE int cccfb_update(const struct ccmode_cfb *mode, cccfb_ctx *ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->cfb(ctx, nbytes, in, out);
+    return mode->cfb(ctx, nbytes, in, out);
 }
 
-CC_INLINE void cccfb_one_shot(const struct ccmode_cfb *mode,
-                              size_t key_len, const void *key, const void *iv,
-                              size_t nbytes, const void *in, void *out)
+CC_INLINE int cccfb_one_shot(const struct ccmode_cfb *mode,
+                             size_t key_len,
+                             const void *key,
+                             const void *iv,
+                             size_t nbytes,
+                             const void *in,
+                             void *out)
 {
-       cccfb_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key, iv);
-       mode->cfb(ctx, nbytes, in, out);
-       cccfb_ctx_clear(mode->size, ctx);
+    int rc;
+    cccfb_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, key_len, key, iv);
+    if (rc == 0) {
+        rc = mode->cfb(ctx, nbytes, in, out);
+    }
+    cccfb_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
 /* CFB8 mode. */
@@ -171,38 +167,44 @@ CC_INLINE void cccfb_one_shot(const struct ccmode_cfb *mode,
 /* Declare a cfb8 key named _name_.  Pass the size field of a struct ccmode_cfb8
  for _size_. */
 #define cccfb8_ctx_decl(_size_, _name_) cc_ctx_decl(cccfb8_ctx, _size_, _name_)
-#define cccfb8_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define cccfb8_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t cccfb8_context_size(const struct ccmode_cfb8 *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long cccfb8_block_size(const struct ccmode_cfb8 *mode)
+CC_INLINE size_t cccfb8_block_size(const struct ccmode_cfb8 *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void cccfb8_init(const struct ccmode_cfb8 *mode, cccfb8_ctx *ctx,
-                           size_t key_len, const void *key, const void *iv)
+CC_INLINE int cccfb8_init(const struct ccmode_cfb8 *mode, cccfb8_ctx *ctx, size_t key_len, const void *key, const void *iv)
 {
-    mode->init(mode, ctx, key_len, key, iv);
+    return mode->init(mode, ctx, key_len, key, iv);
 }
 
-CC_INLINE void cccfb8_update(const struct ccmode_cfb8 *mode,  cccfb8_ctx *ctx,
-                             size_t nbytes, const void *in, void *out)
+CC_INLINE int cccfb8_update(const struct ccmode_cfb8 *mode, cccfb8_ctx *ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->cfb8(ctx, nbytes, in, out);
+    return mode->cfb8(ctx, nbytes, in, out);
 }
 
-CC_INLINE void cccfb8_one_shot(const struct ccmode_cfb8 *mode,
-                               size_t key_len, const void *key, const void *iv,
-                               size_t nbytes, const void *in, void *out)
+CC_INLINE int cccfb8_one_shot(const struct ccmode_cfb8 *mode,
+                              size_t key_len,
+                              const void *key,
+                              const void *iv,
+                              size_t nbytes,
+                              const void *in,
+                              void *out)
 {
-       cccfb8_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key, iv);
-       mode->cfb8(ctx, nbytes, in, out);
-       cccfb8_ctx_clear(mode->size, ctx);
+    int rc;
+    cccfb8_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, key_len, key, iv);
+    if (rc == 0) {
+        rc = mode->cfb8(ctx, nbytes, in, out);
+    }
+    cccfb8_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
 /* CTR mode. */
@@ -210,7 +212,7 @@ CC_INLINE void cccfb8_one_shot(const struct ccmode_cfb8 *mode,
 /* Declare a ctr key named _name_.  Pass the size field of a struct ccmode_ctr
  for _size_. */
 #define ccctr_ctx_decl(_size_, _name_) cc_ctx_decl(ccctr_ctx, _size_, _name_)
-#define ccctr_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccctr_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* This is Integer Counter Mode: The IV is the initial value of the counter
  that is incremented by 1 for each new block. Use the mode flags to select
@@ -221,86 +223,95 @@ CC_INLINE size_t ccctr_context_size(const struct ccmode_ctr *mode)
     return mode->size;
 }
 
-CC_INLINE unsigned long ccctr_block_size(const struct ccmode_ctr *mode)
+CC_INLINE size_t ccctr_block_size(const struct ccmode_ctr *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccctr_init(const struct ccmode_ctr *mode, ccctr_ctx *ctx,
-                          size_t key_len, const void *key, const void *iv)
+CC_INLINE int ccctr_init(const struct ccmode_ctr *mode, ccctr_ctx *ctx, size_t key_len, const void *key, const void *iv)
 {
-    mode->init(mode, ctx, key_len, key, iv);
+    return mode->init(mode, ctx, key_len, key, iv);
 }
 
-CC_INLINE void ccctr_update(const struct ccmode_ctr *mode, ccctr_ctx *ctx,
-                            size_t nbytes, const void *in, void *out)
+CC_INLINE int ccctr_update(const struct ccmode_ctr *mode, ccctr_ctx *ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->ctr(ctx, nbytes, in, out);
+    return mode->ctr(ctx, nbytes, in, out);
 }
 
-CC_INLINE void ccctr_one_shot(const struct ccmode_ctr *mode,
-       size_t key_len, const void *key, const void *iv,
-    size_t nbytes, const void *in, void *out)
+CC_INLINE int ccctr_one_shot(const struct ccmode_ctr *mode,
+                             size_t key_len,
+                             const void *key,
+                             const void *iv,
+                             size_t nbytes,
+                             const void *in,
+                             void *out)
 {
-       ccctr_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key, iv);
-       mode->ctr(ctx, nbytes, in, out);
-       ccctr_ctx_clear(mode->size, ctx);
+    int rc;
+    ccctr_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, key_len, key, iv);
+    if (rc == 0) {
+        rc = mode->ctr(ctx, nbytes, in, out);
+    }
+    ccctr_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
-
 /* OFB mode. */
 
 /* Declare a ofb key named _name_.  Pass the size field of a struct ccmode_ofb
  for _size_. */
 #define ccofb_ctx_decl(_size_, _name_) cc_ctx_decl(ccofb_ctx, _size_, _name_)
-#define ccofb_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccofb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t ccofb_context_size(const struct ccmode_ofb *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long ccofb_block_size(const struct ccmode_ofb *mode)
+CC_INLINE size_t ccofb_block_size(const struct ccmode_ofb *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccofb_init(const struct ccmode_ofb *mode, ccofb_ctx *ctx,
-                          size_t key_len, const void *key, const void *iv)
+CC_INLINE int ccofb_init(const struct ccmode_ofb *mode, ccofb_ctx *ctx, size_t key_len, const void *key, const void *iv)
 {
-    mode->init(mode, ctx, key_len, key, iv);
+    return mode->init(mode, ctx, key_len, key, iv);
 }
 
-CC_INLINE void ccofb_update(const struct ccmode_ofb *mode, ccofb_ctx *ctx,
-                            size_t nbytes, const void *in, void *out)
+CC_INLINE int ccofb_update(const struct ccmode_ofb *mode, ccofb_ctx *ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->ofb(ctx, nbytes, in, out);
+    return mode->ofb(ctx, nbytes, in, out);
 }
 
-CC_INLINE void ccofb_one_shot(const struct ccmode_ofb *mode,
-                              size_t key_len, const void *key, const void *iv,
-                              size_t nbytes, const void *in, void *out)
+CC_INLINE int ccofb_one_shot(const struct ccmode_ofb *mode,
+                             size_t key_len,
+                             const void *key,
+                             const void *iv,
+                             size_t nbytes,
+                             const void *in,
+                             void *out)
 {
-       ccofb_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key, iv);
-       mode->ofb(ctx, nbytes, in, out);
-       ccofb_ctx_clear(mode->size, ctx);
+    int rc;
+    ccofb_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, key_len, key, iv);
+    if (rc == 0) {
+        rc = mode->ofb(ctx, nbytes, in, out);
+    }
+    ccofb_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
-/* Authenticated cipher modes. */
-
 /* XTS mode. */
 
 /* Declare a xts key named _name_.  Pass the size field of a struct ccmode_xts
  for _size_. */
 #define ccxts_ctx_decl(_size_, _name_) cc_ctx_decl(ccxts_ctx, _size_, _name_)
-#define ccxts_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccxts_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* Declare a xts tweak named _name_.  Pass the tweak_size field of a
    struct ccmode_xts for _size_. */
 #define ccxts_tweak_decl(_size_, _name_) cc_ctx_decl(ccxts_tweak, _size_, _name_)
-#define ccxts_tweak_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccxts_tweak_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* Actual symmetric algorithm implementation can provide you one of these.
 
@@ -320,229 +331,595 @@ CC_INLINE size_t ccxts_context_size(const struct ccmode_xts *mode)
     return mode->size;
 }
 
-CC_INLINE unsigned long ccxts_block_size(const struct ccmode_xts *mode)
+CC_INLINE size_t ccxts_block_size(const struct ccmode_xts *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccxts_init(const struct ccmode_xts *mode, ccxts_ctx *ctx,
-                          size_t key_len, const void *key,
-                          const void *tweak_key)
-{
-    mode->init(mode, ctx, key_len, key, tweak_key);
-}
+/*!
+ @function   ccxts_init
+ @abstract   Initialize an XTS context.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      key_nbytes Length of the key arguments in bytes
+ @param      data_key   Key for data encryption
+ @param      tweak_key  Key for tweak generation
 
-CC_INLINE void ccxts_set_tweak(const struct ccmode_xts *mode, ccxts_ctx *ctx,
-                               ccxts_tweak *tweak, const void *iv)
+ @result     0 iff successful.
+
+ @discussion For security reasons, the two keys must be different.
+ */
+CC_INLINE int
+ccxts_init(const struct ccmode_xts *mode, ccxts_ctx *ctx, size_t key_nbytes, const void *data_key, const void *tweak_key)
 {
-       mode->set_tweak(ctx, tweak, iv);
+    return mode->init(mode, ctx, key_nbytes, data_key, tweak_key);
 }
 
-CC_INLINE void *ccxts_update(const struct ccmode_xts *mode, ccxts_ctx *ctx,
-       ccxts_tweak *tweak, unsigned long nblocks, const void *in, void *out)
+/*!
+ @function   ccxts_set_tweak
+ @abstract   Initialize the tweak for a sector.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      tweak      Context for the tweak for this sector
+ @param      iv         Data used to generate the tweak
+
+ @discussion The IV must be exactly one block in length.
+ */
+CC_INLINE int ccxts_set_tweak(const struct ccmode_xts *mode, ccxts_ctx *ctx, ccxts_tweak *tweak, const void *iv)
 {
-       return mode->xts(ctx, tweak, nblocks, in, out);
+    return mode->set_tweak(ctx, tweak, iv);
 }
 
-CC_INLINE void ccxts_one_shot(const struct ccmode_xts *mode,
-                              size_t key_len, const void *key,
-                              const void *tweak_key, const void *iv,
-                              unsigned long nblocks, const void *in, void *out)
+/*!
+ @function   ccxts_update
+ @abstract   Encrypt or decrypt data.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for an instance
+ @param      tweak      Context for the tweak for this sector
+ @param      nblocks    Length of the data in blocks
+ @param      in         Input data
+ @param      out        Output buffer
+
+ @result     The updated internal buffer of the tweak context. May be ignored.
+  */
+CC_INLINE void *
+ccxts_update(const struct ccmode_xts *mode, ccxts_ctx *ctx, ccxts_tweak *tweak, size_t nblocks, const void *in, void *out)
 {
-       ccxts_ctx_decl(mode->size, ctx);
-    ccxts_tweak_decl(mode->tweak_size, tweak);
-       mode->init(mode, ctx, key_len, key, tweak_key);
-    mode->set_tweak(ctx, tweak, iv);
-       mode->xts(ctx, tweak, nblocks, in, out);
-       ccxts_ctx_clear(mode->size, ctx);
-    ccxts_tweak_clear(mode->tweak_size, tweak);
+    return mode->xts(ctx, tweak, nblocks, in, out);
 }
 
+/*!
+ @function   ccxts_one_shot
+ @abstract   Encrypt or decrypt data in XTS mode.
+
+ @param      mode       Descriptor for the mode
+ @param      key_nbytes Length of the key arguments in bytes
+ @param      data_key   Key for data encryption
+ @param      tweak_key  Key for tweak generation
+ @param      iv         Data used to generate the tweak
+ @param      nblocks    Length of the data in blocks
+ @param      in         Input data
+ @param      out        Output buffer
+
+ @result     0 iff successful.
+
+ @discussion For security reasons, the two keys must be different.
+ */
+int ccxts_one_shot(const struct ccmode_xts *mode,
+                   size_t key_nbytes,
+                   const void *data_key,
+                   const void *tweak_key,
+                   const void *iv,
+                   size_t nblocks,
+                   const void *in,
+                   void *out);
+
+/* Authenticated cipher modes. */
+
 /* GCM mode. */
 
 /* Declare a gcm key named _name_.  Pass the size field of a struct ccmode_gcm
  for _size_. */
 #define ccgcm_ctx_decl(_size_, _name_) cc_ctx_decl(ccgcm_ctx, _size_, _name_)
-#define ccgcm_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccgcm_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
+
+#define CCGCM_IV_NBYTES 12
+#define CCGCM_BLOCK_NBYTES 16
+
+/* (2^32 - 2) blocks */
+/* (2^36 - 32) bytes */
+/* (2^39 - 256) bits */
+/* Exceeding this figure breaks confidentiality and authenticity. */
+#define CCGCM_TEXT_MAX_NBYTES ((1ULL << 36) - 32ULL)
 
 CC_INLINE size_t ccgcm_context_size(const struct ccmode_gcm *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long ccgcm_block_size(const struct ccmode_gcm *mode)
+CC_INLINE size_t ccgcm_block_size(const struct ccmode_gcm *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccgcm_init(const struct ccmode_gcm *mode, ccgcm_ctx *ctx,
-                          size_t key_len, const void *key)
+/*!
+ @function   ccgcm_init
+ @abstract   Initialize a GCM context.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      key_nbytes Length of the key in bytes
+ @param      key        Key for the underlying blockcipher (AES)
+
+ @result     0 iff successful.
+
+ @discussion The correct sequence of calls is:
+
+ @code ccgcm_init(...)
+ ccgcm_set_iv(...)
+ ccgcm_aad(...)       (may be called zero or more times)
+ ccgcm_update(...)    (may be called zero or more times)
+ ccgcm_finalize(...)
+
+ To reuse the context for additional encryptions, follow this sequence:
+
+ @code ccgcm_reset(...)
+ ccgcm_set_iv(...)
+ ccgcm_aad(...)       (may be called zero or more times)
+ ccgcm_update(...)    (may be called zero or more times)
+ ccgcm_finalize(...)
+
+ @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length.
+
+ @warning It is not permitted to call @p ccgcm_inc_iv after initializing the cipher via the @p ccgcm_init interface. Nonzero is
+ returned in the event of an improper call sequence.
+
+ @warning This function is not FIPS-compliant. Use @p ccgcm_init_with_iv instead.
+ */
+CC_INLINE int ccgcm_init(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t key_nbytes, const void *key)
 {
-    mode->init(mode, ctx, key_len, key);
+    return mode->init(mode, ctx, key_nbytes, key);
 }
 
-CC_INLINE void ccgcm_set_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx,
-                            size_t iv_size, const void *iv)
+/*!
+ @function   ccgcm_init_with_iv
+ @abstract   Initialize a GCM context to manage IVs internally.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      key_nbytes Length of the key in bytes
+ @param      key        Key for the underlying blockcipher (AES)
+ @param      iv         IV for the first encryption
+
+ @result     0 iff successful.
+
+ @discussion The correct sequence of calls is:
+
+ @code ccgcm_init_with_iv(...)
+ ccgcm_aad(...)       (may be called zero or more times)
+ ccgcm_update(...)    (may be called zero or more times)
+ ccgcm_finalize(...)
+
+ To reuse the context for additional encryptions, follow this sequence:
+
+ @code ccgcm_reset(...)
+ ccgcm_inc_iv(...)
+ ccgcm_aad(...)       (may be called zero or more times)
+ ccgcm_update(...)    (may be called zero or more times)
+ ccgcm_finalize(...)
+
+ The IV must be exactly 12 bytes in length.
+
+ Internally, the IV is treated as a four-byte salt followed by an eight-byte counter. This is to match the behavior of certain
+ protocols (e.g. TLS). In the call to @p ccgcm_inc_iv, the counter component will be interpreted as a big-endian, unsigned value
+ and incremented in place.
+
+ @warning It is not permitted to call @p ccgcm_set_iv after initializing the cipher via the @p ccgcm_init_with_iv interface.
+ Nonzero is returned in the event of an improper call sequence.
+
+ @warning The security of GCM depends on the uniqueness of key-IV pairs. To avoid key-IV repetition, callers should not initialize
+ multiple contexts with the same key material via the @p ccgcm_init_with_iv interface.
+ */
+int ccgcm_init_with_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t key_nbytes, const void *key, const void *iv);
+
+/*!
+ @function   ccgcm_set_iv
+ @abstract   Set the IV for encryption.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      iv_nbytes  Length of the IV in bytes
+ @param      iv         Initialization vector
+
+ @result     0 iff successful.
+
+ @discussion Set the initialization vector for encryption.
+
+ @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length.
+
+ In stateful protocols, if each packet exposes a guaranteed-unique value, it is recommended to format this as a 12-byte value for
+ use as the IV.
+
+ In stateless protocols, it is recommended to choose a 16-byte value using a cryptographically-secure pseudorandom number
+ generator (e.g. @p ccrng).
+
+ @warning This function may not be used after initializing the cipher via @p ccgcm_init_with_iv. Nonzero is returned in the event
+ of an improper call sequence.
+
+ @warning This function is not FIPS-compliant. Use @p ccgcm_init_with_iv instead.
+ */
+CC_INLINE int ccgcm_set_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv)
 {
-       mode->set_iv(ctx, iv_size, iv);
+    return mode->set_iv(ctx, iv_nbytes, iv);
 }
 
-CC_INLINE void ccgcm_gmac(const struct ccmode_gcm *mode, ccgcm_ctx *ctx,
-                          size_t nbytes, const void *in)
+/*!
+ @function   ccgcm_set_iv_legacy
+ @abstract   Set the IV for encryption.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      iv_nbytes  Length of the IV in bytes
+ @param      iv         Initialization vector
+
+ @result     0 iff successful.
+
+ @discussion Identical to @p ccgcm_set_iv except that it allows zero-length IVs.
+
+ @warning Zero-length IVs nullify the authenticity guarantees of GCM.
+
+ @warning Do not use this function in new applications.
+ */
+int ccgcm_set_iv_legacy(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv);
+
+/*!
+ @function   ccgcm_inc_iv
+ @abstract   Increment the IV for another encryption.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      iv         Updated initialization vector
+
+ @result     0 iff successful.
+
+ @discussion Updates the IV internally for another encryption.
+
+ Internally, the IV is treated as a four-byte salt followed by an eight-byte counter. This is to match the behavior of certain
+ protocols (e.g. TLS). The counter component is interpreted as a big-endian, unsigned value and incremented in place.
+
+ The updated IV is copied to @p iv. This is to support protocols that require part of the IV to be specified explicitly in each
+ packet (e.g. TLS).
+
+ @warning This function may be used only after initializing the cipher via @p ccgcm_init_with_iv.
+ */
+int ccgcm_inc_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, void *iv);
+
+/*!
+ @function   ccgcm_aad
+ @abstract   Authenticate additional data.
+
+ @param      mode               Descriptor for the mode
+ @param      ctx                Context for this instance
+ @param      nbytes             Length of the additional data in bytes
+ @param      additional_data    Additional data to authenticate
+
+ @result     0 iff successful.
+
+ @discussion This is typically used to authenticate data that cannot be encrypted (e.g. packet headers).
+
+ This function may be called zero or more times.
+ */
+CC_INLINE int ccgcm_aad(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t nbytes, const void *additional_data)
 {
-       mode->gmac(ctx, nbytes, in);
+    return mode->gmac(ctx, nbytes, additional_data);
 }
 
-CC_INLINE void ccgcm_update(const struct ccmode_gcm *mode, ccgcm_ctx *ctx,
-                            size_t nbytes, const void *in, void *out)
+/*!
+ @function   ccgcm_gmac
+
+ @discussion ccgcm_gmac is deprecated. Use the drop-in replacement 'ccgcm_aad' instead.
+ */
+CC_INLINE int ccgcm_gmac (const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t nbytes, const void *in)
+cc_deprecate_with_replacement("ccgcm_aad", 13.0, 10.15, 13.0, 6.0, 4.0)
 {
-       mode->gcm(ctx, nbytes, in, out);
+    return mode->gmac(ctx, nbytes, in);
 }
 
-CC_INLINE void ccgcm_finalize(const struct ccmode_gcm *mode, ccgcm_ctx *ctx,
-                              size_t tag_size, void *tag)
+/*!
+ @function   ccgcm_update
+ @abstract   Encrypt or decrypt data.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      nbytes     Length of the data in bytes
+ @param      in         Input plaintext or ciphertext
+ @param      out        Output ciphertext or plaintext
+
+ @result     0 iff successful.
+
+ @discussion In-place processing is supported.
+
+ This function may be called zero or more times.
+ */
+CC_INLINE int ccgcm_update(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->finalize(ctx, tag_size, tag);
+    return mode->gcm(ctx, nbytes, in, out);
 }
 
-CC_INLINE void ccgcm_reset(const struct ccmode_gcm *mode, ccgcm_ctx *ctx)
+/*!
+ @function   ccgcm_finalize
+ @abstract   Finish processing and authenticate.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+ @param      tag_nbytes Length of the tag in bytes
+ @param      tag        Authentication tag
+
+ @result     0 iff successful.
+
+ @discussion Finish processing a packet and generate the authentication tag.
+
+ On encryption, @p tag is purely an output parameter. The generated tag is written to @p tag.
+
+ On decryption, @p tag is both an input and an output parameter. Well-behaved callers should provide the authentication tag
+ generated during encryption. The function will return nonzero if the input tag does not match the generated tag. The generated
+ tag will be written into the @p tag buffer whether authentication succeeds or fails.
+
+ @warning The generated tag is written to @p tag to support legacy applications that perform authentication manually. Do not
+ follow this usage pattern in new applications. Rely on the function's error code to verify authenticity.
+ */
+CC_INLINE int ccgcm_finalize(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t tag_nbytes, void *tag)
 {
-    mode->reset(ctx);
+    return mode->finalize(ctx, tag_nbytes, tag);
 }
 
+/*!
+ @function   ccgcm_reset
+ @abstract   Reset the context for another encryption.
+
+ @param      mode       Descriptor for the mode
+ @param      ctx        Context for this instance
+
+ @result     0 iff successful.
 
-CC_INLINE void ccgcm_one_shot(const struct ccmode_gcm *mode,
-                              size_t key_len, const void *key,
-                              size_t iv_len, const void *iv,
-                              size_t adata_len, const void *adata,
-                              size_t nbytes, const void *in, void *out,
-                              size_t tag_len, void *tag)
+ @discussion Refer to @p ccgcm_init for correct usage.
+ */
+CC_INLINE int ccgcm_reset(const struct ccmode_gcm *mode, ccgcm_ctx *ctx)
 {
-       ccgcm_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, key_len, key);
-       mode->set_iv(ctx, iv_len, iv);
-       mode->gmac(ctx, adata_len, adata);
-       mode->gcm(ctx, nbytes, in, out);
-       mode->finalize(ctx, tag_len, tag);
-       ccgcm_ctx_clear(mode->size, ctx);
+    return mode->reset(ctx);
 }
 
+/*!
+ @function   ccgcm_one_shot
+ @abstract   Encrypt or decrypt with GCM.
+
+ @param      mode           Descriptor for the mode
+ @param      key_nbytes     Length of the key in bytes
+ @param      key            Key for the underlying blockcipher (AES)
+ @param      iv_nbytes      Length of the IV in bytes
+ @param      iv             Initialization vector
+ @param      adata_nbytes   Length of the additional data in bytes
+ @param      adata          Additional data to authenticate
+ @param      nbytes         Length of the data in bytes
+ @param      in             Input plaintext or ciphertext
+ @param      out            Output ciphertext or plaintext
+ @param      tag_nbytes     Length of the tag in bytes
+ @param      tag            Authentication tag
+
+ @result     0 iff successful.
+
+ @discussion Perform GCM encryption or decryption.
+
+ @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length.
+
+ In stateful protocols, if each packet exposes a guaranteed-unique value, it is recommended to format this as a 12-byte value for
+ use as the IV.
+
+ In stateless protocols, it is recommended to choose a 16-byte value using a cryptographically-secure pseudorandom number
+ generator (e.g. @p ccrng).
+
+ In-place processing is supported.
+
+ On encryption, @p tag is purely an output parameter. The generated tag is written to @p tag.
+
+ On decryption, @p tag is primarily an input parameter. The caller should provide the authentication tag generated during
+ encryption. The function will return nonzero if the input tag does not match the generated tag.
+
+ @warning To support legacy applications, @p tag is also an output parameter during decryption. The generated tag is written to @p
+ tag. Legacy callers may choose to compare this to the tag generated during encryption. Do not follow this usage pattern in new
+ applications.
+ */
+int ccgcm_one_shot(const struct ccmode_gcm *mode,
+                   size_t key_nbytes,
+                   const void *key,
+                   size_t iv_nbytes,
+                   const void *iv,
+                   size_t adata_nbytes,
+                   const void *adata,
+                   size_t nbytes,
+                   const void *in,
+                   void *out,
+                   size_t tag_nbytes,
+                   void *tag);
+
+/*!
+ @function   ccgcm_one_shot_legacy
+ @abstract   Encrypt or decrypt with GCM.
+
+ @param      mode           Descriptor for the mode
+ @param      key_nbytes     Length of the key in bytes
+ @param      key            Key for the underlying blockcipher (AES)
+ @param      iv_nbytes      Length of the IV in bytes
+ @param      iv             Initialization vector
+ @param      adata_nbytes   Length of the additional data in bytes
+ @param      adata          Additional data to authenticate
+ @param      nbytes         Length of the data in bytes
+ @param      in             Input plaintext or ciphertext
+ @param      out            Output ciphertext or plaintext
+ @param      tag_nbytes     Length of the tag in bytes
+ @param      tag            Authentication tag
+
+ @result     0 iff successful.
+
+ @discussion Identical to @p ccgcm_one_shot except that it allows zero-length IVs.
+
+ @warning Zero-length IVs nullify the authenticity guarantees of GCM.
+
+ @warning Do not use this function in new applications.
+ */
+int ccgcm_one_shot_legacy(const struct ccmode_gcm *mode,
+                          size_t key_nbytes,
+                          const void *key,
+                          size_t iv_nbytes,
+                          const void *iv,
+                          size_t adata_nbytes,
+                          const void *adata,
+                          size_t nbytes,
+                          const void *in,
+                          void *out,
+                          size_t tag_nbytes,
+                          void *tag);
+
 /* CCM */
 
 #define ccccm_ctx_decl(_size_, _name_) cc_ctx_decl(ccccm_ctx, _size_, _name_)
-#define ccccm_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccccm_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 /* Declare a ccm nonce named _name_.  Pass the mode->nonce_ctx_size for _size_. */
 #define ccccm_nonce_decl(_size_, _name_) cc_ctx_decl(ccccm_nonce, _size_, _name_)
-#define ccccm_nonce_clear(_size_, _name_) cc_zero(_size_, _name_)
-
+#define ccccm_nonce_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t ccccm_context_size(const struct ccmode_ccm *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long ccccm_block_size(const struct ccmode_ccm *mode)
+CC_INLINE size_t ccccm_block_size(const struct ccmode_ccm *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccccm_init(const struct ccmode_ccm *mode, ccccm_ctx *ctx,
-                          size_t key_len, const void *key)
+CC_INLINE int ccccm_init(const struct ccmode_ccm *mode, ccccm_ctx *ctx, size_t key_len, const void *key)
 {
-    mode->init(mode, ctx, key_len, key);
+    return mode->init(mode, ctx, key_len, key);
 }
 
-CC_INLINE void ccccm_set_iv(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx,
-                            size_t nonce_len, const void *nonce,
-                            size_t mac_size, size_t auth_len, size_t data_len)
+CC_INLINE int ccccm_set_iv(const struct ccmode_ccm *mode,
+                           ccccm_ctx *ctx,
+                           ccccm_nonce *nonce_ctx,
+                           size_t nonce_len,
+                           const void *nonce,
+                           size_t mac_size,
+                           size_t auth_len,
+                           size_t data_len)
 {
-       mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, auth_len, data_len);
+    return mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, auth_len, data_len);
 }
 
-CC_INLINE void ccccm_cbcmac(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx,
-                          size_t nbytes, const void *in)
+CC_INLINE int ccccm_cbcmac(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in)
 {
-       mode->cbcmac(ctx, nonce_ctx, nbytes, in);
+    return mode->cbcmac(ctx, nonce_ctx, nbytes, in);
 }
 
-CC_INLINE void ccccm_update(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx,
-                            size_t nbytes, const void *in, void *out)
+CC_INLINE int
+ccccm_update(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, void *out)
 {
-       mode->ccm(ctx, nonce_ctx, nbytes, in, out);
+    return mode->ccm(ctx, nonce_ctx, nbytes, in, out);
 }
 
-CC_INLINE void ccccm_finalize(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx,
-                              void *mac)
+CC_INLINE int ccccm_finalize(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, void *mac)
 {
-       mode->finalize(ctx, nonce_ctx, mac);
+    return mode->finalize(ctx, nonce_ctx, mac);
 }
 
-CC_INLINE void ccccm_reset(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx)
+CC_INLINE int ccccm_reset(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx)
 {
-    mode->reset(ctx, nonce_ctx);
+    return mode->reset(ctx, nonce_ctx);
 }
 
-
-CC_INLINE void ccccm_one_shot(const struct ccmode_ccm *mode,
-                              unsigned long key_len, const void *key,
-                              unsigned nonce_len, const void *nonce,
-                              unsigned long nbytes, const void *in, void *out,
-                              unsigned adata_len, const void* adata,
-                              unsigned mac_size, void *mac)
+CC_INLINE int ccccm_one_shot(const struct ccmode_ccm *mode,
+                             size_t key_len,
+                             const void *key,
+                             size_t nonce_len,
+                             const void *nonce,
+                             size_t nbytes,
+                             const void *in,
+                             void *out,
+                             size_t adata_len,
+                             const void *adata,
+                             size_t mac_size,
+                             void *mac)
 {
-       ccccm_ctx_decl(mode->size, ctx);
-       ccccm_nonce_decl(mode->nonce_size, nonce_ctx);
-       mode->init(mode, ctx, key_len, key);
-       mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, adata_len, nbytes);
-       mode->cbcmac(ctx, nonce_ctx, adata_len, adata);
-       mode->ccm(ctx, nonce_ctx, nbytes, in, out);
-       mode->finalize(ctx, nonce_ctx, mac);
-       ccccm_ctx_clear(mode->size, ctx);
-    ccccm_nonce_clear(mode->size, nonce_ctx);
-}
+    int rc;
+    ccccm_ctx_decl(mode->size, ctx);
+    ccccm_nonce_decl(mode->nonce_size, nonce_ctx);
+    rc = mode->init(mode, ctx, key_len, key);
+    if (rc == 0) {
+        rc = mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, adata_len, nbytes);
+    }
+    if (rc == 0) {
+        rc = mode->cbcmac(ctx, nonce_ctx, adata_len, adata);
+    }
+    if (rc == 0) {
+        rc = mode->ccm(ctx, nonce_ctx, nbytes, in, out);
+    }
+    if (rc == 0) {
+        rc = mode->finalize(ctx, nonce_ctx, mac);
+    }
+    ccccm_ctx_clear(mode->size, ctx);
+    ccccm_nonce_clear(mode->nonce_size, nonce_ctx);
 
+    return rc;
+}
 
 /* OMAC mode. */
 
-
 /* Declare a omac key named _name_.  Pass the size field of a struct ccmode_omac
  for _size_. */
 #define ccomac_ctx_decl(_size_, _name_) cc_ctx_decl(ccomac_ctx, _size_, _name_)
-#define ccomac_ctx_clear(_size_, _name_) cc_zero(_size_, _name_)
+#define ccomac_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
 
 CC_INLINE size_t ccomac_context_size(const struct ccmode_omac *mode)
 {
     return mode->size;
 }
 
-CC_INLINE unsigned long ccomac_block_size(const struct ccmode_omac *mode)
+CC_INLINE size_t ccomac_block_size(const struct ccmode_omac *mode)
 {
-       return mode->block_size;
+    return mode->block_size;
 }
 
-CC_INLINE void ccomac_init(const struct ccmode_omac *mode, ccomac_ctx *ctx,
-                           size_t tweak_len, size_t key_len, const void *key)
+CC_INLINE int ccomac_init(const struct ccmode_omac *mode, ccomac_ctx *ctx, size_t tweak_len, size_t key_len, const void *key)
 {
     return mode->init(mode, ctx, tweak_len, key_len, key);
 }
 
-CC_INLINE int ccomac_update(const struct ccmode_omac *mode, ccomac_ctx *ctx,
-       unsigned long nblocks, const void *tweak, const void *in, void *out)
+CC_INLINE int
+ccomac_update(const struct ccmode_omac *mode, ccomac_ctx *ctx, size_t nblocks, const void *tweak, const void *in, void *out)
 {
-       return mode->omac(ctx, nblocks, tweak, in, out);
+    return mode->omac(ctx, nblocks, tweak, in, out);
 }
 
 CC_INLINE int ccomac_one_shot(const struct ccmode_omac *mode,
-       size_t tweak_len, size_t key_len, const void *key,
-       const void *tweak, unsigned long nblocks, const void *in, void *out)
-{
-       ccomac_ctx_decl(mode->size, ctx);
-       mode->init(mode, ctx, tweak_len, key_len, key);
-       int result = mode->omac(ctx, nblocks, tweak, in, out);
-       ccomac_ctx_clear(mode->size, ctx);
-    return result;
+                              size_t tweak_len,
+                              size_t key_len,
+                              const void *key,
+                              const void *tweak,
+                              size_t nblocks,
+                              const void *in,
+                              void *out)
+{
+    int rc;
+    ccomac_ctx_decl(mode->size, ctx);
+    rc = mode->init(mode, ctx, tweak_len, key_len, key);
+    if (rc == 0) {
+        rc = mode->omac(ctx, nblocks, tweak, in, out);
+    }
+    ccomac_ctx_clear(mode->size, ctx);
+    return rc;
 }
 
-
 #endif /* _CORECRYPTO_CCMODE_H_ */