Internet Engineering Task Force | T. Krovetz |
Internet-Draft | Sacramento State |
Updates: 7523 (if approved) | May 11, 2018 |
Intended status: Informational | |
Expires: November 12, 2018 |
OCB For Block Ciphers Without 128-Bit Blocks
draft-krovetz-ocb-wideblock-00
The OCB authenticated-encryption algorithm is specified in RFC 7523, but only for blockciphers with 128-bit blocks such as AES. This document extends RFC 7523 by specifying how OCB is used with blockciphers of any blocklength. When the blocklength is 128 bits, this specification and that in RFC 7523 are identical.
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
This Internet-Draft will expire on November 12, 2018.
Copyright (c) 2018 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
OCB is a shared-key, blockcipher-based authentication scheme specified in [RFC7523]. It was designed with the AES blockcipher in mind and thus envisioned only being used with 128-bit blockciphers. The resulting RFC 7523 does not allow blockciphers with larger or smaller blocklengths. This document respecifies OCB in a more general manner, eliminating the expectation that a 128-bit blockcipher is used. This update is consistent with RFC 7523 and does not contradict it in any way. For applications using 128-bit blockciphers, RFC 7523 should be preferred because it is simpler, self-contained, and has more applicable test vectors.
Changing the blocklength used in OCB is not a simple matter. There are non-trivially defined constants used in OCB that must be recalculated for each different blocklength. What follows is largely a copy of the algorithms from RFC 7523, made more general by using blocklength-dependent symbolic constants.
The security of OCB continues to follow a birthday bound. Both the confidentiality and the authenticity properties of OCB degrade as per s^2 / 2^b, where s is the total number of blocks that the adversary acquires and b is the number of bits per blockcipher block. Note that this means security degrades rapidly when using a blockcipher with a small to moderate blocklength.
There are two types of variables used in this specification, strings and integers. Although strings processed by most implementations of OCB will be strings of bytes, bit-level operations are used throughout this specification document for defining OCB. String variables are always written with an initial upper-case letter while integer variables are written in all lower-case. Following C's convention, a single equals ("=") indicates variable assignment and double equals ("==") is the equality relation. Whenever a variable is followed by an underscore ("_"), the underscore is intended to denote a subscript, with the subscripted expression requiring evaluation to resolve the meaning of the variable. For example, when i == 2, then P_i refers to the variable P_2.
To be complete, the algorithms in this document require specification of two global parameters: a blockcipher and the length of authentication tags in use.
Specifying a blockcipher implicitly defines the following symbols.
The TAGLEN parameter specifies the length of authentication tag used by OCB and may be any positive value up to, and including, the smaller of BLOCKLEN or 256.
As an example, if 128-bit authentication tags and AES with 192-bit keys are to be used, then BLOCKLEN is 128, KEYLEN is 192, ENCIPHER refers to the AES-192 cipher, DECIPHER refers to the AES-192 inverse cipher, and TAGLEN is 128.
Greater values for TAGLEN provide greater assurances of authenticity, but ciphertexts produced by OCB are longer than their corresponding plaintext by TAGLEN bits. See Section 5 for details about TAGLEN and security.
Each value of BLOCKLEN gives rise to constants that need careful choosing to ensure OCB security and efficiency. The value RESIDUE is used in the definition of double given in Section 2, and the values SHIFT, MASKLEN, and TAGREP are used in the OCB-ENCRYPT and OCB-DECRYPT functions given in Section 4.
The following table lists these constants for a collection of blockcipher blocklengths. If a blocklength is needed that is not in the table, Appendix B gives the criteria and algorithm used to determine the constants given here. The same criteria and algorithm should be used to generate other constants for other blocklengths.
Note that there are attacks on OCB with success proportional to a birthday bound related to BLOCKLEN. This means that using small values of BLOCKLEN may lead quickly to poor security. See Section 5 for more information on the security bounds of OCB.
BLOCKLEN | RESIDUE | SHIFT | MASKLEN | TAGREP |
---|---|---|---|---|
32 | 141 | 17 | 4 | 5 |
64 | 27 | 25 | 5 | 6 |
96 | 1601 | 33 | 6 | 7 |
128 | 135 | 8 | 6 | 7 |
192 | 135 | 40 | 7 | 8 |
256 | 1061 | 1 | 8 | 8 |
384 | 4109 | 80 | 8 | 8 |
512 | 293 | 176 | 8 | 8 |
768 | 655377 | 160 | 9 | 8 |
1024 | 524355 | 352 | 9 | 8 |
1600 | 18435 | 192 | 10 | 8 |
OCB is described in this section using pseudocode. Given any collection of inputs of the required types, following the pseudocode description for a function will produce the correct output of the promised type.
OCB has the ability to authenticate unencrypted associated data at the same time that it provides for authentication and encrypts a plaintext. The following hash function is central to providing this functionality. If an application has no associated data, then the associated data should be considered to exist and to be the empty string. HASH, conveniently, always returns zeros(BLOCKLEN) when the associated data is the empty string.
Function name: HASH Input: K, string of KEYLEN bits // Key A, string of any length // Associated data Output: Sum, string of BLOCKLEN bits // Hash result Sum is defined as follows. // // Key-dependent variables // L_* = ENCIPHER(K, zeros(BLOCKLEN)) L_$ = double(L_*) L_0 = double(L_$) L_i = double(L_{i-1}) for every integer i > 0 // // Consider A as a sequence of BLOCKLEN-bit blocks // Let m be the largest integer so that m * BLOCKLEN <= bitlen(A) Let A_1, A_2, ..., A_m and A_* be strings so that A == A_1 || A_2 || ... || A_m || A_*, and bitlen(A_i) == BLOCKLEN for each 1 <= i <= m. Note: A_* may possibly be the empty string. // // Process any whole blocks // Sum_0 = zeros(BLOCKLEN) Offset_0 = zeros(BLOCKLEN) for each 1 <= i <= m Offset_i = Offset_{i-1} xor L_{ntz(i)} Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) end for // // Process any final partial block; compute final hash value // if bitlen(A_*) > 0 then Offset_* = Offset_m xor L_* Zerofill = zeros(BLOCKLEN-(1+bitlen(A_*))) CipherInput = (A_* || 1 || Zerofill) xor Offset_* Sum = Sum_m xor ENCIPHER(K, CipherInput) else Sum = Sum_m end if
This function computes a ciphertext (which includes a bundled authentication tag) when given a plaintext, associated data, nonce and key. For each invocation of OCB-ENCRYPT using the same key K, the value of the nonce input N must be distinct.
Function name: OCB-ENCRYPT Input: K, string of KEYLEN bits // Key N, string of up to BLOCKLEN-(TAGREP+1) bits // Nonce A, string of any length // Associated data P, string of any length // Plaintext Output: C, string of length bitlen(P) + TAGLEN bits // Ciphertext C is defined as follows. // // Key-dependent variables // L_* = ENCIPHER(K, zeros(BLOCKLEN)) L_$ = double(L_*) L_0 = double(L_$) L_i = double(L_{i-1}) for every integer i > 0 // // Consider P as a sequence of BLOCKLEN-bit blocks // Let m be the largest integer so that m * BLOCKLEN <= bitlen(P) Let P_1, P_2, ..., P_m and P_* be strings so that P == P_1 || P_2 || ... || P_m || P_*, and bitlen(P_i) == BLOCKLEN for each 1 <= i <= m. Note: P_* may possibly be the empty string. // // Nonce-dependent and per-encryption variables // Zerofill = zeros(BLOCKLEN-(TAGREP+1+bitlen(N))) Nonce = num2str(TAGLEN mod BLOCKLEN, TAGREP) || Zerofill || 1 || N bottom = str2num(Nonce[BLOCKLEN-MASKLEN+1..BLOCKLEN]) Ktop = ENCIPHER(K, Nonce[1..BLOCKLEN-MASKLEN] || zeros(MASKLEN)) ShiftedKtop = Ktop[1..BLOCKLEN-SHIFT] xor Ktop[1+SHIFT..BLOCKLEN] Stretch = Ktop || ShiftedKtop Offset_0 = Stretch[1+bottom..BLOCKLEN+bottom] Checksum_0 = zeros(BLOCKLEN) // // Process any whole blocks // for each 1 <= i <= m Offset_i = Offset_{i-1} xor L_{ntz(i)} C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) Checksum_i = Checksum_{i-1} xor P_i end for // // Process any final partial block and compute raw tag // if bitlen(P_*) > 0 then Offset_* = Offset_m xor L_* Pad = ENCIPHER(K, Offset_*) C_* = P_* xor Pad[1..bitlen(P_*)] PaddedP = P_* || 1 || zeros(BLOCKLEN-(bitlen(P_*)+1)) Checksum_* = Checksum_m xor PaddedP Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) else C_* = <empty string> Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) end if // // Assemble ciphertext // C = C_1 || C_2 || ... || C_m || C_* || Tag[1..TAGLEN]
This function computes a plaintext when given a ciphertext, associated data, nonce and key. An authentication tag is embedded in the ciphertext. If the tag is not correct for the ciphertext, associated data, nonce and key, then an INVALID signal is produced.
Function name: OCB-DECRYPT Input: K, string of KEYLEN bits // Key N, string of up to BLOCKLEN-(TAGREP+1) bits // Nonce A, string of any length // Associated data C, string of at least TAGLEN bits // Ciphertext Output: P, string of length bitlen(C) - TAGLEN bits, // Plaintext or INVALID indicating authentication failure P is defined as follows. // // Key-dependent variables // L_* = ENCIPHER(K, zeros(BLOCKLEN)) L_$ = double(L_*) L_0 = double(L_$) L_i = double(L_{i-1}) for every integer i > 0 // // Consider C as a sequence of BLOCKLEN-bit blocks // Let m be the largest integer so m * BLOCKLEN <= bitlen(C) - TAGLEN Let C_1, C_2, ..., C_m, C_* and T be strings so that C == C_1 || C_2 || ... || C_m || C_* || T, bitlen(C_i) == BLOCKLEN for each 1 <= i <= m, and bitlen(T) == TAGLEN. Note: C_* may possibly be the empty string. // // Nonce-dependent and per-decryption variables // Zerofill = zeros(BLOCKLEN-(TAGREP+1+bitlen(N))) Nonce = num2str(TAGLEN mod BLOCKLEN, TAGREP) || Zerofill || 1 || N bottom = str2num(Nonce[BLOCKLEN-MASKLEN+1..BLOCKLEN]) Ktop = ENCIPHER(K, Nonce[1..BLOCKLEN-MASKLEN] || zeros(MASKLEN)) ShiftedKtop = Ktop[1..BLOCKLEN-SHIFT] xor Ktop[1+SHIFT..BLOCKLEN] Stretch = Ktop || ShiftedKtop Offset_0 = Stretch[1+bottom..BLOCKLEN+bottom] Checksum_0 = zeros(BLOCKLEN) // // Process any whole blocks // for each 1 <= i <= m Offset_i = Offset_{i-1} xor L_{ntz(i)} P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) Checksum_i = Checksum_{i-1} xor P_i end for // // Process any final partial block and compute raw tag // if bitlen(C_*) > 0 then Offset_* = Offset_m xor L_* Pad = ENCIPHER(K, Offset_*) P_* = C_* xor Pad[1..bitlen(C_*)] PaddedP = P_* || 1 || zeros(BLOCKLEN-bitlen(P_*)-1) Checksum_* = Checksum_m xor PaddedP Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) else P_* = <empty string> Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) end if // // Check for validity and assemble plaintext // if (Tag[1..TAGLEN] == T) then P = P_1 || P_2 || ... || P_m || P_* else P = INVALID end if
What follows is a duplicate of the Security Considerations section of RFC 7523 with numeric literals replaced by their symbolic equivalents. With the ability to change BLOCKLEN comes two important additional considerations. The amount of data that can safely be processed using a single key is related to BLOCKLEN: a larger BLOCKLEN allows more data whereas a smaller BLOCKLEN allows less. Also, authentication tag lengths are limited to BLOCKLEN bits, which means that using OCB with a small BLOCKLEN forces the use of small tags. In all cases, but especially when reducing BLOCKLEN, a careful evaluation of an application's security requirements should be conducted and only if OCB, with a particular BLOCKLEN, meets those requirements should it be used.
OCB achieves two security properties, confidentiality and authenticity. Confidentiality is defined via "indistinguishability from random bits", meaning that an adversary is unable to distinguish OCB-outputs from an equal number of random bits. Authenticity is defined via "authenticity of ciphertexts", meaning that an adversary is unable to produce any valid nonce-ciphertext pair that it has not already acquired. The security guarantees depend on the underlying blockcipher being secure in the sense of a strong pseudorandom permutation. Thus if OCB is used with a blockcipher that is not secure as a strong pseudorandom permutation, the security guarantees vanish. The need for the strong pseudorandom permutation property means that OCB should be used with a conservatively designed, well-trusted blockcipher, such as AES.
Both the confidentiality and the authenticity properties of OCB degrade as per s^2 / 2^BLOCKLEN, where s is the total number of blocks that the adversary acquires. The consequence of this formula is that the proven security disappears when s becomes as large as 2^(BLOCKLEN/2). Thus the user should never use a key to generate an amount of ciphertext that is near to, or exceeds, 2^(BLOCKLEN/2) blocks. In order to ensure that s^2 / 2^BLOCKLEN remains less than about 1/2^32, a given key should be used to encrypt at most 2^(BLOCKLEN/2-16) blocks, including the associated data. To ensure these limits are not crossed, automated key management is recommended in systems exchanging large amounts of data [RFC4107].
When a ciphertext decrypts as INVALID it is the implementor's responsibility to make sure that no information beyond this fact is made adversarially available.
OCB encryption and decryption produce an internal BLOCKLEN-bit authentication tag. The parameter TAGLEN determines how many bits of this internal tag are included in ciphertexts and used for authentication. The value of TAGLEN has two impacts: An adversary can trivially forge with probability 2^{-TAGLEN}, and ciphertexts are TAGLEN bits longer than their corresponding plaintexts. It is up to the application designer to choose an appropriate value for TAGLEN. Long tags cost no more computationally than short ones.
Normally, a given key should be used to create ciphertexts with a single tag length, TAGLEN, and an application should reject any ciphertext that claims authenticity under the same key but a different tag length. While the ciphertext core and all of the bits of the tag do depend on the tag length, this is done for added robustness against misuse and should not suggest that receivers accept ciphertexts employing variable tag lengths under a single key.
Timing attacks are not a part of the formal security model and an implementation should take care to mitigate them in contexts where this is a concern. To render timing attacks impotent, the amount of time to encrypt or decrypt a string should be independent of the key and the contents of the string. The only explicitly conditional OCB operation that depends on private data is double(), which means that using constant-time blockcipher and double() implementations eliminates most (if not all) sources of timing attacks on OCB. Power-usage attacks are likewise out of scope of the formal model, and should be considered for environments where they are threatening.
The OCB encryption scheme reveals in the ciphertext the length of the plaintext. Sometimes the length of the plaintext is a valuable piece of information that should be hidden. For environments where "traffic analysis" is a concern, techniques beyond OCB encryption (typically involving padding) would be necessary.
Defining the ciphertext that results from OCB-ENCRYPT to be the pair (C_1 || C_2 || ... || C_m || C_*, Tag[1..TAGLEN]) instead of the concatenation C_1 || C_2 || ... || C_m || C_* || Tag[1..TAGLEN] introduces no security concerns. Because TAGLEN is fixed, both versions allow ciphertexts to be parsed unambiguously.
It is crucial that, as one encrypts, one does not repeat a nonce. The inadvertent reuse of the same nonce by two invocations of the OCB encryption operation, with the same key, but with distinct plaintext values, undermines the confidentiality of the plaintexts protected in those two invocations, and undermines all of the authenticity and integrity protection provided by that key. For this reason, OCB should only be used whenever nonce uniqueness can be provided with certainty. Note that it is acceptable to input the same nonce value multiple times to the decryption operation. We emphasize that the security consequences are quite serious if an attacker observes two ciphertexts that were created using the same nonce and key values, unless the plaintext and AD values in both invocations of the encrypt operation were identical. First, a loss of confidentiality ensues because the attacker will be able to infer relationships between the two plaintext values. Second, a loss of authenticity ensues because the attacker will be able to recover secret information used to provide authenticity, making subsequent forgeries trivial. Note that there are AEAD schemes, particularly SIV [RFC5297], appropriate for environments where nonces are unavailable or unreliable. OCB is not such a scheme.
Nonces need not be secret, and a counter may be used for them. If two parties send OCB-encrypted plaintexts to one another using the same key, then the space of nonces used by the two parties must be partitioned so that no nonce that could be used by one party to encrypt could be used by the other to encrypt (eg, odd and even counters).
The Internet Assigned Numbers Authority (IANA) has defined a registry for Authenticated Encryption with Associated Data parameters. This document does not specify any concrete AEAD schemes, so contributes nothing to the registry. Any AEAD scheme based on this document, where a permanently registered identifier would be useful, should register such identifier with IANA [RFC5116].
During a short period of 2017 three people inquired about extending OCB to blockciphers with blocklengths other than 128-bits. Thanks go to Jeffrey Walton, Mark Wooding, and Uri Blumenthal for providing the motivation for this work. Mark Wooding has been especially helpful, providing the basis for the code in Appendix B and corroborating test vectors by writing an independent implementation.
[Polys] | Seroussi, G., "Table of low-weight binary irreducible polynomials", Hewlett-Packard technical report HPL-98-135, August 1998. |
[RFC7523] | Krovetz, T. and P. Rogaway, "The OCB authenticated-encryption algorithm", RFC 7523, May 2014. |
[OCB] | Krovetz, T. and P. Rogaway, "The software performance of authenticated-encryption modes", in Fast Software Encryption - FSE 2011, Springer, 2011. |
[RC6] | Rivest, R., Robshaw, M., Sidney, R. and Y. Yin, "The RC6 block cipher", Posted on RSA Data Security website August 20, 1998. |
[RFCRC6] | Krovetz, T., "RC6 and RC5 test vectors for multiple block sizes", RFC XXXX, November 2018. |
[RFC4107] | Bellovin, S. and R. Housley, "Guidelines for cryptographic key management", RFC 4107, June 2005. |
[RFC5116] | McGrew, D., "An interface and algorithms for authenticated encryption", RFC 5116, January 2008. |
[RFC5297] | Harkins, D., "Synthetic Initialization Vector (SIV) authenticated encryption using the Advanced Encryption Standard (AES)", RFC 5297, October 2008. |
[Sage] | The Sage Developers, "SageMath, the Sage Mathematics Software System (Version 7.6)", DOI 10.5281/zenodo.820864, 2017. |
This section gives sample outputs for various inputs using OCB and blockciphers with blocklengths other than 128. In each case, an instance of RC6 is used for the blockcipher [RC6]. The name RC6-w/r/b refers to RC6 with a 4w-bit blocklength, r internal rounds, and a b-byte key.
There are too many possible cases to consider for this section to be exhaustive. Instead a small number of examples are shown in detail with many significant variable assignments in the pseudocode shown. This will help an implementor find most basic errors. Further validation could then be accomplished by comparison with a reference implementation over a much more thorough selection of inputs.
Each of the following entries indicates the blockcipher and tag length used followed by the values K, N, A, P, C, indicating that plaintext P with associated data A when encrypted using OCB with key K, and nonce N, yields ciphertext C (which includes the tag). All strings are represented in hexadecimal (eg, 0F represents the bitstring 00001111). An empty entry indicates the empty string.
K: 000102030405060708090A0B0C0D0E0F N: 000102030405 A: P: C: 474D57A4043E Assignments during HASH(K,A) L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Sum: 0000000000000000 Assignments during OCB-ENCRYPT L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Nonce: C001000102030405 bottom: 5 Ktop: 8298E905914FB488 Stretch: 8298E905914FB48889BA766C814FB488 Offset_0: 531D20B229F69111 Tag: 474D57A4043E7768
RC6-16/16/16 (64-bit blocks), 48-bit tags K: 000102030405060708090A0B0C0D0E0F N: 000102030405 A: 00010203 P: 00010203 C: B75BF470BB0B354C5B92 Assignments during HASH(K,A) L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Offset_*: 39EF0C3FF4475894 CipherInput: 39EE0E3C74475894 Sum: 48068A4FD12ABB4C Assignments during OCB-ENCRYPT L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Nonce: C001000102030405 bottom: 5 Ktop: 8298E905914FB488 Stretch: 8298E905914FB48889BA766C814FB488 Offset_0: 531D20B229F69111 Offset_*: 6AF22C8DDDB1C985 Pad: B75AF6732D339D4B PaddedP: 0001020380000000 Checksum_*: 0001020380000000 C_*: B75BF470 Tag: BB0B354C5B92CBAA
RC6-16/16/16 (64-bit blocks), 48-bit tags K: 000102030405060708090A0B0C0D0E0F N: 000102030405 A: 0001020304050607 P: 0001020304050607 C: 882A4FFE11B0E540D41F335172BD Assignments during HASH(K,A) L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 L_0: E7BC30FFD11D6250 Offset_1: E7BC30FFD11D6250 Sum_1: E3549C18B6F398EB Sum: E3549C18B6F398EB Assignments during OCB-ENCRYPT L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Nonce: C001000102030405 bottom: 5 Ktop: 8298E905914FB488 Stretch: 8298E905914FB48889BA766C814FB488 Offset_0: 531D20B229F69111 L_0: E7BC30FFD11D6250 Offset_1: B4A1104DF8EBF341 Checksum_1: 0001020304050607 C_1: 882A4FFE11B0E540 Tag: D41F335172BD43B7
RC6-16/16/16 (64-bit blocks), 48-bit tags K: 000102030405060708090A0B0C0D0E0F N: 000102030405 A: 000102030405060708090A0B0C0D0E0F10111213 P: 000102030405060708090A0B0C0D0E0F10111213 C: 882A4FFE11B0E540F218C902D76A601F90DF1E27BD403C47DF4E Assignments during HASH(K,A) L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 L_0: E7BC30FFD11D6250 Offset_1: E7BC30FFD11D6250 Sum_1: E3549C18B6F398EB L_1: CF7861FFA23AC4BB Offset_2: 28C451007327A6EB Sum_2: FADB0507B1DA1433 Offset_*: 112B5D3F8760FE7F CipherInput: 013A4F2C0760FE7F Sum: D761B0AFAA584CF7 Assignments during OCB-ENCRYPT L_*: 39EF0C3FF4475894 L_$: 73DE187FE88EB128 Nonce: C001000102030405 bottom: 5 Ktop: 8298E905914FB488 Stretch: 8298E905914FB48889BA766C814FB488 Offset_0: 531D20B229F69111 L_0: E7BC30FFD11D6250 Offset_1: B4A1104DF8EBF341 Checksum_1: 0001020304050607 C_1: 882A4FFE11B0E540 L_1: CF7861FFA23AC4BB Offset_2: 7BD971B25AD137FA Checksum_2: 0808080808080808 C_2: F218C902D76A601F Offset_*: 42367D8DAE966F6E Pad: 80CE0C34E04B0990 PaddedP: 1011121380000000 Checksum_*: 18191A1B88080808 C_*: 90DF1E27 Tag: BD403C47DF4ED926
RC6-64/16/16 (256-bit blocks), 256-bit tags K: 000102030405060708090A0B0C0D0E0F N: 000102030405060708090A0B A: 000102030405060708090A0B0C0D0E0F 101112131415161718191A1B1C1D1E1F 202122232425262728292A2B2C2D2E2F 303132333435363738393A3B3C3D3E3F 404142434445464748494A4B4C4D4E4F P: 000102030405060708090A0B0C0D0E0F 101112131415161718191A1B1C1D1E1F 202122232425262728292A2B2C2D2E2F 303132333435363738393A3B3C3D3E3F 404142434445464748494A4B4C4D4E4F C: 5327CF07146F7B51A5D7AABA93D7F626 2F65ED3931815A5EF681217EBBF2BB13 F464772416E08D4BEAC37DFD8F614D98 AD7D58B1A63A24BB1CFE491D02AE28ED BC6D07CF935C31FC81361EA46FBF568F E4E72EE35BBD8FBBD04B2FCDB9656044 A9EFE1140327CEBB9A1750CDBD1BD3EC Assignments during HASH(K,A) L_*: 6E75A413F50216C512AD330BFABE641B 50E88C29BE5980AA2A09E43990125CBB L_$: DCEB4827EA042D8A255A6617F57CC836 A1D118537CB301545413C8732024B976 L_0: B9D6904FD4085B144AB4CC2FEAF9906D 43A230A6F96602A8A82790E6404976C9 Offset_1: B9D6904FD4085B144AB4CC2FEAF9906D 43A230A6F96602A8A82790E6404976C9 Sum_1: B1836672FE03B925800743FF4DE116B3 C09C00B396CB20B058FAD1AEC4171F57 L_1: 73AD209FA810B6289569985FD5F320DA 8744614DF2CC0551504F21CC8092E9B7 Offset_2: CA7BB0D07C18ED3CDFDD54703F0AB0B7 C4E651EB0BAA07F9F868B12AC0DB9F7E Sum_2: C16F97D1E09FA431655057CF582E8F32 FAE7971E00DB1EA56E7BA4AC493ECD8F Offset_*: A40E14C3891AFBF9CD70677BC5B4D4AC 940EDDC2B5F38753D261551350C9C3C5 CipherInput: E44F5680CD5FBDBE85392D3089F99AE3 140EDDC2B5F38753D261551350C9C3C5 Sum: 964A5EA730124E1EA6CD7874A58F449C 5C3B2ED878115CC292A021FAF261B4FD Assignments during OCB-ENCRYPT L_*: 6E75A413F50216C512AD330BFABE641B 50E88C29BE5980AA2A09E43990125CBB L_$: DCEB4827EA042D8A255A6617F57CC836 A1D118537CB301545413C8732024B976 Nonce: 00000000000000000000000000000000 00000001000102030405060708090A0B bottom: 11 Ktop: 67DB009692E6C7CCEFBFE4F9B810544E DBD469326F0CBA90F94D02A6A85C7C9B Stretch: 67DB009692E6C7CCEFBFE4F9B810544E DBD469326F0CBA90F94D02A6A85C7C9B A86D01BBB72B485530C02D0AC830FCD3 6C7CBB56B115CFB10BD707EBF8E485AD Offset_0: D804B497363E677DFF27CDC082A276DE A349937865D487CA68153542E3E4DD43 L_0: B9D6904FD4085B144AB4CC2FEAF9906D 43A230A6F96602A8A82790E6404976C9 Offset_1: 61D224D8E2363C69B59301EF685BE6B3 E0EBA3DE9CB28562C032A5A4A3ADAB8A Checksum_1: 000102030405060708090A0B0C0D0E0F 101112131415161718191A1B1C1D1E1F C_1: 5327CF07146F7B51A5D7AABA93D7F626 2F65ED3931815A5EF681217EBBF2BB13 L_1: 73AD209FA810B6289569985FD5F320DA 8744614DF2CC0551504F21CC8092E9B7 Offset_2: 127F04474A268A4120FA99B0BDA8C669 67AFC2936E7E8033907D8468233F423D Checksum_2: 20202020202020202020202020202020 20202020202020202020202020202020 C_2: F464772416E08D4BEAC37DFD8F614D98 AD7D58B1A63A24BB1CFE491D02AE28ED Offset_*: 7C0AA054BF249C843257AABB4716A272 37474EBAD0270099BA746051B32D1E86 Pad: FC2C458CD71977BBC97F54EF23F218C0 7C6AD1938FDE8374AF27960469595171 PaddedP: 404142434445464748494A4B4C4D4E4F 80000000000000000000000000000000 Checksum_*: 606162636465666768696A6B6C6D6E6F A0202020202020202020202020202020 C_*: BC6D07CF935C31FC81361EA46FBF568F Tag: E4E72EE35BBD8FBBD04B2FCDB9656044 A9EFE1140327CEBB9A1750CDBD1BD3EC
The following VALIDATE[B] algorithm tests a wider variety of inputs. Parameter B indicates that throughout the validation RC6-(B/4)/16/16 (ie, RC6 with B-bit blocklength, 16 rounds, and 16-byte keys) is the blockcipher used. Please note that when B is not a power of two, then the non-standard version of RC6 documented in [RFCRC6] is used. In all cases TAGLEN is min(B, 256).
Function name: VALIDATE[B] Output: Y, string of length min(B, 256) bits Y is defined as follows. K = 000102030405060708090A0B0C0D0E0F C = <empty string> for i = 0 to 127 do S = (0x00 || 0x01 || 0x02 || ...)[1..8i] N = num2str(3i+1,16) C = C || OCB-ENCRYPT(K,N,S,S) N = num2str(3i+2,16) C = C || OCB-ENCRYPT(K,N,<empty string>,S) N = num2str(3i+3,16) C = C || OCB-ENCRYPT(K,N,S,<empty string>) end for N = num2str(385,16) Y = OCB-ENCRYPT(K,N,C,<empty string>)
Iteration i of the loop adds 2i + (3 * TAGLEN / 8) bytes to C, resulting in an ultimate length for C of 16256 + 48 * TAGLEN bytes. The final OCB-ENCRYPT has an empty plaintext component, so serves only to authenticate C. The output values should be:
VALIDATE[32] == 5A126BD4 VALIDATE[64] == 21CE70BE54BDD72D VALIDATE[96] == 1014F0D84D8060DC47752BAA VALIDATE[128] == 7F9A12DE01C2C3150EBB2593D6531EA4 VALIDATE[192] == 9A078741E919C04D27D788225F4EDC99 EB0864E3AA36C194 VALIDATE[256] == 4D40016D7A255F603110AF8157863D4C C392A2A2026C3CADF275583659389A84 VALIDATE[384] == 64973A1E77815999A50E9B2A0BAFE802 F00F821D5B34E1F63E0D4DF6BA50F600 VALIDATE[512] == 2CE8DA2D843D7373FA138C663305EC25 88FBCCE30DE426E99644E777F3FBCFD5 VALIDATE[768] == 37848B8A255C73CE0EE3BE5C8277340C BE64B54178B8731E052ECEC6BE9E5A07 VALIDATE[1024] == 439667F8BFFFC9D4C16E5CB3DE921F7D AD0B76463AB56321EDB68F2D1D2AEEC0 VALIDATE[1600] == 794CCD79BC11854275C924DF56CB82F2 C443631EF9F9F90251DC6DDC2CCF7F08
OCB, as defined in [RFC7523] and [OCB], uses several "magic numbers" when manipulating 128-bit blocks (135, 8, 6 and 7 for RESIDUE, SHIFT, MASKLEN and TAGREP). These constants are carefully chosen and depend on BLOCKLEN. A table in Section 3.1 gives values for other assorted blocklengths and this section describes how to produce the values for more blocklengths if needed.
Finding MASKLEN and SHIFT for a particular BLOCKLEN begins by following the process described in Section 4.1 of [OCB]. The result of that process is the domain size for every possible shift, 1 through BLOCKLEN-1, in the stretch-then-shift hash used internally by OCB. With that information, MASKLEN and SHIFT are determined as follows. Define MASKLEN as the floor of the base-2 logarithm of the largest domain size found. Keep as SHIFT candidates all shifts with domain sizes of at least 2^MASKLEN. These all provide equal security, but we want a shift that allows efficient implementation too. A shift equal to a large power-of-two would be ideal, but not all BLOCKLEN values produce candidate shifts with that property. Of all the shifts with domains of at least 2^MASKLEN, we continue to keep as candidates those shift values that are minimal modulo 8 (if this minima is equal to zero, then shifts can be performed using byte manipulations). Finally, we prefer shifts that are close to a large power-of-two, so of the remaining candidates, we choose for SHIFT one whose value modulo 8 and modulo 2^k is equal for the largest k, and if more than one has this property we settle on the smallest of those that do. The Sage script at the end of this section makes explicit this process and was run using SageMath 7.6 to generate all of the MASKLEN and SHIFT values given in Section 3.1 [Sage]. Its list of blocklengths can be edited and the script rerun to determine other MASKLEN and SHIFT values.
For the other two constants, TAGREP is defined as min(8, t) where t is the smallest integer making 2^t >= BLOCKLEN, and RESIDUE is extracted from [Polys]. To determine a RESIDUE for BLOCKLEN, find the entry whose largest number is BLOCKLEN and let S be the set of numbers other than BLOCKLEN in this entry. Then, RESIDUE = 1 + sum({2^x | x in S}). For example, when BLOCKLEN is 122 we find the entry "122,6,2,1" making S == {6,2,1}. In this case RESIDUE == 1 + 2^6 + 2^2 + 2^1 == 71.
<CODE BEGINS> # w will iterate over these blocklengths. Edit list as you wish. for w in [32, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1600]: domsize = [0] # domsize[i] will contain domain size of shift i # Find domain size for each possible shift c in 1..w-1 for c in range(1, w): # Build A matrix as specified in Section 4.1 of [OCB] I_rows = [[j == i for j in range(w)] for i in range(w)] J_rows = [[j == i or j == i + c for j in range(w)] for i in range(w)] IJ = matrix(GF(2), I_rows + J_rows) A = [IJ[i:i + w, 0:w] for i in range(w)] # Find number of qualifying sub-matrices (ie, domain size) i = 0 # increase i until not full-rank dom = w # Set dom=i ends loop & sets dom to domain size while i < dom: if A[i].rank() < w: dom=i j = 0 while j < i and i < dom: if (A[i] + A[j]).rank() < w: dom=i j = j + 1 i = i + 1 domsize.append(dom) # set domsize[c] = dom # Generate shifts that are secure, in preference order domain_bits = floor(log(max(domsize), 2)) candidates = (k for i in range(8) for j in range(floor(log(w, 2)),2,-1) for k in range(i,w,2**j) if domsize[k] >= 2**domain_bits) # Print the first one found, or -1 if none print("block bits: %d, mask bits: %d, shift bits: %d" % (w, domain_bits, next(candidates,-1))) <CODE ENDS>