diff options
author | Joe Crayne <joe@jerkface.net> | 2019-11-29 22:33:01 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-01 23:22:43 -0500 |
commit | 2f823f082afc9f7501f2672435ca764e964a3bae (patch) | |
tree | faaabf62a726c9305c12ff132eb4b9f556dd9dd4 /dht/src/Codec/AsciiKey256.hs | |
parent | fddb44cc648da0494be580b832a0b5a61b27f2ff (diff) |
Switched z-base32 to use 4-bit crc.
Diffstat (limited to 'dht/src/Codec/AsciiKey256.hs')
-rw-r--r-- | dht/src/Codec/AsciiKey256.hs | 47 |
1 files changed, 34 insertions, 13 deletions
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 | ||
4 | import Control.Applicative | 4 | import Control.Applicative |
5 | import Control.Monad | 5 | import Control.Monad |
6 | import Data.Bits | ||
6 | import qualified Data.ByteArray as BA | 7 | import qualified Data.ByteArray as BA |
7 | ;import Data.ByteArray as BA (ByteArrayAccess) | 8 | ;import Data.ByteArray as BA (ByteArrayAccess) |
8 | import qualified Data.ByteString as B | 9 | import 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) |
18 | import Data.Word | 19 | import Data.Word |
19 | import Foreign.Ptr | 20 | import Foreign.Ptr |
21 | import System.IO.Unsafe | ||
20 | import qualified Text.ParserCombinators.ReadP as RP | 22 | import qualified Text.ParserCombinators.ReadP as RP |
21 | 23 | ||
22 | stripSuffix :: Text -> Text -> Maybe Text | 24 | stripSuffix :: Text -> Text -> Maybe Text |
@@ -67,14 +69,33 @@ parseToken32 str = fmap (BA.drop 1) $ Base64.decode $ C8.pack $ 'A':map (nmtoken | |||
67 | showToken32 :: ByteArrayAccess bin => bin -> String | 69 | showToken32 :: ByteArrayAccess bin => bin -> String |
68 | showToken32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs | 70 | showToken32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs |
69 | 71 | ||
72 | foreign 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. | ||
78 | crc4itu :: ByteArrayAccess ba => Word8 -- ^ Existing CRC value (usually 0x00) before process a new one. | ||
79 | -> ba -- ^ Data to checksum. | ||
80 | -> Word8 | ||
81 | crc4itu 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. |
72 | parse32Token32 :: String -> Either String ByteString | 85 | parse32Token32 :: String -> Either String ByteString |
73 | parse32Token32 str = fmap (BA.drop 1) $ Base32.decode $ C8.pack $ 'y':map (fixupDigit32 . toLower) (take 52 str) | 86 | parse32Token32 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. | ||
76 | show32Token32 :: ByteArrayAccess bin => bin -> String | 94 | show32Token32 :: ByteArrayAccess bin => bin -> String |
77 | show32Token32 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base32.encode $ BA.cons 0 $ BA.convert bs | 95 | show32Token32 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 | ||
80 | readsPrecKey256 :: (ByteString -> Maybe a) -> [Char] -> [(a, [Char])] | 101 | readsPrecKey256 :: (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 | ||
106 | readP_key256 :: RP.ReadP ByteString | 127 | readP_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 |