PHP implementing Ciphertext Stealing (CTS) with CBC - php

I have been trying to implement Ciphertext Stealing(CTS) in PHP for CBC.
Referring below two links
How can I encrypt/decrypt data using AES CBC+CTS (ciphertext stealing) mode in PHP?
and
http://en.wikipedia.org/wiki/Ciphertext_stealing
I am confused and stuck on the last and simplest step of XOR.
I know this is silly but having tried all the combinations, i don't know what am i missing.
Code follows.
// 1. Decrypt the second to last ciphertext block, using zeros as IV.
$second_to_last_cipher_block = substr($cipher_text, strlen($cipher_text) - 32, 16);
$second_to_last_plain = #mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $second_to_last_cipher_block, MCRYPT_MODE_CBC);
// 2. Pad the ciphertext to the nearest multiple of the block size using the last B-M
// bits of block cipher decryption of the second-to-last ciphertext block.
$n = 16 - (strlen($cipher_text) % 16);
$cipher_text .= substr($second_to_last_plain, -$n);
// 3. Swap the last two ciphertext blocks.
$cipher_block_last = substr($cipher_text, -16);
$cipher_block_second_last = substr($cipher_text, -32, 16);
$cipher_text = substr($cipher_text, 0, -32) . $cipher_block_last . $cipher_block_second_last;
// 4. Decrypt the ciphertext using the standard CBC mode up to the last block.
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($cipher, $key, $iv);
$plain_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher_text, MCRYPT_MODE_CBC , $iv);
// 5. Exclusive-OR the last ciphertext (was already decrypted in step 1) with the second last ciphertext.
// ???
// echo $??? ^ $???;

I find that concrete use cases are very helpful in understanding algorithms. Here are 2 use cases, and a step-by-step walk-through.
Starting point for both Use Cases.
These Use Cases assume that you are decrypting messages uses AES-256 with CBC chaining mode and ciphertext stealing for block quantisation. To generate these Use Cases, I used Delphi 2010 compiler and the TurboPower LockBox3 library (SVN revision 243). In what follows, I use a notation like so...
IV := [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
... to mean that some variable named 'IV' is assigned to be equal to an array of 16 bytes. The left most byte, is the rendering of the Least Signficant (lowest address) byte of the array, and the right-most byte, the most significant. These bytes are written in hexadecimal, so for example if one puts...
X := [2] 03 10
... it means that the LSB is 3 and the MSB is 16.
Use Case One
Let the AES-256 32 byte compressed key (as defined in the AES standard) be...
key = [32] 0D EE 8F 9F 8B 0B D4 A1 17 59 FA 05 FA 2B 65 4F 23 00 29 26 0D EE 8F 9F 8B 0B D4 A1 17 59 FA 05
With TurboPower LockBox 3, this can be achieved by setting the password ('UTF8Password') property of the TCodec component to...
password = (UTF-8) 'Your lips are smoother than vasoline.'
The plaintext message to be sent will be
Message = (UTF-8) 'Leeeeeeeeeroy Jenkins!'
Encoded this is 22 bytes long. AES-256 has a 16 byte block size, so this is some-where between 1 and 2 blocks long.
Let the IV be 1. (Aside: On the Delphi side, this can be achieved by setting
TRandomStream.Instance.Seed := 1;
just before encryption).
Thus the ciphertext message to be decrypted by PHP will be (with 8 byte IV prepended a la LockBox3) ...
ciphertext = [30] 01 00 00 00 00 00 00 00 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5 1D 66 DB 97 2E 2C
(base64 equivalent ='AQAAAAAAAAAXXMCX/+9jWoiDbABiv4flHWbbly4s')
Breaking this down into IV, first ciphertext block (c[0]) and last (partial) ciphertext block (c[ 1])...
IV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5
c[1] = [6] 1D 66 DB 97 2E 2C
Now let's walk-through the decryption with ciphertext stealing.
CV := IV
CV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
In general, the for n'th block (except for the last 2 blocks), our normal CBC algorithm is...
m[n] := Decrypt( c[n]) XOR CV;
CV[n+1] := c[n]
where:
m is the output plaintext block;
Decrypt() means AES-256 ECB decryption on that block;
CV is our Carry-Vector. The chaining mode defines how this changes from block to block.
but for the second last block (N-1) (N=2 in Use Case One), the transformation changes to ... (This exception is made due to the selection of ciphertext stealing)
m[n] := Decrypt( c[n]) XOR CV;
CV[n+1] := CV[n] // Unchanged!
Applying to our use case:
CV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5
Decrypt(c[0]) = [16] 6F 6B 69 6E 73 21 F0 7B 79 F2 AF 27 B1 52 D6 0B
m[0] := Decrypt(c[0]) XOR CV = [16] 6E 6B 69 6E 73 21 F0 7B 79 F2 AF 27 B1 52 D6 0B
Now to process the last block. It is a partial one, 6 bytes long. In general, the processing of the last block goes like this...
y := c[N-1] | LastBytes( m[N-2], BlockSize-Length(c[N-1]));
m[N-1] := Decrypt( y) XOR CV
Applying to Use Case One:
c[1] = [6] 1D 66 DB 97 2E 2C
y := c[1] | LastBytes( m[0], 10)
y = [16] 1D 66 DB 97 2E 2C F0 7B 79 F2 AF 27 B1 52 D6 0B
Decrypt( y) = [16]= 4D 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65
m[1] := Decrypt(y) XOR CV
m[1] = [16] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65
The last step in the decryption process is the emission of the last two blocks. We reverse the order, emitting m[N-1] first, and then emit the first part of m[N-2] (the length of which is equal to the length of c[N-1]). Applying to Use Case One...
Emit m[ 1]
m[1] = [16] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65
Emit the first 6 bytes of m[0]
FirstBytes( m[0], 6) = 6E 6B 69 6E 73 21
Putting it altogether, we get a reconstructed plaintext of ...
[22] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65 6E 6B 69 6E 73 21
which is the UTF-8 encoding of 'Leeeeeeeeeroy Jenkins!'
Use Case Two
In this use case, the message is precisely 2 blocks long. This is called the round case. In round cases, there is no partial block to quantise, so it proceeds as if it were normal CBC. The password, key and IV are the same as in Use Case One. The ciphertext message to be decrypted (included prepended 8 byte IV) is...
Set-up
Ciphertext = [40] 01 00 00 00 00 00 00 00 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83
which is encoded base64 as 'AQAAAAAAAABwdhJYTjgc4ZLKNPuaN8UKdfILRqHfVmDUXHZLUhnagw=='
This breaks down into IV, first block and second block, like so...
IV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A
c[1] = [16] 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83
General and 2nd last block
Decrypt(c[0]) = [16] 45 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
m[0] := Decrypt(c[0]) XOR CV = [16] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
Next CV := c[0] = [16] 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A
Last Block:
Our last block is round in this use case.
Decrypt(c[1]) = [16] 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83
m[1] := Decrypt(c[1]) XOR CV = [16] 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65
The last step in the decryption process is the emission of the last two blocks. In the round case, we don't reverse the order. We emit m[N-2] first, and then m[N-1]. Applying to Use Case Two...
Emit m[0]
m[0] = [16] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
Emit the whole of m1
m[1] = [16] 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65
Putting it altogether, we get a reconstructed plaintext of ...
[32] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65
which is the UTF-8 encoding of 'Dance then, whereever you may be'
Edge Cases to consider.
There are two edge cases, not illustrated by the two Use Cases provided here.
Short messages. A short message is a message, whose length in bytes is:
Not zero; and
Less than one block;
Zero length messages.
In the case of short messages, technically one could still implement ciphertext stealing by using the the IV as the prior block of ciphertext. However, IMHO, this use of ciphertext stealing, in this way, is not justified by lack of research into the impact on cryptographic strength, not to mention the added implementation complexity. In TurboPower LockBox 3, when the message is a short message, and the chaining mode is not a key-streaming one, then the chaining mode is treated as CFB-8bit. CFB-8 bit is a key-streaming mode.
In the case of zero-length messages, its really simple. Zero-length plaintext message maps one-to-one to zero-length ciphertext messages. No IV is needed, generated nor prepended. This mapping is independent of chaining mode and cipher (in the case of block mode ciphers).
Notes on PHP Implementation
Caveat
I am not a PHP programmer. I don't know PHP. Any thing I say here should be taken with a grain of salt.
Arrays of bytes
It looks like you are using PHP strings to store arrays of bytes. This looks dangerous to me. What if one of the byte values was zero? Would that shorten the string? How would strlen() behave in that case? If PHP has a native data type which was an array of byte, then this probably would be safer. But I don't really know. I am just bringing this point to your attention, if you are not already aware of it. Possibly it is not really an issue.
mcrypt_decrypt library
I am not familiar with this library. Does it natively support ciphertext stealing? I assume not. So there are two possible strategies for you.
Call the library's decrypt for all but the last two blocks with CBC mode. Process the last two blocks as I have described to you. But this requires access to the CV. Does the API expose this? If not, the this strategy is not a viable option for you.
Call the library's decrypt for all but the last two blocks with ECB mode, and roll your CBC chaining. Fairly easy to implement, and be definition, you have access to the CV.
How to do XOR in PHP
Some-one else posted an answer to this question, but has currently withdrawn it. But he was right. It looks like to do an XOR in PHP on an array of bytes, iterate through the characters, one by one, and do a byte level XOR. The technique is shown here.

I was looking for a similar answer for perl. Perl's libraries were limited to CBC mode. Here's how I got CTS to work using AES 256 CBC mode and CTS method 3. I thought this may be helpful for PHP as well.
Here's the actual NIST documentation.
Doc ID: NIST800-38A CBC-CS3
Title: �Recommendation for Block Cipher Modes of Operation; Three Variants of Ciphertext Stealing for CBC Mode�
Source: http://csrc.nist.gov/publications/nistpubs/800-38a/addendum-to-nist_sp800-38A.pdf
Here's the code...
use Crypt::CBC;
use Crypt::Cipher::AES;
my $key = pack("H*","0000000000000000000000000000000000000000000000000000000000000000");
my $iv = pack("H*","00000000000000000000000000000000");
my $pt = pack("H*","0000000000000000000000000000000000");
my $ct = aes256_cbc_cts_decrypt( $key, $iv, $pt );
#AES 256 CBC with CTS
sub aes256_cbc_cts_decrypt {
my ($key, $iv, $in) = #_;
my $len_in_bytes = length(unpack("H*", $in)) / 2;
my $in_idx = 0;
my $null_iv = pack( "H32", "00000000000000000000000000000000");
my $cipher = Crypt::CBC->new(
-key => $key,
-iv => $null_iv,
-literal_key => '1',
-keysize => 32,
-blocksize => 16,
-header => 'none',
-cipher => 'Crypt::Cipher::AES');
my $out;
while ( $len_in_bytes >= 16 )
{
my $tmp = substr($in, $in_idx, 16);
my $outblock = $cipher->decrypt($tmp);
if ( ( ($len_in_bytes % 16) eq 0 ) || ( $len_in_bytes > 32 ) )
{
$outblock = $outblock ^ $iv;
$iv = $tmp;
}
$out .= $outblock;
$in_idx += 16;
$len_in_bytes -= 16;
}
if ($len_in_bytes) {
my $tmp = substr($in,$in_idx,$len_in_bytes);
my $out_idx = $in_idx - 16;
$tmp .= substr($out,$out_idx + $len_in_bytes, 16 - $len_in_bytes);
$out .= substr($out, $out_idx, $len_in_bytes) ^ substr($tmp, 0, $len_in_bytes);
substr($out,$out_idx,16) = $iv ^ $cipher->decrypt($tmp);
}
return $out;
}

Related

PHP hmac_hash of 1B constant whit fixed value 1

im trying to solve some code for authorization to remote service, in "manual" they ask me to generate some keys by hash hmac_sha256, auth codes and etc. First key i should generate is:
key1 = Hmac_Sha256(shared_key, 0x01) where 0x01 is 1B constant (whit fixed value 1) key1 will be used as encryption key (32B)
question is how to write 1B constant 0x01 in PHP?
I got this from developers to test code:
shared_key (base64)
bRtFEufmEgrJyhai6ltDSV9svtpN3Jb/5oWBBYhDJ30=
in hex:
6D 1B 45 12 E7 E6 12 0A C9 CA 16 A2 EA 5B 43 49
5F 6C BE DA 4D DC 96 FF E6 85 81 05 88 43 27 7D
and generated key1 should by:
DE B5 81 AB EC C4 A5 A5 5D C7 6C 08 A9 75 49 62
BD A0 54 10 E1 A3 0D 5E 99 05 AD FA 65 6C F2 C9
mine current code is
<?php
define('bit_1', 0x01);
$shared_key = 'bRtFEufmEgrJyhai6ltDSV9svtpN3Jb/5oWBBYhDJ30=';
$shared_key = base64_decode($shared_key); //HEX is correct
$key1 = hash_hmac('sha256', bit_1, $shared_key, true); //HEX is wrong
//7C 07 BE BD FA 97 70 7A 0C 41 CF 9A 4D 1E B0 68
//9D A8 52 FE D4 D8 E7 CC C5 0C 61 F8 7A B0 B5 19
i also tryed bit_1 as (int)1, (string)'1' all produce same wrong key1, thanks for any advice.
0x01 is hexadecimal notation to create an int, which is more than 1 byte. What you want is to express raw bytes directly, for which you use a string in PHP (strings are mere byte arrays):
"\x01"
You can write byte literals with the \xXY notation. In you case: "\x01".
There are also some other ways. For example: pack("H*", "01") and pack("C*", 1)

The AES encryption in php and C use openssl library

I want to encrypt some fix length (512bytes) data by AES encryption algorithm in PHP and later decrypt it in C.
The PHP code looks like below.
$plaintext = "..."; // 512bytes.
$iv = "..."; // 128bits long;
$password = "..."; // 128bits long;
$ciphertext = openssl_encrypt ($plaintext, 'aes-256-cbc', $password, true, $iv);
Then, I write the cipher text in a file, in turn open it by a C program whose source code looks same as the one on this page.
But, luckily, it doesn't working. The output of the C program is something unreadable.
Can anyone tell me what's wrong, and is there an alternative way to fulfil this mission?
UPDATES:
The full PHP code here:
<?php
$string = 'The quick brown fox jumps over the lazy dog';
$pass = '01234567890123456789012345678901';
$iv = 'NiceToMeetYou^-^';
$method = 'aes-256-cbc';
file_put_contents ('./file.encrypted', openssl_encrypt ($string, $method, $pass, TRUE, $iv));
?>
The C code is totally same as this page, except the iv which is changed to NiceToMeetYou^-^.
The PHP's output is
00000000 11 58 bf 4e 1c f7 ff f5 56 dc 9b 01 32 fe 16 66 |.X.N....V...2..f|
00000010 4b aa 0f ca e1 b7 a8 5f c8 64 83 bf d6 88 02 59 |K......_.d.....Y|
00000020 26 0a 62 00 27 2d 78 b4 70 82 d4 9a ac bf 1b c7 |&.b.'-x.p.......|
The file generated by C program is:
0000 - 67 95 70 57 7d d4 52 49-fc 5d 2a 06 3d 66 ef 21 g.pW}.RI.]*.=f.!
0010 - 57 0d e0 cf aa b9 c0 71-b5 ad 0e 0b 56 26 6b 2e W......q....V&k.
0020 - aa 99 4f 47 2e 6e 08 d7-ec f1 bf a0 8e f3 0d 0a ..OG.n..........

Abnormally long RSA-signed key length

I am currently maintaining an Alipay URL-generation library, and there are some interesting things going on in this code snippet (other than the massively confusing naming schemes and function placements)..
I have a function that builds a URL (using create_linkstring()) + its RSA-signed (sign()) counterpart:
function build_mysign($sort_array,$key,$sign_type) {
$prestr = create_linkstring($sort_array);
$prestr = $prestr.$key;
$mysgin = sign($prestr,$sign_type);
return $mysgin;
}
This is my create_linkstring() method:
function create_linkstring($array) {
$arg = "";
while (list ($key, $val) = each ($array)) {
$arg.=$key."=".$val."&";
}
$arg = substr($arg,0,count($arg)-2);
return $arg;
}
This is my sign() function:
function sign($prestr){
$fprivate = fopen(dirname(__FILE__) . '/rsa_private_key.pem', 'r');
$priv_key = fread($fprivate, 123456);
fclose($fprivate);
$privatekeyid = openssl_get_privatekey($priv_key);
// Compute signature
openssl_sign($prestr, $signMsg, $privatekeyid, OPENSSL_ALGO_SHA1);
// Free the key from memory
openssl_free_key($privatekeyid);
$signMsg = base64_encode($signMsg);
return $signMsg;
}
It basically takes an array of keys and values and generates a URL, which then gets signed using the sign() method.
This library actually has two signing mechanisms - MD5 and RSA. I wrote the RSA-signing function, since it wasn't supported by default. Looking at the output URL of using the MD5-signing, the sign= is a 32 char string, so it looks like this sign=779d70d2b4d9b50cad3a4ce144726e9f.
However, using my RSA-signing function, the output is a 172 char string! The input looks like this:
&sign=WiYQIl0x+Vkey3SciP03HDv/7IZKoq2+OcvsSlQJb3NMElG6JawRc5b98ddJOOYjt9YK2YypwlFWgizj0b5wk+HNJB5lSYq7rDCcDGG0m0cKbW/m9P23J8gQaR1x6RovEDaWhs5zv4YTFe83hmPaf4Q/eVa2CpiixjpHd3kjybg=
If I am not wrong, RSA-signed strings should be 128 chars long. I'm not quite sure why that is happening. I'm not 100% if I am appending it with extraneous strings, and I notice that all the RSA-signed keys end with a = which definitely isn't right.
I guess you are confusing the byte length of the RSA signature with the string length of the base64 encoding of the signature.
If you are using a 1024 bit RSA key (a bit short, btw.), the byte length of the signature should be 128 bytes long. The bytes can be of any value, including 0 and other characters that are not printable with UTF-8 or ASCII (and many more that are not good for use in URLs etc.). Thus your code encodes the bytes in base64. The size of 172 characters (including the padding =) is just right: 128bytes / 1024bits
$ echo WiYQIl0x+Vkey3SciP03HDv/7IZKoq2+OcvsSlQJb3NMElG6JawRc5b98ddJOOYjt9YK2YypwlFWgizj0b5wk+HNJB5lSYq7rDCcDGG0m0cKbW/m9P23J8gQaR1x6RovEDaWhs5zv4YTFe83hmPaf4Q/eVa2CpiixjpHd3kjybg= \
| base64 --decode | hexdump -C
00000000 5a 26 10 22 5d 31 f9 59 1e cb 74 9c 88 fd 37 1c |Z&."]1.Y..t...7.|
00000010 3b ff ec 86 4a a2 ad be 39 cb ec 4a 54 09 6f 73 |;...J...9..JT.os|
00000020 4c 12 51 ba 25 ac 11 73 96 fd f1 d7 49 38 e6 23 |L.Q.%..s....I8.#|
00000030 b7 d6 0a d9 8c a9 c2 51 56 82 2c e3 d1 be 70 93 |.......QV.,...p.|
00000040 e1 cd 24 1e 65 49 8a bb ac 30 9c 0c 61 b4 9b 47 |..$.eI...0..a..G|
00000050 0a 6d 6f e6 f4 fd b7 27 c8 10 69 1d 71 e9 1a 2f |.mo....'..i.q../|
00000060 10 36 96 86 ce 73 bf 86 13 15 ef 37 86 63 da 7f |.6...s.....7.c..|
00000070 84 3f 79 56 b6 0a 98 a2 c6 3a 47 77 79 23 c9 b8 |.?yV.....:Gwy#..|
00000080

Encryption using Rijndael AES using 128 bit keys, 16 byte blocks and cipher block chaining

In our project, I must use the Algorithm AES 128 CBC with the following data:
KEY = "abcdef0123456789abcdef0123456789"
IV = "00000000000000000000000000000000"
The text to encryt is
2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~
The result expected is
0D 58 35 AF EB EE 04 C6 DC 24 21 53 8D B7 C3 8A 12 83 97 0E B3 1F 21 A4 7D 2E 3C C6 23 D2 9E F0 46 12 79 C7 AC F9 3B 03 1B E2 B6 9C E4 5C 93 39 55 49 57 F2 9E F6 09 F0 19 EE C9 75 98 3A 03 B5 37 62 2D 7E 0F 19 6B E1 48 F1 C7 CB B8 8E 60 2A
The result text's length is 160 characters.
I tried using many algorithms but all my results are different.
would you encrypt the text with your own method and you validate with the expected result?
Would you paste your results?
This is my test:
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$data_to_encrypt = "2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~";
$key128 = "abcdef0123456789abcdef0123456789";
$iv = "0000000000000000"."0000000000000000";
echo "data_to_encrypt: ".$data_to_encrypt."<br/>";
if (($res = mcrypt_generic_init($cipher, $key128, $iv)) != -1)
{
// PHP pads with NULL bytes if $cleartext is not a multiple of the block size.
$cipherText = mcrypt_generic($cipher,$data_to_encrypt);
mcrypt_generic_deinit($cipher);
$data_encrypted = strtoupper(bin2hex($cipherText));
echo "result encrypt: ".$data_encrypted."<br/>";
echo "len: ".strlen($data_encrypted)."<br/>";
}
This is my answer:
data_to_encrypt: 2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~
result encrypt: C9A4E600BAC6FC4F2077FF62DDB5F9BEAB1C9C567A98E6B81373711A4BC0FFE1748F5E26886896AB87CD375567C5466E6A9F4C079AD19B592E080896BCFDB52324F342A9F94AE71FADB1F6820EB57F7B
len: 160
Thanks in advance for your help and time.
This C program gives the correct result:
#include <stdio.h>
#include <openssl/aes.h>
int main()
{
unsigned char key[16] = {0xab,0xcd,0xef,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67,0x89};
unsigned char iv[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned char plaintext[] = {
'2','~','1','~','0','0','0','0','2','4','~','0','9','1','0','~',
'2','0','1','3','0','7','2','3','0','9','2','4','4','6','~','T',
'~','0','0','0','0','2','0','0','0','~','U','S','D','~','F','~',
'3','7','5','0','1','9','0','0','1','0','1','2','1','2','0','~',
'0','~','0','~','0','0','0','0','0','0','0','0','0','0','0','~',
};
unsigned char ciphertext[sizeof(plaintext)];
AES_KEY aes;
size_t i;
AES_set_encrypt_key(key,128,&aes);
AES_cbc_encrypt(plaintext,ciphertext,sizeof(plaintext),&aes,iv,AES_ENCRYPT);
for(i=0; i<sizeof(ciphertext); i++) {
printf("%02x ", ciphertext[i]);
}
printf("\n");
return 0;
}
gcc -o test test.c -lcrypto
./test
0d 58 35 af eb ee 04 c6 dc 24 21 53 8d b7 c3 8a 12 83 97 0e b3 1f 21 a4 7d 2e 3c c6 23 d2 9e f0 46 12 79 c7 ac f9 3b 03 1b e2 b6 9c e4 5c 93 39 55 49 57 f2 9e f6 09 f0 19 ee c9 75 98 3a 03 b5 37 62 2d 7e 0f 19 6b e1 48 f1 c7 cb b8 8e 60 2a
Your problem is that you need to de-hexify your key and IV strings into bytes before using them.
Firstly, I want to thank to all people that send to me one advice,
Now, I share with you the solution to my question,
I hope it also helps to anyone,
<?php
function hex2bin($hex_string) {
return pack('H*', $hex_string);
}
$data_to_encrypt = '2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~';
$key = 'abcdef0123456789abcdef0123456789';
$iv = '0000000000000000';
$key = hex2bin($key);
$iv = hex2bin($iv);
$data_encrypted = bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data_to_encrypt, MCRYPT_MODE_CBC, $iv));
echo "Data encrypted: ".strtoupper($data_encrypted)."<br/>";
echo "Length: ".strlen($data_encrypted)."<br/>";
?>
Data encrypted: 0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A
Length: 160
God bless you

How do I sha1 hash hex values correctly in PHP?

I have a series of hex bytes. Theoretically, the last 20 bytes are the sha1 hash of the first part:
3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00 BD 0D EA 71 BE 0B 25 75 E7 5C 58 20 31 57 F3 9A EF 69 1B FD
If I apply sha1 to them in PHP like this:
echo sha1("3FF4E525982052700163006800750079006900000074289610099DC9010074A0D7DB0B9DC9014D007900470072006F007500700000002F000000");
I get back:
d68ca0839df6e5ac7069cc548d82f249752f3acb
But I'm looking for this value:
bd0dea71be0b2575e75c58203157f39aef691bfd
(BD 0D EA 71 BE 0B 25 75 E7 5C 58 20 31 57 F3 9A EF 69 1B FD)
Is it because I'm treating the hex values as a string? What do I need to do?
Edit:
Here's the original information I am working from:
ticketBytes
{byte[0x0000003a]}
[0x00000000]: 0x3f
[0x00000001]: 0xf4
[0x00000002]: 0xe5
[0x00000003]: 0x25
[0x00000004]: 0x98
[0x00000005]: 0x20
[0x00000006]: 0x52
[0x00000007]: 0x70
[0x00000008]: 0x01
[0x00000009]: 0x63
[0x0000000a]: 0x00
[0x0000000b]: 0x68
[0x0000000c]: 0x00
[0x0000000d]: 0x75
[0x0000000e]: 0x00
[0x0000000f]: 0x79
[0x00000010]: 0x00
[0x00000011]: 0x69
[0x00000012]: 0x00
[0x00000013]: 0x00
[0x00000014]: 0x00
[0x00000015]: 0x74
[0x00000016]: 0x28
[0x00000017]: 0x96
[0x00000018]: 0x10
[0x00000019]: 0x09
[0x0000001a]: 0x9d
[0x0000001b]: 0xc9
[0x0000001c]: 0x01
[0x0000001d]: 0x00
[0x0000001e]: 0x74
[0x0000001f]: 0xa0
[0x00000020]: 0xd7
[0x00000021]: 0xdb
[0x00000022]: 0x0b
[0x00000023]: 0x9d
[0x00000024]: 0xc9
[0x00000025]: 0x01
[0x00000026]: 0x4d
[0x00000027]: 0x00
[0x00000028]: 0x79
[0x00000029]: 0x00
[0x0000002a]: 0x47
[0x0000002b]: 0x00
[0x0000002c]: 0x72
[0x0000002d]: 0x00
[0x0000002e]: 0x6f
[0x0000002f]: 0x00
[0x00000030]: 0x75
[0x00000031]: 0x00
[0x00000032]: 0x70
[0x00000033]: 0x00
[0x00000034]: 0x00
[0x00000035]: 0x00
[0x00000036]: 0x2f
[0x00000037]: 0x00
[0x00000038]: 0x00
[0x00000039]: 0x00
hashed
{byte[0x00000014]}
[0x00000000]: 0xbd
[0x00000001]: 0x0d
[0x00000002]: 0xea
[0x00000003]: 0x71
[0x00000004]: 0xbe
[0x00000005]: 0x0b
[0x00000006]: 0x25
[0x00000007]: 0x75
[0x00000008]: 0xe7
[0x00000009]: 0x5c
[0x0000000a]: 0x58
[0x0000000b]: 0x20
[0x0000000c]: 0x31
[0x0000000d]: 0x57
[0x0000000e]: 0xf3
[0x0000000f]: 0x9a
[0x00000010]: 0xef
[0x00000011]: 0x69
[0x00000012]: 0x1b
[0x00000013]: 0xfd
Something is very wrong here. SHA1 digests are 160 bits, which is 20 hexadecimal numbers, which is represented by 40 characters. The value you're expecting is 32 characters, which means it's not a SHA1 digest - or something else is missing that I don't yet understand.
Unfortunately this doesn't give you the correct value either, but it might point you in the right direction. Either way it's a much better idea to actually convert the hex code to a binary string before hashing it. Like this:
$str = "3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00";
// Create an array where each entry represents a single byte in hex
$arr = explode(" ", $str);
// Convert the hex to decimal
$arr = array_map("hexdec", $arr);
// Convert the decimal number into the corresponding ASCII character
$arr = array_map("chr", $arr);
// Implode the array into a string, and hash the result
$result = sha1(implode($arr));
echo $result."\n";
The result is fa3ebc158305d09443b4315d35c0eee5aa72daef, which is what vartecs code produces as well. I think there's some aspect of how the correct reference is calculated that we don't know, because the approach used here and by vartec is definitely the most logical way to do it based on the facts that we do know.
$hexes = "3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00";
$hexes = split(' ',$hexes);
$hexes = array_map('hexdec',$hexes);
$hexes = call_user_func_array('pack',array_merge(array('C*'),$hexes));
echo sha1($hexes);
BTW. you can achieve same thing by passing it in another format:
$hexes = "\x3F\xF4\xE5\x25\x98\x20\x52\x70\x01\x63\x00\x68\x00\x75\x00\x79\x00\x69\x00\x00\x00\x74\x28\x96\x10\x09\x9D\xC9\x01\x00\x74\xA0\xD7\xDB\x0B\x9D\xC9\x01\x4D\x00\x79\x00\x47\x00\x72\x00\x6F\x00\x75\x00\x70\x00\x00\x00\x2F\x00\x00\x00";
echo sha1($hexes);
You can use the pack function to convert the hexadecimal string into binary:
$bin = pack('H*', preg_replace('/[^0-9a-fA-F]+/', '', $hex));
convert them into string using chr()..
$string = "3f ........"
$c = split(' ',$string);
$string2 = '';
foreach( $c as $char )
{
$string2 .= chr(hexdec($c));
}
echo sha1($string2);
This works:
function strToHex($string)
{
$hex='';
for ($i=0; $i < strlen($string); $i++)
{
$hex .= dechex(ord($string[$i]));
}
return $hex;
}
echo sha1(strToHex("3FF4E525982052700163006800750079006900000074289610099DC9010074A0D7DB0B9DC9014D007900470072006F007500700000002F000000"));
>> 5b102a482247fef726843f214f8a81b1627bb634
Turned out that I needed to use hash_hmac() with a validation key rather than sha1().

Categories