diff options
author | Joe Crayne <joe@jerkface.net> | 2020-01-09 12:10:10 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-09 12:10:10 -0500 |
commit | 5e2f6f9f8b78b90f0becb60e735abbd62bac6ca6 (patch) | |
tree | 9d7398a42a2925fe4f7e760e7d5ee9ae0a0a75fe /tox-crypto | |
parent | b9194d4637ddfc3b9f762d2e4e29a318087e02db (diff) |
Moved Codec.AsciiKey256 to tox-crypto.
Diffstat (limited to 'tox-crypto')
-rw-r--r-- | tox-crypto/cbits/crc4_itu.c | 44 | ||||
-rw-r--r-- | tox-crypto/src/Codec/AsciiKey256.hs | 149 | ||||
-rw-r--r-- | tox-crypto/src/Crypto/Tox.hs | 11 | ||||
-rw-r--r-- | tox-crypto/tox-crypto.cabal | 5 |
4 files changed, 208 insertions, 1 deletions
diff --git a/tox-crypto/cbits/crc4_itu.c b/tox-crypto/cbits/crc4_itu.c new file mode 100644 index 00000000..8e3b0489 --- /dev/null +++ b/tox-crypto/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 | |||
10 | static 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 | */ | ||
39 | unsigned 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/tox-crypto/src/Codec/AsciiKey256.hs b/tox-crypto/src/Codec/AsciiKey256.hs new file mode 100644 index 00000000..0212d1d0 --- /dev/null +++ b/tox-crypto/src/Codec/AsciiKey256.hs | |||
@@ -0,0 +1,149 @@ | |||
1 | {-# LANGUAGE TupleSections #-} | ||
2 | module Codec.AsciiKey256 where | ||
3 | |||
4 | import Control.Applicative | ||
5 | import Control.Monad | ||
6 | import Control.Monad.Fail as MF | ||
7 | import Data.Bits | ||
8 | import qualified Data.ByteArray as BA | ||
9 | ;import Data.ByteArray as BA (ByteArrayAccess) | ||
10 | import qualified Data.ByteString as B | ||
11 | ;import Data.ByteString (ByteString) | ||
12 | import qualified Data.ByteString.Base16 as Base16 | ||
13 | import qualified Data.ByteString.Base32.Z as Base32 | ||
14 | import qualified Data.ByteString.Base64 as Base64 | ||
15 | import qualified Data.ByteString.Char8 as C8 | ||
16 | import Data.Char | ||
17 | import Data.Int | ||
18 | import qualified Data.Text as T | ||
19 | ;import Data.Text (Text) | ||
20 | import Data.Word | ||
21 | import Foreign.Ptr | ||
22 | import System.IO.Unsafe | ||
23 | import qualified Text.ParserCombinators.ReadP as RP | ||
24 | |||
25 | stripSuffix :: Text -> Text -> Maybe Text | ||
26 | stripSuffix suf x = case T.splitAt (T.length x - T.length suf) x of | ||
27 | (y,end) | end == suf -> Just y | ||
28 | | otherwise -> Nothing | ||
29 | |||
30 | hexdigit :: Char -> Bool | ||
31 | hexdigit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'f') || ( 'A' <= c && c <= 'F') | ||
32 | |||
33 | b64digit :: Char -> Bool | ||
34 | b64digit '.' = True | ||
35 | b64digit '+' = True | ||
36 | b64digit '-' = True | ||
37 | b64digit '/' = True | ||
38 | b64digit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'z') || ( 'A' <= c && c <= 'Z') | ||
39 | |||
40 | -- | Convert to and from a Base64 variant that uses .- instead of +/. | ||
41 | nmtoken64 :: Bool -> Char -> Char | ||
42 | nmtoken64 False '.' = '+' | ||
43 | nmtoken64 False '-' = '/' | ||
44 | nmtoken64 True '+' = '.' | ||
45 | nmtoken64 True '/' = '-' | ||
46 | nmtoken64 _ c = c | ||
47 | |||
48 | |||
49 | -- Apply substitutions for mistaken z-base32 digits. | ||
50 | fixupDigit32 :: Char -> Char | ||
51 | fixupDigit32 'l' = '1' | ||
52 | fixupDigit32 '2' = 'z' | ||
53 | fixupDigit32 'v' = 'u' | ||
54 | fixupDigit32 c = c | ||
55 | |||
56 | zb32digit :: Char -> Bool | ||
57 | zb32digit '1' = True | ||
58 | zb32digit c = or [ '3' <= c && c <= '9' | ||
59 | , 'a' <= c && c <= 'k' | ||
60 | , 'm' <= c && c <= 'u' | ||
61 | , 'w' <= c && c <= 'z' | ||
62 | ] | ||
63 | |||
64 | |||
65 | -- | Parse 43-digit base64 token into 32-byte bytestring. | ||
66 | parseBase64Key256 :: String -> Either String ByteString | ||
67 | parseBase64Key256 str = fmap (BA.drop 1) $ Base64.decode $ C8.pack $ 'A':map (nmtoken64 False) (take 43 str) | ||
68 | |||
69 | -- | Encode 43-digit base64 token from 32-byte bytestring. | ||
70 | showBase64Key256 :: ByteArrayAccess bin => bin -> String | ||
71 | showBase64Key256 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs | ||
72 | |||
73 | foreign import ccall "crc4itu" c_crc4itu :: Word8 -- ^ init crc | ||
74 | -> Ptr Word8 -- ^ data to checksum | ||
75 | -> Int32 -- ^ length of data | ||
76 | -> IO Word8 -- crc in low 4 bits | ||
77 | |||
78 | -- | CRC4-ITU. Return crc in lowest 4 bits. | ||
79 | crc4itu :: ByteArrayAccess ba => Word8 -- ^ Existing CRC value (usually 0x00) before process a new one. | ||
80 | -> ba -- ^ Data to checksum. | ||
81 | -> Word8 | ||
82 | crc4itu crc0 b = unsafePerformIO $ BA.withByteArray b $ \p -> | ||
83 | c_crc4itu crc0 p (fromIntegral $ BA.length b) | ||
84 | |||
85 | -- | Parse 52-digit z-base32 token into 32-byte bytestring. | ||
86 | parseBase32Key256 :: String -> Either String ByteString | ||
87 | parseBase32Key256 str = do | ||
88 | bs <- Base32.decode $ C8.pack $ map (fixupDigit32 . toLower) (take 52 str) ++ "y" | ||
89 | case BA.splitAt 32 bs of | ||
90 | (key,mac) | crc4itu 0 key == shiftR (BA.index mac 0) 4 | ||
91 | -> Right key | ||
92 | _ -> Left "Failed cyclic redundancy check." | ||
93 | |||
94 | -- | Encode 52-digit z-base32 token from 32-byte bytestring. | ||
95 | showBase32Key256 :: ByteArrayAccess bin => bin -> String | ||
96 | showBase32Key256 bs = C8.unpack $ B.take 52 $ Base32.encode (b `B.snoc` shiftL crc 4) | ||
97 | where | ||
98 | b = BA.convert bs | ||
99 | crc = crc4itu 0 bs | ||
100 | |||
101 | -- | Encode 32-byte bytestring for display. | ||
102 | showKey256 :: ByteArrayAccess bin => bin -> String | ||
103 | showKey256 = showBase32Key256 | ||
104 | |||
105 | readsPrecKey256 :: (ByteString -> Maybe a) -> [Char] -> [(a, [Char])] | ||
106 | readsPrecKey256 publicKey str | ||
107 | | (bs,_) <- Base16.decode (C8.pack $ take 64 str) | ||
108 | , Just pub <- publicKey bs | ||
109 | = [ (pub, drop (2 * B.length bs) str) ] | ||
110 | | Right bs <- parseBase32Key256 str | ||
111 | , Just pub <- publicKey bs | ||
112 | = [ (pub, drop 52 str) ] | ||
113 | | Right bs <- parseBase64Key256 str | ||
114 | , Just pub <- publicKey bs | ||
115 | = [ (pub, drop 43 str) ] | ||
116 | | otherwise = [] | ||
117 | |||
118 | |||
119 | parseKey256 :: (MonadFail m, Alternative m) => String -> m ByteString | ||
120 | parseKey256 nidstr = do | ||
121 | let nidbs = C8.pack nidstr | ||
122 | (bs,_) = Base16.decode nidbs | ||
123 | enid = case C8.length nidbs of | ||
124 | 52 -> parseBase32Key256 nidstr | ||
125 | 43 -> parseBase64Key256 nidstr | ||
126 | _ -> Left "Wrong size of key." | ||
127 | idbs <- (guard (B.length bs == 32) >> return bs) | ||
128 | <|> either MF.fail return enid | ||
129 | return idbs | ||
130 | |||
131 | readP_key256 :: RP.ReadP ByteString | ||
132 | readP_key256 = do | ||
133 | (is64,hexhash) <- foldr1 (RP.+++) | ||
134 | [ fmap (16,) (sequence $ replicate 64 (RP.satisfy isHexDigit)) | ||
135 | , fmap (32,) (sequence $ replicate 52 (RP.satisfy zb32digit)) | ||
136 | , fmap (64,) (sequence $ replicate 43 (RP.satisfy b64digit)) | ||
137 | ] | ||
138 | let failure = MF.fail "Bad key." | ||
139 | case is64 of | ||
140 | 32 -> case parseBase32Key256 hexhash of | ||
141 | Right bs -> return bs | ||
142 | _ -> failure | ||
143 | 64 -> case parseBase64Key256 hexhash of | ||
144 | Right bs -> return bs | ||
145 | _ -> failure | ||
146 | 16 -> case Base16.decode $ C8.pack hexhash of | ||
147 | (bs,rem) | B.length bs == 32 && B.null rem -> return bs | ||
148 | _ -> failure | ||
149 | _ -> failure | ||
diff --git a/tox-crypto/src/Crypto/Tox.hs b/tox-crypto/src/Crypto/Tox.hs index 04b55d94..602ead0a 100644 --- a/tox-crypto/src/Crypto/Tox.hs +++ b/tox-crypto/src/Crypto/Tox.hs | |||
@@ -67,6 +67,16 @@ module Crypto.Tox | |||
67 | , encodeSecret | 67 | , encodeSecret |
68 | , decodeSecret | 68 | , decodeSecret |
69 | , xorsum | 69 | , xorsum |
70 | , Codec.AsciiKey256.showBase32Key256 | ||
71 | , Codec.AsciiKey256.showBase64Key256 | ||
72 | , Codec.AsciiKey256.showKey256 | ||
73 | , Codec.AsciiKey256.parseBase64Key256 | ||
74 | , Codec.AsciiKey256.parseBase32Key256 | ||
75 | , Codec.AsciiKey256.parseKey256 | ||
76 | , Codec.AsciiKey256.readP_key256 | ||
77 | , Codec.AsciiKey256.readsPrecKey256 | ||
78 | , Codec.AsciiKey256.stripSuffix | ||
79 | , Codec.AsciiKey256.nmtoken64 | ||
70 | ) where | 80 | ) where |
71 | 81 | ||
72 | import Control.Arrow | 82 | import Control.Arrow |
@@ -99,6 +109,7 @@ import Foreign.Marshal.Alloc | |||
99 | import Foreign.Ptr | 109 | import Foreign.Ptr |
100 | import Foreign.Storable | 110 | import Foreign.Storable |
101 | import System.Endian | 111 | import System.Endian |
112 | import Codec.AsciiKey256 | ||
102 | import Control.Concurrent.STM | 113 | import Control.Concurrent.STM |
103 | #ifdef CRYPTONITE_BACKPORT | 114 | #ifdef CRYPTONITE_BACKPORT |
104 | import Crypto.ECC.Class | 115 | import Crypto.ECC.Class |
diff --git a/tox-crypto/tox-crypto.cabal b/tox-crypto/tox-crypto.cabal index 678cccd5..370b1a85 100644 --- a/tox-crypto/tox-crypto.cabal +++ b/tox-crypto/tox-crypto.cabal | |||
@@ -16,8 +16,9 @@ extra-source-files: CHANGELOG.md | |||
16 | cabal-version: >=1.10 | 16 | cabal-version: >=1.10 |
17 | 17 | ||
18 | library | 18 | library |
19 | C-sources: cbits/crc4_itu.c | ||
19 | exposed-modules: Crypto.Tox | 20 | exposed-modules: Crypto.Tox |
20 | other-modules: DebugTag | 21 | other-modules: DebugTag, Codec.AsciiKey256 |
21 | other-extensions: CPP | 22 | other-extensions: CPP |
22 | , GeneralizedNewtypeDeriving | 23 | , GeneralizedNewtypeDeriving |
23 | , ScopedTypeVariables | 24 | , ScopedTypeVariables |
@@ -40,8 +41,10 @@ library | |||
40 | base | 41 | base |
41 | , cpu | 42 | , cpu |
42 | , memory | 43 | , memory |
44 | , base32-bytestring | ||
43 | , base64-bytestring | 45 | , base64-bytestring |
44 | , base16-bytestring | 46 | , base16-bytestring |
47 | , text | ||
45 | , cereal | 48 | , cereal |
46 | , word64-map | 49 | , word64-map |
47 | , contravariant | 50 | , contravariant |