Thread Links Date Links
Thread Prev Thread Next Thread Index Date Prev Date Next Date Index

Re: Archive.



I attach below all the messages that I sent on or after Apr-14-2004.

-- Shai

On Monday 26 April 2004 01:13 pm, james Hughes wrote:
> Gentlepeople:
>
> Jack Cole and Clement Kent have brought to my attention that the
> archive is not accumulating the emails sent since April 14th.
>
> I have tested it and it now works (again).
>
> I ask each of you to resend the messages that you have sent April 14th
> or later so that they are captured.
> [...]


> If we consider the application is adding these 8 bytes and then later
> we are EME (or similar) the entire 520 bytes, if the attacker tampers
> with the data then the 8 byte check will be garbage and the reader
> knows this.

hmm.. EME-AES is designed for integral number of 16-byte blocks. We
did have an extension that works for any number of bytes, but we never
published it anywhere, and also never wrote a proof of security for it.
(It adds only a single AES encryption operation over the current EME if
you can fit the the tweak and the guard in one 16-byte block, and two
AES encryptions otherwise.) Anyone knows why they decided on 64 bits?

> The points along the way (between the host and the encryptor) can check
> the 8 bytes for validity, and the points after the encryptor just
> passes the bits.
>
> This is more coverage than just adding an 8 byte integrity field
> because it does not protect between the encryptor and the host, it
> only protects between the encryptor and the disk and back...

The protection between the encryptor and the host is non-cryptograpic,
though. And it is not quite "protection" until you specify precisely
how the application should check this block.

-- Shai





On Wednesday 14 April 2004 01:12 pm, james hughes wrote:
> [...]
> 03-110r0.pdf used to allow "DIF stacking". Could we use this to add 2
> data integrity fields, and in the inner integrity field use that for a
> traditional MAC? Then we have a really ugly disk drive with a 528 or
> 536 byte sector?
>
> While these solve the issues for SCSI drives, this still begs the issue
> for ATA or IDE drives (>90% of the market) which will stay at 512 byte
> sectors?

Is 520 bytes an arbitrary number? By that I mean, does the fact that
T10 wants a 8-byte "guard" mean that we have to stick to it as well
(assuming that we ever standardize anything beyond 512 bytes)? From a
security point of view, I see many reasons not to stick to only 8 more
bytes. Actually, I would have liked 544 or 560 bytes (so we have extra
two or three full blocks of 16 bytes).

-- Shai





On Thursday 15 April 2004 10:04 am, Clement Kent wrote:
> On another topic, if we were to have disks with 544 or 560 byte sectors as
> Shai recently suggested, what is the argument for doing the wide-block
> encryption of the EME type? Its primary purpose is to provide
> pseudointegrity. If a data integrity field in the extra bytes in the sector
> can provide traitional integrity at lower computational cost, would it not
> be best to use the simpler LRW algorithm to defeat copy-and-paste attacks,
> and focus on providing integrity in the extra bytes via a keyed MAC?

You're right, there is absolutely no reason to do EME (or LRW, for that
matter) if you have the extra space. In fact, in that case I would
suggest doing counter mode encryption with some MAC, or maybe some
variant of OCB. The only reason to use EME in that conetxt is if you
already have a piece of hardware doing EME and you want to utilize it
(but that indicates that there is really no point in talking about any
extension of EME).

-- Shai






/**
 * eme-ref.c
 *
 * @version 1.0 (May 2003)
 *
 * Reference ANSI C code for EME-AES encryption
 *
 * @author Shai Halevi <shaih@watson.ibm.com>
 *
 * entry points:
 *    void sectorEME(unsigned char outSector[512],
 *                   const unsigned char K[],          // 16, 24, or 32 bytes
 *                   int keyBits,                      // number of bits in K[]
 *                   const unsigned char T[16],        // the "tweak"
 *                   const unsigned char inSector[512],
 *                   int dir                           // 1 for enc, 0 for dec
 *         );
 *
 * This code is hereby placed in the public domain.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* Note: The code below assumes an interface to AES core encryption and
 *    decryption routines, such as provided by the OpenSSL Toolkit
 *    (http://www.openssl.org/), developed by the OpenSSL Project.
 *
 *    This interface can be described by the following declarations
 *    (which were derived from <openssl/aes.h>):
 *
 *    typedef struct {
 *        unsigned long rd_key[4 * 15];
 *        int rounds;
 *    } AES_KEY;
 *
 *    #define AES_ENCRYPT       1
 *    #define AES_DECRYPT       0
 *
 *    int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
 *                            AES_KEY *key);
 *    int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
 *                            AES_KEY *key);
 *    void AES_encrypt(const unsigned char *in, unsigned char *out,
 *                     const AES_KEY *key);
 *    void AES_decrypt(const unsigned char *in, unsigned char *out,
 *                     const AES_KEY *key);
 */
#include <openssl/aes.h>

/* local functions */

/* Encrypt or decrypt one block with AES and the given key */
static void aesBlock(unsigned char out[16], const unsigned char key[],
                     int keyBits, const unsigned char in[16], int dir);

/* Set out = in1 xor in2 */
static void xorBlocks(unsigned char out[16],
                      const unsigned char in1[16],
                      const unsigned char in2[16]);

/* Set out = 2 * in, multiplication in GF(2^{128}) */
static void multByTwo(unsigned char out[16], const unsigned char in[16]);


void sectorEME(unsigned char C[512], const unsigned char K[], int keyBits,
               const unsigned char T[16], const unsigned char P[512], int dir)
{
  int j;
  unsigned char L[16], M[16], MP[16], MC[16];
  unsigned char temp[512];  /* a temporary array, just in case P and C */
                            /*       point to the same memory location */
  unsigned char zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};

  aesBlock(zero, K, keyBits, zero, AES_ENCRYPT); /* L = 2*AES-enc(K; 0) */
  multByTwo(L, zero);

  for (j=0; j<32; j++) {
    xorBlocks(&temp[j*16], &P[j*16], L);     /* PPj = 2**(j-1)*L xor Pj */
    aesBlock(&temp[j*16],
             K, keyBits, &temp[j*16], dir);   /* PPPj = AES-enc(K; PPj)  */
    multByTwo(L, L);
  }

  xorBlocks(MP, temp, T);                    /* MP = (xorSum PPPj) xor T */
  for (j=1; j<32; j++)
    xorBlocks(MP, MP, &temp[j*16]);

  aesBlock(MC, K, keyBits, MP, dir);          /* MC = AES-enc(K; MP)     */
  xorBlocks(M, MP, MC);                      /* M = MP xor MC           */

  for (j=1; j<32; j++) {
    multByTwo(M, M);
    xorBlocks(&temp[j*16],&temp[j*16],M);    /* CCCj = 2**(j-1)*M xor PPPj */
  }

  xorBlocks(temp, MC, T);             /* CCC1 = (xorSum CCCj) xor T xor MC */
  for (j=1; j<32; j++)
    xorBlocks(temp, temp, &temp[j*16]);

  multByTwo(L, zero);                         /* reset L = 2*AES-enc(K; 0) */
  for (j=0; j<32; j++) {
    aesBlock(&temp[j*16],
             K, keyBits, &temp[j*16], dir);    /* CCj = AES-enc(K; CCCj)  */
    xorBlocks(&C[j*16], &temp[j*16],  L);     /* Cj = 2**(j-1)*L xor CCj */
    multByTwo(L, L);
  }
}

static void multByTwo(unsigned char output[16], const unsigned char input[16])
{
  int j;
  unsigned char temp[16];   /* a temporary array, just in case input and */
                            /* output point to the same memory location  */
  temp[0] = 2 * input[0];
  if (input[15] >= 128) temp[0] ^= 135;
  for (j=1; j<16; j++) {
    temp[j] = 2 * input[j];
    if (input[j-1] >= 128) temp[j] += 1;
  }
  for (j=0; j<16; j++) output[j] = temp[j];
}

static void xorBlocks(unsigned char out[16],
                      const unsigned char in1[16], const unsigned char in2[16])
{
  int j; for (j=0; j<16; j++) out[j] = in1[j] ^ in2[j];
}

static void aesBlock(unsigned char out[16], const unsigned char key[],
                     int keyBits, const unsigned char in[16], int dir)
{
  extern void exit(int status);
  int retCode;
  AES_KEY aesKey;

  if (dir==AES_ENCRYPT)
    retCode = AES_set_encrypt_key(key, keyBits, &aesKey);
  else
    retCode = AES_set_decrypt_key(key, keyBits, &aesKey);
  if (retCode!=0) exit(retCode);       /* Not very gracefull, but still... */

  if (dir==AES_ENCRYPT) AES_encrypt(in, out, &aesKey);
  else                  AES_decrypt(in, out, &aesKey);
}
/**
 * testEME.c - generating test-vectors for the EME-AES construction
 *
 * @version 1.0 (May 2003)
 * @author Shai Halevi <shaih@watson.ibm.com>
 *
 *   We use the following procedure to generate the test vectors:
 *
 *   Encryption:
 *       Set buffer = [0, 0, ..., 0]  (a 512-byte array)
 *       Set T = K = [0, 0, ..., 0]  (16-byte blocks)
 *       buffer = EME-encrypt_K^T(buffer)
 *       printf buffer
 *
 *       K = buffer[0..15]          (a 16-byte block)
 *       For i=1 to 10 do
 *           T = buffer[16..31]       (a 16-byte block)
 *           For j=1 to 100 do
 *               buffer = EME-encrypt_K^T(buffer)
 *           end-for
 *           Print buffer
 *       end-for
 *
 *   Decryption:
 *       Set buffer = [0, 0, ..., 0]  (a 512-byte array)
 *       Set T = K = [0, 0, ..., 0]   (16-byte blocks)
 *       buffer = EME-decrypt_K^T(buffer)
 *       printf buffer
 *
 *       K = buffer[0..15]          (a 16-byte block)
 *       For i=1 to 10 do
 *           T = buffer[16..31]       (a 16-byte block)
 *           For j=1 to 100 do
 *               buffer = EME-decrypt_K^T(buffer)
 *           end-for
 *           Print buffer
 *       end-for
 *
 * This code is hereby placed in the public domain.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/aes.h>

extern void
sectorEME(unsigned char C[512], const unsigned char K[], int keyLen,
           const unsigned char T[16], const unsigned char P[512], int dir);

static void emeTestDirection(int dir);
static void blocksPrint (FILE *fp, unsigned char  *blocks,
                         int blockBits, int nBlocks, const char *tag);

int main()
{
  printf("Test vectors for EME-AES, with 128-bit keys and 32 blocks\n");
  emeTestDirection(AES_ENCRYPT);
  emeTestDirection(AES_DECRYPT);

  return 0;
}


static void emeTestDirection(int dir)
{

  int i, j;

  unsigned char keyMaterial[16];
  unsigned char tweak[16];
  unsigned char buf[512];

  char *dirName = (dir==AES_ENCRYPT)? "enc" : "dec";
  printf("\nTesting %sryption:\n", dirName);

  memset(buf, '\0', sizeof(buf));
  memset(tweak, '\0', sizeof(tweak));
  memset(keyMaterial, '\0', sizeof(keyMaterial));

  blocksPrint(stdout, keyMaterial, 128, 1, " key");
  blocksPrint(stdout, buf, 128, 32, " buffer");
  blocksPrint(stdout, tweak, 128, 1, " tweak");

  sectorEME(buf, keyMaterial, 128, tweak, buf, dir);
  printf("after one application of EME-AES-%s\n\n", dirName);
  blocksPrint(stdout, buf, 128, 32, " buffer");
  printf("==============================================================\n\n");

  memcpy(keyMaterial, buf, 16);
  blocksPrint(stdout, keyMaterial, 128, 1, " key");

  for(i=0; i<10; i++) {
    memcpy(tweak, buf+16, 16);
    blocksPrint(stdout, buf, 128, 32, " buffer");
    blocksPrint(stdout, tweak, 128, 1, " tweak");

    for(j=0; j<100; j++) {
      sectorEME(buf, keyMaterial, 128, tweak, buf, dir);
    }
    printf("after 100 applications of EME-AES-%s\n\n", dirName);
  }
  blocksPrint(stdout, buf, 128, 32, " buffer");
  printf("****************************************************************\n");
  printf("****************************************************************\n");
}

/**********************************************************************/
/**********************************************************************/

static void blocksPrint (FILE *fp, unsigned char *blocks,
                         int blockBits, int nBlocks, const char *tag)
{
  int i, j;

  fprintf (fp, "%s=", tag);
  for (j=0; j<nBlocks; j++) {
    for (i = 0; i < blockBits/8; i++) {
      fprintf (fp, "%02X ", blocks[i]);
    }
    fprintf (fp, "\n   ");
    blocks += blockBits/8;
  }
  fprintf (fp, "\n");
  fflush (fp);
} /* blocksPrint */

/**********************************************************************/




I vote for the 2nd option: namely say in the text that vendor specific
parameters SHOULD have names that start with the vendor name, and MUST NOT
have names that begin with "1619".

-- Shai

On Friday 16 April 2004 10:22 am, Curtis Anderson wrote:
> All,
>
> The basic suggestion is to reserve one or more "vendor names"
> for use by the standard.  Two different techniques come to
> my mind, but there must also be others, your choice:
>
> 1) Instead of a name/value pair for the optional extra attributes,
>    you could make it a triple with the vendor name called out
>    specifically.  Then you reserve one vendor name for use by
>    the standard, eg: "1619" as a vendor instead of "EMC".
>
> 2) Specify in the standard that there are restrictions on the
>    names in the optional attribute name/value pairs.  Specifically
>    that no vendor is allowed to use "1619" as the initial four
>    characters in the attribute names.
>
> You could then add extra parameters that might be needed for new
> key types as being owned by the "1619" vendor.
>
> Thanks,
>
>         Curtis
>
> --
> Curtis Anderson