diff --git a/README.md b/README.md
index b5fa4d9f90c5430e6279adce6344bb06ecd0dbc7..173dc50acc465539b4bcfc940c923d30227c690b 100644
--- a/README.md
+++ b/README.md
@@ -22,3 +22,82 @@ with the benefit of the experience gained from creating and maintaining the Pyth
 a number of implementation decisions can be made differently to produce a more efficient, more flexible, simpler implementation and API.
 Also,
 the Python implementation claims no public library API for users outside of the Tahoe-LAFS project itself.
+
+## Cryptographic Library Choice
+
+This library uses cryptonite for cryptography,
+motivated by the following considerations.
+
+SDMF uses
+* SHA256 for tagged hashes for key derivation and for integrity (XXX right word?) checks on some data.
+* AES128 for encryption of the signature key and the application plaintext data.
+* RSA for signatures proving write authority.
+
+There are a number of Haskell libraries that provide all of these:
+
+* Crypto
+  * Does not support the AES mode we require (CTR).
+
+* HsOpenSSL
+  * Bindings to a C library, OpenSSL, which may complicate the build process.
+  * OpenSSL's security and reliability track record also leaves something to be desired.
+
+* cryptonite
+  * Has all of the primitive cryptographic functionality we need.
+
+We want a library that:
+
+* Can be used with reflex-platform
+  * ghc 8.6.5 compatible
+* Can be cross-compiled to different targets from x86_64-linux
+  * Mainly armeabi and armv7
+* Is suitable for real-world security purposes
+  * not a demo or a toy library
+    * documents its limitations
+  * is well-tested
+  * avoids real-world pitfalls (side-channel attacks, etc), not just textbook issues
+  * has more than a handful of other users
+  * is well-maintained
+    * developers are responsive to security reports
+    * has a channel for security-related disclosures
+	* has sound documentation for proper, safe usage
+
+And,
+of course,
+implements the required functionality.
+
+### SHA256
+
+There are a number of Haskell libraries that provide this primitive:
+
+* Crypto
+* HsOpenSSL
+* SHA
+* cryptohash
+* cryptonite
+* dhall
+* hashing
+* nettle
+* sbv
+* tls
+
+### AES128
+
+* Crypto
+* HsOpenSSL
+* cipher-aes
+* cipher-aes128
+* crypto
+* cryptocipher
+* cryptonite
+* cryptostore
+* nettle
+
+### RSA
+
+SDMF depends on RSA for signatures proving write authority.
+
+* Crypto
+* HsOpenSSL
+* RSA
+* cryptonite
diff --git a/make-keypairs/Main.hs b/make-keypairs/Main.hs
index c537ae4d3420c2c0ee42f80ac67c4d3cd281cd2b..d77171e5303c5fedfedabacef1830f9c687e5581 100644
--- a/make-keypairs/Main.hs
+++ b/make-keypairs/Main.hs
@@ -1,11 +1,11 @@
 module Main where
 
-import Codec.Crypto.RSA (generateKeyPair)
-import Crypto.Random (CryptoRandomGen (newGenIO), SystemRandom)
+import qualified Crypto.PubKey.RSA as RSA
 import Data.ASN1.BinaryEncoding (DER (DER))
 import Data.ASN1.Encoding (ASN1Encoding (encodeASN1))
 import Data.ASN1.Types (ASN1Object (toASN1))
 import qualified Data.ByteString.Lazy as LB
+import Data.X509 (PrivKey (PrivKeyRSA))
 
 -- | The size of the keys to generate.
 bits :: Int
@@ -17,11 +17,12 @@ count = 5
 
 main :: IO ()
 main = do
-    g <- newGenIO :: IO SystemRandom
-    mapM_ (genKey g) [0 .. count - 1]
+    mapM_ genKey [0 .. count - 1]
 
-genKey :: (Show a, CryptoRandomGen c) => c -> a -> IO ()
-genKey g n =
-    let (_, priv, _) = generateKeyPair g bits
-        bytes = encodeASN1 DER (toASN1 priv [])
-     in LB.writeFile ("test/data/rsa-privkey-" <> show n <> ".der") bytes
+genKey :: Show a => a -> IO ()
+genKey n = do
+    (_, priv) <- RSA.generate bits e
+    let bytes = encodeASN1 DER (toASN1 (PrivKeyRSA priv) [])
+    LB.writeFile ("test/data/rsa-privkey-" <> show n <> ".der") bytes
+  where
+    e = 0x10001
diff --git a/src/Tahoe/SDMF/Internal/Share.hs b/src/Tahoe/SDMF/Internal/Share.hs
index f4587950a072be0798d3b09a37608e1dfdaf841e..989f0714f57be13589de2ceb8fd6e3b36d9554b3 100644
--- a/src/Tahoe/SDMF/Internal/Share.hs
+++ b/src/Tahoe/SDMF/Internal/Share.hs
@@ -3,16 +3,19 @@ module Tahoe.SDMF.Internal.Share where
 
 import Control.Monad (unless)
 import Crypto.Cipher.AES (AES128)
+import Crypto.Cipher.Types (IV, makeIV)
 import qualified Crypto.PubKey.RSA.Types as RSA
-import Crypto.Types (IV (IV, initializationVector))
 import Data.ASN1.BinaryEncoding (DER (DER))
 import Data.ASN1.Encoding (ASN1Encoding (encodeASN1), decodeASN1')
 import Data.ASN1.Types (ASN1Object (fromASN1, toASN1))
 import Data.Binary (Binary (..), Get, getWord8)
 import Data.Binary.Get (bytesRead, getByteString, getLazyByteString, getRemainingLazyByteString, getWord16be, getWord32be, getWord64be, isEmpty, isolate)
 import Data.Binary.Put (putByteString, putLazyByteString, putWord16be, putWord32be, putWord64be, putWord8)
+import qualified Data.ByteArray as ByteArray
 import qualified Data.ByteString as B
+import Data.ByteString.Base32 (encodeBase32Unpadded)
 import qualified Data.ByteString.Lazy as LB
+import qualified Data.Text as T
 import Data.Word (Word16, Word64, Word8)
 import Data.X509 (PubKey (PubKeyRSA))
 import Tahoe.CHK.Merkle (MerkleTree, leafHashes)
@@ -57,7 +60,7 @@ data Share = Share
     , -- | "R" (root of share hash merkle tree)
       shareRootHash :: B.ByteString
     , -- | The IV for encryption of share data.
-      shareIV :: IV AES128
+      shareIV :: SDMF_IV
     , -- | The total number of encoded shares (k).
       shareTotalShares :: Word8
     , -- | The number of shares required for decoding (N).
@@ -86,12 +89,19 @@ data Share = Share
     }
     deriving (Eq, Show)
 
+newtype SDMF_IV = SDMF_IV (IV AES128)
+    deriving (Eq)
+    deriving newtype (ByteArray.ByteArrayAccess)
+
+instance Show SDMF_IV where
+    show (SDMF_IV iv) = T.unpack . T.toLower . encodeBase32Unpadded . ByteArray.convert $ iv
+
 instance Binary Share where
     put Share{..} = do
         putWord8 0
         putWord64be shareSequenceNumber
         putByteString shareRootHash
-        putByteString . initializationVector $ shareIV
+        putByteString . ByteArray.convert $ shareIV
         putWord8 shareTotalShares
         putWord8 shareRequiredShares
         putWord64be shareSegmentSize
@@ -125,7 +135,12 @@ instance Binary Share where
         unless (version == 0) (fail $ "Only version 0 is supported; got version " <> show version)
         shareSequenceNumber <- getWord64be
         shareRootHash <- getByteString 32
-        shareIV <- IV <$> getByteString 16
+        ivBytes <- getByteString 16
+        shareIV <-
+            SDMF_IV <$> case makeIV ivBytes of
+                Nothing -> fail "Could not decode IV"
+                Just iv -> pure iv
+
         shareTotalShares <- getWord8
         shareRequiredShares <- getWord8
         shareSegmentSize <- getWord64be
diff --git a/tahoe-ssk.cabal b/tahoe-ssk.cabal
index e8e79204194a03efb6105a4378fcea6ea50ce25a..7a873bea65afab04a5eabd94b1b6f4a776218664 100644
--- a/tahoe-ssk.cabal
+++ b/tahoe-ssk.cabal
@@ -69,12 +69,12 @@ library
     , asn1-encoding
     , asn1-types
     , base
+    , base32
     , binary
     , bytestring
-    , crypto-api
-    , crypto-pubkey-types
     , cryptonite
-    , RSA
+    , memory
+    , text
     , x509
 
   -- This dependency isn't ideal.  Move common bits out to
@@ -119,14 +119,11 @@ test-suite tahoe-ssk-test
   build-depends:
     , asn1-encoding
     , asn1-types
-    , base                 ^>=4.14.3.0
+    , base            ^>=4.14.3.0
     , binary
     , bytestring
-    , crypto-api
-    , crypto-pubkey-types
     , cryptonite
     , hedgehog
-    , RSA
     , tahoe-chk
     , tahoe-ssk
     , tasty
@@ -145,6 +142,5 @@ executable make-keypairs
     , asn1-types
     , base
     , bytestring
-    , crypto-api
-    , crypto-pubkey-types
-    , RSA
+    , cryptonite
+    , x509
diff --git a/test/Generators.hs b/test/Generators.hs
index 916105480e795d564e32d12bbe54d0f7c64ded65..be8e2b78e313ddbaff67c27831d3837bb1fca991 100644
--- a/test/Generators.hs
+++ b/test/Generators.hs
@@ -1,9 +1,9 @@
 module Generators where
 
+import Crypto.Cipher.Types (makeIV)
 import Crypto.Hash (HashAlgorithm (hashDigestSize))
 import Crypto.Hash.Algorithms (SHA256 (SHA256))
-import qualified Crypto.PubKey.RSA.Types as RSA
-import Crypto.Types (IV (..))
+import qualified Crypto.PubKey.RSA as RSA
 import Data.ASN1.BinaryEncoding (DER (DER))
 import Data.ASN1.Encoding (ASN1Decoding (decodeASN1), ASN1Encoding (encodeASN1))
 import Data.ASN1.Types (ASN1Object (fromASN1, toASN1))
@@ -17,7 +17,7 @@ import qualified Hedgehog.Gen as Gen
 import qualified Hedgehog.Range as Range
 import Tahoe.CHK.Merkle (MerkleTree (..), makeTreePartial)
 import Tahoe.SDMF (Share (..))
-import Tahoe.SDMF.Internal.Share (HashChain (HashChain))
+import Tahoe.SDMF.Internal.Share (HashChain (HashChain), SDMF_IV (..))
 
 rootHashLength :: Int
 rootHashLength = 32
@@ -28,26 +28,34 @@ ivLength = 16
 signatureLength :: Range.Range Int
 signatureLength = Range.linear 250 260
 
+newtype KeyPair = KeyPair RSA.PrivateKey
+toPrivateKey (KeyPair privKey) = privKey
+toPublicKey = RSA.private_pub . toPrivateKey
+
 {- | Generate SDMF shares.  The contents of the share are not necessarily
  semantically valid.
 -}
 shares :: MonadGen m => m Share
-shares =
-    genRSAKeys >>= \keypair ->
-        Share
-            <$> Gen.word64 Range.exponentialBounded -- shareSequenceNumber
-            <*> Gen.bytes (Range.singleton rootHashLength) -- shareRootHash
-            <*> (IV <$> Gen.bytes (Range.singleton ivLength)) -- shareIV
-            <*> Gen.word8 Range.exponentialBounded -- shareTotalShares
-            <*> Gen.word8 Range.exponentialBounded -- shareRequiredShares
-            <*> Gen.word64 Range.exponentialBounded -- shareSegmentSize
-            <*> Gen.word64 Range.exponentialBounded -- shareDataLength
-            <*> pure (RSA.toPublicKey keypair) -- shareVerificationKey
-            <*> Gen.bytes signatureLength -- shareSignature
-            <*> shareHashChains -- shareHashChain
-            <*> merkleTrees (Range.singleton 1) -- shareBlockHashTree
-            <*> (LB.fromStrict <$> Gen.bytes (Range.exponential 0 1024)) -- shareData
-            <*> (pure . LB.toStrict . toDER . PrivKeyRSA . RSA.toPrivateKey) keypair -- shareEncryptedPrivateKey
+shares = do
+    keypair <- genRSAKeys
+    iv <- makeIV <$> Gen.bytes (Range.singleton ivLength)
+    case iv of
+        Nothing -> error "Could not build IV for SDMF share"
+        Just iv' ->
+            Share
+                <$> Gen.word64 Range.exponentialBounded -- shareSequenceNumber
+                <*> Gen.bytes (Range.singleton rootHashLength) -- shareRootHash
+                <*> pure (SDMF_IV iv') -- shareIV
+                <*> Gen.word8 Range.exponentialBounded -- shareTotalShares
+                <*> Gen.word8 Range.exponentialBounded -- shareRequiredShares
+                <*> Gen.word64 Range.exponentialBounded -- shareSegmentSize
+                <*> Gen.word64 Range.exponentialBounded -- shareDataLength
+                <*> pure (toPublicKey keypair) -- shareVerificationKey
+                <*> Gen.bytes signatureLength -- shareSignature
+                <*> shareHashChains -- shareHashChain
+                <*> merkleTrees (Range.singleton 1) -- shareBlockHashTree
+                <*> (LB.fromStrict <$> Gen.bytes (Range.exponential 0 1024)) -- shareData
+                <*> (pure . LB.toStrict . toDER . PrivKeyRSA . toPrivateKey) keypair -- shareEncryptedPrivateKey
   where
     toDER = encodeASN1 DER . flip toASN1 []
 
@@ -59,7 +67,7 @@ shares =
  challenging, this implementation just knows a few RSA key pairs already and
  will give back one of them.
 -}
-genRSAKeys :: MonadGen m => m RSA.KeyPair
+genRSAKeys :: MonadGen m => m KeyPair
 genRSAKeys = Gen.element (map rsaKeyPair rsaKeyPairBytes)
 
 -- I'm not sure how to do IO in MonadGen so do the IO up front unsafely (but
@@ -68,13 +76,13 @@ rsaKeyPairBytes :: [LB.ByteString]
 {-# NOINLINE rsaKeyPairBytes #-}
 rsaKeyPairBytes = unsafePerformIO $ mapM (\n -> LB.readFile ("test/data/rsa-privkey-" <> show n <> ".der")) [0 .. 4 :: Int]
 
-rsaKeyPair :: LB.ByteString -> RSA.KeyPair
+rsaKeyPair :: LB.ByteString -> KeyPair
 rsaKeyPair bs = do
     let (Right kp) = do
             asn1s <- first show (decodeASN1 DER bs)
             (r, _) <- fromASN1 asn1s
             case r of
-                PrivKeyRSA pk -> pure $ RSA.KeyPair pk
+                PrivKeyRSA pk -> pure $ KeyPair pk
                 _ -> error "Expected RSA Private Key"
     kp