3

I want to sign file with the SunMSCAPI provider. As public key and signatures needs to be imported using MS Crypto API.

Generally generating signatures with SHA1withRSA, ends up with big-endian to little-endian (byte order) conversion.

//generate keystore with java keytool
$Keytool -genkey -alias tsign -keystore c:\test\tsignjks.p12 - keyalg rsa -storetype  pkcs12

In Java application:

//for signing and getting keystore, assuming windows certificate is installed
..ks = KeyStore.getInstance("Windows-MY","SunMSCAPI"); 
PrivateKey priv = ks.getKey("tsign",password); 
Signature rsa = Signature.getInstance("SHA1withRSA","SunMSCAPI"); 
rsa.initSign(priv);
.. 
rsa.update(buffer, 0, len);
..
byte[] realSig = rsa.sign();

//for writing public key for ms crypto api or exporting it from windows certificate store
Certificate cert = ks.getCertificate("tsign");
byte[] encodedCert = cert.getEncoded();
FileOutputStream certfos = new FileOutputStream("tsigncer.cer");
certfos.write(encodedCert);

//for writing signatures for ms crypto api
FileOutputStream sigfos = new FileOutputStream(targetPath + "/"
                + signatureName);
sigfos.write(realSig);

I believe that SunMSCAPI can resolve my problem, but I don't know when i import public key using MS Crypto API, It never import at at first stage (unless i change big endian to little endian byte order) below is my code for crypto API.

LPCSTR file = "tsigncer.cer";
//LPCSTR file = "omsign.p12";
BOOL crypt_res = FALSE;

HCRYPTPROV crypt_prov_hndl = NULL;
 crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_RSA_FULL, 0/*CRYPT_NEWKEYSET*/);
//crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT/*CRYPT_NEWKEYSET*/);

    if (!crypt_res) {
        HRESULT decode_hr = __HRESULT_FROM_WIN32(GetLastError());
        return decode_hr;
    }

    // Load key file
    HANDLE fileHandle = CreateFile(file, // name of the write
                       GENERIC_READ,          // open for writing
                       0,                      // do not share
                       NULL,                   // default security
                       OPEN_EXISTING,             // create new file only
                       FILE_ATTRIBUTE_NORMAL,  // normal file
                       NULL);                  // no attr. template

    if (fileHandle == INVALID_HANDLE_VALUE)
    {
        DWORD d = GetLastError();
        return -1;
    }

    BYTE buffer[2056];
    DWORD fileSize = 0;
    DWORD fileSizeResult = GetFileSize(fileHandle, &fileSize);

    DWORD numBytesRead = 0;
    BOOL fileLoadResult = ReadFile(fileHandle, (PVOID)buffer, fileSizeResult, &numBytesRead, NULL);

    // Import key
    BOOL result = ImportKey(crypt_prov_hndl, (LPBYTE)buffer, numBytesRead);
//result is always false..
Ali
  • 151
  • 3
  • 11

1 Answers1

5

If you work with MSCAPI, it is assumed that you've added your key to the Microsoft Certificate store. You can check if the key is present by going to "Internet Properties" > "Content" > "Certificates" which gives you a list of certificates that are available. If your certificate isn't there, you can't use it. If it's there, you need this code:

SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);

From there on, the code is pretty standard. Please consult my book on digital signatures for more info (the book is free).

IMPORTANT ADDITION: I forgot to mention that SunMSCAPI isn't present in the 64-bit version of Java 6 (I don't know about Java 7). You can fix this by installing the 32-bit version.

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Thanks for reply, I am using java keytool for creating keystore, and exporting public key using keystore in java application as mentioned above in code, while double clicking that file i can install it but it doesnt show in certificate lists. Can you provide me a way for adding selfsigned certificate ? – Ali Apr 05 '13 at 13:24
  • First this: I don't think a JKS key will work. You'll need to create a .p12 file. I usually don't double click files, I go to the Certificates overview, and I manually Import keys. That way, I know exactly what happens. – Bruno Lowagie Apr 05 '13 at 13:32
  • OK! I have created .p12 file using java keytool and installed into windows certificates. Everything works fine i can sign files using Signature.getInstance("SHA1withRSA","SunMSCAPI") BUT for verification still i cannot import public key (that i have created mentioned in above code) using MS Crypto API, that i think is still an issue of big/little endian format. – Ali Apr 05 '13 at 14:56
  • Well, it may be easier to export the public key from the Windows Certificate store. You can choose from all kinds of formats there. – Bruno Lowagie Apr 05 '13 at 15:14
  • Just tried to export from Windows Certificate Store but when i use code it in crypto api , then its always cannot import, but if i change byte order to little endian than it imports, perhaps i am doing something wrong using crypto api. – Ali Apr 05 '13 at 15:36
  • So let me see if I get this right: you have a .cer file with the public certificate, and now you want to import it into a keystore (e.g. cacerts)? Maybe you should create a new question, that's easier than (ab)using the comment section on this topic. – Bruno Lowagie Apr 05 '13 at 15:55
  • Thanks for your support bruno, I have updated this question to be more clear and specific. – Ali Apr 05 '13 at 17:25
  • 1
    The question has become longer and therefor more difficult to understand. As a matter of fact: I don't see the question. Please close this question by accepting the answer and post a new question that only contains your new question. – Bruno Lowagie Apr 07 '13 at 10:26