tel / saltine

Cryptography that's easy to digest (NaCl/libsodium bindings)
https://github.com/tel/saltine
MIT License
61 stars 29 forks source link

Provide helper functions to treat nonces as integers #12

Open redneb opened 10 years ago

redneb commented 10 years ago

Sometimes you want to use an integer as a nonce. For example, Alice might send messages to Bob using the numbers 1,3,5, ... as nonces and similarly Bob might use 2,4,6,... for the messages he sends to Alice. Another common case is to select a random nonce to encrypt the first message and then keep incrementing it for subsequent messages (sort of like a counter mode). I propose to include 2 helper functions to saltine to help with these cases:

succNonce :: Nonce -> Nonce
nonceFromInt :: Integral a => a -> Nonce

Care must be taken to make sure that those functions are implemented in an endianness independent fashion.

Here are naive implementation of the above functions, representing integers in little endian form:

succNonce :: Nonce -> Nonce
succNonce n = n'
  where
    Just n' = SC.decode $ B.pack $ succList $ B.unpack $ SC.encode n

succList :: (Bounded a, Enum a, Eq a) => [a] -> [a]
succList (x : xs)
    | x == maxBound = minBound : succList xs
    | otherwise = succ x : xs
succList [] = []

and

nonceFromInt :: Integral a => a -> Nonce
nonceFromInt x = n
  where
    Just n = SC.decode $ B.pack $ take nonceBytes $ littleEndianBytes x
    -- this is vert ugly, a #const must be used here
    nonceBytes = B.length $ SC.encode $ unsafeDupablePerformIO newNonce

littleEndianBytes :: Integral a => a -> [Word8]
littleEndianBytes x = fromIntegral r : littleEndianBytes q
  where
    (q, r) = x `quotRem` 256

where SC is Crypto.Saltine.Class and B is Data.ByteString.

tel commented 10 years ago

I agree that introducing succNonce is pretty important. What are the use cases for doing Int -> Nonce? My reluctance to introduce that lies in favoring initializing communications with a random nonce instead of something like 0 or any other magic number. I don't think there's a security ramification here, though—nonces need to be unique, not unpredictable.

redneb commented 10 years ago

I was referring to this:

Distinct messages between the same {sender, receiver} set are required to have distinct nonces. For example, the lexicographically smaller public key can use nonce 1 for its first message to the other key, nonce 3 for its second message, nonce 5 for its third message, etc., while the lexicographically larger public key uses nonce 2 for its first message to the other key, nonce 4 for its second message, nonce 6 for its third message, etc.

This kind of nonces are safe for ephemeral keys only. So if a function Integer -> Nonce was to be included, its documentation should include a big fat warning.

Another possibility is to add a nonceBytes :: Int constant and let users do whatever they want to do with the nonces with the help of the IsEncoding class.

redneb commented 10 years ago

Oops, I just found out that there is the constant Crypto.Saltine.Internal.ByteSizes.boxNonce :: Int. I think it deserves to be promoted out of Crypto.Saltine.Internal.*. Maybe it could become a method of the IsNonce class.

tel commented 10 years ago

Genuinely, what I'd like is to keep that stuff hidden in the internal modules and expose a monadic interface which does random nonce generation or auto-incrementing nonces beginning with a random nonce (maybe in a pipes-like interface). Nonces are a fairly dangerous part of using NaCl—it's unbelievably trivial to decrypt messages when a nonce is repeated. I'm wary of users doing whatever they want without having to import a whole bunch of Internal modules.

But no doubt right now the Nonce/Key/IsEncoding interfaces are fairly weak. I'd be very happy to see some better design there.

I'm also very interested in changing out the default exports somehow. In my own use cases SecretKey is the most important kind of cryptography to use, but a higher level, garden variety NaCl toolkit would be a better choice for the Crypto.Saltine module itself.