summaryrefslogtreecommitdiff
path: root/dht/src
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 /dht/src
parentfddb44cc648da0494be580b832a0b5a61b27f2ff (diff)
Switched z-base32 to use 4-bit crc.
Diffstat (limited to 'dht/src')
-rw-r--r--dht/src/Codec/AsciiKey256.hs47
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
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