1

Has anyone had good luck encrypting foreign chars with any javascript library?

I am encrypting foreign characters using jCryption v. 1.4 library (RSA algo). Looks like the library does not work well with foreign characters (I am using cp1251). The encryption works well with ASCII/english chars, but I get garbled chars after decryption of foreign ones.

I believe the problem comes from the way jCryption converts char string to bytes. It shifts the char by 8 bits only and &'s 2 char together. The foreign chars occupy > 8 bits for sure.

Any ideas would be appreciated!
Dmitriy

neubert
  • 15,947
  • 24
  • 120
  • 212
dilit
  • 53
  • 1
  • 8
  • *"The foreign chars occupy > 8 bits for sure."* Indeed, JavaScript uses [16-bit characters](http://es5.github.com/#x8.4). Specifically, JavaScript "strings" are serieses of UTF-16 code units. So a "character" in JavaScript may actually be only part of a character (if it happens to be a character that requires more than one 16-bit code unit to represent). – T.J. Crowder Feb 24 '12 at 22:46
  • 1
    FYI, UTF-16 does not mean that there are only 16 bits per char. Could be 32 bits too. http://en.wikipedia.org/wiki/UTF-16 – dilit Feb 24 '12 at 23:16
  • `@user1231558`: Again: *"if it happens to be a character that requires more than one 16-bit code unit to represent"* That was actually my point. – T.J. Crowder Feb 24 '12 at 23:23

2 Answers2

1

You could first try to base64 encode your message and then encrypting. This will make sure the input only has ascii characters.

So your algorithm would probably be something like this pseudo code.

Encryption
input = "text";
input = base64Encode(input); //there's lots of implementations of this online
cipher = encodeWithJcrypt(input);

Decryption
text = decodeWithJcrypt(cipher);
text = base64Decode(text);
KDV
  • 730
  • 1
  • 6
  • 12
  • Ahhh, smart!! That just might do it. Gotta love this community! Thank you so much for your prompt response. I will try it and report it here. – dilit Feb 24 '12 at 23:12
  • I don't know, encryption only handles plain text as bytes, it does not care about encoding. It's more likely that either the result of the encoding interpreted wrong (the receiving end uses a different character encoding) or that the cipher text has become garbled because it was handled as text. Normally you only need to base 64 encode the cipher text, it is enough to mandate a specific character-encoding for the plain text. – Maarten Bodewes Feb 24 '12 at 23:40
  • Actually JCryption 2.0 works without doing anything else. Your approach is totally valid though. I am sure it is going to work too. Thank you very much. – dilit Feb 25 '12 at 00:51
  • This was totally it man! The only thing I had to do is implement Base64 algorithm for 16-bit chars. Both JCryption and Apache Base64 are for 8 bit chars. – dilit Feb 26 '12 at 01:26
  • Another way to do this is encode into UTF-8. Eg. javascript: encodeURIComponent(usrVal); // convert to utf-8 And on java side UrlDecoder.decode(reqParam, “UTF-8”) – dilit Mar 03 '12 at 21:23
1

Here is the base64 encode for 16-bit Unicode chars(javascript):

var Base64 = {};  // Base64 namespace

Base64.code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

Base64.encode = function(str) { 
    var o1, o2, bits, h1, h2, h3, h4, h5, d6, e=[], pad = '', c, plain, coded;
    var b64 = Base64.code;

    plain = str;

    c = plain.length % 2;  // pad string to length of multiple of 3
    if (c > 0) { while (c++ < 2) { pad += '==='; plain += '\0'; } }

    for (c=0; c<plain.length; c+=2) {  // pack 2 hexadecets into 6 hexets
        o1 = plain.charCodeAt(c);
        o2 = plain.charCodeAt(c+1);

        bits = o1<<16 | o2;

        h1 = bits>>26 & 0x3f;
        h2 = bits>>20 & 0x3f;
        h3 = bits>>14 & 0x3f;
        h4 = bits>>8 & 0x3f;
        h5 = bits>>2 & 0x3f;
        d6 = bits & 0x3;

        // use hextets to index into code string
        e[c/2] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4)
            + b64.charAt(h5) + b64.charAt(d6);
    }
    coded = e.join('');  // join() is far faster than repeated string concatenation in IE

    // replace 'A's from padded nulls with '='s
    coded = coded.slice(0, coded.length-pad.length) + pad;

    return coded;
}

Here is base64 decode for 16-bit unicode chars (java):

private static String BASE64_CODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
private String decodeBase64(String b64Str) {
    try {
        String decodedBase64 = "";

        for (int c = 0, b=0; c < b64Str.length(); c+=6, b+=4) {
            // unpack 5 hexets and 2-bit into 4 octets
            int h1 = BASE64_CODE.indexOf(b64Str.charAt(c));
            int h2 = BASE64_CODE.indexOf(b64Str.charAt(c + 1));
            int h3 = BASE64_CODE.indexOf(b64Str.charAt(c + 2));
            int h4 = BASE64_CODE.indexOf(b64Str.charAt(c + 3));
            int h5 = BASE64_CODE.indexOf(b64Str.charAt(c + 4));
            int d6 = BASE64_CODE.indexOf(b64Str.charAt(c + 5));

            int bits =  h1<<26 |  h2<<20 |  h3<<14 | h4<<8 | h5<<2 | (d6 & 0x3);
            byte o1 = (byte) (bits>>>24 & 0xff);
            byte o2 = (byte) (bits>>>16 & 0xff);
            byte o3 = (byte) (bits>>>8 & 0xff);
            byte o4 = (byte) (bits & 0xff);

            String partialDecodedStr = new String(new byte[] {o1, o2}, "UTF-16");

            //take care of padding
            // - if BASE64_CODE.indexOf(b64Str.charAt(c + 3)) == 64 OR b64Str.charAt(c + 3) == '='
            if (h4 == 0x40) {
               //This 16-bit char was padding: get rid of it
            }
            else
                partialDecodedStr = partialDecodedStr.concat(new String(new byte[] {o3, o4}, "UTF-16"));

            decodedBase64 = decodedBase64.concat( partialDecodedStr);
        }

    return decodedBase64;
}
catch (UnsupportedEncodingException e) {
    //TODO log4j
    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    throw new RuntimeException("Unable to decode base64.");
}
}
Peter O.
  • 32,158
  • 14
  • 82
  • 96
dilit
  • 53
  • 1
  • 8