PGPdisk (formerly CryptDisk) source code review

    PGPdisk (formerly CryptDisk) source code review

    ……………………………………

    PGPdisk (formerly CryptDisk) source code review

    CryptDisk: a source code review

    From: “W. Kinney”

    Subject: CryptDisk 1.0 Source Review

    Date: Wed, 15 Feb 1995 09:42:09 -0700 (MST)

    sent me the source code to CryptDisk for

    review, and I’ve finally had a chance to take a look at it. For those who

    haven’t heard of it, CryptDisk is an encrypted partition driver, an

    equivalent of Secure Drive for the Macintosh. I have been over the encryption

    code in detail, and it looks good. Note that this review is based on the

    source for version 1.0 — [as the current version is later] some of my

    complaints may have already been addressed. Anyhow, here’s what I found in

    the source:

    The program comes in “demo” and “non-demo” versions, the difference being

    whether or not the crypto functions are enabled. The program is $20

    shareware, and source code is an additional $20. A large fraction of the

    program is written in C++, which means that poor slobs like me still stuck

    with Think C 5 can’t compile it. Oh, well.

    There are two IDEA keys: the user key and a session key. The data on the

    disk itself is encrypted with the session key, which is randomly generated

    when the disk is initialized. The session key is encrypted with the user key,

    which is generated from the MD5 hash of a pass phrase and a random salt. When

    the pass phrase for the disk is changed, the user key changes, but not the

    session key. The random salt is also set at disk initialization and does not

    change. Pseudocode for key generation looks like this:

    = randoms

    = MD5[]

    = Randoms

    MD5Init[]

    MD5Update[]

    for (i = 0 to 163)

    MD5Update[]

    MD5Update[(byte)i]

    = MD5Final[]

    = first 8 bytes of

    and

    are then encrypted with IDEA in ECB mode,

    using

    as the key.

    is used to verify that a pass

    phrase entered when mounting the disk is correct.

    The repeated calls to MD5Update are as they should be (rather than repeatedly

    performing a full MD5 transformation on the key buffer), since that avoids

    the possibility of any stable fixed points in MD5. And adding the counter

    field to the hash makes it harder for an attacker to precompute the addition

    steps in MD5. This is all good. But it’s not at all clear why the key is only

    hashed 164 times. Given that this step is only going to be taken once, when

    the disk is mounted, one could easily afford to make the loop much longer,

    making brute-force pass phrase attacks that much more difficult. Especially

    considering that the difficulty of brute-forcing a pass phrase only goes up

    linearly with the number of iterations of the hash, 164 is too small.

    The disk is encrypted in 512-byte blocks with IDEA in cipher-feedback mode.

    The cipher-feedback scheme is really very clever, evidently the same one used

    by Peter Gutmann for in SFS: the initial vector is constructed from the

    plaintext buffer, the same random salt used to construct the user key, and

    the block number of the block being encrypted. The iv is stored on the disk

    by xor’ing it into the plaintext and the whole thing is encrypted. Here’s the

    C code for the encryption and decryption steps for a block of data (this is

    subtle and pretty):

    static void EncryptBlock(CryptStruct *disk, long blkNum, uchar *data)

    {

    short i;

    ulong iv[2];

    iv[0]=iv[1]=0;

    for(i=0;i504;i+=4)

    {

    iv[1]+=*(ulong *)(data + i);

    iv[0]+=iv[1];

    }

    iv[0] ^= *(ulong *)disk->salt;

    iv[1] ^= *(ulong *)(disk->salt+4);

    iv[0] += blkNum;

    iv[1] += blkNum;

    *(ulong *)(data+504) ^= iv[0];

    *(ulong *)(data+508) ^= iv[1];

    iv[0]=*(ulong *)(data+504);

    iv[1]=*(ulong *)(data+508);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBEncrypt(&disk->cfb,data,data,512);

    }

    static void DecryptBlock(CryptStruct *disk, long blkNum, uchar *data)

    {

    short i;

    ulong iv[2];

    iv[0]=*(ulong *)data;

    iv[1]=*(ulong *)(data+4);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBDecrypt(&disk->cfb,data+8,data+8,504);

    iv[0]=*(ulong *)(data+504);

    iv[1]=*(ulong *)(data+508);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBDecrypt(&disk->cfb,data,data,8);

    iv[0]=iv[1]=0;

    for(i=0;i504;i+=4)

    {

    iv[1]+=*(ulong *)(data + i);

    iv[0]+=iv[1];

    }

    iv[0] ^= *(ulong *)disk->salt;

    iv[1] ^= *(ulong *)(disk->salt+4);

    iv[0] += blkNum;

    iv[1] += blkNum;

    *(ulong *)(data+504) ^= iv[0];

    *(ulong *)(data+508) ^= iv[1];

    }

    (Source code © 1995 Will Price, all rights reserved, excerpted with

    permission from the author.)

    Random numbers are generated using Colin Plumb’s “randpool” code, the same

    basic scheme that is used for PGP (see Colin’s article “Truly Random Numbers”

    in Dr. Dobb’s Journal, November 1994,

    p. 113 for a discussion of the

    method). True randoms are collected from the mouse position and the system

    clock — this could be improved somewhat, as the clock is read via the

    TickCount() function, which has a resolution of 1/60 second. Better would be

    to call the Time Manager, which allows measurement to the microsecond. Also,

    on a somewhat pedantic note, there appears to be no attempt to directly

    estimate the amount of entropy actually collected before a session key is

    generated.

    Buffers in memory containing the IDEA keys are not protected from being

    swapped to disk by virtual memory. This means that people who have VM turned

    on on their machine could inadvertently leave a copy of their key lying

    around in the VM space on their disk. This really needs to be fixed (and it’s

    an easy thing to do).

    Oddly, the 68K assembler version of the IDEA core routine is present in the

    source but commented out. This is really fast code written by Colin Plumb (I

    use the same routine in the forthcoming 2.0 release of Curve Encrypt). It’s

    too bad the CryptDisk isn’t using it, as it makes a substantial speed

    difference. (Evidently Will is having trouble getting the code to work!?).

    The bottom line is that, aside from a couple of pretty niggling details,

    CryptDisk looks very solid from a cryptographic standpoint. The only caveat

    is that it appears to be quite insecure on machines using virtual memory.

    Otherwise, it’s a thorough and well constructed piece of code. A very nice

    job. It’s good to see someone finally come out with a product like this for

    the Mac. It fills a real need.

    — Will (the other one)

    From: “W. Kinney”

    Subject: Re: CryptDisk 1.0 Source Review

    Date: Thu, 16 Feb 1995 11:45:10 -0700 (MST)

    I write, regarding hashing the pass phrase:

    considering that the difficulty of brute-forcing a pass phrase only goes up

    linearly with the number of iterations of the hash, 164 is too small.

    Will Price replies:

    This will be addressed in a future version.

    The passphrase will be hashed for 1

    second and then the number of iterations will be stored in the clear in the CryptDisk

    file.

    The file formats will be compatible.

    I would note that I do not consider

    the current implementation much less secure.

    Some Macs aren’t going to MD5 hash

    many more times in 1 second anyway.

    Agreed. It should be noted that neither PGP in conventional encryption mode

    nor Curve Encrypt 1.x hash the pass phrase more than _once_ . If you choose a

    good pass phrase, this step it utterly unnecessary. It only adds security to

    pass phrases which have less than 128 bits of entropy in the first place.

    With the other fixes in place, this product’s security gets a ringing

    endorsement from me!

    Have you found errors nontrivial or marginal, factual, analytical and illogical, arithmetical, temporal, or even typographical? Please let me know; drop me . Thanks!

    |

    |

    |

    |

    |

    |

    |

    |

    This page

    is

    1993-2005 by ,

    via the Creative Commons License. Questions and comments? Send

    to the Geek Times Webmaster.

    Web space graciously donated by , an Internet Service Provider in .

    Leave a Reply

    Your email address will not be published.

    PGPdisk (formerly CryptDisk) source code review

    PGPdisk (formerly CryptDisk) source code review

    ……………………………………

    PGPdisk (formerly CryptDisk) source code review

    CryptDisk: a source code review

    From: “W. Kinney”

    Subject: CryptDisk 1.0 Source Review

    Date: Wed, 15 Feb 1995 09:42:09 -0700 (MST)

    sent me the source code to CryptDisk for

    review, and I’ve finally had a chance to take a look at it. For those who

    haven’t heard of it, CryptDisk is an encrypted partition driver, an

    equivalent of Secure Drive for the Macintosh. I have been over the encryption

    code in detail, and it looks good. Note that this review is based on the

    source for version 1.0 — [as the current version is later] some of my

    complaints may have already been addressed. Anyhow, here’s what I found in

    the source:

    The program comes in “demo” and “non-demo” versions, the difference being

    whether or not the crypto functions are enabled. The program is $20

    shareware, and source code is an additional $20. A large fraction of the

    program is written in C++, which means that poor slobs like me still stuck

    with Think C 5 can’t compile it. Oh, well.

    There are two IDEA keys: the user key and a session key. The data on the

    disk itself is encrypted with the session key, which is randomly generated

    when the disk is initialized. The session key is encrypted with the user key,

    which is generated from the MD5 hash of a pass phrase and a random salt. When

    the pass phrase for the disk is changed, the user key changes, but not the

    session key. The random salt is also set at disk initialization and does not

    change. Pseudocode for key generation looks like this:

    = randoms

    = MD5[]

    = Randoms

    MD5Init[]

    MD5Update[]

    for (i = 0 to 163)

    MD5Update[]

    MD5Update[(byte)i]

    = MD5Final[]

    = first 8 bytes of

    and

    are then encrypted with IDEA in ECB mode,

    using

    as the key.

    is used to verify that a pass

    phrase entered when mounting the disk is correct.

    The repeated calls to MD5Update are as they should be (rather than repeatedly

    performing a full MD5 transformation on the key buffer), since that avoids

    the possibility of any stable fixed points in MD5. And adding the counter

    field to the hash makes it harder for an attacker to precompute the addition

    steps in MD5. This is all good. But it’s not at all clear why the key is only

    hashed 164 times. Given that this step is only going to be taken once, when

    the disk is mounted, one could easily afford to make the loop much longer,

    making brute-force pass phrase attacks that much more difficult. Especially

    considering that the difficulty of brute-forcing a pass phrase only goes up

    linearly with the number of iterations of the hash, 164 is too small.

    The disk is encrypted in 512-byte blocks with IDEA in cipher-feedback mode.

    The cipher-feedback scheme is really very clever, evidently the same one used

    by Peter Gutmann for in SFS: the initial vector is constructed from the

    plaintext buffer, the same random salt used to construct the user key, and

    the block number of the block being encrypted. The iv is stored on the disk

    by xor’ing it into the plaintext and the whole thing is encrypted. Here’s the

    C code for the encryption and decryption steps for a block of data (this is

    subtle and pretty):

    static void EncryptBlock(CryptStruct *disk, long blkNum, uchar *data)

    {

    short i;

    ulong iv[2];

    iv[0]=iv[1]=0;

    for(i=0;i504;i+=4)

    {

    iv[1]+=*(ulong *)(data + i);

    iv[0]+=iv[1];

    }

    iv[0] ^= *(ulong *)disk->salt;

    iv[1] ^= *(ulong *)(disk->salt+4);

    iv[0] += blkNum;

    iv[1] += blkNum;

    *(ulong *)(data+504) ^= iv[0];

    *(ulong *)(data+508) ^= iv[1];

    iv[0]=*(ulong *)(data+504);

    iv[1]=*(ulong *)(data+508);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBEncrypt(&disk->cfb,data,data,512);

    }

    static void DecryptBlock(CryptStruct *disk, long blkNum, uchar *data)

    {

    short i;

    ulong iv[2];

    iv[0]=*(ulong *)data;

    iv[1]=*(ulong *)(data+4);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBDecrypt(&disk->cfb,data+8,data+8,504);

    iv[0]=*(ulong *)(data+504);

    iv[1]=*(ulong *)(data+508);

    ideaCFBReinit(&disk->cfb,(uchar *)iv);

    ideaCFBDecrypt(&disk->cfb,data,data,8);

    iv[0]=iv[1]=0;

    for(i=0;i504;i+=4)

    {

    iv[1]+=*(ulong *)(data + i);

    iv[0]+=iv[1];

    }

    iv[0] ^= *(ulong *)disk->salt;

    iv[1] ^= *(ulong *)(disk->salt+4);

    iv[0] += blkNum;

    iv[1] += blkNum;

    *(ulong *)(data+504) ^= iv[0];

    *(ulong *)(data+508) ^= iv[1];

    }

    (Source code © 1995 Will Price, all rights reserved, excerpted with

    permission from the author.)

    Random numbers are generated using Colin Plumb’s “randpool” code, the same

    basic scheme that is used for PGP (see Colin’s article “Truly Random Numbers”

    in Dr. Dobb’s Journal, November 1994,

    p. 113 for a discussion of the

    method). True randoms are collected from the mouse position and the system

    clock — this could be improved somewhat, as the clock is read via the

    TickCount() function, which has a resolution of 1/60 second. Better would be

    to call the Time Manager, which allows measurement to the microsecond. Also,

    on a somewhat pedantic note, there appears to be no attempt to directly

    estimate the amount of entropy actually collected before a session key is

    generated.

    Buffers in memory containing the IDEA keys are not protected from being

    swapped to disk by virtual memory. This means that people who have VM turned

    on on their machine could inadvertently leave a copy of their key lying

    around in the VM space on their disk. This really needs to be fixed (and it’s

    an easy thing to do).

    Oddly, the 68K assembler version of the IDEA core routine is present in the

    source but commented out. This is really fast code written by Colin Plumb (I

    use the same routine in the forthcoming 2.0 release of Curve Encrypt). It’s

    too bad the CryptDisk isn’t using it, as it makes a substantial speed

    difference. (Evidently Will is having trouble getting the code to work!?).

    The bottom line is that, aside from a couple of pretty niggling details,

    CryptDisk looks very solid from a cryptographic standpoint. The only caveat

    is that it appears to be quite insecure on machines using virtual memory.

    Otherwise, it’s a thorough and well constructed piece of code. A very nice

    job. It’s good to see someone finally come out with a product like this for

    the Mac. It fills a real need.

    — Will (the other one)

    From: “W. Kinney”

    Subject: Re: CryptDisk 1.0 Source Review

    Date: Thu, 16 Feb 1995 11:45:10 -0700 (MST)

    I write, regarding hashing the pass phrase:

    considering that the difficulty of brute-forcing a pass phrase only goes up

    linearly with the number of iterations of the hash, 164 is too small.

    Will Price replies:

    This will be addressed in a future version.

    The passphrase will be hashed for 1

    second and then the number of iterations will be stored in the clear in the CryptDisk

    file.

    The file formats will be compatible.

    I would note that I do not consider

    the current implementation much less secure.

    Some Macs aren’t going to MD5 hash

    many more times in 1 second anyway.

    Agreed. It should be noted that neither PGP in conventional encryption mode

    nor Curve Encrypt 1.x hash the pass phrase more than _once_ . If you choose a

    good pass phrase, this step it utterly unnecessary. It only adds security to

    pass phrases which have less than 128 bits of entropy in the first place.

    With the other fixes in place, this product’s security gets a ringing

    endorsement from me!

    Have you found errors nontrivial or marginal, factual, analytical and illogical, arithmetical, temporal, or even typographical? Please let me know; drop me . Thanks!

    |

    |

    |

    |

    |

    |

    |

    |

    This page

    is

    1993-2005 by ,

    via the Creative Commons License. Questions and comments? Send

    to the Geek Times Webmaster.

    Web space graciously donated by , an Internet Service Provider in .

    Leave a Reply

    Your email address will not be published.