RFC 3961

Encryption and Checksum Specifications for Kerberos 5

๐Ÿ“… published February 2005, from ietf

RFC 3961: Encryption and Checksum Specifications for Kerberos 5 ๐Ÿ’–

okay bestie, let's get into it ๐Ÿงš This is RFC 3961, and it's all about how Kerberos encryption and checksums get defined. Here's the title block:

  • Network Working Group: the group this is part of
  • Author: K. Raeburn, MIT ๐ŸŽ€
  • Category: Standards Track
  • Date: February 2005
  • The header doesn't list any RFCs it obsoletes or updates.

Status of This Memo ๐Ÿ“œ

This document is an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐Ÿซถ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited.

Copyright (C) The Internet Society (2005).

Abstract ๐ŸŒธ

This doc gives you a framework for defining encryption and checksum mechanisms that Kerberos can use ๐Ÿ’… It makes an abstraction layer sitting between Kerberos and its related protocols on one side and the actual mechanisms on the other, so they don't have to know each other's business. It also defines several mechanisms. Some come from RFC 1510, reshaped to fit this new framework, and occasionally fixed in content when the old spec was wrong ๐Ÿ™ˆ New mechanisms are introduced here too โœจ And the big thing it does not do is say which mechanisms count as "required to implement."

Table of Contents ๐Ÿ—‚๏ธ

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .  2
2.  Concepts  . . . . . . . . . . . . . . . . . . . . . . . . . .  2
3.  Encryption Algorithm Profile  . . . . . . . . . . . . . . . .  4
4.  Checksum Algorithm Profile  . . . . . . . . . . . . . . . . .  9
5.  Simplified Profile for CBC Ciphers with Key Derivation  . . . 10
    5.1.  A Key Derivation Function . . . . . . . . . . . . . . . 10
    5.2.  Simplified Profile Parameters . . . . . . . . . . . . . 12
    5.3.  Cryptosystem Profile Based on Simplified Profile  . . . 13
    5.4.  Checksum Profiles Based on Simplified Profile . . . . . 16
6.  Profiles for Kerberos Encryption and Checksum Algorithms  . . 16
    6.1.  Unkeyed Checksums . . . . . . . . . . . . . . . . . . . 17
    6.2.  DES-based Encryption and Checksum Types . . . . . . . . 18
    6.3.  Triple-DES Based Encryption and Checksum Types  . . . . 28
7.  Use of Kerberos Encryption Outside This Specification . . . . 30
8.  Assigned Numbers  . . . . . . . . . . . . . . . . . . . . . . 31
9.  Implementation Notes  . . . . . . . . . . . . . . . . . . . . 32
10. Security Considerations . . . . . . . . . . . . . . . . . . . 33
11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 35
12. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 36
A.  Test vectors  . . . . . . . . . . . . . . . . . . . . . . . . 38
    A.1.  n-fold  . . . . . . . . . . . . . . . . . . . . . . . . 38
    A.2.  mit_des_string_to_key . . . . . . . . . . . . . . . . . 39
    A.3.  DES3 DR and DK  . . . . . . . . . . . . . . . . . . . . 43
    A.4.  DES3string_to_key . . . . . . . . . . . . . . . . . . . 44
    A.5.  Modified CRC-32 . . . . . . . . . . . . . . . . . . . . 44
B.  Significant Changes from RFC 1510 . . . . . . . . . . . . . . 45
Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Normative References. . . . . . . . . . . . . . . . . . . . . . . 47
Informative References. . . . . . . . . . . . . . . . . . . . . . 48
Editor's Address. . . . . . . . . . . . . . . . . . . . . . . . . 49
Full Copyright Statement. . . . . . . . . . . . . . . . . . . . . 50

1. Introduction โœจ

okay so Kerberos is built to encrypt messages of any size ๐Ÿ” It uses block ciphers or, less commonly, stream ciphers. Encryption is how network entities prove who they are during message exchanges. Here's the lowkey cool part: nothing in the Kerberos protocol insists on one specific encryption algorithm ๐Ÿ’œ Any algorithm works, as long as it includes certain operations.

The sections that follow spell out the encryption and checksum mechanisms that are currently defined for Kerberos, plus a framework for defining future ones ๐Ÿฆ‹ They also cover the encoding, chaining, padding, and other requirements for each one. And Appendix A has test vectors for several functions, so you can check your work ๐Ÿ™Œ

2. Concepts ๐ŸŽ€

Both encryption and checksum mechanisms get profiled in later sections. Each profile lays out a collection of operations and attributes that a mechanism must define. A Kerberos encryption or checksum mechanism spec isn't complete unless it defines all of them ๐Ÿ’…

An encryption mechanism must provide confidentiality and integrity of the original plaintext. (Adding a checksum may allow integrity checking, if the encryption mode doesn't have an integrity check of its own.) It must also provide non-malleability [Bellare98] [Dolev91]. Prepending a random confounder to the plaintext is recommended ๐Ÿซถ It should not be possible to tell whether two ciphertexts match the same plaintext without the key. ๐Ÿ”‘

A checksum mechanism [1] must prove the integrity of the associated message, and it must keep the message confidential in case it isn't sent in the clear. Finding two plaintexts with the same checksum should be infeasible. It is NOT required that an eavesdropper be unable to tell whether two checksums belong to the same message, since the messages themselves would presumably be visible to any such eavesdropper ๐Ÿ‘€

Due to advances in cryptography, some cryptographers think using the same key for multiple purposes is unwise ๐Ÿ˜ฌ Kerberos uses keys for a bunch of different functions, so it's desirable to use different keys for each purpose, even though we start with a single long-term or session key ๐Ÿ—๏ธ

So here's how we do it: we list out the different uses of keys within Kerberos, and we make the "usage number" an input to the encryption or checksum mechanisms. Listing those uses is outside the scope of this document. Later sections define simplified profile templates for encryption and checksum mechanisms that apply a key derivation function to a CBC mode (or similar) cipher and a checksum or hash algorithm ๐Ÿ“

We distinguish the "base key" from other documents from the "specific key" used for a specific encryption or checksum operation ๐Ÿงš The specific key is expected, but not required, to be one or more separate keys derived from the original protocol key and the key usage number. The specific key should not be explicitly referenced outside of this document. Other documents typically say something like, "encrypt this octet string using this key and this usage number," and generating the specific key and cipher state (covered in the next section) is implicit. Creating a new cipher-state object, or reusing one from a previous encryption operation, may also be explicit ๐Ÿ’–

New protocols defined in terms of the Kerberos encryption and checksum types should use their own key usage values. Key usages are unsigned 32-bit integers, and zero is not permitted ๐Ÿšซ

All data is assumed to be strings of octets, or eight-bit bytes. Environments with other byte sizes will have to emulate this behavior to get correct results ๐Ÿค“

Each algorithm gets an encryption type (or "etype") or checksum type number, which Kerberos uses to identify it on the wire. The full list of current type number assignments is in section 8 ๐ŸŒˆ

3. Encryption Algorithm Profile ๐Ÿ’…

An encryption mechanism profile must define the following attributes and operations. The operations must be defined as functions in the mathematical sense. No additional or implicit inputs (such as Kerberos principal names or message sequence numbers) are permitted ๐Ÿ™…โ€โ™€๏ธ

  • protocol key format: This describes which octet string values represent valid keys. For encryption mechanisms that don't have perfectly dense key spaces, this describes the representation used to encode keys. It doesn't need to describe invalid specific values, though all key generation routines should avoid them โœจ
  • specific key structure: This isn't a protocol format at all. It describes the keying material derived from the chosen key and used to encrypt or decrypt data, or to compute or verify a checksum. It could be a single key, a set of keys, or a combination of the original key with additional data. The authors recommend using one or more keys derived from the original key through one-way key derivation functions ๐Ÿ”
  • required checksum mechanism: This names a checksum mechanism that must be available whenever this encryption mechanism is used. Kerberos has no built-in way to negotiate checksum mechanisms, so once an encryption mechanism is chosen, the matching checksum mechanism can be used ๐Ÿซถ
  • key-generation seed length, K: This is the length of the random bitstring needed to generate a key with the encryption scheme's random-to-key function (described below). It must be a fixed value, so that various techniques for producing a random bitstring of a given length can be used with key generation functions ๐ŸŽฒ
  • key generation functions: Keys have to be generated in a number of cases, from different kinds of inputs. Every function spec must say how to generate keys in the proper wire format, and it must avoid generating keys that significantly compromise the confidentiality of encrypted data, if the cryptosystem has such keys. Entropy from each source should be preserved as much as possible. Many inputs, though unknown, may be at least partly predictable. For example, a password string is likely to be entirely in the ASCII subset and fairly short in many environments, and a semi-random string may include time stamps. The benefit of that predictability to an attacker must be minimized ๐Ÿ‘€
  • string-to-key (UTF-8 string, UTF-8 string, opaque)->(protocol-key): This function makes a key from two UTF-8 strings and an opaque octet string. One of the strings is usually the principal's pass phrase, but in general it's just a secret string. The other string is a "salt" string, meant to produce different keys from the same password for different users or realms. Even though the strings use UTF-8 encoding, no specific version of Unicode should be assumed, and all valid UTF-8 strings should be allowed. Strings provided in other encodings MUST first be converted to UTF-8 before applying this function ๐ŸŒธ

The third argument, the octet string, may be used to pass mechanism-specific parameters into this function. Since doing so implies knowledge of the specific encryption system, generating non-default parameter values should be an uncommon operation. Normal Kerberos applications should be able to treat this parameter block as an opaque object supplied by the Key Distribution Center, or defaulted to some mechanism-specific constant value ๐Ÿง

The string-to-key function should be a one-way function, so that compromising a user's key in one realm doesn't compromise it in another, even if the same password (but a different salt) is used ๐Ÿ”’

random-to-key (bitstring[K])->(protocol-key)

okay so this one takes a random bitstring of a specific size and turns it into a protocol key ๐ŸŽ€ All the bits of the input are treated as equally random, bestie, even though the entropy in the actual random source might be kinda limited ๐Ÿฅบ

key-derivation (protocol-key, integer)->(specific-key)

the integer input here is the key usage value we covered above ๐Ÿฆ‹ An attacker is assumed to know all the usage values (no secrets there!), and the specific-key output is the one described in section 2 โœจ

string-to-key parameter format

this describes the format of the data block you can pass into the string-to-key function to configure its extra parameters ๐Ÿ’… We also have to set bounds on what's allowed, because otherwise a spoofed KDC could compromise the user's password ๐Ÿ˜ญ If it's practical, it MAY be desirable to build the encoding so that values which would unacceptably weaken the resulting key simply cannot be encoded ๐Ÿ”ฅ

Local security policy MAY permit tighter bounds to avoid excess resource consumption. If it does, the specification SHOULD give RECOMMENDED defaults for these bounds ๐ŸŒธ The description SHOULD also outline the possible weaknesses if bounds checks or other validations are not applied to a parameter string received from the network ๐Ÿ’€

As mentioned above, this SHOULD be considered opaque to most normal applications ๐Ÿ™ˆ

default string-to-key parameters (octet string)

this is the default value for the "params" argument of the string-to-key function, and it SHOULD be used whenever the application protocol (Kerberos or something else) doesn't explicitly set the parameter value ๐Ÿ’– Like we said before, in most cases this parameter block should be treated as an opaque object ๐Ÿซถ

cipher state

this is any info that can get carried over from one encryption or decryption operation to the next, for use with a given specific key โœจ For example, a block cipher used in CBC mode MAY put an initial vector of one block in the cipher state. Other encryption modes MAY track nonces or other data ๐Ÿงš

This state MUST be non-empty and MUST influence encryption so that messages are decrypted in the same order they were encrypted, if the cipher state is carried over from one encryption to the next. Telling apart out-of-order or missing messages from corrupted ones is not required ๐Ÿคทโ€โ™€๏ธ If you want that, you can do it at a higher level by including sequence numbers and NOT "chaining" the cipher state between encryption operations ๐ŸŽ€

The cipher state MAY NOT be reused in multiple encryption or decryption operations. These operations all generate a new cipher state that MAY be used for following operations using the same key and operation ๐Ÿฆ‹

The contents of the cipher state MUST be treated as opaque outside of encryption system specifications ๐Ÿ”’

initial cipher state (specific-key, direction)->(state)

this covers generating the initial value for the cipher state when it's NOT being carried over from a previous encryption or decryption operation ๐ŸŒˆ

It also describes any initial state setup needed before encrypting arbitrary amounts of data with a given specific key. The specific key and the direction of operations (encrypt versus decrypt) MUST be the only inputs needed for this initialization ๐Ÿ‘‘

This state SHOULD be treated as opaque in any uses outside of an encryption algorithm definition ๐Ÿ’œ

IMPLEMENTATION NOTE: [Kerb1510] was vague on whether, and to what degree, an application protocol could control the initial vector used in DES CBC operations. Some existing implementations let you set the initial vector. This framework does NOT provide for application control of the cipher state (beyond "initialize" and "carry over from previous encryption"), because the form and content of the initial cipher state can vary between encryption systems and MAY NOT always be a single block of random data ๐Ÿ™ˆ

New Kerberos application protocols SHOULD NOT assume control over the initial vector, or assume that one even exists. Still, a general-purpose implementation MAY wish to provide the capability, in case applications that explicitly set it get encountered ๐Ÿซ 

encrypt (specific-key, state, octet string)->(state, octet string)

this takes the specific key, the cipher state, and a non-empty plaintext string as input, and spits out ciphertext plus a new cipher state ๐Ÿ” If the basic encryption algorithm doesn't provide integrity protection by itself (like DES in CBC mode), then some form of verifiable MAC or checksum MUST be included ๐Ÿ”ฅ A random factor like a confounder SHOULD be included too, so an observer can't tell whether two messages contain the same plaintext, even when the cipher state and specific keys are the same ๐Ÿ‘€

The exact length of the plaintext doesn't need to be encoded. But if it isn't, and padding is required, the padding MUST be added at the end of the string so the decrypted version can be parsed from the beginning ๐Ÿ“

The spec for the encryption function MUST indicate not only the precise contents of the output octet string, but also the output cipher state. The application protocol MAY carry the output cipher state forward from one encryption with a given specific key to another, and the effect of this "chaining" MUST be defined [2] ๐Ÿ’…

Assuming the specific key and cipher state were correctly produced, NO input octet string may result in an error indication ๐Ÿ™Œ

decrypt (specific-key, state, octet string)->(state, octet string)

this takes the specific key, cipher state, and ciphertext as inputs, and verifies the integrity of the ciphertext ๐Ÿ•ต๏ธโ€โ™€๏ธ If the integrity is intact, it produces the plaintext and a new cipher state. Otherwise an error indication MUST be returned, and the data MUST be discarded ๐Ÿ’€

The result of decryption MAY be longer than the original plaintext, like when the encryption mode adds padding to reach a multiple of a block size. If that happens, any extra octets MUST come after the decoded plaintext ๐Ÿซง An application protocol that needs to know the exact length of the message MUST encode a length or a recognizable "end of message" marker within the plaintext [3] โœจ

Same as with the encryption function, a correct spec for this one MUST indicate not only the contents of the output octet string, but also the resulting cipher state ๐ŸŽ€

pseudo-random (protocol-key, octet-string)->(octet-string)

this pseudo-random function SHOULD generate an octet string of some size that's independent of the octet string input. The PRF output SHOULD be suitable for key generation, even if the octet string input is public. It SHOULD NOT reveal the input key, even if the output is made public ๐Ÿ”‘

These operations and attributes are all that is required to support Kerberos and various proposed preauthentication schemes ๐ŸŒธ

For convenience, certain application protocols MAY want to use the encryption profile, so we add a constraint: for any given plaintext input size, a message size MUST exist between that size and that size plus 65,535, such that the length of the decrypted version of the ciphertext never has extra octets at the end ๐Ÿ’–

Mathematically, that looks like this: for every message length L1, there exists a message size L2 such that

L2 >= L1
L2 < L1 + 65,536
for every message M with |M| = L2, decrypt(encrypt(M)) = M

A document defining a new encryption type SHOULD also describe known weaknesses or attacks, so its security can be fairly assessed. It SHOULD include test vectors or other validation procedures for the operations defined ๐Ÿงช Specific references to information that's readily available elsewhere are sufficient ๐Ÿ“š


4. Checksum Algorithm Profile โœจ

A checksum mechanism profile MUST define the following attributes and operations ๐Ÿ’…

associated encryption algorithm(s)

this indicates the types of encryption keys this checksum mechanism can be used with ๐Ÿ”

A keyed checksum mechanism MAY have more than one associated encryption algorithm, as long as they share the same wire-key format, string-to-key function, default string-to-key-parameters, and key derivation function. (This combination means that, for example, a checksum type, key usage value, and password are enough to get the specific key used to compute a checksum ๐Ÿฆ‹)

An unkeyed checksum mechanism can be used with any encryption type, since the key is ignored. But its use MUST be limited to cases where the checksum itself is protected, to avoid trivial attacks ๐Ÿ™…โ€โ™€๏ธ

get_mic function

this generates a MIC token for a given specific key (see section 3) and message (represented as an octet string), and the token can be used to verify the integrity of the associated message ๐ŸŽ€ It is not required to return the same deterministic result each time. It just needs to generate a token that the verify_mic routine can check ๐Ÿค

The output of this function also dictates the size of the checksum. It MUST be no larger than 65,535 octets ๐Ÿ“

verify_mic function

given a specific key, message, and MIC token, this function figures out whether the message integrity has been compromised ๐Ÿ•ต๏ธโ€โ™€๏ธ For a deterministic get_mic routine, the corresponding verify_mic MAY simply generate another checksum and compare the two ๐ŸŒˆ

The get_mic and verify_mic operations MUST allow inputs of arbitrary length. If any padding is needed, the padding scheme MUST be specified as part of these functions ๐Ÿซถ

These operations and attributes are all that SHOULD be required to support Kerberos and various proposed preauthentication schemes โœจ

As with encryption mechanism definition documents, documents defining new checksum mechanisms SHOULD indicate validation processes and known weaknesses ๐Ÿงช


5. Simplified Profile for CBC Ciphers with Key Derivation ๐ŸŒธ

The profile outlined in sections 3 and 4 describes a big pile of operations that MUST be defined for encryption and checksum algorithms to be used with Kerberos ๐Ÿ˜ญ So here we describe a simpler profile that can generate both encryption and checksum mechanism definitions. It fills in uses of key derivation in the right places, provides integrity protection, and defines multiple operations for the cryptosystem profile based on a smaller set of operations ๐Ÿ’… Not all of the existing cryptosystems for Kerberos fit into this simplified profile, but we recommend that future cryptosystems use it or something based on it [4] ๐Ÿฆ‹

Not all the operations in the complete profiles are defined through this mechanism. Several still MUST be defined for each new algorithm pair ๐Ÿซถ

5.1. A Key Derivation Function ๐Ÿ”‘

Okay so instead of building one giant "protocol key" out of a bunch of encryption keys (way too messy ๐Ÿ’€), we just derive keys from a base key and use those for the actual crypto ops โœจ. The base key must be used only for generating the derived keys, and this derivation must be non-invertible and entropy preserving. With those rules locked in, compromising one derived key doesn't compromise the others ๐Ÿ›ก๏ธ. The base key is also pretty safe, since it's only used for derivation and never exposed to any user data ๐Ÿซถ.

To make a derived key, we first generate a pseudorandom octet string using the DR algorithm (more on that below), and then turn that string into a key with a function that depends on the encryption algorithm. That function needs a specific input length, which also depends on the algorithm. That length sets how long the DR output has to be (the value "k" below). This whole procedure is based on the key derivation in [Blumenthal96] ๐Ÿ’œ.

   Derived Key = DK(Base Key, Well-Known Constant)

   DK(Key, Constant) = random-to-key(DR(Key, Constant))

   DR(Key, Constant) = k-truncate(E(Key, Constant,
                                    initial-cipher-state))

So DR is the random-octet generation function and DK is the key-derivation function built on top of it ๐Ÿงš. E(Key, Plaintext, CipherState) is a cipher, Constant is a well-known constant chosen based on how this function is used, and k-truncate keeps the first k bits of its argument. The k is the key generation seed length that the encryption system needs โญ.

The DR output is a bit string, and the actual key comes from running the cryptosystem's random-to-key operation on it ๐Ÿ”ฅ.

If the Constant is smaller than E's cipher block size, it must be expanded with n-fold() so it can be encrypted ๐ŸŽ€. If E's output is shorter than k bits, it gets fed back into the encryption as many times as it takes. Here's the construction (where | means concatenation):

   K1 = E(Key, n-fold(Constant), initial-cipher-state)
   K2 = E(Key, K1, initial-cipher-state)
   K3 = E(Key, K2, initial-cipher-state)
   K4 = ...

   DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)

n-fold is the algorithm that takes m input bits and stretches them out to n output bits, with every input bit contributing equally to the output. Here's how [Blumenthal96] describes it, word for word:

We first define a primitive called n-folding, which takes a variable-length input block and produces a fixed-length output sequence. The intent is to give each input bit approximately equal weight in determining the value of each output bit. Note that whenever we need to treat a string of octets as a number, the assumed representation is Big-Endian -- Most Significant Byte first. To n-fold a number X, replicate the input value to a length that is the least common multiple of n and the length of X. Before each repetition, the input is rotated to the right by 13 bit positions. The successive n-bit chunks are added together using 1's-complement addition (that is, with end-around carry) to yield a n-bit result....

Test vectors for n-fold are in appendix A [5] ๐Ÿงพ.

In this section, n-fold is always used to produce c bits of output, where c is the cipher block size of E ๐Ÿ’….

The size of the Constant must not be larger than c, because shrinking the Constant with n-folding can cause collisions ๐Ÿ’€.

If the Constant is smaller than c, it must be n-folded out to length c, and that string is then fed into E. If E's block size is less than the random-to-key input size, the output from E is taken as input to a second invocation of E. This keeps going until the bits accumulated are greater than or equal to the random-to-key input size. Once there are enough bits, the first k are used as the random data to build the key with the algorithm-dependent random-to-key function ๐ŸŒˆ.

And here's the big payoff: since the derived key is the result of one or more encryptions under the base key, figuring out the base key from the derived key is the same as figuring it out from a very small number of plaintext/ciphertext pairs. So this construction is exactly as strong as the cryptosystem itself ๐Ÿ‘‘.


5.2. Simplified Profile Parameters ๐Ÿ“‹

These are the operations and attributes that must be defined:

  • protocol key format
  • string-to-key function
  • default string-to-key parameters
  • key-generation seed length, k
  • random-to-key function
    • As above for the normal encryption mechanism profile.

unkeyed hash algorithm, H

This should be a collision-resistant hash algorithm with fixed-size output, suitable for use in an HMAC [HMAC] ๐ŸŒธ. It must support inputs of arbitrary length. Its output must be at least the message block size (below).

HMAC output size, h

This is the size of the leading substring of the HMAC output that should be used in transmitted messages ๐Ÿฆ‹. It should be at least half the output size of the hash function H, and at least 80 bits. It doesn't need to match the output size.

message block size, m

This is the size of the smallest units the cipher can handle in the mode it's being used in ๐Ÿ“. Messages get padded to a multiple of this size. If a block cipher is used in a mode that can handle messages that aren't multiples of the cipher block size, like CBC mode with cipher text stealing (CTS, see [RC5]), this value would be one octet. For traditional CBC mode with padding, it would be the underlying cipher's block size.

This value must be a multiple of eight bits (one octet).

encryption/decryption functions, E and D

These are the basic encryption and decryption functions for messages whose sizes are multiples of the message block size โœจ. No integrity checking or confounder should be included here. For inputs, these functions take the IV or similar data, a protocol-format key, and an octet string, and they return a new IV and an octet string.

The encryption function isn't required to use CBC mode, but it's assumed to be using something with similar properties. In particular, prepending a cipher block-size confounder to the plaintext should alter the entire ciphertext (comparable to choosing and including a random initial vector for CBC mode) ๐Ÿ”.

Encrypting one cipher block (of size c, above) must be deterministic for the random octet generation function DR in the previous section to work. For best security, it should also be no larger than c.

cipher block size, c

This is the block size of the block cipher underlying the encryption and decryption functions above. It's used for key derivation and for the size of the message confounder and initial vector. (If a block cipher isn't in use, some comparable parameter should be figured out instead.) It must be at least 5 octets ๐Ÿซง.

This isn't really an independent parameter. It's a property of the functions E and D. It's listed here so you can tell it apart from the message block size, m.

Although there are still a number of properties to specify, they're fewer and simpler than in the full profile ๐ŸŽ€.


5.3. Cryptosystem Profile Based on Simplified Profile ๐Ÿ’–

Okay, the key derivation function above gets used to produce three intermediate keys ๐Ÿ—๏ธ. One is for computing checksums of unencrypted data. The other two are for encrypting and checksumming plaintext that's going to be sent encrypted.

The ciphertext output is the concatenation of the output of the basic encryption function E and a (possibly truncated) HMAC using the specified hash function H. Both are applied to the plaintext, with a random confounder prefix and enough padding to bring it up to a multiple of the message block size. When the HMAC is computed, the key is used in its protocol key form ๐Ÿฆ‹.

Decryption works by removing the (partial) HMAC, decrypting the rest, and then verifying the HMAC ๐Ÿ•ต๏ธ. The cipher state is an initial vector, initialized to zero.

The substring notation "[1..h]" in the table below should be read with 1-based indexing, and leading substrings are used ๐Ÿ”ข.

                 Cryptosystem from Simplified Profile
------------------------------------------------------------------------
protocol key format       As given.

specific key structure    Three protocol-format keys: { Kc, Ke, Ki }.

key-generation seed       As given.
length

required checksum         As defined below in section 5.4.
mechanism

cipher state              Initial vector (usually of length c)

initial cipher state      All bits zero

encryption function       conf = Random string of length c
                          pad  = Shortest string to bring confounder
                                 and plaintext to a length that's a
                                 multiple of m.
                          (C1, newIV) = E(Ke, conf | plaintext | pad,
                                          oldstate.ivec)
                          H1 = HMAC(Ki, conf | plaintext | pad)
                          ciphertext =  C1 | H1[1..h]
                          newstate.ivec = newIV

decryption function       (C1,H1) = ciphertext
                          (P1, newIV) = D(Ke, C1, oldstate.ivec)
                          if (H1 != HMAC(Ki, P1)[1..h])
                             report error
                          newstate.ivec = newIV

default string-to-key     As given.
params

pseudo-random function    tmp1 = H(octet-string)
                          tmp2 = truncate tmp1 to multiple of m
                          PRF = E(DK(protocol-key, prfconstant),
                                  tmp2, initial-cipher-state)

The "prfconstant" used in the PRF operation is the three-octet string "prf" ๐ŸŒท.

                 Cryptosystem from Simplified Profile
------------------------------------------------------------------------
key generation functions:

string-to-key function    As given.

random-to-key function    As given.

key-derivation function   The "well-known constant" used for the DK
                          function is the key usage number, expressed as
                          four octets in big-endian order, followed by
                          one octet indicated below.

                          Kc = DK(base-key, usage | 0x99);
                          Ke = DK(base-key, usage | 0xAA);
                          Ki = DK(base-key, usage | 0x55);

5.4. Checksum Profiles Based on Simplified Profile โœ…

When an encryption system is defined with the simplified profile from section 5.2, a checksum algorithm may be defined for it as follows ๐Ÿซถ:

              Checksum Mechanism from Simplified Profile
           --------------------------------------------------
           associated cryptosystem   As defined above.

           get_mic                   HMAC(Kc, message)[1..h]

           verify_mic                get_mic and compare

The HMAC function and key Kc are as described in section 5.3 ๐Ÿ’œ.

6. Profiles for Kerberos Encryption and Checksum Algorithms โœจ

Okay bestie, this section is where we meet the Kerberos encryption and checksum systems ๐Ÿ”. Some of them are a little bit vintage and don't meet every requirement from the earlier sections. They're kept around for backward compatibility ๐Ÿ•ฐ๏ธ, but newer implementations should (whenever possible) pick encryption systems that meet all the profile requirements ๐Ÿ’…. The full list of current encryption and checksum type number assignments, including values that are reserved but not defined here, lives in section 8 ๐Ÿ“‹.

6.1. Unkeyed Checksums ๐Ÿงฉ

These checksum types don't use encryption keys, so they can be paired with any encryption type ๐ŸŒˆ. They may only be used with caution, though, and only in limited situations where having no key doesn't open a window for an attack ๐Ÿšช. Preferably they're used as part of an encrypted message [6]. Keyed checksum algorithms are recommended ๐Ÿ”‘.

6.1.1. The RSA MD5 Checksum ๐ŸŒธ

The RSA-MD5 checksum uses the RSA MD5 algorithm [MD5-92] ๐Ÿงฎ. It takes an input message of any length and spits out a 128-bit (sixteen octet) checksum ๐Ÿ’œ.

                              rsa-md5
           ----------------------------------------------
           associated cryptosystem   any

           get_mic                   rsa-md5(msg)

           verify_mic                get_mic and compare

The rsa-md5 checksum algorithm gets assigned checksum type number seven (7) ๐ŸŽ€.

6.1.2. The RSA MD4 Checksum ๐Ÿ“

The RSA-MD4 checksum uses the RSA MD4 algorithm [MD4-92] โœจ. Same deal as MD5: any-length input, 128-bit (sixteen octet) output ๐Ÿซถ.

                              rsa-md4
           ----------------------------------------------
           associated cryptosystem   any

           get_mic                   md4(msg)

           verify_mic                get_mic and compare

The rsa-md4 checksum algorithm gets checksum type number two (2) ๐Ÿฆ‹.

6.1.3. CRC-32 Checksum ๐Ÿงš

Okay, this one is a big "not recommended" energy moment ๐Ÿ˜ฌ. The CRC-32 checksum is based on a cyclic redundancy check described in ISO 3309 [CRC], but it's been modified in a couple of ways ๐Ÿ› ๏ธ. The result is four (4) octets long ๐Ÿ’–. It is neither keyed nor collision-proof, so using it is not recommended ๐Ÿšซ. An attacker running a probabilistic chosen-plaintext attack like the one described in [SG92] might be able to craft a different message that still satisfies the checksum ๐Ÿ’€.

The CRC-32 checksum used in the des-cbc-crc encryption mode matches the 32-bit FCS from ISO 3309 with two exceptions ๐Ÿ”. First, the sum with the all-ones polynomial times x**k is omitted. Second, the final remainder is not ones-complemented ๐Ÿ™ˆ. ISO 3309 describes the FCS in terms of bits, but this document describes the Kerberos protocol in terms of octets ๐Ÿง . To make the ISO 3309 definition clear for computing CRC-32 in the des-cbc-crc encryption mode, the ordering of bits in each octet shall be assumed to be LSB first ๐Ÿ”„. With that bit ordering assumed, the mapping of bits to polynomial coefficients shall be identical to what ISO 3309 specifies ๐ŸŒŸ.

Test values for this modified CRC function are included in appendix A.5 ๐Ÿ“.

                               crc32
           ----------------------------------------------
           associated cryptosystem   any

           get_mic                   crc32(msg)

           verify_mic                get_mic and compare

The crc32 checksum algorithm gets checksum type number one (1) ๐Ÿ‘‘.

6.2. DES-Based Encryption and Checksum Types ๐Ÿ”๐Ÿ’•

These encryption systems encrypt information under the Data Encryption Standard [DES77] using the cipher block chaining mode [DESM80] ๐ŸŽ€. A checksum is computed as described below and placed in the cksum field ๐Ÿงพ. DES blocks are eight bytes, so the data to be encrypted (the confounder, checksum, and message put together) must be padded to an eight byte boundary before encryption ๐Ÿ“. The values of the padding bytes are unspecified ๐Ÿคทโ€โ™€๏ธ.

Plaintext and DES ciphertext are encoded as blocks of eight octets. Those blocks get concatenated to make the 64-bit inputs for the DES algorithms ๐Ÿงฉ. The first octet supplies the eight most significant bits (the octet's MSB becomes the DES input block's MSB, and so on). The second octet supplies the next eight bits, and it keeps going like that. The eighth octet supplies the 8 least significant bits ๐Ÿ’œ.

Encryption under DES with cipher block chaining needs an extra input called an initialization vector ๐ŸŒˆ. The vector is specified below for each encryption system ๐Ÿ“Œ.

The DES specifications [DESI81] identify four 'weak' and twelve 'semi-weak' keys ๐Ÿšจ. These keys SHALL NOT be used for encrypting messages for use in Kerberos ๐Ÿ›‘. The "variant keys" generated for the RSA-MD5-DES, RSA-MD4-DES, and DES-MAC checksum types by an eXclusive-OR of a DES key with a constant aren't checked for this property ๐Ÿ™ƒ.

A DES key is eight octets of data ๐Ÿ—๏ธ. That's 56 bits of actual key data plus eight parity bits, one per octet ๐Ÿ’…. The key is encoded as a series of eight octets written in MSB-first order, and the bits inside the key are encoded in MSB order too ๐Ÿ”ข. For example, if the encryption key is (B1,B2,...,B7,P1,B8,...,B14,P2,B15,...,B49,P7,B50,...,B56,P8), where B1,B2,...,B56 are the key bits in MSB order and P1,P2,...,P8 are the parity bits, then the first octet of the key would be B1,B2,...,B7,P1 (with B1 as the most significant bit). See the [DESM80] introduction for reference ๐Ÿ“–.

Encryption Data Format ๐ŸŽ

The data to be encrypted includes a one-block confounder, a checksum, the encoded plaintext, and any necessary padding, as shown in this diagram ๐Ÿ–ผ๏ธ. The msg-seq field holds the part of the protocol message to be encrypted ๐Ÿ’Œ.

              +-----------+----------+---------+-----+
              |confounder | checksum | msg-seq | pad |
              +-----------+----------+---------+-----+

Here's the recipe ๐Ÿณ. Generate a random confounder of one block and place it in 'confounder'. Zero out the 'checksum' field (sized to exactly hold the checksum you're about to compute). Add the necessary padding. Calculate the checksum over the whole sequence and place the result in 'checksum'. Then encrypt using the specified encryption type and the right key โœจ.

String or Random-Data to Key Transformation ๐Ÿช„

To make a DES key from two UTF-8 text strings (password and salt), concatenate the two strings with password first. Then pad the result with zero-valued octets until it's a multiple of eight octets ๐Ÿง.

The top bit of each octet is discarded. It's always zero if the password is plain ASCII, which is what was assumed when the original specification was written ๐ŸŒธ. The remaining seven bits of each octet form a bitstring. That bitstring gets fan-folded and eXclusive-ORed with itself to produce a 56-bit string ๐ŸŒ€. An eight-octet key is formed from this string, with each octet using seven bits from the bitstring and the least significant bit left unassigned ๐Ÿ”‘. The key is then "corrected" by fixing its parity. If the key matches a 'weak' or 'semi-weak' key from the DES specification, it gets eXclusive-ORed with the constant 0x00000000000000F0 ๐Ÿ’ซ. That key is then used to generate a DES CBC checksum on the initial string with the salt appended ๐Ÿ”—. The CBC checksum result gets "corrected" the same way as above, and that becomes the returned key ๐Ÿ‘‘.

For the string-to-key function, the DES CBC checksum is calculated by CBC encrypting a string using the key as the IV, with the final eight byte block used as the checksum ๐Ÿงก.

Pseudocode time ๐Ÿค“:

     removeMSBits(8byteblock) {
       /* Treats a 64 bit block as 8 octets and removes the MSB in
          each octet (in big endian mode) and concatenates the
          result.  E.g., the input octet string:
             01110000 01100001 11110011  01110011 11110111 01101111
             11110010 01100100
          results in the output bitstring:
             1110000 1100001 1110011  1110011 1110111 1101111
             1110010 1100100  */
     }

     reverse(56bitblock) {
       /* Treats a 56-bit block as a binary string and reverses it.
          E.g., the input string:
             1000001 1010100 1001000  1000101 1001110 1000001
             0101110 1001101
          results in the output string:
             1011001 0111010 1000001  0111001 1010001 0001001
             0010101 1000001  */
     }
     add_parity_bits(56bitblock) {
       /* Copies a 56-bit block into a 64-bit block, left shifts
          content in each octet, and add DES parity bit.
          E.g., the input string:
             1100000 0001111 0011100  0110100 1000101 1100100
             0110110 0010111
          results in the output string:
             11000001 00011111 00111000  01101000 10001010 11001000
             01101101 00101111  */
     }

     key_correction(key) {
          fixparity(key);
          if (is_weak_key(key))
               key = key XOR 0xF0;
          return(key);
     }

     mit_des_string_to_key(string,salt) {
          odd = 1;
          s = string | salt;
          tempstring = 0; /* 56-bit string */
          pad(s); /* with nulls to 8 byte boundary */
          for (8byteblock in s) {
               56bitstring = removeMSBits(8byteblock);
               if (odd == 0) reverse(56bitstring);
               odd = ! odd;
               tempstring = tempstring XOR 56bitstring;
          }
          tempkey = key_correction(add_parity_bits(tempstring));
          key = key_correction(DES-CBC-check(s,tempkey));
          return(key);
     }

     des_string_to_key(string,salt,params) {
          if (length(params) == 0)
               type = 0;
          else if (length(params) == 1)
               type = params[0];
          else
               error("invalid params");
          if (type == 0)
               mit_des_string_to_key(string,salt);
          else
               error("invalid params");
     }

One common extension is to support the "AFS string-to-key" algorithm, which isn't defined here, if the type value above is one (1) ๐Ÿงช.

Random Bitstring to Key ๐ŸŽฒ

For generating a key from a random bitstring, start with a 56-bit string and insert parity bits, same as in the string-to-key operation above ๐Ÿงต. If the result is a weak or semi-weak key, modify it by eXclusive-ORing it with the constant 0x00000000000000F0 ๐Ÿฉท:

     des_random_to_key(bitstring) {
          return key_correction(add_parity_bits(bitstring));
     }

6.2.1. DES with MD5 ๐Ÿ’–

okay so des-cbc-md5 encrypts info under DES in CBC mode, starting with an all-zero initial vector ๐ŸŒธ and an MD5 checksum (described in [MD5-92]) gets computed and tucked into the checksum field โœจ literally the perfect little combo ๐Ÿซถ

Here are the encryption system parameters for des-cbc-md5 ๐ŸŽ€

                             des-cbc-md5
--------------------------------------------------------------------
protocol key format      8 bytes, parity in low bit of each

specific key structure   copy of original key

required checksum        rsa-md5-des
mechanism

key-generation seed      8 bytes
length

cipher state             8 bytes (CBC initial vector)

initial cipher state     all-zero

encryption function      des-cbc(confounder | checksum | msg | pad,
                                  ivec=oldstate)
                         where
                         checksum = md5(confounder | 0000...
                                        | msg | pad)

                         newstate = last block of des-cbc output

decryption function      decrypt encrypted text and verify checksum

                         newstate = last block of ciphertext

                             des-cbc-md5
--------------------------------------------------------------------
default string-to-key    empty string
params

pseudo-random function   des-cbc(md5(input-string), ivec=0)

key generation functions:

string-to-key            des_string_to_key

random-to-key            des_random_to_key

key-derivation           identity

the des-cbc-md5 encryption type is assigned the etype value three (3) ๐Ÿ‘‘


6.2.2. DES with MD4 ๐Ÿฆ‹

the des-cbc-md4 mode is giving the same vibe ๐Ÿ’… it also encrypts under DES in CBC mode with an all-zero initial vector, and an MD4 checksum (described in [MD4-92]) gets computed and placed in the checksum field ๐ŸŒˆ

                             des-cbc-md4
--------------------------------------------------------------------
protocol key format      8 bytes, parity in low bit of each

specific key structure   copy of original key

required checksum        rsa-md4-des
mechanism

key-generation seed      8 bytes
length

cipher state             8 bytes (CBC initial vector)

initial cipher state     all-zero

encryption function      des-cbc(confounder | checksum | msg | pad,
                                  ivec=oldstate)
                         where
                         checksum = md4(confounder | 0000...
                                        | msg | pad)

                         newstate = last block of des-cbc output

                             des-cbc-md4
--------------------------------------------------------------------

decryption function      decrypt encrypted text and verify checksum

                         newstate = last block of ciphertext

default string-to-key    empty string
params

pseudo-random function   des-cbc(md5(input-string), ivec=0)

key generation functions:

string-to-key            des_string_to_key

random-to-key            copy input, then fix parity bits

key-derivation           identity

ngl this one has a plot twist ๐Ÿ™ˆ des-cbc-md4 uses md5, not md4, in the PRF definition. don't mix them up bestie ๐Ÿ˜ญ

the des-cbc-md4 encryption algorithm is assigned the etype value two (2) ๐Ÿ“


6.2.3. DES with CRC ๐Ÿงš

the des-cbc-crc type uses DES in CBC mode, with the key used as the initialization vector ๐Ÿ”ฅ it also uses a four-octet CRC-based checksum computed as described in section 6.1.3. heads up, this is not a standard CRC-32 checksum. it's a slightly modified one ๐Ÿ‘€

                             des-cbc-crc
--------------------------------------------------------------------
protocol key format      8 bytes, parity in low bit of each

specific key structure   copy of original key

required checksum        rsa-md5-des
mechanism

key-generation seed      8 bytes
length

cipher state             8 bytes (CBC initial vector)

                             des-cbc-crc
--------------------------------------------------------------------
initial cipher state     copy of original key

encryption function      des-cbc(confounder | checksum | msg | pad,
                                  ivec=oldstate)
                         where
                         checksum = crc(confounder | 00000000
                                        | msg | pad)

                         newstate = last block of des-cbc output

decryption function      decrypt encrypted text and verify checksum

                         newstate = last block of ciphertext

default string-to-key    empty string
params

pseudo-random function   des-cbc(md5(input-string), ivec=0)

key generation functions:

string-to-key            des_string_to_key

random-to-key            copy input, then fix parity bits

key-derivation           identity

the des-cbc-crc encryption algorithm is assigned the etype value one (1) ๐ŸŽ€


6.2.4. RSA MD5 Cryptographic Checksum Using DES ๐ŸŒธ

the RSA-MD5-DES checksum is a keyed, collision-proof checksum ๐Ÿ” here's how it works, bestie: it prepends an eight octet confounder before the text, applies the RSA MD5 checksum algorithm, then encrypts the confounder and the checksum with DES in CBC mode. the key gets XORed with the hex constant 0xF0F0F0F0F0F0F0F0 first, so that's the variant you actually use โœจ the initialization vector should be zero, and the resulting checksum is 24 octets long ๐Ÿ’…

                              rsa-md5-des
   ----------------------------------------------------------------
   associated cryptosystem   des-cbc-md5, des-cbc-md4, des-cbc-crc

   get_mic                   des-cbc(key XOR 0xF0F0F0F0F0F0F0F0,
                                     conf | rsa-md5(conf | msg))

   verify_mic                decrypt and verify rsa-md5 checksum

the rsa-md5-des checksum algorithm is assigned a checksum type number of eight (8) ๐Ÿฆ‹


6.2.5. RSA MD4 Cryptographic Checksum Using DES ๐Ÿงš

the RSA-MD4-DES checksum is basically the same energy ๐Ÿ’œ it's keyed and collision-proof too. it prepends an eight octet confounder, applies the RSA MD4 checksum algorithm [MD4-92], and then encrypts the confounder and the checksum with DES in CBC mode. the key is XORed with the constant 0xF0F0F0F0F0F0F0F0 [7] to get the variant, and the initialization vector should be zero. the resulting checksum is 24 octets long ๐ŸŽ€

                              rsa-md4-des
   ----------------------------------------------------------------
   associated cryptosystem   des-cbc-md5, des-cbc-md4, des-cbc-crc

   get_mic                   des-cbc(key XOR 0xF0F0F0F0F0F0F0F0,
                                     conf | rsa-md4(conf | msg),
                                     ivec=0)

   verify_mic                decrypt and verify rsa-md4 checksum

the rsa-md4-des checksum algorithm is assigned a checksum type number of three (3) ๐Ÿ“


6.2.6. RSA MD4 Cryptographic Checksum Using DES Alternative ๐ŸŒˆ

the RSA-MD4-DES-K checksum is a keyed, collision-proof checksum too ๐Ÿ”‘ it applies the RSA MD4 checksum algorithm, then encrypts the result with DES in CBC mode, using a DES key as both the key and the initialization vector. the resulting checksum is 16 octets long. it's tamper-proof and believed to be collision-proof ๐Ÿ›ก๏ธ

โš ๏ธ heads up: this checksum type is the old method for encoding the RSA-MD4-DES checksum. it is no longer recommended, so be careful with it ๐Ÿ’€
                             rsa-md4-des-k
   ----------------------------------------------------------------
   associated cryptosystem   des-cbc-md5, des-cbc-md4, des-cbc-crc

   get_mic                   des-cbc(key, md4(msg), ivec=key)

   verify_mic                decrypt, compute checksum and compare

the rsa-md4-des-k checksum algorithm is assigned a checksum type number of six (6) ๐ŸŒธ


6.2.7. DES CBC Checksum โœจ

the DES-MAC checksum goes like this ๐Ÿซถ you prepend an eight octet confounder to the plaintext, pad it with zero-valued octets if needed so the length is a multiple of eight octets, and run DES CBC-mode encryption on the result using the key and an all-zero initialization vector. then you take the last block of the ciphertext, prepend the same confounder, and encrypt that pair with DES in CBC mode using the key variant (the key XORed with 0xF0F0F0F0F0F0F0F0). the initialization vector should be zero. the resulting checksum is 128 bits (sixteen octets) long, and 64 bits of it are redundant ๐Ÿคฏ it's tamper-proof and collision-proof ๐Ÿ’–

                                des-mac
---------------------------------------------------------------------
associated     des-cbc-md5, des-cbc-md4, des-cbc-crc
cryptosystem

get_mic        des-cbc(key XOR 0xF0F0F0F0F0F0F0F0,
                       conf | des-mac(key, conf | msg | pad, ivec=0),
                       ivec=0)

verify_mic     decrypt, compute DES MAC using confounder, compare

the des-mac checksum algorithm is assigned a checksum type number of four (4) ๐Ÿฆ‹


6.2.8. DES CBC Checksum Alternative ๐Ÿ’…

the DES-MAC-K checksum is computed by doing DES CBC-mode encryption of the plaintext, with zero-valued padding bytes if needed to make the length a multiple of eight octets. the last block of the ciphertext becomes the checksum value ๐Ÿงš it's keyed with an encryption key, and that same key is also used as the initialization vector. the resulting checksum is 64 bits (eight octets) long, and it's tamper-proof and collision-proof ๐Ÿ”ฅ

โš ๏ธ this one is the old way of encoding the DESMAC checksum. it is no longer recommended ๐Ÿ˜ญ
                              des-mac-k
   ----------------------------------------------------------------
   associated cryptosystem   des-cbc-md5, des-cbc-md4, des-cbc-crc

   get_mic                   des-mac(key, msg | pad, ivec=key)

   verify_mic                compute MAC and compare

the des-mac-k checksum algorithm is assigned a checksum type number of five (5) ๐ŸŒˆ

6.3. Triple-DES Based Encryption and Checksum Types โœจ

okay so this pair is built on the Triple DES cryptosystem running in Outer-CBC mode, with HMAC-SHA1 handling the message authentication ๐Ÿ”๐Ÿ’…

a Triple DES key is basically three DES keys stuck together, just like the des-cbc-md5 description above ๐Ÿงฉ and each of the three gets made from its own separate chunk of random data ๐ŸŽฒโœจ

encrypted data using this type must be generated the way section 5.3 describes ๐ŸŒธ if your input isn't a multiple of the block size, zero-valued octets must be used to pad the plaintext out to the next eight-octet boundary ๐Ÿ“ and the confounder must be eight random octets, which is one block ๐Ÿซถ

here's the simplified profile for Triple DES, with the key derivation from section 5 ๐Ÿฆ‹

             des3-cbc-hmac-sha1-kd, hmac-sha1-des3-kd
          ------------------------------------------------
          protocol key format     24 bytes, parity in low
                                  bit of each

          key-generation seed     21 bytes
          length

             des3-cbc-hmac-sha1-kd, hmac-sha1-des3-kd
          ------------------------------------------------
          hash function           SHA-1

          HMAC output size        160 bits

          message block size      8 bytes

          default string-to-key   empty string
          params

          encryption and          triple-DES encrypt and
          decryption functions    decrypt, in outer-CBC
                                  mode (cipher block size
                                  8 octets)

          key generation functions:

          random-to-key           DES3random-to-key (see
                                  below)

          string-to-key           DES3string-to-key (see
                                  below)

the des3-cbc-hmac-sha1-kd encryption type gets the value sixteen (16) ๐Ÿ‘‘ and the hmac-sha1-des3-kd checksum algorithm gets checksum type number twelve (12) ๐Ÿ’œ


6.3.1. Triple DES Key Production (random-to-key, string-to-key)

so here's how the 168 bits of random key data turn into a protocol key value ๐Ÿงš first, the 168 bits get split into three groups of 56 bits, and each group gets expanded into 64 bits like this โœจ

DES3random-to-key:
      1  2  3  4  5  6  7  p
      9 10 11 12 13 14 15  p
     17 18 19 20 21 22 23  p
     25 26 27 28 29 30 31  p
     33 34 35 36 37 38 39  p
     41 42 43 44 45 46 47  p
     49 50 51 52 53 54 55  p
     56 48 40 32 24 16  8  p

the "p" bits are parity bits, worked out from the data bits ๐ŸŽ€ then the outputs from all three expansions get fixed up so they dodge "weak" and "semi-weak" keys (same trick as section 6.2), and then they're glued together to form the protocol key value ๐Ÿ”—

the string-to-key function is what turns UTF-8 passwords into DES3 keys ๐Ÿ”‘ and it leans on the "N-fold" algorithm and the DK function, both from section 5 ๐Ÿ’…

the n-fold algorithm gets applied to the password string smooshed together with a salt value ๐Ÿ’– for 3-key triple DES that means a 168-fold of the input password string, which makes an intermediate key, and then the DK function derives the user's long-term key from that ๐ŸŒˆ here's the DES3 string-to-key function in pseudocode ๐Ÿ’€

DES3string-to-key(passwordString, salt, params)
    if (params != emptyString)
     error("invalid params");
    s = passwordString + salt
    tmpKey = random-to-key(168-fold(s))
    key = DK (tmpKey, KerberosConstant)

weak key checking happens inside both the random-to-key and DK operations ๐Ÿ™ˆ and the KerberosConstant value is the byte string {0x6b 0x65 0x72 0x62 0x65 0x72 0x6f 0x73}, which is just the ASCII for the string "kerberos" ๐ŸŒธ


7. Use of Kerberos Encryption Outside This Specification ๐ŸŒˆ

ngl this part is so relatable ๐Ÿ˜ญ a bunch of Kerberos-based application protocols and preauthentication systems have been built and deployed, and they all do encryption and message integrity checks in their own ways ๐Ÿ’… sometimes there's a good reason to pin a protocol to specific algorithms, but we think that's usually not the case, and more generic approaches that don't depend on particular algorithms are going to be way more useful ๐Ÿฆ‹ nobody wants every protocol designer reinventing the wheel for protecting data, handling multiple keys, and so on, so this section is a general framework ๐ŸŽ€ it's meant to be enough for Kerberos itself and for lots of preauthentication systems and application protocols, while steering clear of some sneaky assumptions that can creep into protocol designs ๐Ÿ‘‘

some problematic assumptions we've seen (and honestly, sometimes made ourselves) are these ๐Ÿ™ˆ

  • a random bitstring is always valid as a key. not true for DES keys with parity ๐Ÿ’€
  • the basic block encryption chaining mode provides no integrity checking, or can easily be separated from such checking. not true for many modes in development that do both at once โœจ
  • a checksum for a message always comes out the same value. not true if a confounder is in the mix ๐ŸŒธ
  • an initial vector is used. this may not be true if a block cipher in CBC mode isn't in use ๐Ÿซถ

these assumptions might hold for any particular set of encryption and checksum algorithms, but they might not hold for the next algorithms that get defined ๐Ÿ˜ฌ and then the application protocol is stuck, unable to use those algorithms without updating its spec ๐Ÿ’”

the Kerberos protocol only uses the attributes and operations from sections 3 and 4 ๐Ÿ’œ and preauthentication systems and application protocols that use Kerberos are encouraged to do the same ๐Ÿงš the specific key and string-to-key parameters should generally be treated as opaque ๐Ÿ”’ the string-to-key parameters are handled as an octet string, but how the specific key structure is represented is implementation defined, and it might not even be one single object ๐ŸŒˆ

we don't recommend this, but some application protocols are definitely going to keep using the key data directly, even if it's only in some of the existing protocol specs ๐Ÿ˜ค so an implementation meant to support general Kerberos applications may need to make the key data available, along with the attributes and operations from sections 3 and 4 [8] ๐Ÿ’…


8. Assigned Numbers ๐Ÿ”ข

these encryption-type numbers are already assigned or reserved for Kerberos and related protocols ๐ŸŽ€

   encryption type                etype      section or comment
   -----------------------------------------------------------------
   des-cbc-crc                        1             6.2.3
   des-cbc-md4                        2             6.2.2
   des-cbc-md5                        3             6.2.1
   [reserved]                         4
   des3-cbc-md5                       5
   [reserved]                         6
   des3-cbc-sha1                      7
   dsaWithSHA1-CmsOID                 9           (pkinit)
   md5WithRSAEncryption-CmsOID       10           (pkinit)
   sha1WithRSAEncryption-CmsOID      11           (pkinit)
   rc2CBC-EnvOID                     12           (pkinit)
   rsaEncryption-EnvOID              13   (pkinit from PKCS#1 v1.5)
   rsaES-OAEP-ENV-OID                14   (pkinit from PKCS#1 v2.0)
   des-ede3-cbc-Env-OID              15           (pkinit)
   des3-cbc-sha1-kd                  16              6.3
   aes128-cts-hmac-sha1-96           17          [KRB5-AES]
   aes256-cts-hmac-sha1-96           18          [KRB5-AES]
   rc4-hmac                          23          (Microsoft)
   rc4-hmac-exp                      24          (Microsoft)
   subkey-keymaterial                65     (opaque; PacketCable)

(heads up: the "des3-cbc-sha1" assignment is a deprecated version that uses no key derivation ๐Ÿ™…โ€โ™€๏ธ so don't mix it up with des3-cbc-sha1-kd!)

several numbers have been reserved for encryption systems that aren't defined here ๐Ÿง and encryption-type numbers have unfortunately been overloaded here and there in Kerberos-related protocols, so some of those reserved numbers won't ever line up with encryption systems that fit the profile we just laid out ๐Ÿ˜ฉ

next up, the checksum-type numbers that are assigned or reserved ๐Ÿ’œ same deal as before, some checksum numbers have been overloaded too ๐Ÿ™ˆ

   Checksum type              sumtype        checksum         section or
                                value            size         reference
   ---------------------------------------------------------------------
   CRC32                            1               4           6.1.3
   rsa-md4                          2              16           6.1.2
   rsa-md4-des                      3              24           6.2.5
   des-mac                          4              16           6.2.7
   des-mac-k                        5               8           6.2.8
   rsa-md4-des-k                    6              16           6.2.6
   rsa-md5                          7              16           6.1.1
   rsa-md5-des                      8              24           6.2.4
   rsa-md5-des3                     9              24             ??
   sha1 (unkeyed)                  10              20             ??
   hmac-sha1-des3-kd               12              20            6.3
   hmac-sha1-des3                  13              20             ??
   sha1 (unkeyed)                  14              20             ??
   hmac-sha1-96-aes128             15              20         [KRB5-AES]
   hmac-sha1-96-aes256             16              20         [KRB5-AES]
   [reserved]                  0x8003               ?         [GSS-KRB5]

encryption and checksum-type numbers are signed 32-bit values ๐Ÿ”ข zero is invalid, negative numbers are reserved for local use ๐Ÿ  and all standardized values must be positive โœจ


9. Implementation Notes ๐Ÿ“

the "interface" described here is the minimal info that must be defined to make a cryptosystem useful within Kerberos in an interoperable way ๐Ÿซถ the functional notation that shows up in some places isn't an attempt to define an API for cryptographic functionality within Kerberos ๐Ÿ™…โ€โ™€๏ธ real implementations with clean APIs will probably expose extra info that could be derived from a spec written to the framework here ๐Ÿ’… for example, an application designer might want to know the largest number of bytes that can be encrypted without overflowing a certain size output buffer, or the other way around, the maximum number of bytes you might get from decrypting a ciphertext of a given size ๐Ÿงฎ (and fun fact, an implementation of the GSS-API Kerberos mechanism [GSS-KRB5] will need some of these ๐ŸŒธ)

the presence of a mechanism in this document shouldn't be read as meaning it has to be implemented for compliance with any spec ๐Ÿšจ required mechanisms will be specified elsewhere ๐Ÿ’œ also, some of the mechanisms described here are kept around for backward compatibility, and they're now considered pretty weak for protecting critical data ๐Ÿ’€

10. Security Considerations ๐Ÿ”

Okay bestie, DES has been getting absolutely roasted ๐Ÿ’€ by large-scale attacks for years now, so it is no longer considered a strong encryption mechanism. Triple-DES is generally the one people reach for instead, even though it's slower (poorer performance ๐Ÿ˜ญ). Check [ESP-DES] for a summary of some of the potential attacks and [EFF-DES] for a detailed look at how particular attacks are built. Still, most Kerberos implementations keep DES as their primary interoperable encryption type, so it's giving "we can't let go yet" ๐Ÿซ .

DES has four 'weak' keys and twelve 'semi-weak' keys, and using single-DES here avoids them โœจ. BUT DES also has 48 'possibly-weak' keys [Schneier96] that are not avoided ๐Ÿ˜ฌ. (Heads up: the tables in many editions of that reference have errors ๐Ÿ“š.)

DES weak keys have the property that E1(E1(P)) = P, where E1 means encrypting a single block with key 1. DES semi-weak keys, aka "dual" keys, come in pairs with E1(P) = D2(P), and so E2(E1(P)) = P. Because CBC mode and the leading random confounder are used, though, these properties are unlikely to be a security problem ๐Ÿ’œ.

Many of the choices about when to do weak-key corrections are about compatibility with existing implementations more than any risk analysis ๐Ÿงฉ.

Checks are also done for the component DES keys inside a triple-DES key. The nature of weak keys makes it extremely unlikely they'll weaken triple-DES encryption. It's only slightly more likely that the middle of the three sub-keys matches one of the other two, which effectively turns the encryption into single-DES. That's a case we make no effort to avoid ๐Ÿ™ƒ.

The true CRC-32 checksum is not collision-proof. An attacker could use a probabilistic chosen-plaintext attack to generate a valid message even if a confounder is used [SG92]. Collision-proof checksums are of course recommended for environments where these attacks are a significant threat ๐Ÿ›ก๏ธ. The "simplifications" (read: bugs) introduced when CRC-32 was implemented for Kerberos cause leading zeros to be effectively ignored, so messages differing only in leading zero bits will have the same checksum ๐Ÿ’€.

[HMAC] and [IPSEC-HMAC] discuss weaknesses of the HMAC algorithm. Unlike [IPSEC-HMAC], the triple-DES specification here does not use the suggested truncation of the HMAC output. As pointed out in [IPSEC-HMAC], SHA-1 was not developed for use as a keyed hash function, which is a criterion of HMAC. [HMAC-TEST] contains test vectors for HMAC-SHA-1 ๐Ÿงช.

The mit_des_string_to_key function was originally built on the assumption that all input would be ASCII. It ignores the top bit of each input byte. Folding with XOR also isn't an especially good mixing mechanism for preserving randomness ๐Ÿ˜ฉ.

The n-fold function used in the string-to-key operation for des3-cbc-hmac-sha1-kd was designed so that each bit of input contributes equally to the output. It was not designed to maximize or equally distribute randomness in the input, and randomness may conceivably be lost with partially structured input. This should only be an issue for highly structured passwords, though ๐Ÿ”‘.

[RFC1851] discusses the relative strength of triple-DES encryption. The relatively slow speed of triple-DES may also be an issue for some applications ๐Ÿข.

[Bellovin91] suggests that analyses of encryption schemes include a model of an attacker who can submit known plaintexts to be encrypted with an unknown key, and who can perform many types of operations on known protocol messages. Recent chosen-plaintext attacks on Kerberos version 4 totally prove the value of this suggestion ๐Ÿ‘‘.

The use of unkeyed encrypted checksums, like those used in the single-DES cryptosystems specified in [Kerb1510], allows cut-and-paste attacks, especially if a confounder is not used. Unkeyed encrypted checksums are also vulnerable to chosen-plaintext attacks: an attacker with access to an encryption oracle can easily encrypt the required unkeyed checksum along with the chosen plaintext [Bellovin99]. These weaknesses, combined with a common implementation design choice described below, allow for a cross-protocol attack from version 4 to version 5 ๐Ÿ˜ฑ.

The use of a random confounder is an important way to stop an attacker from making effective use of protocol exchanges as an encryption oracle. In Kerberos version 4, encrypting constant plaintext to constant ciphertext makes an effective encryption oracle for an attacker. The use of random confounders in [Kerb1510] frustrates this sort of chosen-plaintext attack ๐ŸŒธ.

Using the same key for multiple purposes can enable or increase the scope of chosen-plaintext attacks. Some software that implements both versions 4 and 5 of the Kerberos protocol uses the same keys for both versions. That lets the version 4 encryption oracle be used to attack version 5. Vulnerabilities to attacks like this cross-protocol attack make it unwise to use a key for multiple purposes ๐Ÿšซ.

โš ๏ธ This document, like the Kerberos protocol, does not address limiting the amount of data a key may be used with to a quantity based on the robustness of the algorithm or the size of the key. It is assumed that any defined algorithms and key sizes will be strong enough to support very large amounts of data, or that they will be deprecated once significant attacks are known.

This document also places no bounds on the amount of data that can be handled in various operations. To avoid denial of service attacks, implementations will probably seek to restrict message sizes at some higher level ๐Ÿงฑ.


11. IANA Considerations ๐Ÿ“‹

Two registries for numeric values have been created: Kerberos Encryption Type Numbers and Kerberos Checksum Type Numbers. These are signed values ranging from -2147483648 to 2147483647. Positive values should be assigned only for algorithms specified in accordance with this specification for use with Kerberos or related protocols. Negative values are for private use, so local and experimental algorithms should use those. Zero is reserved and may not be assigned ๐Ÿ”ข.

Positive encryption- and checksum-type numbers may be assigned following either of two policies described in [BCP26].

Standards-track specifications may be assigned values under the Standards Action policy ๐Ÿ›๏ธ.

Specifications in non-standards track RFCs may be assigned values after Expert Review. A non-IETF specification may be assigned values by publishing an Informational or standards-track RFC that references the external specification. That specification must be public and published in some permanent record, much like the IETF RFCs. It is highly desirable, though not required, that the full specification be published as an IETF RFC โœจ.

Smaller encryption type values should be used for IETF standards-track mechanisms, and much higher values (16777216 and above) for other mechanisms. (Rationale: in the Kerberos ASN.1 encoding, smaller numbers encode to smaller octet sequences, so this favors standards-track mechanisms with slightly smaller messages ๐Ÿง .) Aside from that guideline, IANA may choose numbers as it sees fit.

Internet-Draft specifications should not include values for encryption- and checksum-type numbers. Instead, they should indicate that values would be assigned by IANA when the document is approved as an RFC. For development and interoperability testing, values in the private-use range (negative values) may be used, but they should not be included in the draft specification ๐Ÿงช.

Each registered value should have an associated unique reference name. The lists given in section 8 were used to create the initial registry. They include reservations for specifications in progress in parallel with this document, and certain other values believed to already be in use ๐Ÿ“š.


12. Acknowledgements ๐Ÿซถ

This document is an extension of the encryption specification included in [Kerb1510] by B. Clifford Neuman and John Kohl, and much of the text on background, concepts, and DES specifications is drawn directly from that document ๐Ÿ’–.

The abstract framework presented in this document was put together by Jeff Altman, Sam Hartman, Jeff Hutzelman, Cliff Neuman, Ken Raeburn, and Tom Yu. The details were refined several times based on comments from John Brezak and others ๐Ÿ‘‘.

Marc Horowitz wrote the original specification of triple-DES and key derivation in a pair of Internet-Drafts (under the names draft-horowitz-key-derivation and draft-horowitz-kerb-key-derivation). Those were later folded into a draft revision of [Kerb1510], from which this document was later split off ๐ŸŒˆ.

Tom Yu provided the text describing the modifications to the standard CRC algorithm as Kerberos implementations actually use it, and some of the text in the Security Considerations section ๐Ÿฆ‹.

Miroslav Jurisic provided information for one of the UTF-8 test cases for the string-to-key functions ๐ŸŒธ.

Marcus Watts noticed some errors in earlier versions and pointed out that the simplified profile could easily be modified to support cipher text stealing modes ๐Ÿ“.

Simon Josefsson contributed some clarifications to the DES "CBC checksum" and string-to-key and weak key descriptions, plus some test vectors ๐Ÿงš.

Simon Josefsson, Louis LeVay, and others also caught some errors in earlier versions of this document ๐Ÿ’œ.


A. Test Vectors ๐Ÿงช

This section provides test vectors for various functions defined or described in this document. For convenience, most inputs are ASCII strings, though some UTF-8 samples are provided for string-to-key functions. Keys and other binary data are specified as hexadecimal strings โœจ.

A.1. n-fold โœจ

okay so the n-fold function lives in section 5.1 ๐ŸŽ€ and there's a little plot twist there: the sample vector in the original paper that defines the algorithm looks wrong ๐Ÿ˜ญ so we've got better test cases, courtesy of Marc Horowitz and Simon Josefsson ๐Ÿซถ

   64-fold("012345") =
   64-fold(303132333435) = be072631276b1955

   56-fold("password") =
   56-fold(70617373776f7264) = 78a07b6caf85fa

   64-fold("Rough Consensus, and Running Code") =
   64-fold(526f75676820436f6e73656e7375732c20616e642052756e
           6e696e6720436f6465) = bb6ed30870b7f0e0

   168-fold("password") =
   168-fold(70617373776f7264) =
            59e4a8ca7c0385c3c37b3f6d2000247cb6e6bd5b3e

   192-fold("MASSACHVSETTS INSTITVTE OF TECHNOLOGY")
   192-fold(4d41535341434856534554545320494e5354495456544520
            4f4620544543484e4f4c4f4759) =
            db3b0d8f0b061e603282b308a50841229ad798fab9540c1b

   168-fold("Q") =
   168-fold(51) =
            518a54a2 15a8452a 518a54a2 15a8452a
            518a54a2 15

   168-fold("ba") =
   168-fold(6261) =
            fb25d531 ae897449 9f52fd92 ea9857c4
            ba24cf29 7e

Here are some extra values for the folded forms of the string "kerberos" ๐Ÿ’œ The 64-bit one is the star of the show because the des3 string-to-key in section 6.3.1 uses it ๐Ÿ‘‘

   64-fold("kerberos") =
            6b657262 65726f73
   128-fold("kerberos") =
            6b657262 65726f73 7b9b5b2b 93132b93
   168-fold("kerberos") =
            8372c236 344e5f15 50cd0747 e15d62ca
            7a5a3bce a4
   256-fold("kerberos") =
            6b657262 65726f73 7b9b5b2b 93132b93
            5c9bdcda d95c9899 c4cae4de e6d6cae4
Note: the first octets match the input string exactly whenever the output length is a multiple of the input length ๐Ÿ‘€

A.2. mit_des_string_to_key ๐Ÿงš

okay the function mit_des_string_to_key is defined in section 6.2, and here are a bunch of test values ๐Ÿ’– We also show some of the middle steps so you can see the receipts ๐Ÿงพ The fourth test is the one with UTF-8 across three characters, and the last two are built on purpose to make the fan-folding produce an intermediate key that hits the weak-key fixups ๐Ÿ”ฅ Heads up though: we don't have any tests that trigger those fixups on the final key ๐Ÿ™ˆ

Here's how the UTF-8 encodings used in the test vector look ๐ŸŒˆ

UTF-8 encodings used in test vector:
eszett    U+00DF   C3 9F   s-caron   U+0161    C5 A1
c-acute   U+0107   C4 87   g-clef    U+1011E   F0 9D 84 9E

Now the test vectors themselves ๐Ÿ’…

Test vector:

salt:        "ATHENA.MIT.EDUraeburn"
                           415448454e412e4d49542e4544557261656275726e
password:    "password"    70617373776f7264
fan-fold result:           c01e38688ac86c2e
intermediate key:          c11f38688ac86d2f
DES key:                   cbc22fae235298e3

salt:       "WHITEHOUSE.GOVdanny"
                        5748495445484f5553452e474f5664616e6e79
password:   "potatoe"   706f7461746f65
fan-fold result:        a028944ee63c0416
intermediate key:       a129944fe63d0416
DES key:                df3d32a74fd92a01

salt:      "EXAMPLE.COMpianist"  4558414D504C452E434F4D7069616E697374
password:  g-clef (U+1011E)      f09d849e
fan-fold result:                 3c4a262c18fab090
intermediate key:                3d4a262c19fbb091
DES key:                         4ffb26bab0cd9413

salt: "ATHENA.MIT.EDUJuri" + s-caron(U+0161) + "i" + c-acute(U+0107)
                         415448454e412e4d49542e4544554a757269c5a169c487
password:       eszett(U+00DF)
                                c39f
fan-fold result:b8f6c40e305afc9e
intermediate key:               b9f7c40e315bfd9e
DES key:                        62c81a5232b5e69d

salt:       "AAAAAAAA"   4141414141414141
password:   "11119999"   3131313139393939
fan-fold result:         e0e0e0e0f0f0f0f0
intermediate key:        e0e0e0e0f1f1f101
DES key:                 984054d0f1a73e31

salt:       "FFFFAAAA"   4646464641414141
password:   "NNNN6666"   4e4e4e4e36363636
fan-fold result:         1e1e1e1e0e0e0e0e
intermediate key:        1f1f1f1f0e0e0efe
DES key:                 c4bf6b25adf7a4f8

This trace from Simon Josefsson is my favourite because it shows every single step of one of the inputs ๐Ÿ“ It's giving full detective mode ๐Ÿ•ต๏ธโ€โ™€๏ธ

   This trace provided by Simon Josefsson shows the intermediate
   processing stages of one of the test inputs:

      string_to_key (des-cbc-md5, string, salt)
             ;; string:
             ;; `password' (length 8 bytes)
             ;; 70 61 73 73 77 6f 72 64
             ;; salt:
             ;; `ATHENA.MIT.EDUraeburn' (length 21 bytes)
             ;; 41 54 48 45 4e 41 2e 4d  49 54 2e 45 44 55 72 61
             ;; 65 62 75 72 6e
      des_string_to_key (string, salt)
             ;; String:
             ;; `password' (length 8 bytes)
             ;; 70 61 73 73 77 6f 72 64
             ;; Salt:
             ;; `ATHENA.MIT.EDUraeburn' (length 21 bytes)
             ;; 41 54 48 45 4e 41 2e 4d  49 54 2e 45 44 55 72 61
             ;; 65 62 75 72 6e
      odd = 1;
      s = string | salt;
      tempstring = 0; /* 56-bit string */
      pad(s); /* with nulls to 8 byte boundary */
             ;; s = pad(string|salt):
             ;; `passwordATHENA.MIT.EDUraeburn\x00\x00\x00'
             ;; (length 32 bytes)
             ;; 70 61 73 73 77 6f 72 64  41 54 48 45 4e 41 2e 4d
             ;; 49 54 2e 45 44 55 72 61  65 62 75 72 6e 00 00 00
      for (8byteblock in s) {
             ;; loop iteration 0
             ;; 8byteblock:
             ;; `password' (length 8 bytes)
             ;; 70 61 73 73 77 6f 72 64
             ;; 01110000 01100001 01110011  01110011 01110111 01101111
             ;; 01110010 01100100
      56bitstring = removeMSBits(8byteblock);
             ;; 56bitstring:
             ;; 1110000 1100001 1110011  1110011 1110111 1101111
             ;; 1110010 1100100
      if (odd == 0) reverse(56bitstring);    ;; odd=1
      odd = ! odd
      tempstring = tempstring XOR 56bitstring;
             ;; tempstring
             ;; 1110000 1100001 1110011  1110011 1110111 1101111
             ;; 1110010 1100100

      for (8byteblock in s) {
             ;; loop iteration 1
             ;; 8byteblock:
             ;; `ATHENA.M' (length 8 bytes)
             ;; 41 54 48 45 4e 41 2e 4d
             ;; 01000001 01010100 01001000  01000101 01001110 01000001
             ;; 00101110 01001101
      56bitstring = removeMSBits(8byteblock);
             ;; 56bitstring:
             ;; 1000001 1010100 1001000  1000101 1001110 1000001
             ;; 0101110 1001101
      if (odd == 0) reverse(56bitstring);    ;; odd=0
      reverse(56bitstring)
             ;; 56bitstring after reverse
             ;; 1011001 0111010 1000001  0111001 1010001 0001001
             ;; 0010101 1000001
      odd = ! odd
      tempstring = tempstring XOR 56bitstring;
             ;; tempstring
             ;; 0101001 1011011 0110010  1001010 0100110 1100110
             ;; 1100111 0100101

      for (8byteblock in s) {
             ;; loop iteration 2
             ;; 8byteblock:
             ;; `IT.EDUra' (length 8 bytes)
             ;; 49 54 2e 45 44 55 72 61
             ;; 01001001 01010100 00101110  01000101 01000100 01010101
             ;; 01110010 01100001
      56bitstring = removeMSBits(8byteblock);
             ;; 56bitstring:
             ;; 1001001 1010100 0101110  1000101 1000100 1010101
             ;; 1110010 1100001
      if (odd == 0) reverse(56bitstring);    ;; odd=1
      odd = ! odd
      tempstring = tempstring XOR 56bitstring;
             ;; tempstring
             ;; 1100000 0001111 0011100  0001111 1100010 0110011
             ;; 0010101 1000100

      for (8byteblock in s) {
             ;; loop iteration 3
             ;; 8byteblock:
             ;; `eburn\x00\x00\x00' (length 8 bytes)
             ;; 65 62 75 72 6e 00 00 00
             ;; 01100101 01100010 01110101  01110010 01101110 00000000
             ;; 00000000 00000000
      56bitstring = removeMSBits(8byteblock);
             ;; 56bitstring:
             ;; 1100101 1100010 1110101  1110010 1101110 0000000
             ;; 0000000 0000000
      if (odd == 0) reverse(56bitstring);    ;; odd=0
      reverse(56bitstring)
             ;; 56bitstring after reverse
             ;; 0000000 0000000 0000000  0111011 0100111 1010111
             ;; 0100011 1010011
      odd = ! odd
      tempstring = tempstring XOR 56bitstring;
             ;; tempstring
             ;; 1100000 0001111 0011100  0110100 1000101 1100100
             ;; 0110110 0010111

      for (8byteblock in s) {
      }
             ;; for loop terminated

      tempkey = key_correction(add_parity_bits(tempstring));
             ;; tempkey
             ;; `\xc1\x1f8h\x8a\xc8m\x2f' (length 8 bytes)
             ;; c1 1f 38 68 8a c8 6d 2f
             ;; 11000001 00011111 00111000  01101000 10001010 11001000
             ;; 01101101 00101111

      key = key_correction(DES-CBC-check(s,tempkey));
             ;; key
             ;; `\xcb\xc2\x2f\xae\x23R\x98\xe3' (length 8 bytes)
             ;; cb c2 2f ae 23 52 98 e3
             ;; 11001011 11000010 00101111  10101110 00100011 01010010
             ;; 10011000 11100011

             ;; string_to_key key:
             ;; `\xcb\xc2\x2f\xae\x23R\x98\xe3' (length 8 bytes)
             ;; cb c2 2f ae 23 52 98 e3

A.3. DES3 DR and DK ๐ŸŽ€

these tests show the derived-random (DR) and derived-key (DK) values for the des3-hmac-sha1-kd encryption scheme ๐Ÿฆ‹ They use the DR and DK functions from section 6.3.1 ๐Ÿ’œ The input keys were randomly generated, but the usage values come straight from this specification ๐ŸŒธ

   key:                 dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92
   usage:               0000000155
   DR:                  935079d14490a75c3093c4a6e8c3b049c71e6ee705
   DK:                  925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd

   key:                 5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2
   usage:               00000001aa
   DR:                  9f58e5a047d894101c469845d67ae3c5249ed812f2
   DK:                  9e58e5a146d9942a101c469845d67a20e3c4259ed913f207

   key:                 98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc
   usage:               0000000155
   DR:                  12fff90c773f956d13fc2ca0d0840349dbd39908eb
   DK:                  13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf

   key:                 622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5
   usage:               00000001aa
   DR:                  f8debf05b097e7dc0603686aca35d91fd9a5516a70
   DK:                  f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e

   key:                 d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb
   usage:               6b65726265726f73 ("kerberos")
   DR:                  2270db565d2a3d64cfbfdc5305d4f778a6de42d9da
   DK:                  2370da575d2a3da864cebfdc5204d56df779a7df43d9da43

   key:                 c1081649ada74362e6a1459d01dfd30d67c2234c940704da
   usage:               0000000155
   DR:                  348056ec98fcc517171d2b4d7a9493af482d999175
   DK:                  348057ec98fdc48016161c2a4c7a943e92ae492c989175f7

   key:                 5d154af238f46713155719d55e2f1f790dd661f279a7917c
   usage:               00000001aa
   DR:                  a8818bc367dadacbe9a6c84627fb60c294b01215e5
   DK:                  a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1

   key:                 798562e049852f57dc8c343ba17f2ca1d97394efc8adc443
   usage:               0000000155
   DR:                  c813f88b3be2b2f75424ce9175fbc8483b88c8713a
   DK:                  c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49

   key:                 26dce334b545292f2feab9a8701a89a4b99eb9942cecd016
   usage:               00000001aa
   DR:                  f58efc6f83f93e55e695fd252cf8fe59f7d5ba37ec
   DK:                  f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d

A.4. DES3string_to_key โœจ

okay so this is where we get the keys for triple-DES, and they're generated with the key derivation from section 6.3.1 ๐Ÿ” here are some of the input strings and the keys they produce, bestie ๐Ÿ’–

salt:   "ATHENA.MIT.EDUraeburn"
passwd: "password"
key:    850bb51358548cd05e86768c313e3bfef7511937dcf72c3e

salt:   "WHITEHOUSE.GOVdanny"
passwd: "potatoe"
key:    dfcd233dd0a43204ea6dc437fb15e061b02979c1f74f377a

salt:   "EXAMPLE.COMbuckaroo"
passwd: "penny"
key:    6d2fcdf2d6fbbc3ddcadb5da5710a23489b0d3b69d5d9d4a

salt:   "ATHENA.MIT.EDUJuri" + s-caron(U+0161) + "i"
         + c-acute(U+0107)
passwd: eszett(U+00DF)
key:    16d5a40e1ce3bacb61b9dce00470324c831973a7b952feb0

salt:   "EXAMPLE.COMpianist"
passwd: g-clef(U+1011E)
key:    85763726585dbc1cce6ec43e1f751f07f1c4cbb098f40b19

A.5. Modified CRC-32 ๐Ÿฆ‹

so here are the modified-CRC32 values for a bunch of ASCII and octet strings ๐ŸŒธ only the printable ASCII characters get checksummed, and there's no C-style trailing zero-valued octet tacked on at the end ๐Ÿ™ˆ you'll see the 32-bit modified CRC and the output bytes in the order Kerberos uses them. the octets are split up on purpose so you can see they're octet values and not 32-bit numbers, since that's the handiest form for some implementations to work with ๐Ÿ’… the bit and byte order you use inside your own code doesn't matter at all, the octet sequence that comes out is the part that counts โœจ

mod-crc-32("foo") =                                     33 bc 32 73
mod-crc-32("test0123456789") =                          d6 88 3e b8
mod-crc-32("MASSACHVSETTS INSTITVTE OF TECHNOLOGY") =   f7 80 41 e3
mod-crc-32(8000) =                                      4b 98 83 3b
mod-crc-32(0008) =                                      32 88 db 0e
mod-crc-32(0080) =                                      20 83 b8 ed
mod-crc-32(80) =                                        20 83 b8 ed
mod-crc-32(80000000) =                                  3b b6 59 ed
mod-crc-32(00000001) =                                  96 30 07 77

B. Significant Changes from RFC 1510 ๐ŸŽ€

the encryption and checksum mechanism profiles are brand new, and that's a big glow-up ๐ŸŒˆ the old spec defined a few operations for various mechanisms, but it never said what abstract properties a new mechanism should have, or how to make sure a mechanism spec is complete enough for different implementations to actually talk to each other ๐Ÿ˜ญ so the new profiles are different from the old one in a few ways:

Some message definitions in [Kerb1510] could be read as permitting the initial vector to be specified by the application; the text was too vague. It is explicitly not permitted in this specification. Some encryption algorithms may not use initialization vectors, so relying on chosen, secret initialization vectors for security is unwise. Also, the prepended confounder in the existing algorithms is roughly equivalent to a per-message initialization vector that is revealed in encrypted form. However, carrying state across from one encryption to another is explicitly permitted through the opaque "cipher state" object.

so the app can't pick the initial vector anymore, and that's a whole vibe check ๐Ÿ™…โ€โ™€๏ธ carrying state between encryptions is still allowed though, through that opaque "cipher state" object ๐Ÿงš

key derivation is new ๐Ÿ”‘

several new methods got introduced, including making a key in wire-protocol format from random input data ๐ŸŽฒ

the means for influencing the string-to-key algorithm are laid out way more clearly now ๐Ÿ‘‘

triple-DES support is new ๐Ÿ’œ

the pseudo-random function is new too ๐Ÿฆ‹

the des-cbc-crc, DES string-to-key, and CRC descriptions got updated so they line up with what existing implementations actually do ๐Ÿ™Œ

[Kerb1510] didn't say what character set or encoding to use for pass phrases and salts, which was lowkey chaos ๐Ÿซ 

in [Kerb1510], key types, encryption algorithms, and checksum algorithms were only loosely connected, and nobody really described the connection well ๐Ÿ˜ต in this spec, key types and encryption algorithms have a one-to-one correspondence, and the links between encryption and checksum algorithms are described so checksums can be computed from negotiated keys without negotiating a checksum type separately ๐Ÿ’…

Notes ๐Ÿ“

[1] ngl, Message Authentication Code (MAC) or Message Integrity Check (MIC) would fit a lot of the uses in this document better, but we keep saying checksum for historical reasons ๐Ÿ™ƒ

[2] extending CBC mode across messages would be one obvious example of this chaining ๐Ÿ”— another could be counter mode, with a counter that's randomly initialized and attached to the ciphertext, and a second message could keep incrementing that counter when chaining the cipher state, so you don't have to send another counter value ๐Ÿ”ข but this chaining is only useful for uninterrupted, ordered sequences of messages, so keep that in mind ๐Ÿ‘€

[3] for Kerberos, the encrypted objects will usually be ASN.1 DER encodings, which tell you their length in the first few octets ๐Ÿ“

[4] as of when this was written, new modes of operation had been proposed, and some of them might let you do encryption and integrity protection at the same time ๐Ÿคฏ once some of those proposals get enough analysis, we may want to make a new simplified profile based on one of them ๐ŸŒŸ

[5] it should be noted that the sample vector in appendix B.2 of the original paper looks incorrect ๐Ÿ˜ฌ two independent implementations from the specification (one in C by Marc Horowitz, and another in Scheme by Bill Sommerfeld) agree on a value that's different from the one in [Blumenthal96] ๐Ÿซฃ

[6] for example, in MIT's implementation of [Kerb1510], the rsa-md5 unkeyed checksum of application data may be included in an authenticator encrypted in a service's key ๐Ÿ”

[7] using a variant of the key limits a key to one particular function, which separates generating a checksum from other encryption done with the session key ๐Ÿงฉ the constant 0xF0F0F0F0F0F0F0F0 was picked because it keeps the key parity intact ๐ŸŽฏ the properties of DES ruled out using the complement ๐Ÿšซ the same constant is used for a similar purpose in the Message Integrity Check in the Privacy Enhanced Mail standard ๐Ÿ’Œ

[8] one of the more common reasons for directly performing encryption is direct control over the negotiation, to pick a "sufficiently strong" encryption algorithm (whatever that even means for a given application) ๐Ÿคทโ€โ™€๏ธ Kerberos doesn't directly give you any facility for negotiating encryption types between the application client and server, but there are other ways to get similar goals, like requesting only "strong" session key types from the KDC and assuming the application server will understand and support whatever type the KDC actually returns ๐Ÿงšโ€โ™€๏ธ

Normative References ๐Ÿ“š

[BCP26] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.

[Bellare98] Bellare, M., Desai, A., Pointcheval, D., and P. Rogaway, "Relations Among Notions of Security for Public-Key Encryption Schemes". Extended abstract published in Advances in Cryptology-Crypto 98 Proceedings, Lecture Notes in Computer Science Vol. 1462, H. Krawcyzk ed., Springer-Verlag, 1998.

[Blumenthal96] Blumenthal, U. and S. Bellovin, "A Better Key Schedule for DES-Like Ciphers", Proceedings of PRAGOCRYPT '96, 1996.

[CRC] International Organization for Standardization, "ISO Information Processing Systems - Data Communication - High-Level Data Link Control Procedure - Frame Structure," IS 3309, 3rd Edition, October 1984.

[DES77] National Bureau of Standards, U.S. Department of Commerce, "Data Encryption Standard," Federal Information Processing Standards Publication 46, Washington, DC, 1977.

[DESI81] National Bureau of Standards, U.S. Department of Commerce, "Guidelines for implementing and using NBS Data Encryption Standard," Federal Information Processing Standards Publication 74, Washington, DC, 1981.

[DESM80] National Bureau of Standards, U.S. Department of Commerce, "DES Modes of Operation," Federal Information Processing Standards Publication 81, Springfield, VA, December 1980.

[Dolev91] Dolev, D., Dwork, C., and M. Naor, "Non-malleable cryptography", Proceedings of the 23rd Annual Symposium on Theory of Computing, ACM, 1991.

[HMAC] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.

[KRB5-AES] Raeburn, K., "Advanced Encryption Standard (AES) Encryption for Kerberos 5", RFC 3962, February 2005.

[MD4-92] Rivest, R., "The MD4 Message-Digest Algorithm", RFC 1320, April 1992.

[MD5-92] Rivest, R., "The MD5 Message-Digest Algorithm ", RFC 1321, April 1992.

[SG92] Stubblebine, S. and V. D. Gligor, "On Message Integrity in Cryptographic Protocols," in Proceedings of the IEEE Symposium on Research in Security and Privacy, Oakland, California, May 1992.

Informative References ๐ŸŒท

[Bellovin91] Bellovin, S. M. and M. Merrit, "Limitations of the Kerberos Authentication System", in Proceedings of the Winter 1991 Usenix Security Conference, January, 1991.

[Bellovin99] Bellovin, S. M. and D. Atkins, private communications, 1999.

[EFF-DES] Electronic Frontier Foundation, "Cracking DES: Secrets of Encryption Research, Wiretap Politics, and Chip Design", O'Reilly & Associates, Inc., May 1998.

[ESP-DES] Madson, C. and N. Doraswamy, "The ESP DES-CBC Cipher Algorithm With Explicit IV", RFC 2405, November 1998.

[GSS-KRB5] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC 1964, June 1996.

[HMAC-TEST] Cheng, P. and R. Glenn, "Test Cases for HMAC-MD5 and HMAC-SHA-1", RFC 2202, September 1997.

[IPSEC-HMAC] Madson, C. and R. Glenn, "The Use of HMAC-SHA-1-96 within ESP and AH", RFC 2404, November 1998.

[Kerb] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The Kerberos Network Authentication Service (V5)", Work in Progress, September 2004.

[Kerb1510] Kohl, J. and C. Neuman, "The Kerberos Network Authentication Service (V5)", RFC 1510, September 1993.

[RC5] Baldwin, R. and R. Rivest, "The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms", RFC 2040, October 1996.

[RFC1851] Karn, P., Metzger, P., and W. Simpson, "The ESP Triple DES Transform", RFC 1851, September 1995.

[Schneier96] Schneier, B., "Applied Cryptography Second Edition", John Wiley & Sons, New York, NY, 1996. ISBN 0-471-12845-7.

Editor's Address ๐ŸŽ€

Kenneth Raeburn Massachusetts Institute of Technology 77 Massachusetts Avenue Cambridge, MA 02139

EMail: raeburn@mit.edu

Okay bestie, the legal bit ๐Ÿงพ. Copyright (C) The Internet Society (2005). ๐Ÿ“œ

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. โœจ

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ๐Ÿ’€


Intellectual Property ๐Ÿฆ‹

Okay so the IETF is not taking a side ๐Ÿ™…โ€โ™€๏ธ on whether any Intellectual Property Rights or other rights that might be claimed to apply to the implementation or use of the technology in this document are valid or in scope, or whether any license under those rights might be available. It also doesn't claim it has done any independent effort to find those rights. ๐Ÿ” If you want the details on the IETF's procedures for rights in IETF Documents, check out BCP 78 and BCP 79. ๐Ÿ“š

Copies of IPR disclosures made to the IETF Secretariat, and any assurances of licenses to be made available, can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. ๐ŸŒ The same goes for the result of an attempt to get a general license or permission to use those proprietary rights, made by implementers or users of this specification. ๐ŸŽ€

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. ๐Ÿซถ Send that info to the IETF at ietf-ipr@ietf.org. ๐Ÿ’Œ


Acknowledgement ๐ŸŒธ

Funding for the RFC Editor function is currently provided by the Internet Society. ๐Ÿ’œ Thank you, Internet Society, you're literally keeping the lights on ๐Ÿงšโœจ

๐Ÿ“ฆ where this page comes from