diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Fedor Gogolev
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/crypto-pubkey-openssh.cabal b/crypto-pubkey-openssh.cabal
new file mode 100644
--- /dev/null
+++ b/crypto-pubkey-openssh.cabal
@@ -0,0 +1,33 @@
+Name:               crypto-pubkey-openssh
+Version:            0.0.0
+Synopsis:           OpenSSH public keys parser
+Description:        OpenSSH public keys parser
+License:            MIT
+License-file:       LICENSE
+Copyright:          Fedor Gogolev <knsd@knsd.net>
+Author:             Fedor Gogolev <knsd@knsd.net>
+Maintainer:         Fedor Gogolev <knsd@knsd.net>
+Homepage:           https://github.com/knsd/crypto-pubkey-openssh
+Bug-reports:        https://github.com/knsd/crypto-pubkey-openssh/issues
+Category:           Cryptography, Parsing
+Stability:          Alpha
+Build-type:         Simple
+Cabal-version:      >= 1.12
+Tested-with:        GHC == 7.6.*
+
+Library
+  Hs-source-dirs:   src
+  Ghc-options:      -Wall -fno-warn-orphans
+  Default-language: Haskell2010
+  Build-depends:    base                      == 4.6.*
+                  , bytestring                == 0.10.*
+                  , base64-bytestring         == 1.0.*
+                  , cereal                    == 0.3.*
+                  , attoparsec                == 0.10.*
+                  , crypto-pubkey-types       == 0.2.*
+
+  Exposed-modules:  Crypto.PubKey.OpenSsh
+
+Source-repository head
+  Type:             git
+  Location:         https://github.com/knsd/crypto-pubkey-openssh
diff --git a/src/Crypto/PubKey/OpenSsh.hs b/src/Crypto/PubKey/OpenSsh.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/PubKey/OpenSsh.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Crypto.PubKey.OpenSsh
+    ( OpenSshPublicKey(..)
+    , openSshPublicKeyParser
+    , parseOpenSshPublicKey
+    ) where
+
+import Prelude hiding (take)
+
+import Control.Monad (void, replicateM)
+import Data.ByteString.Char8 (ByteString)
+
+import Data.Attoparsec.ByteString.Char8 (Parser, parseOnly, take, space,
+                                         isSpace, takeTill)
+import Data.Serialize (Get, getBytes, runGet, getWord32be, getWord8)
+import qualified Data.ByteString.Base64 as Base64
+import qualified Crypto.Types.PubKey.DSA as DSA
+import qualified Crypto.Types.PubKey.RSA as RSA
+
+data OpenSshPublicKey = OpenSshPublicKeyRsa RSA.PublicKey
+                      | OpenSshPublicKeyDsa DSA.PublicKey
+    deriving (Eq, Show)
+
+data OpenSshPublicKeyType = OpenSshPublicKeyTypeRsa
+                          | OpenSshPublicKeyTypeDsa
+    deriving (Eq, Show)
+
+typeSize :: Int
+typeSize = 7
+
+readType :: Monad m => ByteString -> m OpenSshPublicKeyType
+readType "ssh-rsa" = return OpenSshPublicKeyTypeRsa
+readType "ssh-dss" = return OpenSshPublicKeyTypeDsa
+readType _ = fail "Invalid key type"
+
+calculateSize :: Integer -> Int
+calculateSize = go 1
+  where
+    go i n | 2 ^ (i * 8) > n = i
+           | otherwise       = go (i + 1) n
+
+getInteger :: Get Integer
+getInteger = do
+    size <- fmap fromIntegral getWord32be
+    ints <- fmap reverse $ replicateM size $ fmap toInteger getWord8
+    return $ fst $ flip foldl1 (zip ints ([0..] :: [Integer])) $
+        \(a, _) (c, p) -> (c * (256 ^ p) + a, p)
+
+getOpenSshPublicKey :: Get OpenSshPublicKey
+getOpenSshPublicKey = do
+    size <- fmap fromIntegral $ getWord32be
+    getBytes size >>= readType >>= \typ -> case typ of
+        OpenSshPublicKeyTypeRsa -> parseRsa
+        OpenSshPublicKeyTypeDsa -> parseDsa
+  where
+    parseRsa = do 
+        e <- getInteger
+        n <- getInteger
+        return $ OpenSshPublicKeyRsa $ RSA.PublicKey (calculateSize n) n e
+    parseDsa = do
+        p <- getInteger
+        q <- getInteger
+        g <- getInteger
+        y <- getInteger
+        return $ OpenSshPublicKeyDsa $ DSA.PublicKey (p, g, q) y
+
+openSshPublicKeyParser :: Parser OpenSshPublicKey
+openSshPublicKeyParser = do
+    _typ <- readType =<< take typeSize
+    void space
+    b64 <- takeTill isSpace
+    binary <- either fail return $ Base64.decode b64
+    either fail return $ runGet getOpenSshPublicKey binary
+
+parseOpenSshPublicKey :: ByteString -> Either String OpenSshPublicKey
+parseOpenSshPublicKey = parseOnly openSshPublicKeyParser
