summaryrefslogtreecommitdiff
path: root/tox-crypto
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2020-01-09 12:10:10 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-09 12:10:10 -0500
commit5e2f6f9f8b78b90f0becb60e735abbd62bac6ca6 (patch)
tree9d7398a42a2925fe4f7e760e7d5ee9ae0a0a75fe /tox-crypto
parentb9194d4637ddfc3b9f762d2e4e29a318087e02db (diff)
Moved Codec.AsciiKey256 to tox-crypto.
Diffstat (limited to 'tox-crypto')
-rw-r--r--tox-crypto/cbits/crc4_itu.c44
-rw-r--r--tox-crypto/src/Codec/AsciiKey256.hs149
-rw-r--r--tox-crypto/src/Crypto/Tox.hs11
-rw-r--r--tox-crypto/tox-crypto.cabal5
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
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/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 #-}
2module Codec.AsciiKey256 where
3
4import Control.Applicative
5import Control.Monad
6import Control.Monad.Fail as MF
7import Data.Bits
8import qualified Data.ByteArray as BA
9 ;import Data.ByteArray as BA (ByteArrayAccess)
10import qualified Data.ByteString as B
11 ;import Data.ByteString (ByteString)
12import qualified Data.ByteString.Base16 as Base16
13import qualified Data.ByteString.Base32.Z as Base32
14import qualified Data.ByteString.Base64 as Base64
15import qualified Data.ByteString.Char8 as C8
16import Data.Char
17import Data.Int
18import qualified Data.Text as T
19 ;import Data.Text (Text)
20import Data.Word
21import Foreign.Ptr
22import System.IO.Unsafe
23import qualified Text.ParserCombinators.ReadP as RP
24
25stripSuffix :: Text -> Text -> Maybe Text
26stripSuffix suf x = case T.splitAt (T.length x - T.length suf) x of
27 (y,end) | end == suf -> Just y
28 | otherwise -> Nothing
29
30hexdigit :: Char -> Bool
31hexdigit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'f') || ( 'A' <= c && c <= 'F')
32
33b64digit :: Char -> Bool
34b64digit '.' = True
35b64digit '+' = True
36b64digit '-' = True
37b64digit '/' = True
38b64digit 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 +/.
41nmtoken64 :: Bool -> Char -> Char
42nmtoken64 False '.' = '+'
43nmtoken64 False '-' = '/'
44nmtoken64 True '+' = '.'
45nmtoken64 True '/' = '-'
46nmtoken64 _ c = c
47
48
49-- Apply substitutions for mistaken z-base32 digits.
50fixupDigit32 :: Char -> Char
51fixupDigit32 'l' = '1'
52fixupDigit32 '2' = 'z'
53fixupDigit32 'v' = 'u'
54fixupDigit32 c = c
55
56zb32digit :: Char -> Bool
57zb32digit '1' = True
58zb32digit 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.
66parseBase64Key256 :: String -> Either String ByteString
67parseBase64Key256 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.
70showBase64Key256 :: ByteArrayAccess bin => bin -> String
71showBase64Key256 bs = map (nmtoken64 True) $ C8.unpack $ BA.drop 1 $ Base64.encode $ BA.cons 0 $ BA.convert bs
72
73foreign 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.
79crc4itu :: ByteArrayAccess ba => Word8 -- ^ Existing CRC value (usually 0x00) before process a new one.
80 -> ba -- ^ Data to checksum.
81 -> Word8
82crc4itu 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.
86parseBase32Key256 :: String -> Either String ByteString
87parseBase32Key256 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.
95showBase32Key256 :: ByteArrayAccess bin => bin -> String
96showBase32Key256 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.
102showKey256 :: ByteArrayAccess bin => bin -> String
103showKey256 = showBase32Key256
104
105readsPrecKey256 :: (ByteString -> Maybe a) -> [Char] -> [(a, [Char])]
106readsPrecKey256 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
119parseKey256 :: (MonadFail m, Alternative m) => String -> m ByteString
120parseKey256 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
131readP_key256 :: RP.ReadP ByteString
132readP_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
72import Control.Arrow 82import Control.Arrow
@@ -99,6 +109,7 @@ import Foreign.Marshal.Alloc
99import Foreign.Ptr 109import Foreign.Ptr
100import Foreign.Storable 110import Foreign.Storable
101import System.Endian 111import System.Endian
112import Codec.AsciiKey256
102import Control.Concurrent.STM 113import Control.Concurrent.STM
103#ifdef CRYPTONITE_BACKPORT 114#ifdef CRYPTONITE_BACKPORT
104import Crypto.ECC.Class 115import 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
16cabal-version: >=1.10 16cabal-version: >=1.10
17 17
18library 18library
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