I am using Perl to perform CBC DES encryption using the Crypt::CBC library:
#!/usr/bin/perl
use Crypt::CBC;
$key = "\x4A\x6F\xC2\x2A\x44\xE2\xA4\x48";
$iv = "\x00\x00\x00\x00\x00\x00\x00\x00";
$data = "\x51\x55\x45\x53\x54\x49\x4F\x4E";
print "TXT->", $data, "\n";
print "HEX->", unpack("H*", $data), "\n";
$cipher = Crypt::CBC->new(-literal_key => 1,
-key => $key,
-iv => $iv,
-header => 'none');
$ciphertext = $cipher->encrypt($data);
print "ENC->", unpack("H*", $ciphertext), "\n";
The output of the code is:
TXT->QUESTION
HEX->5155455354494f4e
ENC->8220553e09f1b31ba7691f3f7fb52416
My data is conveniently of size 64bits (16 hex digits) which is in accordance with the DES standard. According to Wikipedia
DES is the archetypal block cipher — an algorithm that takes a fixed-length string of plaintext bits and transforms it through a series of complicated operations into another ciphertext bitstring of the same length
Why is it that the encoded output is of longer byte length than the original input?
Thanks.
Working backward from the second block (a7691f3f7fb52416) gives 8a285d3601f9bb13, and XORed with the first block (8220553e09f1b31b) gives 0808080808080808 (HEX). Something is producing the block value of 0808080808080808 as a second input block value.
So all you have to do is figure out where the backspace characters came from as a second block input.
See https://metacpan.org/pod/Crypt::CBC
This:
#!/usr/bin/perl
use Crypt::CBC;
$key = "\x4A\x6F\xC2\x2A\x44\xE2\xA4\x48";
$iv = "\x00\x00\x00\x00\x00\x00\x00\x00";
$data = "\x51\x55\x45\x53\x54\x49\x4F\x4E";
print "TXT->", $data, "\n";
print "HEX->", unpack("H*", $data), "\n";
$cipher = Crypt::CBC->new(-literal_key => 1,
-key => $key,
-iv => $iv,
-header => 'none',
-padding => 'null');
$ciphertext = $cipher->encrypt($data);
print "ENC->", unpack("H*", $ciphertext), "\n";
Gave:
david_koontz#Macbook: cbc_des
TXT->QUESTION
HEX->5155455354494f4e
ENC->8220553e09f1b31b
david_koontz#Macbook:
I made the mistake poking around because I know a fair bit about DES, not so much perl.
Adding the padding null seemed to do the trick, after I learned how to add Crypt::CBC and Crypt::DES to a perl library.
I used http://code.google.com/p/dpades/source/browse/trunk/simu_js/JS-DES.html to do the encryptions and decryptions necessary to figure out what's going on. Use the view raw file button and save JS-DES.html locally, open it with a browser.
The encrypted message is longer because it includes the IV. BTW, a fixed IV does not make sense, it should be random and newly generated for each message.
Related
So I'm looking to use SHA-512 with PBKDF2 to implement Bitcoin BIP-039. I have managed to work out that SHA-512 falls under SHA2 but when I specify that as the hashing function, even with 64 byte output, it still reports as using SHA-256. Am I missing something? I tried adding +512 to the hash_class but that didn't work.
#!/usr/bin/perl
#
use Crypt::PBKDF2;
my $sentence="Hellothere";
my $salt="mnemonic";
my $pbkdf2 = Crypt::PBKDF2->new(
hash_class => 'HMACSHA2', #
iterations => 2048, #
output_len => 64, #
);
my $hash = $pbkdf2->generate($sentence,$salt);
print "$hash\n";
Gives
{X-PBKDF2}HMACSHA2+256:AAAIAA:bW5lbW9uaWM=:NLw67sZbhQYsPhrEYm9e5ruslS6/ivK1vDfICtCN07rb7RuBkQxAoZIyTG7sTmsob30JwoP64Fvzpjx6Cqc+KQ==
Passing this to the new() call works.
hash_args=>{sha_size => 512}
{X-PBKDF2}HMACSHA2+512:AAAIAA:bW5lbW9uaWM=:WG00S/OSlPeYJ/HWeIPkVdQHpSXnpzG0Ixb+j70pbgDgdCAemPBLbjYBbcUtnfSS2dzMJng73eAlGSSnDi+dDQ==
use Crypt::KeyDerivation 'pbkdf2';
my $data = pbkdf2("Hellothere", "mnemonic", 2048, 'SHA512', 64);
print unpack("H*", $data), "\n";
(I have already cross posted onto another site and will update either with the solution but so far struggling with an answer)
19th Dec 2013 7:06pm PT --- I found the solution and I updated below.
I am outputting two items of data per line. The first column of data is not fixed length, and I want the second item of data to be correctly aligned in the same position each time so I am using sprintf to format the data and then mail out the data
The print command output illustrates that the data is formatted correctly.
Yet, when the output in my email is different, the alignment is all wrong.
I initially thought it was the mailer (MIME::Lite) program but I am not sure it is.
Reason why I think that is because I using eclipse Perl environment, when I look at the debug variable list, I see that the strings are padded out exactly like the output in my email, yet the print statement shows the data correctly aligned!!!
Please help me understand what is going on here and how to fix it.
use MIME::Lite;
$smtp = "mailserver";
$internal_email_address = 'myemailaddess';
$a = sprintf ("%-60s %-s\n", "the amount for Apple is ","34");
$b = sprintf ("%-60s %-s\n", "the amount for Lemons is", "7");
print $a;
print $b;
$c = $a.$b;
mailer( $internal_email_address,"issue", $c);
sub mailer {
my ( $addr, $subj, $output ) = #_;
print "$_\n" for $addr;
print "$_\n" for $subj;
print "$_\n" for $output;
$msg = MIME::Lite->new(
From => 'xxxx',
To => $addr,
Subject => $subj,
Data => $output
);
MIME::Lite->send( 'smtp', $smtp, Timeout => 60 );
eval { $msg->send };
$mailerror = "Status: ERROR email - MIME::Lite->send failed: $#\n" if $#;
if ( $mailerror eq '' ) {
$status = "Status: Mail sent\n";
}
else {
$status = $mailerror;
}
}
$a = sprintf ("%-10s %-s\n", "the amount for Apple is ","34");
The argument "the amount for Apple is" is too long for the format specifier %-10s, so the actual amount of space used for that argument will be the length of the string.
You could use a format specifier with a larger value (e.g., %-25s) that can accomodate any value you're likely to apply to it.
Or if you want sprintf to truncate the argument at 10 characters, use the format specifier %-10.10s.
How to handle over non-ANSI characters to Crypt::Blowfish in Perl?
The following script was written in charset UTF-8 and fails only on § or ö.
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use utf8;
use Crypt::Blowfish;
my $cipher = Crypt::Blowfish->new( pack 'H16', '12345678' );
my #chars = ( 'a', '§', 'ö', '9' );
printf( "%s: %s",
$_, ( eval { $cipher->encrypt( $_ x 8 ) } ) ? "ok\n" : "fail: $#" )
for ( #chars );
Ciphers work on streams or blocks of bytes, but you aren't providing it with bytes. You are providing it with Unicode cope points.
You need to serialise any text you want to encrypt into bytes before you can encrypt it, which is to say, you need to encode your text.
use Encode qw( encode_utf8 );
my $bytes = encode_utf8($char x 8);
Furthermore, you shouldn't use Crypt::Blowfish directly. That will produce weak encryption. You want to access it through Crypt::CBC. This provides salting, chaining and padding.
use Crypt::CBC qw( );
use Encode qw( encode_utf8 decode_utf8 );
my $cipher = Crypt::CBC->new(
-key => '... key phrase ...',
-cipher => 'Blowfish',
);
my $cipher_bytes = $cipher->encrypt(encode_utf8($plain_text));
my $plain_text = decode_utf8($cipher->decrypt($cipher_bytes));
Many of the Crypt::* modules are block encryption algorithms. So, they can work only with blocks with fixed length. Since '§' is a UTF8 character, it actually contain more than 1 byte, thats why your code is failing. Another issue is that you using use utf8 pragma, which means utf8 constant strings will be created with "utf8 flag". This can lead to big changes in binary algorithms, like encryption.
I'd suggest you to use Crypt::CBC module(check it on the CPAN); and, remove utf8 flag before encryption: utf8::encode($_);
I'm trying to transmit UTF-8 strings in complex data structures with SOAP::Lite. However, as it turns out, SOAP::Lite quietly converts all UTF-8 strings into base-64-encoded octets. The problem with that is that the deserializing does not revert the conversion and only does a straight base64 decode.
This leaves me confused as to how a user is supposed to ensure that they get UTF-8 data from the SOAP::Lite response. Walking the tree and running decode_utf8 on all strings seems wasteful.
Any suggestions?
Edit: In a nutshell, how do i make this test pass without monkey-patching?
I just hit the same problem and found the above discussion useful. As you say in the OP, the problem is that the data is encoded in base64 and the is_utf8 flag get lost. what happens in the serlializer treats any string with a non-ascii character as binary. I got it to do what I wanted by tweaking the serializer as below. It could have odd consequences, but it works in my situation..
use strictures;
use Test::More;
use SOAP::Lite;
use utf8;
use Data::Dumper;
my $data = "mü\x{2013}";
my $ser = SOAP::Serializer->new;
$ser->typelookup->{trick_into_ignoring} = [9, \&utf8::is_utf8 ,'as_utf8_string'];
my $xml = $ser->envelope( freeform => $data );
my ( $cycled ) = values %{ SOAP::Deserializer->deserialize( $xml )->body };
is( length( $data ), length( $cycled ), "UTF-8 string is the same after serializing" );
done_testing;
sub check_utf8 {
my ($val) = #_;
return utf8::is_utf8($val);
}
package SOAP::Serializer;
sub as_utf8_string {
my $self = shift;
my($value, $name, $type, $attr) = #_;
return $self->as_string($value, $name, $type, $attr);
}
1;
The 9 means the utf8 check is performed before the check for non-ascii characters. if the utf8 flag is on then it treats it as a 'normal' string.
Use of is_utf8 (line 278) is evil and wrong. As we can't trust SOAP::Lite with encoding character data properly (to be fair, this code was likely written before word got around in the community how to do this particular kind of string processing), we shall give it octet data only and therefore have to handle encoding/decoding ourself. Pick a single encoding, apply it before handing off data to S::L, reverse it after receiving data.
use utf8;
use strictures;
use Encode qw(decode encode);
use SOAP::Lite qw();
use Test::More;
my $original = 'mü';
my $xml = SOAP::Serializer->envelope(
freeform => encode('UTF-8', $original, Encode::FB_CROAK | Encode::LEAVE_SRC)
);
my ($roundtrip) = map {
decode('UTF-8', $_, Encode::FB_CROAK | Encode::LEAVE_SRC)
} values %{SOAP::Deserializer->deserialize($xml)->body};
is(length($original), length($roundtrip),
'Perl character string round-trips without changing length');
done_testing;
I'm trying to write some Perl to inter operate with hash functions in other languages, namely Java at this point. We have found what is presumably a correct source, RFC 4868 which includes some test keys & strings along with their hashed values. I'm using the following snippet, and can't get Perl to come up with the same result. I can only assume that I'm using it incorrectly—can anyone point me in the right direction?
use Digest::SHA qw(hmac_sha512_hex);
my $key = '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b';
my $value = '4869205468657265';
print hmac_sha512_hex($value, $key);
The output is '4ef7 ... 5d40', though RFC 4868 (and my compatriot's Java implementation) returns '87aa ... 6854'
use Digest::SHA qw(hmac_sha512_hex);
my $key = pack('H*','0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b');
my $value = "Hi There";
print hmac_sha512_hex($value, $key);
Gives
87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854
Quoting RFC:
Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
0b0b0b0b (20 bytes)
Data = 4869205468657265 ("Hi There")
PRF-HMAC-SHA-512 = 87aa7cdea5ef619d4ff0b4241a1d6cb0
2379f4e2ce4ec2787ad0b30545e17cde
daa833b7d6b8a702038b274eaea3f4e4
be9d914eeb61f1702e696c203a126854
P.S. Adding '0x' to the string doesn't make it binary, it makes it start with '0' and 'x' ;-)
The test key needs to be 20 bytes where each byte has the hex value 0x0B, not a string of 40 characters. The test value is the string "Hi There", not the string "4869205468657625". Try this:
use Digest::SHA qw(hmac_sha512_hex);
my $key = "\x0b" x 20;
my $value = 'Hi There';
print hmac_sha512_hex($value, $key) . "\n";