diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2017
+
+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 Author name here nor the names of other
+      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
+OWNER 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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# eap
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/eap.cabal b/eap.cabal
new file mode 100644
--- /dev/null
+++ b/eap.cabal
@@ -0,0 +1,28 @@
+name:                eap
+version:             0.1.0.0
+synopsis:            Extensible Authentication Protocol (EAP)
+description:         This module provides types and on the wire de/coding of EAP packets as per RFC 3748
+homepage:            https://github.com/erickg/eap#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Erick Gonzalez
+maintainer:          erick@codemonkeylabs.de
+copyright:           2017 Erick Gonzalez
+category:            Network
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Network.EAP.Encoding
+                     , Network.EAP.Types
+  build-depends:       base >= 4.7 && < 5
+                     , binary
+                     , bytestring
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+source-repository head
+  type:     git
+  location: https://github.com/erickg/eap
diff --git a/src/Network/EAP/Encoding.hs b/src/Network/EAP/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/EAP/Encoding.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-|
+Module      : Network.EAP.Encoding
+Description : Provides on the wire de/coding of EAP packets as per RFC 3748
+Copyright   : (c) Erick Gonzalez, 2017
+License     : BSD3
+Maintainer  : erick@codemonkeylabs.de
+Stability   : experimental
+Portability : POSIX
+
+This basically provides Binary instances for the EAP Packet type and the embedded messages it
+encapsulates. So you basically decode a (lazy) bytestring and get an EAP Packet back or you can
+encode an EAP packet to ByteString you can send on the wire as is. Simple as that.
+
+-}
+module Network.EAP.Encoding where
+
+import Data.Binary                     (Binary(..), encode, decode)
+import Data.Binary.Get                 (Get,
+                                        getRemainingLazyByteString,
+                                        getLazyByteString,
+                                        getWord8,
+                                        getWord16be)
+import Data.Binary.Put                 (putLazyByteString, putWord8, putWord16be)
+import Data.Word                       (Word16)
+import Network.EAP.Types
+
+import qualified Data.ByteString.Lazy.Char8 as LB
+
+instance Binary Packet where
+    put Packet{..} = do
+      let packetData   = encode getPacketMessage
+          packetLength = fromIntegral $ 4 + LB.length packetData -- EAP header length is 4 bytes
+      put getPacketType
+      putWord8 getPacketId
+      putWord16be packetLength
+      putLazyByteString packetData
+
+    get = do
+      packetType   <- get
+      packetId     <- getWord8
+      packetLength <- getWord16be
+      let dataLength = packetLength - 4
+      packetMessage <- getMessage $ fromIntegral dataLength
+      return $ Packet packetType packetId packetMessage
+
+-- | Given the length of data to decode, decode an EAP message in the Get Monad. Used internally
+-- so you probably don't need to use this.
+getMessage :: Word16 -> Get (Maybe Message)
+getMessage 0 = return Nothing
+getMessage dataLength = do
+  packetData <- getLazyByteString $ fromIntegral dataLength
+  return . Just . decode $ packetData
+
+instance Binary Message where
+    put (IdentityMessage str)     = putLazyByteString str
+    put (NotificationMessage str) = putLazyByteString str
+    put (NakMessage value)        = putWord8 value
+    put MD5ChallengeMessage{..}   = do
+      putWord8 . fromIntegral . LB.length $ getMD5ChallengeValue
+      putLazyByteString getMD5ChallengeValue
+      putLazyByteString getMD5ChallengeName
+    put (OTPMessage str)              = putLazyByteString str
+    put (GenericTokenCardMessage str) = putLazyByteString str
+
+    get = do
+      messageType <- getWord8
+      getMessage' messageType
+        where getMessage' 1 = getRemainingLazyByteString >>= return . IdentityMessage
+              getMessage' 2 = getRemainingLazyByteString >>= return . NotificationMessage
+              getMessage' 3 = getWord8 >>= return . NakMessage
+              getMessage' 4 = do
+                valueSize <- getWord8
+                value     <- getLazyByteString $ fromIntegral valueSize
+                name      <- getRemainingLazyByteString
+                return $ MD5ChallengeMessage value name
+              getMessage' 5 = getRemainingLazyByteString >>= return . OTPMessage
+              getMessage' 6 = getRemainingLazyByteString >>= return . GenericTokenCardMessage
+              getMessage' n = fail $ "Invalid EAP Message Type " ++ show n
+
+instance Binary PacketType where
+    put = putWord8 . fromIntegral . fromEnum
+    get = getWord8 >>= return . toEnum . fromIntegral
diff --git a/src/Network/EAP/Types.hs b/src/Network/EAP/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/EAP/Types.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-|
+Module      : Network.EAP.Types
+Description : Provides types and definitions for EAP as per RFC 3748
+Copyright   : (c) Erick Gonzalez, 2017
+License     : BSD3
+Maintainer  : erick@codemonkeylabs.de
+Stability   : experimental
+Portability : POSIX
+
+The types in this module are pretty much self explanatory. See RFC 3748 for further information
+on what a given type or definition means.
+
+-}
+module Network.EAP.Types where
+
+import Data.ByteString.Lazy.Char8        (ByteString)
+import Data.Data                         (Data)
+import Data.Word                         (Word8)
+
+data Packet = Packet { getPacketType    :: PacketType,
+                       getPacketId      :: Word8,
+                       getPacketMessage :: Maybe Message }
+            deriving (Show, Eq, Data)
+
+data PacketType = RequestPacket
+                | ResponsePacket
+                | SuccessPacket
+                | FailurePacket
+                  deriving (Show, Eq, Data)
+
+instance Enum PacketType where
+    toEnum 1 = RequestPacket
+    toEnum 2 = ResponsePacket
+    toEnum 3 = SuccessPacket
+    toEnum 4 = FailurePacket
+    toEnum n = error $ "Invalid EAP packet type " ++ show n
+    fromEnum RequestPacket  = 1
+    fromEnum ResponsePacket = 2
+    fromEnum SuccessPacket  = 3
+    fromEnum FailurePacket  = 4
+
+data Message = IdentityMessage         { getIdentityMessage         :: ByteString }
+             | NotificationMessage     { getNotificationMessage     :: ByteString }
+             | NakMessage              { getAuthenticationType      :: Word8 }
+             | MD5ChallengeMessage     { getMD5ChallengeValue       :: ByteString,
+                                         getMD5ChallengeName        :: ByteString }
+             | OTPMessage              { getOTPMessage              :: ByteString }
+             | GenericTokenCardMessage { getGenericTokenCardMessage :: ByteString }
+               deriving (Show, Eq, Data)
