Question

I am using CAPICOM assembly with VBS logic to encrypt some text, this works good but the problem starts when trying to replicate the same using Java.

This is my VBS code:

Option Explicit

Dim strToEncrypt: strToEncrypt = "Content-Type: plain/text; name=""C:\Users\Luigi\Desktop\hello.txt""" & vbCrLf & _
  "Content-Disposition: attachment; filename=""C:\Users\Luigi\Desktop\hello.txt""" & vbCrLf & _
  "test"
Dim encryptedStr: encryptedStr = CRYPTO_SHA1(strToEncrypt)

WScript.Echo encryptedStr

Private Function CRYPTO_SHA1(strData) 'As String
  Const CAPICOM_HASH_ALGORITHM_SHA1 = 0

  Dim hash: Set hash = CreateObject("CAPICOM.HashedData")
  Dim util: Set util = CreateObject("CAPICOM.Utilities")
  Dim stm: Set stm = CreateObject("ADODB.Stream")

  stm.Open
  stm.Type = 2 'adTypeText
  stm.Charset = "us-ascii"
  stm.WriteText strData
  stm.Position = 0
  stm.Type = 1 'adTypeBinary

  hash.Algorithm = CAPICOM_HASH_ALGORITHM_SHA1
  hash.Hash stm.Read

  CRYPTO_SHA1 = util.Base64Encode(util.HexToBinary(hash.Value))
  CRYPTO_SHA1 = Left(CRYPTO_SHA1, Len(CRYPTO_SHA1)-Len(vbCrLf))

  stm.Close
  Set stm = Nothing
  Set util = Nothing
  Set hash = Nothing
End Function

By debugging the above code, I can get the following:

Hash object value is:

hash.Value = 636D0172D7FAC85AF9DB57FAE6C7D98B17DE5159

The final result as encryptedStr is:

encryptedStr = Y20Bctf6yFr521f65sfZixfeUVk=

So, in Java I am trying to replicate the same and I assume this can be done by...

  1. Getting SHA1 hash of the String or InputStream (because at VBS code there is an stm object that represents a Stream).

  2. Use some HexToBinary method (by implementing this because by default this method doesn't exist in Java).

  3. Use BASE64Encoder for the binary String from SHA1 hash.

  4. Finally, use Left method from org.apache.commons.lang.StringUtils (replicate of the VBS code) and then output encryptedStr as base64 String.

This is what I've tried so far in Java to at least generate the SHA1 hash (supposed to be the same as hash.Value in VBS:

package my.package;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;

public class SHA1Encrypt {

    public static void main(String[] args) throws Exception {

        String str = "Content-Type: plain/text; name=\"C:\\Users\\Luigi\\Desktop\\hello.txt\"" + "\n" +
                  "Content-Disposition: attachment; filename=\"C:\\Users\\Luigi\\Desktop\\hello.txt\"" + "\n" +
                  "test";

        String SHA1FromString = getSHA1FromString(str);
        String SHA1FromIS = getSHA1FromIS(str);

        System.out.println("SHA1 from String is: " + SHA1FromString.toUpperCase());
        System.out.println("SHA1 from InputStream is: " + SHA1FromIS.toUpperCase());

    }

    public static String getSHA1FromString(String str) throws Exception {
        MessageDigest sha1 = MessageDigest.getInstance("SHA1");
        sha1.update(str.getBytes());
        byte[] digest = sha1.digest();
        return byteArrayToHexString(digest);
    }

    public static String getSHA1FromIS(String str) throws Exception{

        MessageDigest sha1 = MessageDigest.getInstance("SHA1");

        InputStream is = new ByteArrayInputStream(str.getBytes());
        BufferedInputStream bis = new BufferedInputStream(is);
        DigestInputStream   dis = new DigestInputStream(bis, sha1);

        while (dis.read() != -1); 
        byte[] digest = sha1.digest();
        return byteArrayToHexString(digest);
    }

    public static String byteArrayToHexString(byte[] b) {
        String result = "";
        for (int i=0; i < b.length; i++) {
          result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
        }
        return result;
    }

}

The above code will output the following:

SHA1 from String is: 825CA9AF2795F3CCD41EC3B756CC7514E490842F
SHA1 from InputStream is: 825CA9AF2795F3CCD41EC3B756CC7514E490842F

The problem:

  • I am using the same String to be encrypted in both cases (VBS and Java).

  • When I execute VBS code I get this SHA1 hash value from CAPICOM:

    636D0172D7FAC85AF9DB57FAE6C7D98B17DE5159

  • When I execute Java code I get this SHA1 hash value:

    825CA9AF2795F3CCD41EC3B756CC7514E490842F

  • I won't never get the same base64 String as encryptedStr if SHA1 hash is not the same.


My Question:

What I am doing wrong and why did SHA1 hash gets computed different in both cases. Can someone please explain what is happening or what is the correct way to implement this and get the same result in Java?

Just to know, I found this link that helps a little and says that they can get the same hash but doesn't fix the problem for my case:

http://us.generation-nt.com/answer/capicom-hasheddata-java-binary-files-help-44910362.html?page=2

If someone wants to install CAPICOM and test VBS code, you can do the following:

  1. Copy "capicom.dll" to "C:\WINDOWS\system32"
  2. Click on Start/Programs/Accessories/Command Prompt
  3. Type "C:"
  4. Type "cd C:\WINDOWS\system32"
  5. Type "regsvr32.exe capicom.dll"
  6. Click on the "OK" button.
  7. Type "exit"

And download the capicom.dll yourself directly from Microsoft at:

http://www.microsoft.com/downloads/details.aspx?FamilyID=860EE43A-A843-462F-ABB5-FF88EA5896F6&displaylang=en

Was it helpful?

Solution

Solved:

The correct way to express the String is using this way:

String str = "Content-Type: plain/text; name=\"C:\\Users\\Luigi\\Desktop\\hello.txt\"" + "\r\n" +
             "Content-Disposition: attachment; filename=\"C:\\Users\\Luigi\\Desktop\\hello.txt\"" + "\r\n" +
             "test";

instead of \n, we need to use \r\n, then SHA1 hashes will be the same.

Thanks Ansgar Wiechers for exposing this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top