locked
CryptCreateHash 256 bits on XP SP2? RRS feed

  • Question

  • I'm trying to AES256 decrypt a file on XP SP2 (which does not have SHA256) that was encrypted using Java (also written by me). So I need to arrive at a common method.

    Currently the Win32 decryption code looks like the following (minus error handling):

      CryptAcquireContext(prov, NULL, nprov, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
      CryptCreateHash(*prov, CALG_SHA1, 0, 0, hash);
      CryptHashData(*hash, (PBYTE)password, 64 * sizeof(wchar_t), 0);
      CryptDeriveKey(*prov, algid, *hash, CRYPT_EXPORTABLE, key);
      loop:
          CryptDecrypt(key, 0, r < sizeof(buf), 0, buf, &d)

    and the Java encryption procedure is:

      byte[] pbytes = password.substring(0, 64).getBytes("UTF-16LE");
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] hash = new byte[32];
      System.arraycopy(ZEROS, 0, hash, 16, 16);
      md.update(pbytes, 0, pbytes.length);
      md.digest(hash, 0, 20);

      Cypher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
      IvParameterSpec iv = new IvParameterSpec(ZEROS);
      c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(hash, "AES"), iv);

      FileOutputStream fos = new FileOutputStream(dpath);
      CipherOutputStream cos = new CipherOutputStream(fos, c);
      loop:
          cos.write(data, 0, n);

    This seems like it should work but it does not. The code runs successfully but the plaintext is not recovered.

    So my first guess would be the CryptDeriveKey is doing something I cannot see. Because the hash is only 20 bytes, will it pad to 32 with zeros have I have done on the Java side?

    Do I need to use the upper 16 bits of CryptDeriveKey's dwFlags to specify the key should be 256 bits?

    How can I get a raw char * to the hash and key so that I can hexdump it to the console and isolate the step that is failing?

    Or better still, is there a way to create a 256 bit hash and key on XP SP2 for use with AES256?

    Mike
    Thursday, January 14, 2010 8:06 PM

Answers

  • Nevermind. Apparently the solution is to use CryptImportKey. The CryptImportKey even Remarks section even describes this somewhat but the whole process is a little awkward. At least the blob structures could be properly defined.

    Anyway, for posterity, here's the short version of how to get an HCRYPTKEY from an array of bytes:

    BYTE kbytes[] = {
        0x71, 0x0B, 0xC9, 0xC9, 0xDE, 0x7B, 0x84, 0x4E,
        0x62, 0xB4, 0xCF, 0xEF, 0x36, 0xF8, 0xCB, 0x03
    };
    BYTE iv[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };

    struct _kblob {
        BLOBHEADER hdr;
        DWORD keySize;
        BYTE bytes[16];
    } kblob;

    kblob.hdr.bType = PLAINTEXTKEYBLOB;
    kblob.hdr.bVersion = CUR_BLOB_VERSION;
    kblob.hdr.reserved = 0;
    kblob.hdr.aiKeyAlg = CALG_AES_128;
    kblob.keySize = 16;
    memcpy(kblob.bytes, kbytes, 16);

    CryptImportKey(prov, (BYTE *)&kblob, sizeof(struct _kblob), 0, 0, &key);
    CryptSetKeyParam(key, KP_IV, iv, 0);
    CryptDecrypt(key, 0, ...)
    Friday, January 15, 2010 4:17 PM

All replies

  • Hello Mike

    Is JAVA able to call native Windows APIs like .NET Pinvoke does?

    If yes, I suggest calling CrptoAPI directly from JAVA instead of using JDK API because there may be differences between the two implementations (currently or in future)
    Dave
    Friday, January 15, 2010 8:37 AM
  • No. I don't understand. If the same key is used, the products should be completely predictable. Meaning there should be no problem decrypting data encrypted on any other platform. What differences are you speaking of?

    I am now trying to simply decrypt data using a 16 byte MD5 hash as the key and CALG_AES_128 and it still does not work - the plaintext is not recovered successfully.

    Also when I try to export the HCRYPTOKEY using CryptExportKey with SIMPLEBLOB, I get a "Key does not exist" error even though the CryptDeriveKey operation was successful. Do I need to provide a keystore with CryptAcquireContext? How can I recover the key as a char * so that I can hexdump it's value?

    I have used crypto libraries on other platforms (linux and java) and never ran into anything like this. Am I doing something fundamentally wrong or what?
    Friday, January 15, 2010 3:14 PM
  • Nevermind. Apparently the solution is to use CryptImportKey. The CryptImportKey even Remarks section even describes this somewhat but the whole process is a little awkward. At least the blob structures could be properly defined.

    Anyway, for posterity, here's the short version of how to get an HCRYPTKEY from an array of bytes:

    BYTE kbytes[] = {
        0x71, 0x0B, 0xC9, 0xC9, 0xDE, 0x7B, 0x84, 0x4E,
        0x62, 0xB4, 0xCF, 0xEF, 0x36, 0xF8, 0xCB, 0x03
    };
    BYTE iv[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };

    struct _kblob {
        BLOBHEADER hdr;
        DWORD keySize;
        BYTE bytes[16];
    } kblob;

    kblob.hdr.bType = PLAINTEXTKEYBLOB;
    kblob.hdr.bVersion = CUR_BLOB_VERSION;
    kblob.hdr.reserved = 0;
    kblob.hdr.aiKeyAlg = CALG_AES_128;
    kblob.keySize = 16;
    memcpy(kblob.bytes, kbytes, 16);

    CryptImportKey(prov, (BYTE *)&kblob, sizeof(struct _kblob), 0, 0, &key);
    CryptSetKeyParam(key, KP_IV, iv, 0);
    CryptDecrypt(key, 0, ...)
    Friday, January 15, 2010 4:17 PM