smoky has asked for the wisdom of the Perl Monks concerning the following question:

Hey all, I have this java method which I need to convert:
import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import sun.misc.BASE64Encoder; public class x{ public static String encrypt(String plaintext){ MessageDigest md = null; try{ //Set encryption type, and set text to encrypt md = MessageDigest.getInstance("SHA"); md.update(plaintext.getBytes("UTF-8")); } catch(Exception e) { return ""; } //Encrypt bytes and return value byte raw[] = md.digest(); return (new BASE64Encoder()).encode(raw); }
I managed to get the idea of what it is doing, and how I should implement it in Perl but I just can't quite manage to get the right results.
use Digest::SHA; use utf8; no utf8; use MIME::Base64 qw(encode_base64 decode_base64); $x = "password"; utf8::encode($x); @ascii = unpack("C*", $x); print "UTF-8 : "; foreach $val (@ascii) { print $val; } print "\n"; $sha = Digest::SHA->new; $sha->add(@ascii); @z = unpack("C*",$sha->digest); print "Encrypted Bytes : "; foreach $val (@z) { print $val; } print "\n";
Any ideas?

Replies are listed 'Best First'.
Re: Convert Java to Perl -> Script attached
by moritz (Cardinal) on Mar 03, 2009 at 12:18 UTC
    Afaict it's as simple as
    use Encode qw(encode_utf8); use Digest::SHA1(sha1_base64); my $encoded = sha1_base64(encode_utf8($string));

    But since my java is a bit rusty I might be wrong after all.

      Sweet, cheers !
      Hey Guys, Sorry about the lame reply earlier .. I had to rush off ..
      PERL: UTF-8 : 11297115115119111114100 Encrypted Bytes : 1481382315991371591892351772197193603919425451170179 JAVA: UTF-8 : 11297115115119111114100 Encrypted Bytes : 91-8697-28-55-7163636-1263711108-85127126-26-113-40 Encoded: W6ph5Mm5Pz8GgiULbPgzG37mj9g=
      I can't get the encrypted bytes to match. Ignore the encoded, its what it needs to be eventually.

        I'd go with moritz's solution and simply use Digest::SHA1::sha1_base64(), but just in case you want to know why your attempt didn't work, here's why:

        $sha->add(@ascii);

        should've been

        $sha->add(encode_utf8($x));

        You just need to add the (UTF-8) string itself, not a list of stringified byte values such as "112", "97", "115"...  (i.e. you did compute the digest of the string "11297115115119111114100").

        Also, in your Java code, you're printing out the digest as signed bytes. To get the same behaviour in Perl, you'd need to

        @z = unpack("c*",$sha->digest);

        which would then print out as expected (when adding spaces for better readability (print "@z\n") ):

        91 -86 97 -28 -55 -71 63 63 6 -126 37 11 108 -8 51 27 126 -26 -113 -40
        BTW, here are two quick versions for running: JAVA
        import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import sun.misc.BASE64Encoder; public class enc{ public static void main(String[] args){ String plaintext = "password"; MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); } catch(NoSuchAlgorithmException e) { System.exit(1); } try { //Encoding into UTF-8 System.out.print("UTF-8 : "); for(byte b : plaintext.getBytes("UTF-8")){ System.out.print(b); } System.out.println(); md.update(plaintext.getBytes("UTF-8")); } catch(UnsupportedEncodingException e) { System.exit(1); } byte raw[] = md.digest(); System.out.print("Encrypted Bytes : "); for(byte b : raw){ System.out.print(b); } System.out.println(); String hash = (new BASE64Encoder()).encode(raw); System.out.println("Encoded: " + hash); }}
        PERL
        use Digest::SHA; use utf8; no utf8; use MIME::Base64 qw(encode_base64 decode_base64); $x = "password"; utf8::encode($x); @ascii = unpack("C*", $x); print "UTF-8 : "; foreach $val (@ascii) { print $val; } print "\n"; $sha = Digest::SHA->new; $sha->add(@ascii); @z = unpack("C*",$sha->digest); print "Encrypted Bytes : "; foreach $val (@z) { print $val; } print "\n"; #$x = "jsmith"; #utf8::encode($x); # #print "0. \t\t" . $x . "\n"; #Encrypt, into bytes #@y = $sha->digest; #print "1. \t\t" . $y . "\n"; #Encode #$z = encode_base64($y); #print "2. \t\t" . $z . "\n"; #Print #print "Needs to be: \t5yfRRkrhJDbomacm2lsvEdg4GyY=";
        name them as enc.java and enc.pl ;)
Re: Convert Java to Perl -> Script attached
by roboticus (Chancellor) on Mar 03, 2009 at 11:36 UTC
    smoky:

    You missed having a perfect question by a few items:

    1. What is the Java function returning?
    2. What result are you getting from your Perl function?
    3. What input data are you using?

    Add that to your node, and I'm sure you'll get some good feedback. I didn't see anything obvious, except that you seem to be skipping the base-64 encoding after creating your digest. But I've not used UTF encoding, nor Digest::SHA in any of my perl programs, so I'm not sure.

    ...roboticus
      Hey Roboticus, Thanks for the reply. 1. The java function is returning a String which represents an encoded / encrypted string. The encoding / encryption needs to be perfect to match a legacy system. 2. The Perl program returns a wrong value after trying to SHA the string, I believe. 3. Input data would just be "password"
        What does java myprogram password return? Show the value. Also show what perl myprogram password returns. Wrong value isn't good enough.
        smoky:

        I meant the actual values returned by both the java and perl programs. I can't tell if a change returns the wrong value if I don't know what the right value is. Also, if I were to download your perl program and get it running, I can't tell if it matches the output of the Java program unless I go through the hassle of installing java and getting the java sample to run. By leaving out the java results, you greatly reduce the number of people who are going to bother to try to assist.

        Also, you can often get a hint about a problem based on the data itself without running the program. Some characters couldn't appear in a Base-64 encoding, for example.

        ...roboticus