diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+crypto-pubkey-openssh [![Build Status](https://secure.travis-ci.org/knsd/crypto-pubkey-openssh.png)](http://travis-ci.org/knsd/crypto-pubkey-openssh)
+=====================
+
+OpenSSH keys decoder/encoder, example.
+
+```haskell
+import System.Environment (getArgs)
+import qualified Data.ByteString as B
+
+import Crypto.PubKey.OpenSsh (decodePrivate)
+
+main :: IO ()
+main = do
+    fname <- fmap head getArgs
+    content <- B.readFile fname
+    case decodePrivate content of
+        Left e -> error e
+        Right key -> print key
+```
diff --git a/crypto-pubkey-openssh.cabal b/crypto-pubkey-openssh.cabal
--- a/crypto-pubkey-openssh.cabal
+++ b/crypto-pubkey-openssh.cabal
@@ -1,5 +1,5 @@
 Name:               crypto-pubkey-openssh
-Version:            0.2.6
+Version:            0.2.7
 Synopsis:           OpenSSH keys decoder/encoder
 Description:        OpenSSH keys decoder/encoder
 License:            MIT
@@ -17,6 +17,9 @@
 Cabal-version:      >= 1.12
 Tested-with:        GHC == 7.6.*
 
+Extra-source-files:
+  README.md
+
 Flag OpenSsh
   Description:      Test with ssh-keygen
   Default:          False
@@ -25,15 +28,15 @@
   Hs-source-dirs:   src
   Ghc-options:      -Wall -fno-warn-orphans
   Default-language: Haskell2010
-  Build-depends:    base                       == 4.7.*  || == 4.6.*  || == 4.5.*
-                  , bytestring                 == 0.10.* || == 0.9.*
-                  , base64-bytestring          == 1.0.*
-                  , cereal                     == 0.4.*
-                  , attoparsec                 >= 0.10
-                  , crypto-pubkey-types        == 0.4.*
-                  , pem                        == 0.2.*
-                  , asn1-types                 == 0.2.*
-                  , asn1-encoding              == 0.8.*
+  Build-depends:    base                       >= 4.5 && < 5
+                  , bytestring
+                  , base64-bytestring
+                  , cereal
+                  , attoparsec
+                  , crypto-pubkey-types
+                  , pem
+                  , asn1-types
+                  , asn1-encoding
 
   Exposed-modules:  Crypto.PubKey.OpenSsh
   Other-modules:    Crypto.PubKey.OpenSsh.Types
@@ -49,23 +52,27 @@
   if flag(OpenSsh)
     cpp-options: -DOPENSSH
 
-  Build-depends:    base                       == 4.7.*  || == 4.6.*  || == 4.5.*
-                  , bytestring                 == 0.10.* || == 0.9.*
-                  , base64-bytestring          == 1.0.*
-                  , cereal                     == 0.4.*
-                  , attoparsec                 >= 0.10
-                  , crypto-pubkey-types        == 0.4.*
-                  , pem                        == 0.2.*
-                  , asn1-types                 == 0.2.*
-                  , asn1-encoding              == 0.8.*
+  Build-depends:    base                       >= 4.5 && < 5
+                  , bytestring
+                  , base64-bytestring
+                  , cereal
+                  , attoparsec
+                  , crypto-pubkey-types
+                  , pem
+                  , asn1-types
+                  , asn1-encoding
 
-                  , tasty                      == 0.8.*
-                  , tasty-quickcheck           == 0.8.*
-                  , QuickCheck                 >= 2.6
-                  , temporary                  == 1.2.*  || == 1.1.*
-                  , process                    == 1.2.*
-                  , filepath                   == 1.3.*
-                  , deepseq                    == 1.3.*
+                  , tasty
+                  , tasty-quickcheck
+                  , QuickCheck
+                  , temporary
+                  , process
+                  , filepath
+                  , deepseq
+
+  Other-modules:    Crypto.PubKey.OpenSsh.Encode.Tests
+                    Crypto.PubKey.OpenSsh.Decode.Tests
+                    SshKeygen
 
 Source-repository head
   Type:             git
diff --git a/tests/Crypto/PubKey/OpenSsh/Decode/Tests.hs b/tests/Crypto/PubKey/OpenSsh/Decode/Tests.hs
new file mode 100644
--- /dev/null
+++ b/tests/Crypto/PubKey/OpenSsh/Decode/Tests.hs
@@ -0,0 +1,87 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Crypto.PubKey.OpenSsh.Decode.Tests
+    ( tests
+    ) where
+
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.QuickCheck (testProperty, once)
+
+import Crypto.PubKey.OpenSsh.Decode (decodePublic, decodePrivate)
+import Data.ByteString.Char8 ()
+
+testDecodeRSAPublic :: Bool
+testDecodeRSAPublic =
+    case decodePublic rsaPub of
+        Left _  -> False
+        Right _ -> True
+ where
+  rsaPub = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtuy+p1/IHUtofNeUg6Ex2Sc3f0B+97VsfAq65pyKvAAqAtZpR96Vr35hbaNEb+j3fpAXjrxouM87q5KksWD+0qFWNhDv7rBg6ENQJNLf5lfssiFacrVv1/SG2UP8VDkCMxpJyzcHE5ajmSzcjEFoerRudV2g05PPlw4fNyuhVaMQjNUejg+17CUPS8e7TxUoRvnVuBVSMezMn11n81djakzuit7nXj1L7WVqNHtAlbstK2aDdCB3yBOtOwBQVwvFwQfHpQ8hwrYoKAXPw3YTd9sPTtJ0qz0cZH89t7redHABRhOWdf7+cm0LpubqwWvv0SLlFRMwefoMsGcnJ6E7P tommd@Vodka"
+
+testDecodeRSAPrivate :: Bool
+testDecodeRSAPrivate =
+    case decodePrivate rsaPriv of
+        Left _  -> False
+        Right _ -> True
+ where
+ rsaPriv = "-----BEGIN RSA PRIVATE KEY-----\n\
+\MIIEpAIBAAKCAQEAw6s7oDCoXjEkrLDRVZDyWLVaiqxZyOTA33TyGSELv9ZiQzkr\n\
+\ti+AOyuTWkmZjHYdLDWBYYQvwEjufzneHvNLw87/1zsQrd6ZPUwEOkh0RqG9mxoV\n\
+\JFgpruzKoG6BNgnUti/S9idErit+XEx9ff8bmmjawdC10czAdL3zCpZaEXw4JAwC\n\
+\sgQB1J1/Mw4cnzMqKyxPtSPZjhiZZ6y2bVCfNfnOZ9dvIDa/unEWlFSDPjX0+zSM\n\
+\mjRzDoE04jtoAI0v3iynZ26kea+YU4oni2MQ7EL4Y1CmLAWm4/9APhf3Xt0EJOIt\n\
+\Ngv1j2468+8WF5aTEitb8D2ZRFYPiLWMaJlhGwIDAQABAoIBAQCWAPXLDsJkw4P8\n\
+\J+mzkVVZEF8DJLIIQuZh6MOY5C6fuPjH1FJgbvX9ZqCmfPoMJpiixboUSkRZQxAj\n\
+\1Pcl/xq8WDrmg897m8UaquYq0FTjuScketBudnAuPDXy3ASOqua5bNxr/Rq383wB\n\
+\wloKd8Jvk6bxItHgrvl0BhMGsNEHyT36SXmc7HsgCzifuXMo5E3uqTGP/+wLWCRy\n\
+\NO+AqStSjQbQZtLVOvNdQYknv+uqm/m5LyO1Vi2pPl0vEgpwiq4C/8W+YT2ya3dz\n\
+\QfG+Fsewu5WDdHTBgTN4F/p2tgG6Zg+fdfRkF2NNwJXiGb1TTmR1IMZtzqDQ5mys\n\
+\dk40xuAxAoGBAOTMhUpINw2rSaduEWAxnSAZFMAIozKBOJD1Q2+kYbYMHPOPN+CN\n\
+\NCUrWpEiFa+vM+BIrQsG6M7Nb9VmefOKuS7vetIUYWsJ2hO8oX2+8ZiPcBwU3izX\n\
+\wAoGq0yeUaG4yGZUrkP2Gfm+jUdj/AoGOnG9pd/CYDevVNnOSyWko8RVAoGBANru\n\
+\Zupv8fIXDcnqYGBAbHpBQkojAzccBHxyE/4BUJlFIZWDAMem50op49SsF6gKrxtO\n\
+\IvXb1+58axGza84F7cXmQgR0nV8AXMzBlI31HyvftMv8Yb1h+oXbjCFI99lMz6/F\n\
+\jkCSzoiLGo0NAEmqRb4TThSjj8vfiw+zxsllQH+vAoGAFmKcN+RQ3pl/n035jTvN\n\
+\b7KEgTVXIj3aVvRoIKgolzMgMgQ1J1cpXuma9tAq5wFxReRWadnHNVSMOIjKLbXI\n\
+\4Hq1vZAY5+wS1hOCiVcBNDf0dArmoeSJ+XElmV10ByqZEMoAMs4FRJYMJIv3wNNT\n\
+\LIWtkPLnjwssdhLk703oZ/ECgYB/4JCsjwa7aUvcjNIOZpL2NfgKZbkTD4JvThLv\n\
+\YsU5QXAEbKif9ZVTdHRnXL3Uoaj2QgWZpffSjUnc5PgrNrtTxNL610K0ovmRf+DN\n\
+\qkey0NBB9gEBJaG3Xi3To1Nh0cPd337fqOCKUPYJPXbVkGd8Rrpsw7zSUJhha5jJ\n\
+\OiMacQKBgQCxDCTOUqDksmXkDutXi/f/dMIwfMXaNuTc3ectyaBC05+0B10uLfnv\n\
+\7jurNd89OFTHsu7CLfbwDzu+Q+GWTWemUk2ieq9z0Ct5aIzjxoALNnKiu5pH1YDH\n\
+\Mf6ApFppkCpTkQ0sEERn0zH/hNQct1cwflfQi7JN+3GGax7oySmQRQ==\n\
+\-----END RSA PRIVATE KEY-----"
+
+testDecodeDSAPublic :: Bool
+testDecodeDSAPublic =
+    case decodePublic dsaPub of
+        Left _  -> False
+        Right _ -> True
+ where
+  dsaPub = "ssh-dss AAAAB3NzaC1kc3MAAACBALco1Yeq0uPETFRf72VbmH+sMttQMbs1GRF+9vbkI7GJZtaRCE2+jtVSiFXDBm4Yuxf+pqvdQ6Jl1X/zuED/YzN2GIVhHMzy12KQ27E8B63vIP/hhLaYv7Tw00yE7HzxBrbx4rfdkPguam0Mjzqhck4cwVKsKhuSinaGTwqMF+KRAAAAFQCziBsxBGOF2YDzsXnBs+Jv0p2GewAAAIEAiCaFUZcLEO5WTAi/lQNo42ZyXP2rl1jeugPVCtDSWhSEHU1EIJcmmCx//ofaOz/X2uJAv15ZjLY8xZW41N2wHA64mhjaXzBBUeVqAOgoYW8dQOo2XNFmU7idWsYxhsUUknWDf9A6v4blUgQNHn1u8c4Y3xcfCEHfZB6om6XA7aAAAACAI3H1hNNXWzd5Fuqpj1ZeUKFAOfFbYeD3XBIKwwMPdrVZW/PMJ3s+Ic90V0paKBA0+Sgvg+EHWK213+zEp29+lL50Nne7jh//smQ0zBKMiRre7iZ+rEDM4nWZOM3vzClfgilTDkkQ4TCjz7yMm21ZqApt+Lq5uNOK6DJB4PszCwI= tommd@Vodka"
+
+testDecodeDSAPrivate :: Bool
+testDecodeDSAPrivate =
+    case decodePrivate dsaPriv of
+        Left _  -> False
+        Right _ -> True
+ where
+  dsaPriv = "-----BEGIN DSA PRIVATE KEY-----\n\
+\MIIBuwIBAAKBgQC3KNWHqtLjxExUX+9lW5h/rDLbUDG7NRkRfvb25COxiWbWkQhN\n\
+\vo7VUohVwwZuGLsX/qar3UOiZdV/87hA/2MzdhiFYRzM8tdikNuxPAet7yD/4YS2\n\
+\mL+08NNMhOx88Qa28eK33ZD4LmptDI86oXJOHMFSrCobkop2hk8KjBfikQIVALOI\n\
+\GzEEY4XZgPOxecGz4m/SnYZ7AoGBAIgmhVGXCxDuVkwIv5UDaONmclz9q5dY3roD\n\
+\1QrQ0loUhB1NRCCXJpgsf/6H2js/19riQL9eWYy2PMWVuNTdsBwOuJoY2l8wQVHl\n\
+\agDoKGFvHUDqNlzRZlO4nVrGMYbFFJJ1g3/QOr+G5VIEDR59bvHOGN8XHwhB32Qe\n\
+\qJulwO2gAoGAI3H1hNNXWzd5Fuqpj1ZeUKFAOfFbYeD3XBIKwwMPdrVZW/PMJ3s+\n\
+\Ic90V0paKBA0+Sgvg+EHWK213+zEp29+lL50Nne7jh//smQ0zBKMiRre7iZ+rEDM\n\
+\4nWZOM3vzClfgilTDkkQ4TCjz7yMm21ZqApt+Lq5uNOK6DJB4PszCwICFAG6JRA/\n\
+\iyaf5dPPUem5PxQeKx1b\n\
+\-----END DSA PRIVATE KEY-----"
+
+tests :: TestTree
+tests = testGroup "Crypto.PubKey.OpenSsh.Decode.Tests"
+    [ testProperty "Decode Public RSA" $ once testDecodeRSAPublic
+    , testProperty "Decode Private RSA" $ once testDecodeRSAPrivate
+    , testProperty "Decode Public DSA" $ once testDecodeDSAPublic
+    , testProperty "Decode Private DSA" $ once testDecodeDSAPrivate
+    ]
diff --git a/tests/Crypto/PubKey/OpenSsh/Encode/Tests.hs b/tests/Crypto/PubKey/OpenSsh/Encode/Tests.hs
new file mode 100644
--- /dev/null
+++ b/tests/Crypto/PubKey/OpenSsh/Encode/Tests.hs
@@ -0,0 +1,20 @@
+module Crypto.PubKey.OpenSsh.Encode.Tests
+    ( tests
+    ) where
+
+import Control.DeepSeq (deepseq)
+import Data.Word (Word8)
+
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.QuickCheck (testProperty)
+
+import Crypto.PubKey.OpenSsh.Encode (fixZeroByte)
+
+-- | In version 0.2.0 `fixZeroByte` function fails with empty input
+testFixZeroByte :: [Word8] -> Bool
+testFixZeroByte i = fixZeroByte i `deepseq` True
+
+tests :: TestTree
+tests = testGroup "Crypto.PubKey.OpenSsh.Encode.Tests"
+    [ testProperty "regression test testFixZeroByte" testFixZeroByte
+    ]
diff --git a/tests/SshKeygen.hs b/tests/SshKeygen.hs
new file mode 100644
--- /dev/null
+++ b/tests/SshKeygen.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+
+module SshKeygen where
+
+import Data.Monoid ((<>))
+import System.FilePath.Posix ((</>), (<.>))
+import System.Process (runCommand, waitForProcess)
+import System.IO.Temp (withSystemTempDirectory)
+import qualified Data.ByteString.Char8 as SB
+
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.QuickCheck (Property, Arbitrary(..), elements, suchThat, testProperty)
+import Test.QuickCheck.Monadic (monadicIO, run, assert)
+
+import Crypto.PubKey.OpenSsh.Types (OpenSshKeyType(..), OpenSshPublicKey(..),
+                                    OpenSshPrivateKey(..))
+import Crypto.PubKey.OpenSsh (encodePublic, decodePublic,
+                              encodePrivate, decodePrivate)
+
+import qualified Crypto.PubKey.OpenSsh.Encode.Tests
+
+type StrictByteString = SB.ByteString
+type PrivateKey = StrictByteString
+type PublicKey = StrictByteString
+
+instance Arbitrary OpenSshKeyType where
+    arbitrary = elements [OpenSshKeyTypeRsa, OpenSshKeyTypeDsa]
+
+openSshKeys :: OpenSshKeyType -> IO (PrivateKey, PublicKey)
+openSshKeys t = withSystemTempDirectory base $ \dir -> do
+    let path = dir </> typ
+    let run = "ssh-keygen -t " <> typ <> " -N \"\" -f " <> path
+    waitForProcess =<< runCommand run
+    priv <- SB.readFile $ path
+    pub <- fmap SB.init $ SB.readFile $ path <.> "pub"
+    return (priv, pub)
+  where
+    base = "crypto-pubkey-openssh-tests"
+    typ = case t of
+        OpenSshKeyTypeRsa -> "rsa"
+        OpenSshKeyTypeDsa -> "dsa"
+
+testWithOpenSsh :: OpenSshKeyType -> Property
+testWithOpenSsh t = monadicIO $ do
+    (priv, pub) <- run $ openSshKeys t
+    assert $ checkPublic (decodePublic pub) pub
+    assert $ checkPrivate (decodePrivate priv) priv
+  where
+    checkPublic = case t of
+        OpenSshKeyTypeRsa -> \r b -> case r of
+            Right k@(OpenSshPublicKeyRsa _ _) ->
+                encodePublic k == b
+            _                                 -> False
+        OpenSshKeyTypeDsa -> \r b -> case r of
+            Right k@(OpenSshPublicKeyDsa _ _) ->
+                encodePublic k == b
+            _                                 -> False
+    checkPrivate = case t of
+        OpenSshKeyTypeRsa -> \r b -> case r of
+            Right k@(OpenSshPrivateKeyRsa _) ->
+                encodePrivate k == b
+            _                                 -> False
+        OpenSshKeyTypeDsa -> \r b -> case r of
+            Right k@(OpenSshPrivateKeyDsa _ _) ->
+                encodePrivate k == b
+            _                                 -> False
+
+tests :: TestTree
+tests = testGroup "SshKeygen"
+    [ testProperty "decode/encode" $ testWithOpenSsh
+    ]
