Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / Security / June 2004

Tip: Looking for answers? Try searching our database.

Creating a Private Key from byte array

Thread view: 
Adrian - 02 Jun 2004 16:07 GMT
Hi,

I have a 256 byte array in my code which I have to use a key in a
MD5withRSA hash.
As far as I can tell, in order to use the MD5withRSA algorithm I need
to use the Singature object.
In order to initiate the Signature object, I need a PrivateKey object.

How do I instantiate a PrivateKey object using my byte array?

I have only managed to create a SecretKey object with my byte array,
but the Signature requires a PrivateKey. I can not cast a SecretKey to
a PrivateKey...

What is the easiest way to create and initialze a new PrivateKey?

Thanks,

Adrian
Michael Amling - 03 Jun 2004 03:39 GMT
> Hi,
>
> I have a 256 byte array in my code which I have to use a key in a
> MD5withRSA hash.

  MD5 is a hash algorithm. What is MD5withRSA?

> As far as I can tell, in order to use the MD5withRSA algorithm I need
> to use the Singature object.
> In order to initiate the Signature object, I need a PrivateKey object.

  RSA keys come in pairs. There's a public key that can be given out
freely and used by anyone to verify a signature, and for each public key
there's a corresponding private key that can be used to sign. They have
to be generated in pairs, because it's not feasible to derive a private
key from the corresponding public key.
  Did your 256-byte array come from a program that generates a
public/private RSA key pair? If not, then you're not going to be able to
get an RSA private key from it. Maybe you could tell us what you are
trying to accomplish.

> How do I instantiate a PrivateKey object using my byte array?
>
[quoted text clipped - 7 lines]
>
> Adrian

Signature

--Mike Amling

Adrian - 03 Jun 2004 08:35 GMT
Hi Mike,

Thanks for your reply.

This is what I'm trying to do:

There is an existing c++ application which creates a MAC signature /
hash for a message using the MS CryptoAPI. It calls the
CryptHashMessage method on the API with a hardcoded 256 byte key and
uses szOID_RSA_MD5 as the algorithm. szOID_RSA_MD5 is a constant which
maps to "1.2.840.113549.1.1.4".

The following is a code snippet from the c++ app:

   CRYPT_HASH_MESSAGE_PARA stHashParms;  
    BYTE * paHashBuffer = NULL;
    DWORD dwHashBufferSize = DEFAULT_HASH_BUFFER_SIZE;
    const BYTE* rgpbToBeHashed[3];    
    DWORD rgcbToBeHashed[3];

    DebugTrace(_T("CSecureDataMgr::HashData() has been called. Data
buffer size is (%d) bytes. Context buffer size is (%d)
bytes."),bufBytesData1.m_dwSize,bufBytesData2.m_dwSize);

    // Initialize hashing parameters.
    ZeroMemory(&stHashParms,sizeof(stHashParms));
    ZeroMemory(&rgpbToBeHashed,sizeof(rgpbToBeHashed));
    ZeroMemory(&rgcbToBeHashed,sizeof(rgcbToBeHashed));

    // We want hash the contents of the BSTR
    stHashParms.cbSize = sizeof(stHashParms);
   
    // Set the encoding type.
    stHashParms.dwMsgEncodingType = X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING;

    // Set the cryptographic provider name to null (this will default to
RSA)
    stHashParms.hCryptProv = NULL;

    // set auxillary info to null (we dont use it)
    stHashParms.pvHashAuxInfo = NULL;

    // Set the algorithm used to perform the hashing. Note we opt for RSA
MD5 here.
    stHashParms.HashAlgorithm.pszObjId = szOID_RSA_MD5; //algorithm
    stHashParms.HashAlgorithm.Parameters.cbData = 0;

    while (SUCCEEDED(hr) && (bufHashBuffer.m_pBytes == NULL))
    {
        // initialize hashing buffer structure
        rgpbToBeHashed[0] = g_abCSecureDataMgrKey;  //this is the key
        rgcbToBeHashed[0] = sizeof(g_abCSecureDataMgrKey);
        rgpbToBeHashed[1] = bufBytesData1.m_pBytes;
        rgcbToBeHashed[1] = bufBytesData1.m_dwSize;
        rgpbToBeHashed[2] = bufBytesData2.m_pBytes;
        rgcbToBeHashed[2] = bufBytesData2.m_dwSize;

        //  Allocate and intialize a buffer to receive the hashed value.
        bufHashBuffer.Alloc(dwHashBufferSize);

        // Attempt to hash the message.
        bHashed = CryptHashMessage(&stHashParms,
                                  TRUE,
                                  3,
                                  rgpbToBeHashed,
                                  rgcbToBeHashed,
                                  NULL,
                                  NULL,
                                  bufHashBuffer.m_pBytes,
                                  &dwHashBufferSize);

****************************************************************************

My task is to replicate this exact functionality in Java. (i.e. to be
able to create a MAC for a message in Java, which can then be
re-created by the C++).

I have tried using a Mac object, instantiating it with the same key
and calling the "HmacMD5" algorithm. The hash I receive in Java is
different to the c++ value... I tried doing some tricks like reversing
the byte order and adding a null byte to the end of the message.
Apparently these are well known CryptoAPI -> JCE compatability issues.

My next avenue is to try using the Signature object with the
"MD5withRSA" algorithm (this is one of the algorithms that the IBM JCE
Signature object supports).
In order to create a Signature object in Java, I need a PrivateKey.
However, all I have available to me is the hardcoded 256 byte array
that the C++ app is using.

To be honest I'm not even sure if I'm on the right track here.
"MD5withRSA" sounds very similar to the szOID_RSA_MD5 which the C++ is
using, so I thought its worth a try.

Any suggestions would be greatly appreciated!

Thanks,

Adrian

> > Hi,
> >
[quoted text clipped - 28 lines]
> >
> > Adrian
Michael Amling - 03 Jun 2004 15:04 GMT
> Hi Mike,
>
[quoted text clipped - 4 lines]
> There is an existing c++ application which creates a MAC signature /
> hash for a message using the MS CryptoAPI.

  "MAC", "signature" and "hash" are all different, and it does not pay
to confuse them.
  A hash has no key.
  A MAC has one key, which is used both to form the Message
Authentication Code of a message and to verify the MAC of that message.
  A signature has two keys, a private key which is needed to form the
signature of a message and a public key, which is used to verify the
signature of that message.

> It calls the
> CryptHashMessage method on the API with a hardcoded 256 byte key and
[quoted text clipped - 66 lines]
> able to create a MAC for a message in Java, which can then be
> re-created by the C++).

  Well, let me tell you, I can't tell from looking at this code if it's
finding a hash or a MAC, and if it's a MAC, what the MAC algorithm is.
If it's the HMAC-MD5 algorithm, I would expect that the characters
"hmac" would appear in the source somewhere.
  So, the first step I would take is to make sure we know what
algorithm it is we want to duplicate in Java. If the algorithm is
HMAC-MD5 (which you've mentioned in previous posts) with a 128-bit key,
then the first question is whether the above code puts out hex
0C7F795D3F611FAE11252AE8DDA603D7 as the HMAC-MD5 of the 24-bit message
hex 616263 when the HMAC key is 128 zero bits. I'd follow that with a
couple more experiments to make sure we understand the endian
conventions. E.g., with the 128-bit key hex
00000000000000000000000000000001, the HMAC-MD5 of that same message hex
616263 is hex CC2380E605E833C027928AD3F57646C7.
  If the C++ code puts out something else, then we have to discover
what algorithm it's using.

> I have tried using a Mac object, instantiating it with the same key
> and calling the "HmacMD5" algorithm. The hash I receive in Java is
> different to the c++ value...

  What does your Java implementation say the HMAC-MD5 MAC is for
message hex 616263 with key hex 00000000000000000000000000000000?

> I tried doing some tricks like reversing
> the byte order and adding a null byte to the end of the message.
[quoted text clipped - 6 lines]
> However, all I have available to me is the hardcoded 256 byte array
> that the C++ app is using.

  There are lots of ways to represent an RSA private key. Some just
have a value of d. Some include p and q. Some have the inverses of e mod
p and mod q for use with the Chinese Remainder Theorem. Some include
bits that describe which of d, p, q, e**-1 mod p, e**-1 mod q are
included. It's unlikely you'd be able to take 256 bytes that is
allegedly an RSA private key and use it successfully without knowing its
structure.

> To be honest I'm not even sure if I'm on the right track here.
> "MD5withRSA" sounds very similar to the szOID_RSA_MD5 which the C++ is
[quoted text clipped - 38 lines]
>>>
>>>Adrian

Signature

--Mike Amling

Adrian - 15 Jun 2004 06:16 GMT
> > Hi Mike,
> >
[quoted text clipped - 170 lines]
> >>>
> >>>Adrian

PROBLEM SOLVED!!

After 2 weeks of playing with this I managed to get the correct MD5 in
JCE hash.

These are the steps required:

1) I discovered that callintg CryptHashMessage in the MS Crypto API
with an array of strings to hash, is the same as calling the
CryptCreateHash method multiple times, OR just calling it once with a
concatenated string that contains the concatenated contents of all of
the array elements used in the CryptHashMessage call.

2) Calling CryptHashMessage using szOID_RSA_MD5 as the hash algorithm
corresponds to calling CryptCreateHash using CALG_MD5 (or 32771) as
the algorithm.

3) The difference between doing this in C++ and in Java was that I had
to put an empty byte after each byte of the Java message.

Below is my Java code which produces the same MD5 hash as the C++ code
I posted earlier:

    public String getMD5Hash(String message, byte[] key) throws
IOException, NoSuchAlgorithmException
    {
        //set IBMJCE Provider
        Provider ibmJce = new IBMJCE();
        Security.insertProviderAt(ibmJce, 0);
       
        //create MD5 digest
        MessageDigest md = MessageDigest.getInstance("MD5");

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        java.security.DigestOutputStream dbaos = new
java.security.DigestOutputStream(baos, md);
       
        //put null bytes after each byte in the message
        //this is required to get the same result as the C++ application
        byte[] nulledMessage = new byte[message.getBytes().length * 2] ;   
        for (int i = 0; i < message.getBytes().length; i++)
        {
            nulledMessage[i*2] = message.getBytes()[i];
            nulledMessage[(i*2) + 1] = (byte)0;
        }
       
        //append the key to the beginning of the message
        byte[] concArray = new byte[nulledMessage.length + key.length];
        System.arraycopy (key, 0, concArray, 0, key.length);
        System.arraycopy (nulledMessage, 0, concArray, key.length,
nulledMessage.length);

        dbaos.write(concArray);
        dbaos.close();

        //get the MD5 digest
        byte[] digest = md.digest();
           
        //convert to hex string
        return toHexString(digest);
    }

I hope this helps the next person with this problem.

Happy Hashing,

Adrian


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.