summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-11-29 22:33:01 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-01 23:22:43 -0500
commit2f823f082afc9f7501f2672435ca764e964a3bae (patch)
treefaaabf62a726c9305c12ff132eb4b9f556dd9dd4
parentfddb44cc648da0494be580b832a0b5a61b27f2ff (diff)
Switched z-base32 to use 4-bit crc.
-rw-r--r--dht/cbits/crc4_itu.c44
-rw-r--r--dht/src/Codec/AsciiKey256.hs47
2 files changed, 78 insertions, 13 deletions
diff --git a/dht/cbits/crc4_itu.c b/dht/cbits/crc4_itu.c
new file mode 100644
index 00000000..8e3b0489
--- /dev/null
+++ b/dht/cbits/crc4_itu.c
@@ -0,0 +1,44 @@
1/*-----------------------------------------------------------------
2| crc4_itu.c
3|
4| CRC4-ITU library using lookup table method.
5|
6*-------------------------------------------------------------------*/
7
8#include <stddef.h>
9
10static unsigned char const crc4itu_bbox[256] = {
11 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6,
12 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb,
13 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5,
14 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2, 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8,
15 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0,
16 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd,
17 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3,
18 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe,
19 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa,
20 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7,
21 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9,
22 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4,
23 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc,
24 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1,
25 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf,
26 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2
27};
28
29/**
30 * CRC4-ITU function
31 *
32 * Parameters:
33 * crc Existing CRC value (usually 0x00) before process a new one.
34 * data Pointer to data to be hashed with CRC
35 * len Size of data
36 *
37 * Returns: CRC value in lowest 4 bits.
38 */
39unsigned char crc4itu(unsigned char crc, unsigned char *data, unsigned int len) {
40 if (data == NULL) return 0;
41 crc &= 0xf;
42 while (len--) crc = crc4itu_bbox[crc ^ *data++];
43 return crc;
44}
diff --git a/dht/src/Codec/AsciiKey256.hs b/dht/src/Codec/AsciiKey256.hs
index 6040f454..ee17b7c1 100644
--- a/dht/src/Codec/AsciiKey256.hs
+++ b/dht/src/Codec/AsciiKey256.hs
@@ -3,6 +3,7 @@ module Codec.AsciiKey256 where
3 3
4import Control.Applicative 4import Control.Applicative
5import Control.Monad 5import Control.Monad
6import Data.Bits
6import qualified Data.ByteArray as BA 7import qualified Data.ByteArray as BA
7 ;import Data.ByteArray as BA (ByteArrayAccess) 8 ;import Data.ByteArray as BA (ByteArrayAccess)
8import qualified Data.ByteString as B 9import qualified Data.ByteString as B
@@ -17,6 +18,7 @@ import qualified Data.Text as T
17 ;import Data.Text (Text) 18 ;import Data.Text (Text)
18import Data.Word 19import Data.Word
19import Foreign.Ptr 20import Foreign.Ptr
21import System.IO.Unsafe
20import qualified Text.ParserCombinators.ReadP as RP 22import qualified Text.ParserCombinators.ReadP as RP
21 23
22stripSuffix :: Text -> Text -> Maybe Text 24stripSuffix :: Text -> Text -> Maybe Text
@@ -67,14 +69,33 @@ parseToken32 str = fmap (BA.drop 1) $ Base64.decode $ C8.pack $ 'A':map (nmtoken
67showToken32 :: ByteArrayAccess bin => bin -> String 69showToken32 :: ByteArrayAccess bin => bin -> String
68showToken32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs 70showToken32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs
69 71
72foreign import ccall "crc4itu" c_crc4itu :: Word8 -- ^ init crc
73 -> Ptr Word8 -- ^ data to checksum
74 -> Int32 -- ^ length of data
75 -> IO Word8 -- crc in low 4 bits
76
77-- | CRC4-ITU. Return crc in lowest 4 bits.
78crc4itu :: ByteArrayAccess ba => Word8 -- ^ Existing CRC value (usually 0x00) before process a new one.
79 -> ba -- ^ Data to checksum.
80 -> Word8
81crc4itu crc0 b = unsafePerformIO $ BA.withByteArray b $ \p ->
82 c_crc4itu crc0 p (fromIntegral $ BA.length b)
70 83
71-- | Parse 52-digit z-base32 token into 32-byte bytestring. 84-- | Parse 52-digit z-base32 token into 32-byte bytestring.
72parse32Token32 :: String -> Either String ByteString 85parse32Token32 :: String -> Either String ByteString
73parse32Token32 str = fmap (BA.drop 1) $ Base32.decode $ C8.pack $ 'y':map (fixupDigit32 . toLower) (take 52 str) 86parse32Token32 str = do
74 87 bs <- Base32.decode $ C8.pack $ map (fixupDigit32 . toLower) (take 52 str) ++ "y"
75-- | Encode 62-digit z-base32 token from 32-byte bytestring. 88 case BA.splitAt 32 bs of
89 (key,mac) | crc4itu 0 key == shiftR (BA.index mac 0) 4
90 -> Right key
91 _ -> Left "Failed cyclic redundancy check."
92
93-- | Encode 52-digit z-base32 token from 32-byte bytestring.
76show32Token32 :: ByteArrayAccess bin => bin -> String 94show32Token32 :: ByteArrayAccess bin => bin -> String
77show32Token32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base32.encode $ BA.cons 0 $ BA.convert bs 95show32Token32 bs = C8.unpack $ B.take 52 $ Base32.encode (b `B.snoc` shiftL crc 4)
96 where
97 b = BA.convert bs
98 crc = crc4itu 0 bs
78 99
79 100
80readsPrecKey256 :: (ByteString -> Maybe a) -> [Char] -> [(a, [Char])] 101readsPrecKey256 :: (ByteString -> Maybe a) -> [Char] -> [(a, [Char])]
@@ -96,11 +117,11 @@ parseKey256 nidstr = do
96 let nidbs = C8.pack nidstr 117 let nidbs = C8.pack nidstr
97 (bs,_) = Base16.decode nidbs 118 (bs,_) = Base16.decode nidbs
98 enid = case C8.length nidbs of 119 enid = case C8.length nidbs of
99 52 -> Base32.decode (C8.pack $ 'y' : map (fixupDigit32 . toLower) nidstr) 120 52 -> parse32Token32 nidstr
100 43 -> Base64.decode (C8.pack $ 'A' : map (nmtoken64 False) nidstr) 121 43 -> parseToken32 nidstr
101 _ -> Left "Wrong size of key." 122 _ -> Left "Wrong size of key."
102 idbs <- (guard (B.length bs == 32) >> return bs) 123 idbs <- (guard (B.length bs == 32) >> return bs)
103 <|> either fail (return . B.drop 1) enid 124 <|> either fail return enid
104 return idbs 125 return idbs
105 126
106readP_key256 :: RP.ReadP ByteString 127readP_key256 :: RP.ReadP ByteString
@@ -112,12 +133,12 @@ readP_key256 = do
112 ] 133 ]
113 let failure = fail "Bad key." 134 let failure = fail "Bad key."
114 case is64 of 135 case is64 of
115 32 -> case Base32.decode $ C8.pack $ 'y' : map (fixupDigit32 . toLower) hexhash of 136 32 -> case parse32Token32 hexhash of
116 Right bs | B.length bs - 1==32 -> return (BA.drop 1 bs) 137 Right bs -> return bs
117 _ -> failure 138 _ -> failure
118 64 -> case Base64.decode $ C8.pack $ 'A' : map (nmtoken64 False) hexhash of 139 64 -> case parseToken32 hexhash of
119 Right bs | B.length bs - 1==32 -> return (BA.drop 1 bs) 140 Right bs -> return bs
120 _ -> failure 141 _ -> failure
121 16 -> case Base16.decode $ C8.pack hexhash of 142 16 -> case Base16.decode $ C8.pack hexhash of
122 (bs,rem) | B.length bs == 32 && B.null rem -> return bs 143 (bs,rem) | B.length bs == 32 && B.null rem -> return bs
123 _ -> failure 144 _ -> failure