Bug 11757 – toHexString doesn't support dynamic array
Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-12-17T04:23:00Z
Last change time
2013-12-17T07:09:23Z
Assigned to
nobody
Creator
pro.mathias.lang
Comments
Comment #0 by pro.mathias.lang — 2013-12-17T04:23:30Z
import std.digest.md;
import std.digest.sha;
ubyte[] hmac_md5(ubyte[] key, string msg)
{
immutable auto blocksize = 64;
if (key.length > blocksize)
key = md5Of(key);
if (key.length < blocksize)
key.length = blocksize;
ubyte[blocksize] okp = 0x5c;
ubyte[blocksize] ikp = 0x36;
for (size_t i = 0; i < blocksize; ++i)
okp[i] ^= key[i];
for (size_t i = 0; i < blocksize; ++i)
ikp[i] ^= key[i];
return md5Of(okp ~ md5Of(ikp ~ cast(ubyte[])(msg)));
}
ubyte[] hmac_md5(string key, string msg)
{
return hmac_md5(cast(ubyte[])(key), msg);
}
unittest {
auto md5hmac = hmac_md5("key", "The quick brown fox jumps over the lazy dog");
assert(toHexString(md5hmac) == "80070713463E7749B90C2DC24911E275");
}
This unittest will fail (toHexString returns 'E0166C00000000000000000000000000'), but if you replace ubyte[] with ubyte[16] -or auto-, it'll pass.
DMD 2.064.2
Comment #1 by bearophile_hugs — 2013-12-17T04:44:30Z
(In reply to comment #0)
> return hmac_md5(cast(ubyte[])(key), msg);
Don't use cast() unless you know what you are doing.
> 'E0166C00000000000000000000000000'), but if you replace ubyte[] with ubyte[16]
> -or auto-, it'll pass.
One advantage of the current design of toHexString() is that it can't fail, because the type system makes its usage safe and correct for most situations. (Unless you use cast() randomly).
Comment #2 by pro.mathias.lang — 2013-12-17T05:32:59Z
(In reply to comment #1)
> (In reply to comment #0)
>
> > return hmac_md5(cast(ubyte[])(key), msg);
>
> Don't use cast() unless you know what you are doing.
>
>
> > 'E0166C00000000000000000000000000'), but if you replace ubyte[] with ubyte[16]
> > -or auto-, it'll pass.
>
> One advantage of the current design of toHexString() is that it can't fail,
> because the type system makes its usage safe and correct for most situations.
> (Unless you use cast() randomly).
Fair enough. I'm just a beginner, with a C[++] background, so keeping in mind that string == immutable(char[]), chars are UTF-8, and my string is pure ASCII, I "just" expected it to work.
I'll close this as invalid so, but I wouldn't be against an enlightment of what's going on (and how to convert a string to an ubyte safely).
Thanks bearophile !
Comment #3 by bearophile_hugs — 2013-12-17T07:09:23Z
(In reply to comment #2)
> Fair enough. I'm just a beginner, with a C[++] background, so keeping in mind
> that string == immutable(char[]), chars are UTF-8, and my string is pure ASCII,
> I "just" expected it to work.
> I'll close this as invalid so, but I wouldn't be against an enlightment of
> what's going on (and how to convert a string to an ubyte safely).
In D fixed-sized arrays are values. ubyte[16] is a value, it's 16 unsigned bytes.
A string is a struct that contains two words: a length and a pointer to a series of immutable chars.
When you have similar doubts or questions I suggest you to ask them in the D.learn newsgroup.
Your D code has several problems. This is a fist try at improving your code, but some small problems still need to be fixed:
import std.digest.md, std.digest.sha, std.string;
enum size_t blockSize = 64;
enum size_t digestSize = 16;
ubyte[digestSize] hmacMD5(in ubyte[blockSize] key, in ubyte[] msg)
pure nothrow {
ubyte[key.length] okp = 0x5c;
okp[] ^= key[];
ubyte[key.length] ikp = 0x36;
ikp[] ^= key[];
// Heap allocations here:
return md5Of(okp ~ md5Of(ikp ~ msg));
}
ubyte[digestSize] hmacMD5(in string key, in string msg)
pure nothrow {
ubyte[blockSize] key2;
if (key.length > blockSize)
key2[0 .. digestSize] = key.md5Of;
else if (key.length < blockSize)
key2[0 .. key.length] = key[].representation;
return hmacMD5(key2, msg.representation);
}
void main() {
immutable r = hmacMD5("key", "The quick brown fox jumps over the lazy dog");
assert(r.toHexString == "80070713463E7749B90C2DC24911E275");
}