Re: [erlang-questions] blowfish ECB implementation in erlang?

View: New views
2 Messages — Rating Filter:   Alert me  

Parent Message unknown Re: [erlang-questions] blowfish ECB implementation in erlang?

by puzza007 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On Fri, Sep 25, 2009 at 1:19 PM, Paul Oliver <puzza007@...> wrote:
On Wed, Sep 23, 2009 at 8:33 PM, Larry Ogrodnek <larry@...> wrote:
Hi, I'm wondering if anyone has put together an implementation of blowfish ECB?

thanks.

Hi Larry,

Check the following page for the patch that added cfb64.

http://www.nabble.com/Patch-to-add-Blowfish-cfb64-to-crypto-app-td24232164.html

You should almost be able to copy this verbatim to add ecb.

Cheers,
Paul.

Hi Larry,

The attached patch should do ECB for you.  It works for me on the test data I obtained from http://www.schneier.com/code/vectors.txt.

puzza@imac:~/Downloads/otp_src_R13B02-1$ /tmp/bin/erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]

Eshell V5.7.3  (abort with ^G)
1> %% FEDCBA9876543210 == Key = <<254,220,186,152,118,84,50,16>>
1> %% 0123456789ABCDEF == Clear = <<1,35,69,103,137,171,205,239>>
1> %% 0ACEAB0FC6A0A28D == Enc = <<10,206,171,15,198,160,162,141>>
1>
1> crypto:start().
ok
2> Key = <<254,220,186,152,118,84,50,16>>.
<<254,220,186,152,118,84,50,16>>
3> Clear = <<1,35,69,103,137,171,205,239>>.
<<1,35,69,103,137,171,205,239>>
4> Enc = <<10,206,171,15,198,160,162,141>>.
<<10,206,171,15,198,160,162,141>>
5> Enc == crypto:blowfish_ecb_encrypt(Key, Clear).
true
6>  Clear == crypto:blowfish_ecb_decrypt(Key, Enc).
true
7>

I'm off on holiday tomorrow so if it doesn't work as it should I'll take another look in a couple of weeks.  ;}  If it works OK please reply and perhaps it can be picked up in a future OTP release.

Cheers,
Paul.



________________________________________________________________
erlang-patches mailing list. See http://www.erlang.org/faq.html
erlang-patches (at) erlang.org

0001-Blowfish-ECB.patch (5K) Download Attachment

Re: [erlang-questions] blowfish ECB implementation in erlang?

by puzza007 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sun, Sep 27, 2009 at 11:35 PM, Paul Oliver <puzza007@...> wrote:


On Fri, Sep 25, 2009 at 1:19 PM, Paul Oliver <puzza007@...> wrote:
On Wed, Sep 23, 2009 at 8:33 PM, Larry Ogrodnek <larry@...> wrote:
Hi, I'm wondering if anyone has put together an implementation of blowfish ECB?

thanks.

Hi Larry,

Check the following page for the patch that added cfb64.

http://www.nabble.com/Patch-to-add-Blowfish-cfb64-to-crypto-app-td24232164.html

You should almost be able to copy this verbatim to add ecb.

Cheers,
Paul.

Hi Larry,

The attached patch should do ECB for you.  It works for me on the test data I obtained from http://www.schneier.com/code/vectors.txt.

puzza@imac:~/Downloads/otp_src_R13B02-1$ /tmp/bin/erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]

Eshell V5.7.3  (abort with ^G)
1> %% FEDCBA9876543210 == Key = <<254,220,186,152,118,84,50,16>>
1> %% 0123456789ABCDEF == Clear = <<1,35,69,103,137,171,205,239>>
1> %% 0ACEAB0FC6A0A28D == Enc = <<10,206,171,15,198,160,162,141>>
1>
1> crypto:start().
ok
2> Key = <<254,220,186,152,118,84,50,16>>.
<<254,220,186,152,118,84,50,16>>
3> Clear = <<1,35,69,103,137,171,205,239>>.
<<1,35,69,103,137,171,205,239>>
4> Enc = <<10,206,171,15,198,160,162,141>>.
<<10,206,171,15,198,160,162,141>>
5> Enc == crypto:blowfish_ecb_encrypt(Key, Clear).
true
6>  Clear == crypto:blowfish_ecb_decrypt(Key, Enc).
true
7>

I'm off on holiday tomorrow so if it doesn't work as it should I'll take another look in a couple of weeks.  ;}  If it works OK please reply and perhaps it can be picked up in a future OTP release.

Cheers,
Paul.

Hi,

I've rounded out the patch to include the rest of the blowfish functions from openssl and included a primitive test program.

Cheers,
Paul.

[blowfish_ecb_cbc_ofb.patch]

diff --git a/lib/crypto/c_src/crypto_drv.c b/lib/crypto/c_src/crypto_drv.c
index a5b301f..9d99591 100644
--- a/lib/crypto/c_src/crypto_drv.c
+++ b/lib/crypto/c_src/crypto_drv.c
@@ -212,6 +212,11 @@ static ErlDrvEntry crypto_driver_entry = {
 
 #define DRV_BF_CFB64_ENCRYPT     59
 #define DRV_BF_CFB64_DECRYPT     60
+#define DRV_BF_ECB_ENCRYPT       61
+#define DRV_BF_ECB_DECRYPT       62
+#define DRV_BF_OFB64_ENCRYPT     63
+#define DRV_BF_CBC_ENCRYPT       64
+#define DRV_BF_CBC_DECRYPT       65
 
 /* #define DRV_CBC_IDEA_ENCRYPT    34 */
 /* #define DRV_CBC_IDEA_DECRYPT    35 */
@@ -507,17 +512,63 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf,
                          (command == DRV_CBC_DES_ENCRYPT));
         return dlen;
 
+    case DRV_BF_ECB_ENCRYPT:
+    case DRV_BF_ECB_DECRYPT:
+    {
+ /* buf = klen[4] key data */
+ int bf_direction;
+ const unsigned char *bf_dbuf; /* blowfish input data */
+ BF_KEY bf_key; /* blowfish key 8 */
+
+ klen = get_int32(buf);
+ key = buf + 4;
+ bf_dbuf = key + klen;
+ dlen = len - 4 - klen;
+ if (dlen < 0) return -1;
+ BF_set_key(&bf_key, klen, key);
+ bin = return_binary(rbuf,rlen,dlen);
+ if (bin==NULL) return -1;
+ bf_direction = command == DRV_BF_ECB_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT;
+ BF_ecb_encrypt(bf_dbuf, bin, &bf_key, bf_direction);
+ return dlen;
+    }
+
+    case DRV_BF_CBC_ENCRYPT:
+    case DRV_BF_CBC_DECRYPT:
+    {
+ /* buf = klen[4] key ivec[8] data */
+ char* ivec;
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ int bf_direction;
+ const unsigned char *bf_dbuf; /* blowfish input data */
+ BF_KEY bf_key; /* blowfish key 8 */
+
+ klen = get_int32(buf);
+ key = buf + 4;
+ ivec = key + klen;
+ bf_dbuf = ivec + 8;
+ dlen = len - 4 - klen - 8;
+ if (dlen < 0) return -1;
+ BF_set_key(&bf_key, klen, key);
+ memcpy(bf_tkey, ivec, 8);
+ bin = return_binary(rbuf,rlen,dlen);
+ if (bin==NULL) return -1;
+ bf_direction = command == DRV_BF_CBC_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT;
+ BF_cbc_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, bf_direction);
+ return dlen;
+    }
+
     case DRV_BF_CFB64_ENCRYPT:
     case DRV_BF_CFB64_DECRYPT:
     {
  /* buf = klen[4] key ivec[8] data */
  char* ivec;
- unsigned char bf_tkey[8]; /* blowfish ivec */    
- int bf_n; /* blowfish ivec pos */    
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ int bf_n; /* blowfish ivec pos */
  int bf_direction;
- const unsigned char *bf_dbuf; /* blowfish input data */  
+ const unsigned char *bf_dbuf; /* blowfish input data */
  BF_KEY bf_key; /* blowfish key 8 */
-
+
  klen = get_int32(buf);
  key = buf + 4;
  ivec = key + klen;
@@ -534,6 +585,30 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf,
  return dlen;
     }
 
+    case DRV_BF_OFB64_ENCRYPT:
+    {
+ /* buf = klen[4] key ivec[8] data */
+ char* ivec;
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ int bf_n; /* blowfish ivec pos */
+ const unsigned char *bf_dbuf; /* blowfish input data */
+ BF_KEY bf_key; /* blowfish key 8 */
+
+ klen = get_int32(buf);
+ key = buf + 4;
+ ivec = key + klen;
+ bf_dbuf = ivec + 8;
+ dlen = len - 4 - klen - 8;
+ if (dlen < 0) return -1;
+ BF_set_key(&bf_key, klen, key);
+ memcpy(bf_tkey, ivec, 8);
+ bin = return_binary(rbuf,rlen,dlen);
+ if (bin==NULL) return -1;
+ bf_n = 0;
+ BF_ofb64_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, &bf_n);
+ return dlen;
+    }
+
 /*     case DRV_CBC_IDEA_ENCRYPT: */
 /*     case DRV_CBC_IDEA_DECRYPT: */
          /* buf = key[16] ivec[8] data */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 7d96017..38dacc0 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -337,6 +337,53 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
           <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
       </desc>
     </func>
+
+    <func>
+      <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name>
+      <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
+      <type>
+        <v>Key = Text = iolist() | binary()</v>
+        <v>IVec = Cipher = binary()</v>
+      </type>
+      <desc>
+        <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
+      </desc>
+      <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name>
+      <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
+      <type>
+        <v>Key = Text = iolist() | binary()</v>
+        <v>IVec = Cipher = binary()</v>
+      </type>
+      <desc>
+        <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
+      </desc>
+    </func>
+
+    <func>
+      <name>blowfish_cbc_encrypt(Key, Text) -> Cipher</name>
+      <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
+      <type>
+        <v>Key = Text = iolist() | binary()</v>
+        <v>IVec = Cipher = binary()</v>
+      </type>
+      <desc>
+        <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
+          arbitrary initializing vector. The length of <c>IVec</c>
+          must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p>
+      </desc>
+      <name>blowfish_cbc_decrypt(Key, Text) -> Cipher</name>
+      <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
+      <type>
+        <v>Key = Text = iolist() | binary()</v>
+        <v>IVec = Cipher = binary()</v>
+      </type>
+      <desc>
+        <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
+          arbitrary initializing vector. The length of <c>IVec</c>
+          must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p>
+      </desc>
+    </func>
+
     <func>
       <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name>
       <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64
@@ -367,6 +414,23 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
           must be 64 bits (8 bytes).</p>
       </desc>
     </func>
+
+    <func>
+      <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name>
+      <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64
+        bit feedback</fsummary>
+      <type>
+        <v>Key = Text = iolist() | binary()</v>
+        <v>IVec = Cipher = binary()</v>
+      </type>
+      <desc>
+        <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit
+          feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
+          arbitrary initializing vector. The length of <c>IVec</c>
+          must be 64 bits (8 bytes).</p>
+      </desc>
+    </func>
+
     <func>
       <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
       <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5189677..fa33bad 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -30,7 +30,10 @@
 -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac_96/2]).
 -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
 -export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
--export([blowfish_cfb64_encrypt/3,blowfish_cfb64_decrypt/3]).
+-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
+-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
+-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
+-export([blowfish_ofb64_encrypt/3]).
 -export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
 -export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
 -export([exor/2]).
@@ -115,6 +118,11 @@
 
 -define(BF_CFB64_ENCRYPT, 59).
 -define(BF_CFB64_DECRYPT, 60).
+-define(BF_ECB_ENCRYPT,   61).
+-define(BF_ECB_DECRYPT,   62).
+-define(BF_OFB64_ENCRYPT, 63).
+-define(BF_CBC_ENCRYPT,   64).
+-define(BF_CBC_DECRYPT,   65).
 
 %% -define(IDEA_CBC_ENCRYPT, 34).
 %% -define(IDEA_CBC_DECRYPT, 35).
@@ -303,12 +311,27 @@ des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
 %%
 %% Blowfish
 %%
+blowfish_ecb_encrypt(Key, Data) when byte_size(Data) >= 8 ->
+    control_bin(?BF_ECB_ENCRYPT, Key, list_to_binary([Data])).
+
+blowfish_ecb_decrypt(Key, Data) when byte_size(Data) >= 8 ->
+    control_bin(?BF_ECB_DECRYPT, Key, list_to_binary([Data])).
+
+blowfish_cbc_encrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 ->
+    control_bin(?BF_CBC_ENCRYPT, Key, list_to_binary([IVec, Data])).
+
+blowfish_cbc_decrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 ->
+    control_bin(?BF_CBC_DECRYPT, Key, list_to_binary([IVec, Data])).
+
 blowfish_cfb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
     control_bin(?BF_CFB64_ENCRYPT, Key, list_to_binary([IVec, Data])).
 
 blowfish_cfb64_decrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
     control_bin(?BF_CFB64_DECRYPT, Key, list_to_binary([IVec, Data])).
 
+blowfish_ofb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
+    control_bin(?BF_OFB64_ENCRYPT, Key, list_to_binary([IVec, Data])).
+
 %%
 %% AES in cipher feedback mode (CFB)
 %%


[bf_test.erl]

-module(bf_test).

-include_lib("eunit/include/eunit.hrl").

-define(KEY, to_bin("0123456789ABCDEFF0E1D2C3B4A59687")).
-define(IVEC, to_bin("FEDCBA9876543210")).
%% "7654321 Now is the time for " (includes trailing '\0')
-define(DATA, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000")).
-define(DATA_PADDED, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")).


ecb_test(KeyBytes, ClearBytes, CipherBytes) ->
        crypto:start(),
        {Key, Clear, Cipher} =
                {to_bin(KeyBytes), to_bin(ClearBytes), to_bin(CipherBytes)},
        crypto:blowfish_ecb_encrypt(Key, Clear) =:= Cipher.

ecb_1_test() -> ?assert(ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78")).
ecb_2_test() -> ?assert(ecb_test("FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A")).
ecb_3_test() -> ?assert(ecb_test("3000000000000000", "1000000000000001", "7D856F9A613063F2")).
ecb_4_test() -> ?assert(ecb_test("1111111111111111", "1111111111111111", "2466DD878B963C9D")).
ecb_5_test() -> ?assert(ecb_test("0123456789ABCDEF", "1111111111111111", "61F9C3802281B096")).
ecb_6_test() -> ?assert(ecb_test("1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7")).
ecb_7_test() -> ?assert(ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78")).
ecb_8_test() -> ?assert(ecb_test("FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D")).
ecb_9_test() -> ?assert(ecb_test("7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B")).
ecb_10_test() -> ?assert(ecb_test("0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0")).
ecb_11_test() -> ?assert(ecb_test("07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4")).
ecb_12_test() -> ?assert(ecb_test("3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB")).
ecb_13_test() -> ?assert(ecb_test("04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A")).
ecb_14_test() -> ?assert(ecb_test("0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918")).
ecb_15_test() -> ?assert(ecb_test("0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98")).
ecb_16_test() -> ?assert(ecb_test("43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5")).
ecb_17_test() -> ?assert(ecb_test("07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79")).
ecb_18_test() -> ?assert(ecb_test("04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3")).
ecb_19_test() -> ?assert(ecb_test("37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969")).
ecb_20_test() -> ?assert(ecb_test("1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B")).
ecb_21_test() -> ?assert(ecb_test("584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E")).
ecb_22_test() -> ?assert(ecb_test("025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD")).
ecb_23_test() -> ?assert(ecb_test("49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019")).
ecb_24_test() -> ?assert(ecb_test("4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3")).
ecb_25_test() -> ?assert(ecb_test("49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5")).
ecb_26_test() -> ?assert(ecb_test("018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778")).
ecb_27_test() -> ?assert(ecb_test("1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201")).
ecb_28_test() -> ?assert(ecb_test("0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2")).
ecb_29_test() -> ?assert(ecb_test("1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE")).
ecb_30_test() -> ?assert(ecb_test("E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D")).
ecb_31_test() -> ?assert(ecb_test("0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4")).
ecb_32_test() -> ?assert(ecb_test("FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC")).
ecb_33_test() -> ?assert(ecb_test("0123456789ABCDEF", "0000000000000000", "245946885754369A")).
ecb_34_test() -> ?assert(ecb_test("FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A")).

%% Chaining mode tests
cbc_test() ->
        crypto:start(),
        ?assert(crypto:blowfish_cbc_encrypt(?KEY, ?IVEC, ?DATA_PADDED) =:=
                        to_bin("6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC")).

cfb64_test() ->
        crypto:start(),
        ?assert(crypto:blowfish_cfb64_encrypt(?KEY, ?IVEC, ?DATA) =:=
                        to_bin("E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3")).

ofb64_test() ->
        crypto:start(),
        ?assert(crypto:blowfish_ofb64_encrypt(?KEY, ?IVEC, ?DATA) =:=
                        to_bin("E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA")).

%% @spec to_bin(string()) -> binary()
%% @doc Convert a hexadecimal string to a binary.
to_bin(L) ->
    to_bin(L, []).

%% @spec dehex(char()) -> integer()
%% @doc Convert a hex digit to its integer value.
dehex(C) when C >= $0, C =< $9 ->
    C - $0;
dehex(C) when C >= $a, C =< $f ->
    C - $a + 10;
dehex(C) when C >= $A, C =< $F ->
    C - $A + 10.

to_bin([], Acc) ->
    iolist_to_binary(lists:reverse(Acc));
to_bin([C1, C2 | Rest], Acc) ->
    to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).



________________________________________________________________
erlang-patches mailing list. See http://www.erlang.org/faq.html
erlang-patches (at) erlang.org