Subject: RE: Need some explanations about privarte key in OpenPGP format, CFB mode

From: "Cornel GLIGAN" <[email-masked]>
Date: Fri, 15 Feb 2002 08:47:54 +0200

Hi!

First fo all, I want to thank you for you answer me.

Here are my problems:

>OpenPGP does symmetric encryption using a variant of Cipher Feedback
>Mode (CFB mode). This section describes the procedure it uses in
>detail. This mode is what is used for Symmetrically Encrypted Data
>Packets; the mechanism used for encrypting secret key material is
>similar, but described in those sections above.

In the "secret key material" section I found this: 
>Encryption/decryption of the secret data is done in CFB mode using
>the key created from the passphrase and the Initial Vector from the
>packet.

(and now, back to the CFB mode)
>OpenPGP CFB mode uses an initialization vector (IV) of all zeros,
>and prefixes the plaintext with BS+2 octets of random data, such
>that octets BS+1 and BS+2 match octets BS-1 and BS.  It does a CFB
>"resync" after encrypting those BS+2 octets.

I want to mention that I want to keep a secret key in format OpenPGP not
a plain text.
1) What value should I fill in IV?
2) Are those BS+2 octets just for plain text or even for secret key
material?

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

3) Do the C[i] octets represent the final form for OpenPGP format? 

>12. 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.

4) Let's assume that I encrypt the algorithm-specific portion with IDEA.
What it happens with the last block of data if the length of the
algorithm-specific portion is not multiple of 8 (64 bit)? (and, of
course, the last block it will be less than BS - in this case 8 octets)

Thank you in advance,

Cornel Gligan-Ignatescu

---

From: Derek Atkins <[email-masked]>
Date: 15 Feb 2002 09:26:15 -0500

> 2) Are those BS+2 octets just for plain text or even for secret key

The OpenPGP CFB module uses an "Encrypted Initialization".  The way this
works is:
        1) start with an IV of all zeros (in the CFB Context)
        2) Create a buffer of "BS+2" bytes
        3) Fill in the first BS bytes with random bytes
        4) copy the last two bytes of BS into the extra two bytes at the end
        5) CFB Encrypt the "BS+2" bytes <-- This is the encrypted IV
        6) Re-Sync the CFB context.
        7) Start ecnrypting your data.

This is done EVERY TIME you initialize a CFB context.  These extra
BS+2 bytes are prefixed before every CFB encryption.

> 3) Do the C[i] octets represent the final form for OpenPGP format? 

Yes.  Although C[0]..C[BS+2] are the encrypted IV bytes, not your data
bytes.

> course, the last block it will be less than BS - in this case 8 octets)

You clearly don't understand how CFB mode works.  You don't encrypt
your input in block-sized chunks; you rotate your feedback register in
block-sized chunks.  The ciphertext is just an xor of the feedback
register with the plaintext, and you rotate the feedback register by
encrypting your output.  So if the last block of plaintext is only 1
byte, you only use one byte from the last feedback and toss the rest
of your feedback on the floor.

> Cornel Gligan-Ignatescu

-derek

-- 
       Derek Atkins
       Computer and Internet Security Consultant
       [email-masked]             www.ihtfp.com

---

From: "Michael Young" <[email-masked]>
Date: Fri, 15 Feb 2002 11:39:12 -0500

>I want to mention that I want to keep a secret key in format OpenPGP not

In this context, the "multi-precision integers comprising the secret
key data" are the plaintext.

> 1) What value should I fill in IV?

In the secret key context, the IV should be filled with random bits.
That IV is included in the unencrypted section of the secret key packet.

For message packets, the IV is initially zero, but the first material
to be encrypted is random, which has similar effect.

> 2) Are those BS+2 octets just for plain text or even for secret key

The "BS+2" scheme is only used in the Symmetrically Encrypted Data
("message") packets.

Secret key material is encrypted in a pure CFB mode; see below.

> 3) Do the C[i] octets represent the final form for OpenPGP format? 

Yes.

> course, the last block it will be less than BS - in this case 8 octets)

CFB mode can use any "block size".  The underlying cipher is always
applied to the "feedback register", which is a whole block, even if
the CFB input is smaller.  If the CFB input is N bytes, only the first
N bytes of the encrypted feedback register are used; they are XORed
with the CFB input to form the CFB output.  The CFB output is then
shifted into the feedback register.

The "block size" under CFB can even change from one input to the
next.  To decrypt, you also need to know how the data was blocked.
RFC2440 uses the phrase "resync" to describe where blocks smaller
than the underlying cipher are processed.  For example, at the
front of a message packet, a full block of random material is
processed, following by an 2-byte block of repeated material --
those two bytes are *not* combined with subsequent plaintext to
form a "full block", but are processed by themselves.
Also, version 3 secret keys are processed one MPI at a time
(including only the data, not the length), so the last bytes
of each MPI may be a short block.

Here is some Java-like pseudo-code for CFB that isn't tied to
the OpenPGP behavior.

  Cipher engine;  // underlying cipher, used in "ECB" mode
  byte [] FR;     // feedback register, block-sized; initialized with IV

  void cfb_encrypt(byte [] src, byte [] dest, int length) {
    // assumes length <= ECB block size; if not, reject or break up the input

    // encrypt the FR, and XOR first "length" bytes with src into dest
    byte [] FRE = engine.encrypt(FR);
    for (int i = 0; i < length; i++)
      dest[i] = src[i] ^ FRE[i];

    // shift "length" bytes of result into FR
    int j = 0;
    for (int i = length; i < FR.length; i++) FR[j++] = FR[i];
    for (int i = 0; j < FR.length; i++) FR[j++] = dest[i];
  }