Google Answers Logo
View Question
 
Q: Converting C++ DES code snippet to Java ( No Answer,   2 Comments )
Question  
Subject: Converting C++ DES code snippet to Java
Category: Computers > Security
Asked by: codingmonkey-ga
List Price: $25.00
Posted: 09 Sep 2004 13:15 PDT
Expires: 09 Oct 2004 13:15 PDT
Question ID: 398998
There is a snippet of C++ DES encryption/decription code which I could use some
help in converting to Java.  Unfortunately I'm not familiar enough with DES to
map the encryption/decription functionality to the appropriate Java JCE routines.

I have included a sample C++ program which contains the encryption and
decription methods, and a corresponding Java program with the empty
encryption and decryption methods.

The two C++ methods which I would like to convert to Java are:

    std::string encrypt(const std::string& str)
    std::string decrypt(const std::string& str)

Here are the Java methods which need to be implemented:

    public static String encrypt(String text)
    public static String decrypt(String text)

The solution should only rely on classes included with JDK 1.4
(e.g. import java.security.*), and not on any 3rd party libraries.  The included
test program contains helper routines for padding the input string and converting
the encoded data to a human-readable string.

The solution should be able to encrypt the string "hello" to
"32:88:DA:F8:D4:8A:91:9C:" and (decrypt it) back.  Basically mapping the
C++ des_cbc_encrypt() method call to the appropriate Java JCE methods.


/********************************* C++ Code **********************************/

#include <iostream>
#include "openssl/des.h"

std::string desPad(const std::string& Pad);
std::string asciiToHexString(const char* ascii, const int length);
std::string hexToAsciiString(const std::string& hex);

std::string encrypt(const std::string& str);
std::string decrypt(const std::string& str);

const int HEX_BUFFER_CHAR_SIZE = 4;

using namespace std;

int main() {

    string text = "hello";
    cout << "text:      " << text.c_str() << endl;

    string encrypted = encrypt(text);
    cout << "encrypted: " << encrypted.c_str() << endl;

    string decrypted = decrypt(encrypted);
    cout << "decrypted: " << decrypted.c_str() << endl;
}

std::string encrypt(const std::string& str) {

    char encrypted_buffer[256];
    string tmp;

    des_cblock key;
    des_cblock initkey;
    des_key_schedule ks;
    
    des_string_to_key("string1", &initkey);
    des_string_to_key("string2", &key);

    key_sched(&key, ks);
    
    memset(encrypted_buffer, 0, sizeof(encrypted_buffer));

    tmp.assign(desPad(str));

    des_cbc_encrypt(reinterpret_cast<const u_char *>(tmp.c_str()),
                    reinterpret_cast<u_char *>(encrypted_buffer),
                    tmp.length(), ks, &initkey, DES_ENCRYPT);

    return asciiToHexString(encrypted_buffer, tmp.length());
}

std::string decrypt(const std::string& text) {

    des_cblock       key = {0};
    des_cblock       initkey = {0};
    des_key_schedule ks = {0};

    u_char encrypted_buffer[256] = {0};
    u_char decrypted_buffer[256] = {0};

    des_string_to_key("string1", &initkey);
    des_string_to_key("string2", &key);

    key_sched(&key, ks);

    string decrypted;

    memset(encrypted_buffer, 0, sizeof(encrypted_buffer));
    memset(decrypted_buffer, 0, sizeof(decrypted_buffer));

    const char* str = hexToAsciiString(text).c_str();
    int length = strlen(str);

    memcpy(encrypted_buffer, str, length);

    des_cbc_encrypt(encrypted_buffer, decrypted_buffer, length,
                    ks, &initkey, DES_DECRYPT);

    decrypted_buffer[length] = 0;
 
    decrypted.assign(reinterpret_cast<char*>(decrypted_buffer));

    int pos = decrypted.find_first_of(" ");
    if (pos != std::string::npos) {
        decrypted.erase(pos);
    }

    return decrypted;
}

std::string desPad(const std::string& Pad) {
    char Spaces[8] = "       ";

    if (Pad.length() % 8) {
        Spaces[8 - (Pad.length() % 8)] = 0;
    } else {
        Spaces[0] = 0;
    }

    return Pad + Spaces;
}

std::string hexToAsciiString(const std::string& hex) {
    std::string asciiConversion;
    int tempHexInt = 0;
    int charPos = 0;

    for (unsigned int i = 0; i < hex.length(); ++i) {
        if (hex[i] == ':') {
            asciiConversion += ' ';
            asciiConversion[charPos] = tempHexInt;
            ++charPos;
            tempHexInt = 0;
        } else {
            tempHexInt *= 0x10;
            tempHexInt += 
                ((isalpha(hex[i])) ? hex[i] - 'A' + 10 : hex[i] - '0');
        }
    }

    return asciiConversion;
}

std::string asciiToHexString(const char* ascii, const int length) {
    std::string hexConversion;
    char tempBuffer[HEX_BUFFER_CHAR_SIZE] = { 0 };

    // Iterate through each character and conver it into hex
    for(int i = 0; i < length; i++) {
        sprintf(tempBuffer,"%02X:",(unsigned char)ascii[i]);
        hexConversion += tempBuffer;
    }

    return hexConversion;
}

/********************************* Java Code **********************************/

public class Test {

    public static void main(String[] args) {

        String input     = "32:88:DA:F8:D4:8A:91:9C:";
        String expected  = "hello";

        String decrypted = decrypt(input);
        System.out.println("decrypted: "+text);

        if (decrypted.equals(expected)) {
            System.out.println("successfully decrypted!");
        }
        
        String encrypted = encrypt(decrypted);
        System.out.println("encrypted: "+text);

        if (encrypted.equals(input)) {
            System.out.println("successfully encrypted!");
        }
    }

    public static String encrypt(String text) {
        /* Implement this method */
    }

    public static String decrypt(String text) {
        /* Implement this method */
    }

    public static String pad(String text) {
        StringBuffer sb = new StringBuffer();
        sb.append(text);

        int count = 8 - (text.length() % 8);
        for (int i = 0; i < count; i++) {
            sb.append(' ');
        }

        return sb.toString();
    }

    public static String asciiToHexString(byte[] bytes)
        throws UnsupportedEncodingException 
    {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < bytes.length; i++) {
            sb.append(Integer.toHexString(0xff & bytes[i])).append(":");
        }

        return sb.toString();
    }

    public static String hexToAsciiString(String hex) {
        if (hex == null || hex.length() == 0) return null;

        String tokens[] = hex.split("[:]");
        byte[] data = new byte[tokens.length];

        for (int i = 0; i < tokens.length; i++) {
            data[i] = (byte)Integer.parseInt(tokens[i], 16);
        }

        return new String(data);
    }
}

/******************************************************************************/

Clarification of Question by codingmonkey-ga on 10 Sep 2004 09:59 PDT
Thank you for taking the time read my question and post a reply.  Definitely
the Java Developers Almanac code samples have been very helpful to me.  Using
the code samples I have been able to DES encrypt (and decrypt) strings.  
Unfortunately however I have not been able to generate the same encrypted 
strings as the C++ code.  Being able to generate the same encrypted strings 
is critical to this project, as we must be able to decrypt (in Java) the previously
encrypted strings (in C++).

The part that I'm missing is how to initialize the Java Cipher and SecretKey
to produce the same encrypted results as the C++ code.

The C++ code uses the following method to encode the string:

    int des_cbc_encrypt(des_cblock *in, des_cblock *out, long length, 
                        des_key_schedule schedule, des_cblock ivec, int encrypt);

So, it is using DES encryption with CBC.  As the input data is always padded
(with spaces to the next 8 bytes), padding should not be necessary (right?).  
Thus I have been initializing the Cipher as follows:

    Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");

Assuming we are initializing the cipher correctly, then all that is left to 
initialize is the secret key.   

The C++ code passes a schedule and initialization vector to the des_cbc_encrypt 
method as follows:

    des_cblock key;
    des_cblock ivec;
    des_key_schedule schedule;
    
    des_string_to_key("string1", &ivec);
    des_string_to_key("string2", &key);

    key_sched(&key, schedule);

    des_cbc_encrypt(in, out, length, schedule, &ivec, DES_ENCRYPT);

How would I create the secret key (in Java) such that it is setup with the
same schedule an initialization vector?

     SecretKey key = KeyGenerator.getInstance(???).generateKey();


Again for reference, the two methods of interest in C++ and Java:

/********************************* C++ Code **********************************/

std::string encrypt(const std::string& str) {

    char encrypted_buffer[256];
    memset(encrypted_buffer, 0, sizeof(encrypted_buffer));

    string tmp;
    tmp.assign(desPad(str));

    des_cblock key;
    des_cblock ivec;
    des_key_schedule schedule;
    
    des_string_to_key("string1", &ivec);
    des_string_to_key("string2", &key);

    key_sched(&key, schedule);

    des_cbc_encrypt(reinterpret_cast<const u_char *>(tmp.c_str()),
                    reinterpret_cast<u_char *>(encrypted_buffer),
                    tmp.length(), schedule, &ivec, DES_ENCRYPT);

    return asciiToHexString(encrypted_buffer, tmp.length());
}

/********************************* Java Code **********************************/

public static String encrypt(String text) {
    try {
    
        byte[] bytes = pad(text).getBytes("ASCII");
    
        // Create the cipher 
        Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
        SecretKey key = KeyGenerator.getInstance("DES").generateKey();
        
        // Initialize the cipher for encryption
        cipher.init(Cipher.ENCRYPT_MODE, key);
        
        // Encrypt the cleartext
        byte[] ciphertext = cipher.doFinal(bytes);

    :    
}

/******************************************************************************/

And also for reference the des_cbc_encrypt man page info:

    http://web.mit.edu/macdev/Development/MITKerberos/MITKerberosLib/DESLib/Documentation/api.html

    int des_cbc_encrypt(des_cblock *in, des_cblock *out, long length, 
                        des_key_schedule schedule, des_cblock ivec, int encrypt);
    
    des_cbc_encrypt() encrypts/decrypts using the cipher-blockchaining mode of DES.

    If the encrypt argument is nonzero, the routine cipher-block-chain
    encrypts the cleartext data pointed to by the in argument into the
    ciphertext pointed to by the out argument, using the key schedule
    provided by the schedule argument, and initialization vector provided
    by the ivec argument. If the length argument is not an integral
    multiple of eight bytes, the last block is copied to a temp and zero
    filled (highest addresses). out is ALWAYS an integral multiple of
    eight bytes.
Answer  
There is no answer at this time.

Comments  
Subject: Re: Converting C++ DES code snippet to Java
From: raistlinmajere-ga on 10 Sep 2004 07:38 PDT
 
public class DesEncrypter {
        Cipher ecipher;
        Cipher dcipher;
    
        DesEncrypter(SecretKey key) {
            try {
                ecipher = Cipher.getInstance("DES");
                dcipher = Cipher.getInstance("DES");
                ecipher.init(Cipher.ENCRYPT_MODE, key);
                dcipher.init(Cipher.DECRYPT_MODE, key);
    
            } catch (javax.crypto.NoSuchPaddingException e) {
            } catch (java.security.NoSuchAlgorithmException e) {
            } catch (java.security.InvalidKeyException e) {
            }
        }
    
        public String encrypt(String str) {
            try {
                // Encode the string into bytes using utf-8
                byte[] utf8 = str.getBytes("UTF8");
    
                // Encrypt
                byte[] enc = ecipher.doFinal(utf8);
    
                // Encode bytes to base64 to get a string
                return new sun.misc.BASE64Encoder().encode(enc);
            } catch (javax.crypto.BadPaddingException e) {
            } catch (IllegalBlockSizeException e) {
            } catch (UnsupportedEncodingException e) {
            } catch (java.io.IOException e) {
            }
            return null;
        }
    
        public String decrypt(String str) {
            try {
                // Decode base64 to get bytes
                byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
    
                // Decrypt
                byte[] utf8 = dcipher.doFinal(dec);
    
                // Decode using utf-8
                return new String(utf8, "UTF8");
            } catch (javax.crypto.BadPaddingException e) {
            } catch (IllegalBlockSizeException e) {
            } catch (UnsupportedEncodingException e) {
            } catch (java.io.IOException e) {
            }
            return null;
        }
    }

Here's an example that uses the class:

    try {
        // Generate a temporary key. In practice, you would save this key.
        // See also e464 Encrypting with DES Using a Pass Phrase.
        SecretKey key = KeyGenerator.getInstance("DES").generateKey();
    
        // Create encrypter/decrypter class
        DesEncrypter encrypter = new DesEncrypter(key);
    
        // Encrypt
        String encrypted = encrypter.encrypt("Don't tell anybody!");
    
        // Decrypt
        String decrypted = encrypter.decrypt(encrypted);
    } catch (Exception e) {
    }
Subject: Re: Converting C++ DES code snippet to Java
From: raistlinmajere-ga on 12 Sep 2004 15:29 PDT
 
I don't think you can recreate the same key. You should save the key
generated by C and pass it to Java, without worrying about security,
because the data is not decryptable without password, even knowing the
key.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy