stego-uuid (empty) → 1.0.0.0
raw patch · 6 files changed
+202/−0 lines, 6 filesdep +basedep +bytestringdep +cryptonitesetup-changed
Dependencies added: base, bytestring, cryptonite, memory, random, stego-uuid, uuid
Files
- LICENSE +29/−0
- README.md +51/−0
- Setup.hs +2/−0
- src/Crypto/Stego/UUID.hs +47/−0
- stego-uuid.cabal +51/−0
- test/Test.hs +22/−0
+ LICENSE view
@@ -0,0 +1,29 @@+BSD 3-Clause License++Copyright (c) 2017, Dimitri DeFigueiredo+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++* Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived from+ this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,51 @@+# stego-uuid+A generator and verifier for steganographic numbers that look random++The standard use of this package is to generate a 64-bit number and use+this, along with a secret key, as input to the marking function.++Example:++```haskell++secretHi = KeyHi64 12345 -- secret key hi 64 bits+secretLo = KeyLo64 67890 -- secret key low 64 bits++main :: IO ()+main = do++ putStrLn "Is this marked?"+ r <- randomIO :: IO Word64 -- get 64-bit random number+ let x = mark secretHi secretLo r -- produce marked 128-bit UUID+ print x + print (isMarked secretHi secretLo x) -- True+```++## Security considerations+This is a poor man's MAC. We use SHA256 to generate the second half of the UUID from the 64-bit+random looking input and the secret key. The small number of bits limits the security.++We will start getting collisions on the 64-bit random number after about 2^32 numbers are used.+But this just means we will be providing the function with the same input, so the same output+will be produced.++### False Negatives+This is zero. If you produced the number with the `mark` function, this number will always be+detected with `isMarked` as long as you provide the correct key.++### False positives+This is false detection. We worry about a UUID that was *not* generated using `mark` but is+detected as marked by `isMarked`. (A malicious adversary can always replay any UUIDs known as+marked. Thus, we will consider only new UUIDs.)++Assuming SHA256 is a perfect pseudo-random function, its truncated output, i.e. the last 64 bits of+the UUID, does not leak any information about the secret key. Given a fixed secret key, for any+64-bit input (corresponding to the the first half of the UUID), there is a unique 64-bit output+(corresponding to the second half of the UUID). There is only one such output per 64-bit input. So,+the probability of finding such input from a random draw is 2^(-64). The adversary would have more+than a 1/2 chance of finding it after 2^63 guesses.++### Information leakage+The adversary can only know a UUID is marked if it is able to differentiate the output of truncated+SHA256 from a pseudo-random function. I am unaware of any significant results in doing so. The key+is 128-bits in length, so going through all possible values is currently unfeasible.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Crypto/Stego/UUID.hs view
@@ -0,0 +1,47 @@+{- |+Module: Crypto.Stego.UUID+See README.md for an example and security considerations.+-}++module Crypto.Stego.UUID (+ mark ,+ isMarked,+ StegoKeyHi (..),+ StegoKeyLo (..)+ ) where+++import Data.Maybe+import Data.Word++import Data.UUID+import Crypto.Hash++import qualified Data.ByteArray as BA+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL++-- | Secret key, high 64 bits.+newtype StegoKeyHi = KeyHi64 Word64+-- | Secret key, low 64 bits.+newtype StegoKeyLo = KeyLo64 Word64++-- | Creates a secretly "marked" UUID given a two-part secret key and random input+mark :: StegoKeyHi -> StegoKeyLo -> Word64 -> UUID+mark (KeyHi64 selfKeyHi) (KeyLo64 selfKeyLo) rand =+ let selfKeyHiAsLazyBS = BSB.toLazyByteString (BSB.word64BE selfKeyHi)+ selfKeyLoAsLazyBS = BSB.toLazyByteString (BSB.word64BE selfKeyLo)+ randAsLazyBS = BSB.toLazyByteString (BSB.word64BE rand)+ hashInput = BSL.concat [randAsLazyBS, selfKeyHiAsLazyBS, selfKeyLoAsLazyBS]+ digest = hash (BSL.toStrict hashInput) :: Digest SHA256+ hashBitsStrict = BS.take 8 (BA.convert digest)+ halfAndHalf = BSL.concat [randAsLazyBS, BSL.fromStrict hashBitsStrict]+ in fromJust (fromByteString halfAndHalf)++-- | Detects UUIDs previously marked with the given key+isMarked :: StegoKeyHi -> StegoKeyLo -> UUID -> Bool+isMarked selfKeyHi selfKeyLo uuid =+ let (rHi, rLo, _, _) = toWords uuid+ r = fromIntegral rHi * 2^(32 :: Int) + fromIntegral rLo+ in mark selfKeyHi selfKeyLo r == uuid
+ stego-uuid.cabal view
@@ -0,0 +1,51 @@+name: stego-uuid+version: 1.0.0.0+synopsis: Generator and verifier for steganographic numbers+description:+ `stego-uuid` allows one to mark 128-bit UUIDs. If created from a random 64-bit number, the+ whole 128-bit UUID will look random to everyone, except those who know the secret detection key.++homepage: https://github.com/dimitri-xyz/stego-uuid#readme+author: Dimitri DeFigueiredo+maintainer: defigueiredo@ucdavis.edu+Bug-Reports: https://github.com/dimitri-xyz/stego-uuid/issues+copyright: 2017 Dimitri DeFigueiredo+license: BSD3+license-file: LICENSE+category: Steganography, Cryptography+build-type: Simple+extra-doc-files: README.md+cabal-version: >=1.20++library+ hs-source-dirs: src+ exposed-modules: Crypto.Stego.UUID++ default-language: Haskell2010+ build-depends: base >= 4.9.1 && < 5+ , uuid >= 1.3.13 && < 1.4+ , cryptonite >= 0.21 && < 0.22+ , bytestring >= 0.10.8 && < 0.11+ , memory >= 0.14.1 && < 0.15++ ghc-options: -Wall -fwarn-incomplete-record-updates -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -j+++test-suite test-stego-uuid++ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Test.hs++ build-depends: base >= 4.9.1 && < 5+ , stego-uuid+ , random >= 1.1 && < 1.2+ , uuid >= 1.3.13 && < 1.4++ ghc-options: -Wall -fwarn-incomplete-record-updates -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -j -threaded -rtsopts -with-rtsopts=-N++ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/dimitri-xyz/stego-uuid
+ test/Test.hs view
@@ -0,0 +1,22 @@+import System.Random+import Data.Word+import Data.UUID++import Crypto.Stego.UUID+++secretHi = KeyHi64 12345+secretLo = KeyLo64 67890++main :: IO ()+main = do++ putStrLn ""+ r <- randomIO :: IO Word64+ let x = mark secretHi secretLo r+ print x+ print (isMarked secretHi secretLo x) -- True++ y <- randomIO :: IO UUID+ print y+ print (isMarked secretHi secretLo y) -- False