{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-} module SSHKey where import qualified Data.ByteString.Lazy.Char8 as L8 import qualified Data.ByteString.Lazy as L #if defined(VERSION_memory) import qualified Data.ByteString.Char8 as S8 import Data.ByteArray.Encoding import FunctorToMaybe #elif defined(VERSION_dataenc) import qualified Codec.Binary.Base64 as Base64 #endif import Data.Binary.Get ( runGet ) import Data.Binary.Put ( putWord32be, runPut, putByteString ) import Data.Binary ( get, put ) import Data.Monoid ( (<>) ) import Data.Maybe ( listToMaybe ) import Data.Char ( isSpace ) import Control.Monad ( guard ) import LengthPrefixedBE type Key = (Integer,Integer) sshrsa :: Integer -> Integer -> L.ByteString sshrsa e n = runPut $ do putWord32be 7 putByteString "ssh-rsa" put (LengthPrefixedBE e) put (LengthPrefixedBE n) keyblob :: Key -> L.ByteString keyblob (n,e) = "ssh-rsa " <> blob where bs = sshrsa e n #if defined(VERSION_memory) blob = L.fromStrict $ convertToBase Base64 (L.toStrict bs) #elif defined(VERSION_dataenc) blob = L8.pack $ Base64.encode (L.unpack bs) #endif blobkey :: L8.ByteString -> Maybe Key blobkey bs = do let (pre,bs1) = L8.splitAt 7 bs guard $ pre == "ssh-rsa" let (sp,bs2) = L8.span isSpace bs1 guard $ not (L8.null sp) bs3 <- listToMaybe $ L8.words bs2 #if defined(VERSION_memory) qq <- fmap L.fromStrict $ functorToMaybe $ convertFromBase Base64 $ L.toStrict bs3 #elif defined(VERSION_dataenc) qq <- L.pack `fmap` Base64.decode (L8.unpack bs3) #endif decode_sshrsa qq where decode_sshrsa :: L8.ByteString -> Maybe Key decode_sshrsa bs = do let (pre,bs1) = L8.splitAt 11 bs guard $ pre == runPut (putWord32be 7 >> putByteString "ssh-rsa") let rsakey = flip runGet bs1 $ do LengthPrefixedBE e <- get LengthPrefixedBE n <- get return (n,e) return rsakey