Question

The bottom of page 50 in RFC 4880 describes how to encrypt plaintext data to store in the Symmetrically Encrypted Integrity Protected Data Packet (Tag 18). It says that the CFB mode is used. I have written code for CFB so that it works as described in section 13.9 (for Symmetrically Encrypted Data Packets (Tag 9)). However, at page 50, it also says:

Unlike the Symmetrically Encrypted Data Packet, no special CFB resynchronization is done after encrypting this prefix data.

So for Tag 18, the steps should look like:

Step by step, here is the procedure:

  1. The feedback register (FR) is set to the IV, which is all zeros.

  2. FR is encrypted to produce FRE (FR Encrypted). This is the encryption of an all-zero value.

  3. FRE is xored with the first BS octets of random data prefixed to the plaintext to produce C1 through C[BS], the first BS octets of ciphertext.

  4. FR is loaded with C[1] through C[BS].

  5. FR is encrypted to produce FRE, the encryption of the first BS octets of ciphertext.

  6. The left two octets of FRE get xored with the next two octets of data that were prefixed to the plaintext. This produces C[BS+1] and C[BS+2], the next two octets of ciphertext.

  7. (̶T̶h̶e̶ ̶r̶e̶s̶y̶n̶c̶h̶r̶o̶n̶i̶z̶a̶t̶i̶o̶n̶ ̶s̶t̶e̶p̶)̶ ̶F̶R̶ ̶i̶s̶ ̶l̶o̶a̶d̶e̶d̶ ̶w̶i̶t̶h̶ ̶C̶[̶3̶]̶ ̶t̶h̶r̶o̶u̶g̶h̶ C̶[̶B̶S̶+̶2̶]̶.̶

  8. FR is encrypted to produce̶ FRE

  9. FRE is xored with the first BS octets of the given plaintext, now that we have finished encrypting the BS+2 octets of prefixed data. This produces C[BS+3] through C[BS+(BS+2)], the next BS octets of ciphertext.

  10. FR is loaded with C[BS+3] to C[BS + (BS+2)] (which is C11-C18 for an 8-octet block).

    1. FR is encrypted to produce FRE.

    2. FRE is xored with the next BS octets of plaintext, to produce the next BS octets of ciphertext. These are loaded into FR, and the process is repeated until the plaintext is used up.

Since the resynchronization step is not done, step 8 uses step 5's FRE, so it can be ignored right?

From the above steps, what did I misinterpret in the following code? I know that it works for Tag 9, with the resynchronisation step, but something is not adding up for Tag 18.

std::string CFB_encrypt(SymAlg * crypt, uint8_t packet, std::string data, std::string prefix){
    uint8_t BS = crypt -> blocksize() >> 3;
    // 1
    std::string IV(BS, 0);
    // 2
    std::string FR = IV;
    std::string FRE = crypt -> encrypt(FR);
    // 3
    FRE = xor_strings(FRE, prefix);
    std::string C = FRE;
    // 4
    FR = C;
    // 5
    FRE = crypt -> encrypt(FR);
    // 6
    C += xor_strings(FRE.substr(0, 2), prefix.substr(BS - 2, 2));
    // 7
    if (packet == 9){
        FR = C.substr(2, BS);
    }
    // 8
    FRE = crypt -> encrypt(FR);
    // 9
    C += xor_strings(FRE, data.substr(0, BS));
    unsigned int x = BS;
    while (x < data.size()){
        // 10
        FR = C.substr(x + 2, BS);
        // 11
        FRE = crypt -> encrypt(FR);
        // 12
        C += xor_strings(FRE, data.substr(x, BS));
        x += BS;
    }
    return C;
}

What did I miss?

Was it helpful?

Solution 2

This chunk of code somehow works. I don't get it:

    else {
        plaintext = "  "+plaintext;
        // 9.  FRE is xored with the first 8 octets of the given plaintext, now
        //     that we have finished encrypting the 10 octets of prefixed data.
        //     This produces C11-C18, the next 8 octets of ciphertext.
        for (var i = 2; i &lt; block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
        var tempCiphertext = ciphertext.substring(0,2*block_size).split('');
        var tempCiphertextString = ciphertext.substring(block_size);
        for(n=block_size; n&lt;plaintext.length; n+=block_size) {
            // 10. FR is loaded with C11-C18
            for (var i = 0; i &lt; block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
            tempCiphertextString='';

            // 11. FR is encrypted to produce FRE.
            FRE = blockcipherencryptfn(FR, key);

            // 12. FRE is xored with the next 8 octets of plaintext, to produce the
            //     next 8 octets of ciphertext.  These are loaded into FR and the
            //     process is repeated until the plaintext is used up.
            for (var i = 0; i &lt; block_size; i++){ tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i)));
            tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i));
            }
        }
        ciphertext = tempCiphertext.join('');

    }
    return ciphertext;
}

OTHER TIPS

Your step 3 here:

3. FRE is xored with the first BS octets of random data prefixed to the plaintext

doesn't match up with your code:

// 3
std::string C = FRE;

There is no xoring going on here. Try changing it to:

std::string C = xor_strings(FRE, prefix.substr(0,8));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top