diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Stephen Blackheath
+
+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 Stephen Blackheath 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/Network/ADB/Client.hs b/Network/ADB/Client.hs
new file mode 100644
--- /dev/null
+++ b/Network/ADB/Client.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, OverloadedStrings,
+        ForeignFunctionInterface, EmptyDataDecls #-}
+module Network.ADB.Client (
+        Session,
+        withClientSession,
+        withConnect,
+        module Network.ADB.Transport
+    ) where
+
+import Network.ADB.Common
+import Network.ADB.Transport
+
+import Control.Applicative
+import Control.Concurrent
+import Control.Concurrent.MVar
+import Control.Exception
+import Control.Monad.Error
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as C
+import qualified Data.ByteString.Unsafe as B
+import qualified Data.ByteString.Internal as BI
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Monoid
+import Foreign
+import Foreign.C
+import Prelude hiding (read, catch)
+
+
+withClientSession :: Transport (ErrorT TransportError IO)
+                  -> (Session (ErrorT TransportError IO) -> ErrorT TransportError IO a)
+                  -> ErrorT TransportError IO a
+withClientSession tra code = do
+    negotiate tra
+    withSession tra code
+
+-- | Performs negotiation on a packetTransport
+negotiate :: (MonadError TransportError m, Applicative m, MonadIO m) =>
+             Transport m -> m ()
+negotiate tra = do
+    write tra $ formatPacket $ Packet SYNC 1 0 B.empty
+    write tra $ formatPacket $ Packet CNXN a_VERSION mAX_PAYLOAD "host::\0"
+    auth <- liftIO adbAuthNew
+    awaitCNXN auth
+  where
+    awaitCNXN auth = do
+        pkt <- readPacket tra
+        case pktCommand pkt of
+            CNXN -> return ()
+            AUTH -> do
+                --liftIO $ putStrLn $ "RECV "++show pkt
+                mReply <- liftIO $ adbAuth auth pkt
+                case mReply of
+                    Just reply -> do
+                        --liftIO $ putStrLn $ "SEND "++show reply
+                        write tra $ formatPacket reply
+                    Nothing -> return ()
+                awaitCNXN auth
+            _    -> awaitCNXN auth
+
+data ADBAuth_Struct
+type ADBAuth = Ptr ADBAuth_Struct
+
+foreign import ccall unsafe "adb_auth_new" adbAuthNew
+    :: IO ADBAuth
+
+{- Handle adb's AUTH command. If it wants to reply, it will return
+   with 1 and pkt will contain the packet to be sent. -}
+foreign import ccall unsafe "adb_auth" _adb_auth
+    :: ADBAuth -> Ptr Word8 -> IO CInt
+
+adbAuth :: ADBAuth -> Packet -> IO (Maybe Packet)
+adbAuth auth pkt = do
+    pkt_c <- B.unsafeUseAsCStringLen (formatPacket pkt) $ \(pkt_c, len) -> do
+        p <- mallocBytes (4096 + 24)
+        BI.memcpy p (castPtr pkt_c) len
+        return p
+    ret <-_adb_auth auth pkt_c
+    if ret /= 0
+        then do
+            outLen <- peekElemOff (castPtr pkt_c :: Ptr Word32) 3
+            let olen = fromIntegral outLen + 24
+            bs' <- BI.create olen $ \p -> BI.memcpy p pkt_c olen
+            free pkt_c
+            case parsePacket bs' of
+                Left err -> fail $ "bad packet from adbAuth: "++err
+                Right opkt -> return $ Just opkt
+        else do
+            free pkt_c
+            return Nothing
+
+withConnect :: Session (ErrorT TransportError IO) 
+            -> C.ByteString
+            -> (Transport (ErrorT TransportError IO) -> ErrorT TransportError IO a)
+            -> ErrorT TransportError IO a
+withConnect session@(Session allocLocalID writePkt readPkt) uri code = do
+    localID <- liftIO allocLocalID
+    writePkt $ Packet OPEN localID 0 (uri <> B.singleton 0)
+    let awaitResult = do
+            pkt <- readPkt
+            if pktCommand pkt == OKAY && pktArg1 pkt == localID
+                then return $ Just $ pktArg0 pkt
+                else if pktCommand pkt == CLSE && pktArg1 pkt == localID
+                    then return $ Nothing
+                    else awaitResult
+    mTransportID <- awaitResult
+
+    case mTransportID of
+        Nothing -> do
+            throwError $ ConnectionFailure "no response"
+        Just remoteID -> do
+            withConversation session localID remoteID code
+
diff --git a/Network/ADB/Common.hs b/Network/ADB/Common.hs
new file mode 100644
--- /dev/null
+++ b/Network/ADB/Common.hs
@@ -0,0 +1,224 @@
+{-# LANGUAGE FlexibleContexts #-}
+module Network.ADB.Common where
+
+import Network.ADB.Transport
+
+import Control.Applicative
+import Control.Concurrent
+import Control.Exception
+import Control.Monad.Error
+import Data.Bits
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.List
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Sequence (Seq, (<|), (|>))
+import qualified Data.Sequence as Seq
+import Data.Serialize
+import Data.Word
+import Prelude hiding (read)
+
+
+mAX_PAYLOAD :: Word32
+mAX_PAYLOAD = 4096
+
+a_VERSION :: Word32
+a_VERSION = 0x01000000        -- ADB protocol version
+
+data Command = SYNC | CNXN | AUTH | OPEN | OKAY | CLSE | WRTE
+    deriving (Eq, Ord, Show)
+
+fromCommand :: Command -> Word32
+fromCommand SYNC = 0x434e5953
+fromCommand CNXN = 0x4e584e43
+fromCommand AUTH = 0x48545541
+fromCommand OPEN = 0x4e45504f
+fromCommand OKAY = 0x59414b4f
+fromCommand CLSE = 0x45534c43
+fromCommand WRTE = 0x45545257
+
+toCommand :: Word32 -> Maybe Command
+toCommand 0x434e5953 = Just SYNC
+toCommand 0x4e584e43 = Just CNXN
+toCommand 0x48545541 = Just AUTH
+toCommand 0x4e45504f = Just OPEN 
+toCommand 0x59414b4f = Just OKAY 
+toCommand 0x45534c43 = Just CLSE 
+toCommand 0x45545257 = Just WRTE
+toCommand _          = Nothing
+
+data Packet = Packet {
+        pktCommand :: Command,
+        pktArg0    :: Word32,
+        pktArg1    :: Word32,
+        pktPayload :: ByteString
+    }
+    deriving Show
+
+formatPacket :: Packet -> ByteString
+formatPacket pkt = runPut $ do
+    let cmd = fromCommand . pktCommand $ pkt
+    putWord32le $ cmd
+    putWord32le . pktArg0 $ pkt
+    putWord32le . pktArg1 $ pkt
+    putWord32le . fromIntegral . B.length . pktPayload $ pkt
+    putWord32le . foldl' (+) 0 . map fromIntegral . B.unpack . pktPayload $ pkt
+    putWord32le . complement $ cmd
+    putByteString . pktPayload $ pkt
+
+parsePacket :: ByteString -> Either String Packet
+parsePacket = runGet $ do
+    cmdNo <- getWord32le
+    case toCommand cmdNo of
+        Just cmd -> do
+            arg0 <- getWord32le
+            arg1 <- getWord32le
+            len <- getWord32le
+            _ <- getWord32le
+            _ <- getWord32le
+            payload <- getByteString (fromIntegral len)
+            return $ Packet cmd arg0 arg1 payload
+        Nothing  -> fail $ "bad command"
+
+readPacket :: (MonadError TransportError m, Functor m, Applicative m) =>
+              Transport m -> m Packet
+readPacket rem = do
+    Right [cmdNo, arg0, arg1, len, chk, magic] <- runGet (sequence $ replicate 6 getWord32le) <$> readFully rem (6*4)
+    when (cmdNo /= complement magic) $ throwError IllegalData
+    cmd <- case toCommand cmdNo of
+        Just cmd -> return cmd
+        Nothing  -> throwError IllegalData
+    when (len > fromIntegral mAX_PAYLOAD) $ throwError IllegalData
+    payload <- if len == 0 then pure B.empty else readFully rem (fromIntegral len)
+    return $ Packet cmd arg0 arg1 payload
+
+data Session m = Session (IO Word32) (Packet -> m ()) (m Packet)
+
+withSession :: Transport (ErrorT TransportError IO)
+            -> (Session (ErrorT TransportError IO) -> ErrorT TransportError IO a)
+            -> ErrorT TransportError IO a
+withSession tra code = do
+    nextLocalIDRef <- liftIO $ newMVar 0
+    let doAlloc 0      = doAlloc 1
+        doAlloc nextID = return $ (nextID+1, nextID)
+        allocLocalID = modifyMVar nextLocalIDRef doAlloc
+
+    (chansVar, ch) <- liftIO $ do
+        me <- myThreadId
+        ch <- newChan
+        chansVar <- newMVar $ M.insert me ch M.empty
+        return (chansVar, ch)
+    let readPkt = do
+            ee <- liftIO $ do
+                ch <- modifyMVar chansVar $ \chans -> do
+                    me <- myThreadId
+                    case me `M.lookup` chans of
+                        Just ch -> return (chans, ch)
+                        Nothing -> do
+                            ch' <- dupChan ch
+                            return (M.insert me ch' chans, ch')
+                readChan ch
+            case ee of
+                Left err -> throwError err
+                Right pkt -> return pkt
+
+    readThr <- liftIO $ forkIO $ do
+        forever $ do
+            epkt <- runErrorT $ readPacket tra
+            case epkt of
+                Left err -> writeChan ch (Left err)
+                Right pkt -> writeChan ch (Right pkt)
+
+    ee <- liftIO $ runErrorT (code (Session allocLocalID (write tra . formatPacket) readPkt))
+      `finally` killThread readThr
+    case ee of
+        Left err -> throwError err
+        Right a  -> return a
+
+withConversation :: Session (ErrorT TransportError IO)
+                                  -> Word32
+                                  -> Word32
+                                  -> (Transport (ErrorT TransportError IO) -> ErrorT TransportError IO a)
+                                  -> ErrorT TransportError IO a
+withConversation session@(Session allocLocalID writePkt readPkt0) localID remoteID code = do
+    queueVar <- liftIO $ newMVar Seq.empty
+    (chansVar, ch) <- liftIO $ do
+        me <- myThreadId
+        ch <- newChan
+        chansVar <- newMVar $ M.insert me ch M.empty
+        return (chansVar, ch)
+    let readPkt = do
+            ee <- liftIO $ do
+                ch <- modifyMVar chansVar $ \chans -> do
+                    me <- myThreadId
+                    case me `M.lookup` chans of
+                        Just ch -> return (chans, ch)
+                        Nothing -> do
+                            ch' <- dupChan ch
+                            return (M.insert me ch' chans, ch')
+                readChan ch
+            case ee of
+                Left err -> throwError err
+                Right pkt -> return pkt
+
+    readThr <- liftIO $ forkIO $ do
+        forever $ do
+            epkt <- runErrorT $ readPkt0
+            case epkt of
+                Left err -> writeChan ch (Left err)
+                Right pkt -> do
+                    case pktCommand pkt of
+                        WRTE | pktArg1 pkt == localID -> do
+                            modifyMVar_ queueVar $ return . (|> pktPayload pkt)
+                            runErrorT $ writePkt $ Packet OKAY localID remoteID B.empty
+                            writeChan ch (Right pkt)
+                        _                             -> writeChan ch (Right pkt)
+
+    let traNew = Transport {
+            write =
+                let writeLoop bs = case bs of
+                        bs | B.null bs -> return ()
+                        bs -> do
+                            let (now, next) = B.splitAt (fromIntegral mAX_PAYLOAD) bs
+                            writePkt $ Packet WRTE localID remoteID now
+                            let awaitResult = do
+                                    pkt <- readPkt
+                                    case pktCommand pkt of
+                                        CLSE | pktArg1 pkt == localID -> throwError ClosedByPeer
+                                        OKAY | pktArg0 pkt == remoteID -> writeLoop next
+                                        _ -> awaitResult
+                            awaitResult
+                in  \bs -> writeLoop bs,
+            read = \n -> do
+                let readLoop = do
+                        q <- liftIO $ readMVar queueVar
+                        if Seq.length q == 0 then do
+                                pkt <- readPkt
+                                case pktCommand pkt of
+                                    CLSE | pktArg1 pkt == localID -> throwError ClosedByPeer
+                                    _ -> readLoop
+                            else do
+                                let hd = q `Seq.index` 0
+                                if B.length hd > n then do
+                                    let (mine, notMine) = B.splitAt n hd
+                                    liftIO $ modifyMVar_ queueVar $ return . (\q -> notMine <| Seq.drop 1 q)
+                                    return mine
+                                  else do
+                                    liftIO $ modifyMVar_ queueVar $ return . (Seq.drop 1)
+                                    return hd
+                readLoop,
+            close = do
+                writePkt $ Packet CLSE localID remoteID B.empty
+                let awaitResult = do
+                        pkt <- readPkt
+                        case pktCommand pkt of
+                            CLSE | pktArg1 pkt == localID -> throwError ClosedByPeer
+                            _ -> awaitResult
+                awaitResult
+          }
+    ea <- liftIO $ runErrorT (code traNew) `finally` killThread readThr
+    case ea of
+        Left err -> throwError err
+        Right a  -> return a
+
diff --git a/Network/ADB/Server.hs b/Network/ADB/Server.hs
new file mode 100644
--- /dev/null
+++ b/Network/ADB/Server.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, OverloadedStrings,
+        ForeignFunctionInterface, EmptyDataDecls #-}
+module Network.ADB.Server (
+        Session,
+        withServerSession,
+        withAccept,
+        module Network.ADB.Transport
+    ) where
+
+import Control.Applicative
+import Control.Concurrent
+import Control.Monad.Error
+import Data.ByteString.Char8 (ByteString)
+import qualified Data.ByteString.Char8 as C
+import Data.Monoid
+import Network.ADB.Common
+import Network.ADB.Transport
+
+
+withServerSession :: Transport (ErrorT TransportError IO)
+                  -> ByteString
+                  -> (Session (ErrorT TransportError IO) -> ErrorT TransportError IO a)
+                  -> ErrorT TransportError IO a
+withServerSession tra descriptor code = do
+    negotiate descriptor tra
+    withSession tra code
+
+-- | Performs negotiation on a packetTransport
+negotiate :: (MonadError TransportError m, Applicative m, MonadIO m) =>
+             ByteString
+          -> Transport m -> m ()
+negotiate descriptor tra = do
+        pkt <- readPacket tra
+        case pkt of
+            Packet CNXN _ _ _ -> write tra $ formatPacket $ Packet CNXN a_VERSION mAX_PAYLOAD (descriptor <> "\0")
+            _                 -> negotiate descriptor tra
+
+-- | Loop forever, accepting incoming connections. The specified function returns some
+-- code to spawn on a new thread if we should accept a connection on the specified URI.
+withAccept :: Session (ErrorT TransportError IO) 
+           -> (C.ByteString -> Maybe (Transport (ErrorT TransportError IO) -> ErrorT TransportError IO ()))
+           -> ErrorT TransportError IO ()
+withAccept session@(Session allocLocalID writePkt readPkt) qCode = forever $ do
+    pkt <- readPkt
+    case pkt of
+        Packet OPEN remoteID 0 uri ->
+            if "\0" `C.isSuffixOf` uri
+                then case qCode (C.take (C.length uri - 1) uri) of
+                         Just code -> do
+                             _ <- liftIO $ forkIO $ do
+                                 localID <- allocLocalID
+                                 _ <- runErrorT $ do
+                                     writePkt $ Packet OKAY localID remoteID C.empty
+                                     withConversation session localID remoteID code
+                                 return ()
+                             return ()
+                         Nothing -> writePkt $ Packet CLSE 0 remoteID C.empty
+                else writePkt $ Packet CLSE 0 remoteID C.empty
+        _ -> return ()
+
diff --git a/Network/ADB/Socket.hs b/Network/ADB/Socket.hs
new file mode 100644
--- /dev/null
+++ b/Network/ADB/Socket.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Network.ADB.Socket where
+
+import Control.Exception
+import Control.Monad.Error
+import Network.ADB.Transport
+import Network.Socket (Socket, sClose)
+import Network.Socket.ByteString
+import System.IO.Error
+import Prelude hiding (read)
+
+
+socketTransport :: Socket -> Transport (ErrorT TransportError IO)
+socketTransport s = Transport {
+        write = \bs -> do
+            --liftIO $ putStrLn $ hexdump 0 (C.unpack bs)   -- ###
+            ee <- liftIO . try $ sendAll s bs
+            case ee of
+                Left (exc :: IOError) -> throwError ClosedByPeer
+                Right () -> return (),
+        read = \n -> do
+            ee <- liftIO . try $ recv s n
+            case ee of
+                Left (exc :: IOError) -> throwError ClosedByPeer
+                Right blk -> do
+                    --liftIO $ putStrLn $ hexdump 0 (C.unpack blk)   -- ###
+                    return blk,
+        close = do
+            ee <- liftIO . try $ sClose s
+            case ee of
+                Left (exc :: IOError) -> throwError ClosedByPeer
+                Right blk -> return blk
+    }
+
diff --git a/Network/ADB/Transport.hs b/Network/ADB/Transport.hs
new file mode 100644
--- /dev/null
+++ b/Network/ADB/Transport.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Network.ADB.Transport where
+
+
+import Control.Exception
+import Control.Monad.Error
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as C
+import Data.Monoid
+import Network.Socket.ByteString
+import System.IO.Error (IOError(..))
+import Prelude hiding (read)
+
+
+-- | \'m\' is the monad to to run it in, \'h\' is the heuristic value which, where
+-- \'e\' is 'ByteString', is the number of bytes to read.  \'e\' is the stream
+-- element type.
+data Transport m = Transport {
+        write :: ByteString -> m (),  -- ^ Write an item.
+        read  :: Int -> m ByteString, -- ^ Read an item with 'h' being the heuristic to say what it
+                                      -- is we want to read.
+        close :: m ()
+    }
+
+data TransportError = ADBFailure String
+                    | SocketFailure IOError
+                    | ConnectionFailure ByteString
+                    | ClosedByPeer
+                    | IllegalData
+    deriving Show
+
+instance Error TransportError where
+    noMsg = IllegalData
+    strMsg _ = IllegalData
+
+-- | Block until the specified number of bytes has been read.
+readFully :: Monad m => Transport m -> Int -> m ByteString
+readFully rem n = doRecv C.empty
+  where
+    doRecv sofar | C.length sofar == n = return sofar
+    doRecv sofar = do
+        blk <- read rem (n - C.length sofar)
+        doRecv (sofar `mappend` blk)
+
diff --git a/Network/ADB/adb.h b/Network/ADB/adb.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/adb.h
@@ -0,0 +1,43 @@
+#ifndef _ADB_PACKET_H_
+#define _ADB_PACKET_H_
+
+#define A_VERSION 0x01000000        // ADB protocol version
+
+#define ADB_CLASS              0xff
+#define ADB_SUBCLASS           0x42
+#define ADB_PROTOCOL           0x1
+
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_AUTH 0x48545541
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+
+typedef struct amessage {
+    unsigned command;       /* command identifier constant      */
+    unsigned arg0;          /* first argument                   */
+    unsigned arg1;          /* second argument                  */
+    unsigned data_length;   /* length of payload (0 is allowed) */
+    unsigned data_check;    /* checksum of data payload         */
+    unsigned magic;         /* command ^ 0xffffffff             */
+} amessage;
+
+#define MAX_PAYLOAD 4096
+
+typedef struct apacket
+{
+    amessage msg;
+    unsigned char data[MAX_PAYLOAD];
+} apacket;
+
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN         1
+/* Response */
+#define ADB_AUTH_SIGNATURE     2
+#define ADB_AUTH_RSAPUBLICKEY  3
+
+#endif
+
diff --git a/Network/ADB/adb_auth.c b/Network/ADB/adb_auth.c
new file mode 100644
--- /dev/null
+++ b/Network/ADB/adb_auth.c
@@ -0,0 +1,133 @@
+#define _HASKELL_HOOKS_
+
+#if defined(TEXT_BASE)
+#define U_BOOT
+#endif
+
+#if !defined(U_BOOT)
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#else
+#include <common.h>
+#include <malloc.h>
+#endif
+
+#include "adb_auth.h"
+
+
+#define RSANUMBYTES 256           /* 2048 bit key length */
+#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
+
+typedef struct RSAPublicKey {
+    int len;                  /* Length of n[] in number of uint32_t */
+    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
+    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
+    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+    int exponent;             /* 3 or 65537 */
+} RSAPublicKey;
+
+#include "adb_auth_private_key.h"
+
+void adb_auth_init(ADBAuth* auth)
+{
+    auth->ctx = NULL;
+    RSA_priv_key_new(&auth->ctx,
+        public_n, public_n_length,
+        public_e, public_e_length,
+        private_d, private_d_length);
+    auth->key_try_ix = 0;
+}
+
+#if defined(_HASKELL_HOOKS_)
+ADBAuth* adb_auth_new(void)
+{
+    ADBAuth* auth = (ADBAuth*)malloc(sizeof(ADBAuth));
+    adb_auth_init(auth);
+    return auth;
+}
+#endif
+
+void adb_auth_free(ADBAuth* auth)
+{
+    RSA_free(auth->ctx);
+}
+
+static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+                                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+                                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+                                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+                                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+                                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+                                'w', 'x', 'y', 'z', '0', '1', '2', '3',
+                                '4', '5', '6', '7', '8', '9', '+', '/'};
+static int mod_table[] = {0, 2, 1};
+
+void base64_encode(const unsigned char *data,
+                    size_t input_length,
+                    char* encoded_data) {
+
+    int output_length = 4 * ((input_length + 2) / 3);
+    int i, j;
+
+    for (i = 0, j = 0; i < input_length;) {
+
+        uint32_t octet_a = i < input_length ? data[i++] : 0;
+        uint32_t octet_b = i < input_length ? data[i++] : 0;
+        uint32_t octet_c = i < input_length ? data[i++] : 0;
+
+        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+        encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
+    }
+
+    for (i = 0; i < mod_table[input_length % 3]; i++)
+        encoded_data[output_length - 1 - i] = '=';
+    encoded_data[output_length] = 0;
+}
+
+static const uint8_t prefix[] = {
+  0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14
+};
+
+/* Handle adb's AUTH command. If it wants to reply, it will return
+ * with 1 and pkt will contain the packet to be sent. */
+int adb_auth(ADBAuth* auth, apacket* pkt)
+{
+    switch (pkt->msg.arg0) {
+    case ADB_AUTH_TOKEN:
+        if (auth->key_try_ix == 0) {
+            uint8_t digest[4096];
+            uint8_t answer[MAX_PAYLOAD];
+            int outLen;
+            memcpy(digest, prefix, sizeof(prefix));
+            memcpy(digest+sizeof(prefix), pkt->data, pkt->msg.data_length);
+            outLen = RSA_encrypt(auth->ctx, digest, sizeof(prefix)+pkt->msg.data_length, answer, 1);
+            memcpy(pkt->data, answer, outLen);
+            pkt->msg.command = A_AUTH;
+            pkt->msg.arg0 = ADB_AUTH_SIGNATURE;
+            pkt->msg.arg1 = 0;
+            pkt->msg.data_length = (unsigned) outLen;
+            auth->key_try_ix = 1;
+            return 1;
+        }
+        else {
+            base64_encode((const unsigned char *) &public_key, sizeof(public_key), (char*)pkt->data);
+            pkt->msg.command = A_AUTH;
+            pkt->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+            pkt->msg.arg1 = 0;
+            pkt->msg.data_length = (unsigned) strlen((const char*)pkt->data) + 1;
+            return 1;
+        }
+    case ADB_AUTH_SIGNATURE:
+        return 0;
+    case ADB_AUTH_RSAPUBLICKEY:
+        return 0;
+    default:
+        return 0;
+    }
+}
+
diff --git a/Network/ADB/adb_auth.h b/Network/ADB/adb_auth.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/adb_auth.h
@@ -0,0 +1,26 @@
+#ifndef _ADB_AUTH_H_
+#define _ADB_AUTH_H_
+
+#include "adb.h"
+#if !defined(U_BOOT)
+#include <stdint.h>
+#endif
+#include "crypto.h"
+
+typedef struct {
+    RSA_CTX* ctx;
+    int key_try_ix;
+} ADBAuth;
+
+void adb_auth_init(ADBAuth* auth);
+#if defined(_HASKELL_HOOKS_)
+ADBAuth* adb_auth_new(void);
+#endif
+void adb_auth_free(ADBAuth* auth);
+
+/* Handle adb's AUTH command. If it wants to reply, it will return
+ * with 1 and pkt will contain the packet to be sent. */
+int adb_auth(ADBAuth* auth, apacket* pkt);
+
+#endif
+
diff --git a/Network/ADB/adb_auth_private_key.h b/Network/ADB/adb_auth_private_key.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/adb_auth_private_key.h
@@ -0,0 +1,22 @@
+const uint8_t public_n[] = {
+0xde,0xcc,0xf3,0x1,0xaf,0xa,0xf3,0xd,0xcf,0x3f,0x42,0x9d,0x19,0x1f,0x11,0x2,0xd1,0x7f,0xfe,0x14,0x42,0xc0,0x5c,0x4a,0x3,0x91,0x91,0xe5,0xee,0x18,0x93,0x12,0xd8,0xf2,0xce,0x5d,0x10,0x5d,0x41,0xf6,0xda,0x26,0x6a,0x6a,0x86,0x94,0x7e,0x12,0x25,0x10,0x86,0x89,0x59,0x5a,0x64,0x5,0x32,0x99,0x8a,0xed,0x57,0xf3,0x73,0x6f,0xdf,0xd1,0x5a,0x54,0x8a,0xd6,0xf1,0xcd,0xbd,0x4,0xbb,0xdf,0x37,0x4d,0x67,0xf3,0xdd,0xbb,0x54,0xe3,0x6a,0x81,0xcc,0x3a,0x46,0x8c,0x67,0x77,0x74,0x2c,0xab,0x88,0x32,0xb6,0x34,0x30,0x5f,0x73,0x8b,0x49,0x1e,0x72,0x2b,0x76,0xb0,0x29,0x2e,0xa4,0x99,0x50,0xd7,0x71,0xcc,0x4b,0x32,0x9a,0x92,0x65,0x68,0x6e,0xe6,0x62,0xcf,0x40,0x29,0x88,0x1c,0x91,0x29,0x3,0xe5,0x8f,0xe5,0x21,0xd,0x19,0xe3,0x78,0x53,0xb0,0x2e,0x14,0xe4,0xb0,0x6a,0x11,0xc9,0xa7,0x2f,0xe4,0x57,0xbf,0xa7,0xaf,0xe3,0xf4,0x1e,0xe8,0x6a,0x20,0xfd,0x2e,0xdf,0x85,0xe7,0x79,0x21,0xd0,0x6a,0x19,0xca,0xd3,0xd3,0x56,0x9e,0x62,0x54,0x0,0xff,0x6c,0x36,0xf9,0x26,0x51,0x14,0x3f,0xa8,0xcb,0xe7,0x32,0x67,0x9f,0xd6,0x24,0x2e,0x13,0x73,0x6c,0xb6,0xeb,0x1,0x5,0xe5,0xd9,0xd8,0x21,0xc6,0x26,0x4b,0x36,0xcf,0xf0,0x21,0xe5,0xc6,0xa0,0xe0,0x11,0x68,0x69,0x41,0xe9,0x72,0x5d,0x1e,0xc6,0xf5,0x6e,0x49,0x9b,0x9d,0x70,0xc4,0xf4,0x25,0x1b,0xfd,0xa1,0x2a,0x16,0x1,0xaa,0x3f,0x9a,0xa3,0xdb,0x2b,0xf0,0xea,0x2c,0xdc,0x87
+};
+const int public_n_length = 256;
+
+const uint8_t public_e[] = {
+0x1,0x0,0x1
+};
+const int public_e_length = 3;
+
+const uint8_t private_d[] = {
+0x18,0x38,0x7,0x22,0x63,0xb8,0xb8,0xfb,0x3,0x50,0x49,0x19,0x72,0xa5,0xa1,0xdf,0xc0,0x8e,0x3d,0x3c,0x4e,0x95,0x42,0x72,0xf9,0x38,0x55,0xb7,0xbc,0xce,0x7,0xe,0xc1,0x6e,0x83,0x68,0x32,0x63,0x30,0xcc,0x78,0xa2,0x3c,0x67,0x20,0x1,0xfc,0x42,0x54,0xad,0x1b,0x32,0xca,0xf7,0xbc,0x6f,0xa4,0x34,0x74,0x99,0xa0,0x39,0xe2,0x8e,0x82,0xb1,0xeb,0x33,0xcd,0x73,0xd8,0xd,0x19,0x42,0xee,0x79,0x31,0x35,0xc4,0xdb,0x9,0x7b,0x57,0x9a,0xf0,0xf4,0xf3,0x12,0x52,0xa0,0xe8,0x8e,0x5f,0x9e,0x8b,0x76,0xde,0xac,0x57,0xb7,0xfa,0x68,0x40,0xf7,0xcd,0xcb,0x73,0x56,0xf,0x88,0x2a,0x7d,0xd1,0xfc,0xab,0xae,0xbf,0x1a,0x5d,0x81,0xd7,0xf0,0x16,0xe,0x18,0x15,0x1d,0x9a,0x13,0xeb,0x22,0xed,0x67,0x9e,0xb3,0x7f,0x1d,0xba,0x9f,0xcd,0x7b,0xea,0xa5,0x2e,0xa3,0xf2,0x81,0xe7,0x98,0xd9,0x96,0x5f,0xd1,0xc0,0xdd,0xa9,0xcc,0x8d,0x41,0xf8,0xde,0x56,0xa0,0x81,0xd7,0xf4,0x6d,0x41,0x1e,0xce,0x28,0xc7,0xb4,0x9f,0xc5,0x4,0x39,0x53,0x48,0x61,0xe4,0xbe,0x6b,0x51,0x9b,0x75,0x40,0xf4,0xb2,0x62,0xdc,0x99,0x49,0xf5,0xfe,0xbd,0xa5,0x27,0x69,0xbc,0xa2,0x9b,0xad,0x38,0xcb,0xc7,0xe,0x45,0x1e,0x71,0x7f,0x76,0x7a,0xd0,0x76,0xd0,0xb4,0x9e,0xf3,0x95,0x23,0x24,0xb7,0x83,0x1f,0x9d,0x59,0x5d,0x8d,0x3d,0x82,0x68,0xbb,0xa9,0xe1,0xda,0x2,0x66,0x9b,0x11,0x98,0xf,0xea,0xd1,0x45,0x32,0x39,0x8f,0x9a,0x25,0xd7,0x86,0xe3,0xa1,0xed,0xe1
+};
+const int private_d_length = 256;
+
+const RSAPublicKey public_key = {
+    64,
+    -2086480183,
+    {-366158713,-1545917456,27934618,-39769578,-990632677,1234935152,516355438,1105818205,-535730071,568706720,1261883376,-668875226,17163737,1936504555,-702271981,-416127073,339716299,922297937,1409351532,-749298078,1780075219,-411491888,-47259771,518548000,-1481645068,803493823,1779550631,773121200,-478653520,-450818791,688121231,696786065,-429732032,-1838847890,-867487078,-1722755215,-1339478364,510798710,1601407817,850801712,1949084552,1183606647,1786891322,-574925597,927819763,-1123763233,-1965624883,-539927980,1475572591,848923373,1499096069,621840009,-2037088750,-635016598,274547190,-655176099,-300379374,59871717,1119902794,-780141036,421466370,-817937763,-1358236915,-556993791},
+    {-680089223,-223086018,455213076,259709388,556542659,-293057354,821528073,611556400,1521274678,1831462719,-304674729,842545110,973521751,-1143655792,473154895,-830707796,431437851,1815820373,-470513650,530194457,-794607273,1045821062,-512396943,-1380884004,1414132505,-1519702595,1005872574,-1044378383,-1979521599,-1171128315,-178710083,1377281803,1179717166,690438544,-217276920,1386046529,-925429649,-225916267,-1932816566,294396292,-527282176,1931197632,1042941970,-899269333,-1000286626,-413143069,-840851972,-629220562,1733300887,1505400970,1739245412,1881390228,1919690447,-1705906620,1316237371,1755947382,2057267192,-576770208,799408462,-1261886496,-1539284638,-376040433,539488060,1993460921},
+    65537
+};
diff --git a/Network/ADB/bigint.c b/Network/ADB/bigint.c
new file mode 100644
--- /dev/null
+++ b/Network/ADB/bigint.c
@@ -0,0 +1,1536 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small 
+ * cache. A bigint context may maintain state by being made "permanent". 
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#if defined(TEXT_BASE)
+#define U_BOOT
+#endif
+
+#if !defined(U_BOOT)
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#else
+#include <common.h>
+#include <malloc.h>
+#endif
+#include "os_port.h"
+#include "bigint_impl.h"
+#include "bigint.h"
+
+#define V1      v->comps[v->size-1]                 /**< v1 for division */
+#define V2      v->comps[v->size-2]                 /**< v2 for division */
+#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */
+#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#else
+#define check(A)                /**< disappears in normal production mode */
+#endif
+
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+    /* calloc() sets everything to zero */
+    BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+   
+    /* the radix */
+    ctx->bi_radix = alloc(ctx, 2); 
+    ctx->bi_radix->comps[0] = 0;
+    ctx->bi_radix->comps[1] = 1;
+    bi_permanent(ctx->bi_radix);
+    return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not 
+ * properly freed.
+ * @param ctx [in]   The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+    bi_depermanent(ctx->bi_radix); 
+    bi_free(ctx, ctx->bi_radix);
+
+    if (ctx->active_count != 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_terminate: there were %d un-freed bigints\n",
+                       ctx->active_count);
+#endif
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+
+    bi_clear_cache(ctx);
+    free(ctx);
+}
+
+/**
+ *@brief Clear the memory cache.
+ */
+void bi_clear_cache(BI_CTX *ctx)
+{
+    bigint *p, *pn;
+
+    if (ctx->free_list == NULL)
+        return;
+    
+    for (p = ctx->free_list; p != NULL; p = pn)
+    {
+        pn = p->next;
+        free(p->comps);
+        free(p);
+    }
+
+    ctx->free_count = 0;
+    ctx->free_list = NULL;
+}
+
+/**
+ * @brief Increment the number of references to this object. 
+ * It does not do a full copy.
+ * @param bi [in]   The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+        bi->refs++;
+    return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in]   The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != 1)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_permanent: refs was not 1\n");
+#endif
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+
+    bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in]   The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_depermanent: bigint was not permanent\n");
+#endif
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+
+    bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again. 
+ *
+ * The memory itself it not actually freed, just tagged as being available 
+ * @param ctx [in]   The bigint session context.
+ * @param bi [in]    The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+    check(bi);
+    if (bi->refs == PERMANENT)
+    {
+        return;
+    }
+
+    if (--bi->refs > 0)
+    {
+        return;
+    }
+
+    bi->next = ctx->free_list;
+    ctx->free_list = bi;
+    ctx->free_count++;
+
+    if (--ctx->active_count < 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_free: active_count went negative "
+                "- double-freed bigint?\n");
+#endif
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in]   The bigint session context.
+ * @param i [in]     The (unsigned) integer to be converted.
+ * 
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+    bigint *biR = alloc(ctx, 1);
+    biR->comps[0] = i;
+    return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in]   The bigint session context.
+ * @param bi  [in]   The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+    bigint *biR = alloc(ctx, bi->size);
+    check(bi);
+    memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+    return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int n;
+    comp carry = 0;
+    comp *pa, *pb;
+
+    check(bia);
+    check(bib);
+
+    n = max(bia->size, bib->size);
+    more_comps(bia, n+1);
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do
+    {
+        comp  sl, rl, cy1;
+        sl = *pa + *pb++;
+        rl = sl + carry;
+        cy1 = sl < *pa;
+        carry = cy1 | (rl < sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    *pa = carry;                  /* do overflow */
+    bi_free(ctx, bib);
+    return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx, 
+        bigint *bia, bigint *bib, int *is_negative)
+{
+    int n = bia->size;
+    comp *pa, *pb, carry = 0;
+
+    check(bia);
+    check(bib);
+
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do 
+    {
+        comp sl, rl, cy1;
+        sl = *pa - *pb++;
+        rl = sl - carry;
+        cy1 = sl > *pa;
+        carry = cy1 | (rl > sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    if (is_negative)    /* indicate a negative result */
+    {
+        *is_negative = carry;
+    }
+
+    bi_free(ctx, trim(bib));    /* put bib back to the way it was */
+    return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+    int j = 0, n = bia->size;
+    bigint *biR = alloc(ctx, n + 1);
+    comp carry = 0;
+    comp *r = biR->comps;
+    comp *a = bia->comps;
+
+    check(bia);
+
+    /* clear things to start with */
+    memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+    do
+    {
+        long_comp tmp = *r + (long_comp)a[j]*b + carry;
+        *r++ = (comp)tmp;              /* downsize */
+        carry = (comp)(tmp >> COMP_BIT_SIZE);
+    } while (++j < n);
+
+    *r = carry;
+    bi_free(ctx, bia);
+    return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations. 
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param u [in]    A bigint which is the numerator.
+ * @param v [in]    Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return  The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+    int n = v->size, m = u->size-n;
+    int j = 0, orig_u_size = u->size;
+    uint8_t mod_offset = ctx->mod_offset;
+    comp d;
+    bigint *quotient, *tmp_u;
+    comp q_dash;
+
+    check(u);
+    check(v);
+
+    /* if doing reduction and we are < mod, then return mod */
+    if (is_mod && bi_compare(v, u) > 0)
+    {
+        bi_free(ctx, v);
+        return u;
+    }
+
+    quotient = alloc(ctx, m+1);
+    tmp_u = alloc(ctx, n+1);
+    v = trim(v);        /* make sure we have no leading 0's */
+    d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+    /* clear things to start with */
+    memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+    /* normalise */
+    if (d > 1)
+    {
+        u = bi_int_multiply(ctx, u, d);
+
+        if (is_mod)
+        {
+            v = ctx->bi_normalised_mod[mod_offset];
+        }
+        else
+        {
+            v = bi_int_multiply(ctx, v, d);
+        }
+    }
+
+    if (orig_u_size == u->size)  /* new digit position u0 */
+    {
+        more_comps(u, orig_u_size + 1);
+    }
+
+    do
+    {
+        /* get a temporary short version of u */
+        memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+        /* calculate q' */
+        if (U(0) == V1)
+        {
+            q_dash = COMP_RADIX-1;
+        }
+        else
+        {
+            q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+
+            if (v->size > 1 && V2)
+            {
+                /* we are implementing the following:
+                if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - 
+                        q_dash*V1)*COMP_RADIX) + U(2))) ... */
+                comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - 
+                                            (long_comp)q_dash*V1);
+                if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+                {
+                    q_dash--;
+                }
+            }
+        }
+
+        /* multiply and subtract */
+        if (q_dash)
+        {
+            int is_negative;
+            tmp_u = bi_subtract(ctx, tmp_u, 
+                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+            more_comps(tmp_u, n+1);
+
+            Q(j) = q_dash; 
+
+            /* add back */
+            if (is_negative)
+            {
+                Q(j)--;
+                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+                /* lop off the carry */
+                tmp_u->size--;
+                v->size--;
+            }
+        }
+        else
+        {
+            Q(j) = 0; 
+        }
+
+        /* copy back to u */
+        memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+    } while (++j <= m);
+
+    bi_free(ctx, tmp_u);
+    bi_free(ctx, v);
+
+    if (is_mod)     /* get the remainder */
+    {
+        bi_free(ctx, quotient);
+        return bi_int_divide(ctx, trim(u), d);
+    }
+    else            /* get the quotient */
+    {
+        bi_free(ctx, u);
+        return trim(quotient);
+    }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
+{
+    int i = biR->size - 1;
+    long_comp r = 0;
+
+    check(biR);
+
+    do
+    {
+        r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+        biR->comps[i] = (comp)(r / denom);
+        r %= denom;
+    } while (--i >= 0);
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, 
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of 
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the 
+ * simple algorithm from an article by Dusse and Kaliski to efficiently 
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+    int i;
+    comp t = 1;
+    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */
+    long_comp two_2_i = 4;      /* 2^i */
+    comp N = bim->comps[0];
+
+    for (i = 2; i <= COMP_BIT_SIZE; i++)
+    {
+        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+        {
+            t += two_2_i_minus_1;
+        }
+
+        two_2_i_minus_1 <<= 1;
+        two_2_i <<= 1;
+    }
+
+    return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components) 
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-num_shifts;
+    comp *x = biR->comps;
+    comp *y = &biR->comps[num_shifts];
+
+    check(biR);
+
+    if (i <= 0)     /* have we completely right shifted? */
+    {
+        biR->comps[0] = 0;  /* return 0 */
+        biR->size = 1;
+        return biR;
+    }
+
+    do
+    {
+        *x++ = *y++;
+    } while (--i > 0);
+
+    biR->size -= num_shifts;
+    return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components) 
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-1;
+    comp *x, *y;
+
+    check(biR);
+
+    if (num_shifts <= 0)
+    {
+        return biR;
+    }
+
+    more_comps(biR, biR->size + num_shifts);
+
+    x = &biR->comps[i+num_shifts];
+    y = &biR->comps[i];
+
+    do
+    {
+        *x-- = *y--;
+    } while (i--);
+
+    memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+    return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+    int i, j = 0, offset = 0;
+
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        biR->comps[offset] += data[i] << (j*8);
+
+        if (++j == COMP_BYTE_SIZE)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and 
+ * convert them into bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+    int size = strlen(data);
+    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+    int i, j = 0, offset = 0;
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+        biR->comps[offset] += num << (j*4);
+
+        if (++j == COMP_NUM_NIBBLES)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+    int i, j;
+
+    if (x == NULL)
+    {
+        printf("%s: (null)\n", label);
+        return;
+    }
+
+    printf("%s: (size %d)\n", label, x->size);
+    for (i = x->size-1; i >= 0; i--)
+    {
+        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+        {
+            comp mask = 0x0f << (j*4);
+            comp num = (x->comps[i] & mask) >> (j*4);
+            putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+        }
+    }  
+
+    printf("\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence. 
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in]  The bigint session context.
+ * @param x [in]  The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+    int i, j, k = size-1;
+
+    check(x);
+    memset(data, 0, size);  /* ensure all leading 0's are cleared */
+
+    for (i = 0; i < x->size; i++)
+    {
+        for (j = 0; j < COMP_BYTE_SIZE; j++)
+        {
+            comp mask = 0xff << (j*8);
+            int num = (x->comps[i] & mask) >> (j*8);
+            data[k--] = num;
+
+            if (k < 0)
+            {
+                goto buf_done;
+            }
+        }
+    }
+buf_done:
+
+    bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction. 
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in]  The bigint session context.
+ * @param bim [in]  The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+    int k = bim->size;
+    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    bigint *R, *R2;
+#endif
+
+    ctx->bi_mod[mod_offset] = bim;
+    bi_permanent(ctx->bi_mod[mod_offset]);
+    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+    bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    /* set montgomery variables */
+    R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1);     /* R */
+    R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1);  /* R^2 */
+    ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2);             /* R^2 mod m */
+    ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R);               /* R mod m */
+
+    bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+    ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+    ctx->bi_mu[mod_offset] = 
+        bi_divide(ctx, comp_left_shift(
+            bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+    bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in]  The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+    bi_depermanent(ctx->bi_mod[mod_offset]);
+    bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+    bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bi_depermanent(ctx->bi_mu[mod_offset]); 
+    bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); 
+    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/** 
+ * Perform a standard multiplication between two bigints.
+ *
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods. 
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, 
+        int inner_partial, int outer_partial)
+{
+    int i = 0, j;
+    int n = bia->size;
+    int t = bib->size;
+    bigint *biR = alloc(ctx, n + t);
+    comp *sr = biR->comps;
+    comp *sa = bia->comps;
+    comp *sb = bib->comps;
+
+    check(bia);
+    check(bib);
+
+    /* clear things to start with */
+    memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+
+    do 
+    {
+        long_comp tmp;
+        comp carry = 0;
+        int r_index = i;
+        j = 0;
+
+        if (outer_partial && outer_partial-i > 0 && outer_partial < n)
+        {
+            r_index = outer_partial-1;
+            j = outer_partial-i-1;
+        }
+
+        do
+        {
+            if (inner_partial && r_index >= inner_partial) 
+            {
+                break;
+            }
+
+            tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry;
+            sr[r_index++] = (comp)tmp;              /* downsize */
+            carry = tmp >> COMP_BIT_SIZE;
+        } while (++j < n);
+
+        sr[r_index] = carry;
+    } while (++i < t);
+
+    bi_free(ctx, bia);
+    bi_free(ctx, bib);
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications 
+ * being done instead of 4. The additional additions/subtractions are O(N) 
+ * rather than O(N^2) and so for big numbers it saves on a few operations 
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+    bigint *x0, *x1;
+    bigint *p0, *p1, *p2;
+    int m;
+
+    if (is_square)
+    {
+        m = (bia->size + 1)/2;
+    }
+    else
+    {
+        m = (max(bia->size, bib->size) + 1)/2;
+    }
+
+    x0 = bi_clone(ctx, bia);
+    x0->size = m;
+    x1 = bi_clone(ctx, bia);
+    comp_right_shift(x1, m);
+    bi_free(ctx, bia);
+
+    /* work out the 3 partial products */
+    if (is_square)
+    {
+        p0 = bi_square(ctx, bi_copy(x0));
+        p2 = bi_square(ctx, bi_copy(x1));
+        p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+    }
+    else /* normal multiply */
+    {
+        bigint *y0, *y1;
+        y0 = bi_clone(ctx, bib);
+        y0->size = m;
+        y1 = bi_clone(ctx, bib);
+        comp_right_shift(y1, m);
+        bi_free(ctx, bib);
+
+        p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+        p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+        p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+    }
+
+    p1 = bi_subtract(ctx, 
+            bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+    comp_left_shift(p1, m);
+    comp_left_shift(p2, 2*m);
+    return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    check(bia);
+    check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+    {
+        return regular_multiply(ctx, bia, bib, 0, 0);
+    }
+
+    return karatsuba(ctx, bia, bib, 0);
+#else
+    return regular_multiply(ctx, bia, bib, 0, 0);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+    int t = bi->size;
+    int i = 0, j;
+    bigint *biR = alloc(ctx, t*2+1);
+    comp *w = biR->comps;
+    comp *x = bi->comps;
+    long_comp carry;
+    memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+    do
+    {
+        long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+        w[2*i] = (comp)tmp;
+        carry = tmp >> COMP_BIT_SIZE;
+
+        for (j = i+1; j < t; j++)
+        {
+            uint8_t c = 0;
+            long_comp xx = (long_comp)x[i]*x[j];
+            if ((COMP_MAX-xx) < xx)
+                c = 1;
+
+            tmp = (xx<<1);
+
+            if ((COMP_MAX-tmp) < w[i+j])
+                c = 1;
+
+            tmp += w[i+j];
+
+            if ((COMP_MAX-tmp) < carry)
+                c = 1;
+
+            tmp += carry;
+            w[i+j] = (comp)tmp;
+            carry = tmp >> COMP_BIT_SIZE;
+
+            if (c)
+                carry += COMP_RADIX;
+        }
+
+        tmp = w[i+t] + carry;
+        w[i+t] = (comp)tmp;
+        w[i+t+1] = tmp >> COMP_BIT_SIZE;
+    } while (++i < t);
+
+    bi_free(ctx, bi);
+    return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+    check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (bia->size < SQU_KARATSUBA_THRESH) 
+    {
+        return regular_square(ctx, bia);
+    }
+
+    return karatsuba(ctx, bia, NULL, 1);
+#else
+    return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+    int r, i;
+
+    check(bia);
+    check(bib);
+
+    if (bia->size > bib->size)
+        r = 1;
+    else if (bia->size < bib->size)
+        r = -1;
+    else
+    {
+        comp *a = bia->comps; 
+        comp *b = bib->comps; 
+
+        /* Same number of components.  Compare starting from the high end
+         * and working down. */
+        r = 0;
+        i = bia->size - 1;
+
+        do 
+        {
+            if (a[i] > b[i])
+            { 
+                r = 1;
+                break; 
+            }
+            else if (a[i] < b[i])
+            { 
+                r = -1;
+                break; 
+            }
+        } while (--i >= 0);
+    }
+
+    return r;
+}
+
+/*
+ * Allocate and zero more components.  Does not consume bi. 
+ */
+static void more_comps(bigint *bi, int n)
+{
+    if (n > bi->max_comps)
+    {
+        bi->max_comps = max(bi->max_comps * 2, n);
+        bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+    }
+
+    if (n > bi->size)
+    {
+        memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+    }
+
+    bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+    bigint *biR;
+
+    /* Can we recycle an old bigint? */
+    if (ctx->free_list != NULL)
+    {
+        biR = ctx->free_list;
+        ctx->free_list = biR->next;
+        ctx->free_count--;
+
+        if (biR->refs != 0)
+        {
+#ifdef CONFIG_SSL_FULL_MODE
+            printf("alloc: refs was not 0\n");
+#endif
+#if !defined(U_BOOT)
+            abort();
+#endif
+        }
+
+        more_comps(biR, size);
+    }
+    else
+    {
+        /* No free bigints available - create a new one. */
+        biR = (bigint *)malloc(sizeof(bigint));
+        biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+        biR->max_comps = size;  /* give some space to spare */
+    }
+
+    biR->size = size;
+    biR->refs = 1;
+    biR->next = NULL;
+    ctx->active_count++;
+    return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+    int i = COMP_BIT_SIZE-1;
+    comp shift = COMP_RADIX/2;
+    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */
+
+    check(biexp);
+
+    do
+    {
+        if (test & shift)
+        {
+            return i+(biexp->size-1)*COMP_BIT_SIZE;
+        }
+
+        shift >>= 1;
+    } while (i-- != 0);
+
+    return -1;      /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+    comp test = biexp->comps[offset / COMP_BIT_SIZE];
+    int num_shifts = offset % COMP_BIT_SIZE;
+    comp shift = 1;
+    int i;
+
+    check(biexp);
+
+    for (i = 0; i < num_shifts; i++)
+    {
+        shift <<= 1;
+    }
+
+    return (test & shift) != 0;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+    if (bi->refs <= 0)
+    {
+        printf("check: zero or negative refs in bigint\n");
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+
+    if (bi->next != NULL)
+    {
+        printf("check: attempt to use a bigint from "
+                "the free list\n");
+#if !defined(U_BOOT)
+        abort();
+#endif
+    }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+    check(bi);
+
+    while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+    {
+        bi->size--;
+    }
+
+    return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bixy [in]  A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+    int i = 0, n;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    comp mod_inv = ctx->N0_dash[mod_offset];
+
+    check(bixy);
+
+    if (ctx->use_classical)     /* just use classical instead */
+    {
+        return bi_mod(ctx, bixy);
+    }
+
+    n = bim->size;
+
+    do
+    {
+        bixy = bi_add(ctx, bixy, comp_left_shift(
+                    bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+    } while (++i < n);
+
+    comp_right_shift(bixy, n);
+
+    if (bi_compare(bixy, bim) >= 0)
+    {
+        bixy = bi_subtract(ctx, bixy, bim, NULL);
+    }
+
+    return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation 
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+    check(bi);
+
+    if (bi->size > mod)
+    {
+        bi->size = mod;
+    }
+
+    return bi;
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bi [in]  A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+    bigint *q1, *q2, *q3, *r1, *r2, *r;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    int k = bim->size;
+
+    check(bi);
+    check(bim);
+
+    /* use Classical method instead  - Barrett cannot help here */
+    if (bi->size > k*2)
+    {
+        return bi_mod(ctx, bi);
+    }
+
+    q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
+
+    /* do outer partial multiply */
+    q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); 
+    q3 = comp_right_shift(q2, k+1);
+    r1 = comp_mod(bi, k+1);
+
+    /* do inner partial multiply */
+    r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1);
+    r = bi_subtract(ctx, r1, r2, NULL);
+
+    /* if (r >= m) r = r - m; */
+    if (bi_compare(r, bim) >= 0)
+    {
+        r = bi_subtract(ctx, r, bim, NULL);
+    }
+
+    return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm 
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+    int k = 1, i;
+    bigint *g2;
+
+    for (i = 0; i < window-1; i++)   /* compute 2^(window-1) */
+    {
+        k <<= 1;
+    }
+
+    ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, g1);
+    bi_permanent(ctx->g[0]);
+    g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0]));   /* g^2 */
+
+    for (i = 1; i < k; i++)
+    {
+        ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+        bi_permanent(ctx->g[i]);
+    }
+
+    bi_free(ctx, g2);
+    ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is 
+ * one of the optimisations used for performance.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+    int i = find_max_exp_index(biexp), j, window_size = 1;
+    bigint *biR = int_to_bi(ctx, 1);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    uint8_t mod_offset = ctx->mod_offset;
+    if (!ctx->use_classical)
+    {
+        /* preconvert */
+        bi = bi_mont(ctx, 
+                bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset]));    /* x' */
+        bi_free(ctx, biR);
+        biR = ctx->bi_R_mod_m[mod_offset];                              /* A */
+    }
+#endif
+
+    check(bi);
+    check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+    for (j = i; j > 32; j /= 5) /* work out an optimum size */
+        window_size++;
+
+    /* work out the slide constants */
+    precompute_slide_window(ctx, window_size, bi);
+#else   /* just one constant */
+    ctx->g = (bigint **)malloc(sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, bi);
+    ctx->window = 1;
+    bi_permanent(ctx->g[0]);
+#endif
+
+    /* if sliding-window is off, then only one bit will be done at a time and
+     * will reduce to standard left-to-right exponentiation */
+    do
+    {
+        if (exp_bit_is_one(biexp, i))
+        {
+            int l = i-window_size+1;
+            int part_exp = 0;
+
+            if (l < 0)  /* LSB of exponent will always be 1 */
+                l = 0;
+            else
+            {
+                while (exp_bit_is_one(biexp, l) == 0)
+                    l++;    /* go back up */
+            }
+
+            /* build up the section of the exponent */
+            for (j = i; j >= l; j--)
+            {
+                biR = bi_residue(ctx, bi_square(ctx, biR));
+                if (exp_bit_is_one(biexp, j))
+                    part_exp++;
+
+                if (j != l)
+                    part_exp <<= 1;
+            }
+
+            part_exp = (part_exp-1)/2;  /* adjust for array */
+            biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
+            i = l-1;
+        }
+        else    /* square it */
+        {
+            biR = bi_residue(ctx, bi_square(ctx, biR));
+            i--;
+        }
+    } while (i >= 0);
+     
+    /* cleanup */
+    for (i = 0; i < ctx->window; i++)
+    {
+        bi_depermanent(ctx->g[i]);
+        bi_free(ctx, ctx->g[i]);
+    }
+
+    free(ctx->g);
+    bi_free(ctx, bi);
+    bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+    return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+    return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint to perform the exp/mod.
+ * @param bim [in]  The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+    bigint *biR, *tmp_biR;
+
+    /* Set up a temporary bigint context and transfer what we need between
+     * them. We need to do this since we want to keep the original modulus
+     * which is already in this context. This operation is only called when
+     * doing peer verification, and so is not expensive :-) */
+    BI_CTX *tmp_ctx = bi_initialize();
+    bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+    tmp_biR = bi_mod_power(tmp_ctx, 
+                bi_clone(tmp_ctx, bi), 
+                bi_clone(tmp_ctx, biexp));
+    biR = bi_clone(ctx, tmp_biR);
+    bi_free(tmp_ctx, tmp_biR);
+    bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+    bi_terminate(tmp_ctx);
+
+    bi_free(ctx, bi);
+    bi_free(ctx, bim);
+    bi_free(ctx, biexp);
+    return biR;
+}
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ *
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint to perform the exp/mod.
+ * @param dP [in] CRT's dP bigint
+ * @param dQ [in] CRT's dQ bigint
+ * @param p [in] CRT's p bigint
+ * @param q [in] CRT's q bigint
+ * @param qInv [in] CRT's qInv bigint
+ * @return The result of the CRT operation
+ */
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+        bigint *dP, bigint *dQ,
+        bigint *p, bigint *q, bigint *qInv)
+{
+    bigint *m1, *m2, *h;
+
+    /* Montgomery has a condition the 0 < x, y < m and these products violate
+     * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 1;
+#endif
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    m1 = bi_mod_power(ctx, bi_copy(bi), dP);
+
+    ctx->mod_offset = BIGINT_Q_OFFSET;
+    m2 = bi_mod_power(ctx, bi, dQ);
+
+    h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);
+    h = bi_multiply(ctx, h, qInv);
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 0;         /* reset for any further operation */
+#endif
+    return bi_add(ctx, m2, bi_multiply(ctx, q, h));
+}
+#endif
+/** @} */
diff --git a/Network/ADB/bigint.h b/Network/ADB/bigint.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/bigint.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia, 
+        bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B)      bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B)         bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B)         bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B)         bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+        bigint *dP, bigint *dQ,
+        bigint *p, bigint *q,
+        bigint *qInv);
+#endif
+
+#endif
diff --git a/Network/ADB/bigint_impl.h b/Network/ADB/bigint_impl.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/bigint_impl.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET     0    /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET     1    /**< p modulo offset. */
+#define BIGINT_Q_OFFSET     2    /**< q module offset. */
+#define BIGINT_NUM_MODS     3    /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS     1    
+#endif
+
+/* Architecture specific functions for big ints */
+#if defined(CONFIG_INTEGER_8BIT)
+#define COMP_RADIX          256U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       8   /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      1   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    2   /**< Used For diagnostics only. */
+typedef uint8_t comp;	        /**< A single precision component. */
+typedef uint16_t long_comp;     /**< A double precision component. */
+typedef int16_t slong_comp;     /**< A signed double precision component. */
+#elif defined(CONFIG_INTEGER_16BIT)
+#define COMP_RADIX          65536U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       16  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      2   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    4   /**< Used For diagnostics only. */
+typedef uint16_t comp;	        /**< A single precision component. */
+typedef uint32_t long_comp;     /**< A double precision component. */
+typedef int32_t slong_comp;     /**< A signed double precision component. */
+#else /* regular 32 bit */
+#define COMP_RADIX          4294967296ULL         /**< Max component + 1 */
+#define COMP_MAX            0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       32  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */
+typedef uint32_t comp;	        /**< A single precision component. */
+typedef uint64_t long_comp;     /**< A double precision component. */
+typedef int64_t slong_comp;     /**< A signed double precision component. */
+#endif
+
+/**
+ * @struct  _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+    struct _bigint* next;       /**< The next bigint in the cache. */
+    short size;                 /**< The number of components in this bigint. */
+    short max_comps;            /**< The heapsize allocated for this bigint */
+    int refs;                   /**< An internal reference count. */
+    comp* comps;                /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint;  /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in 
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+    bigint *active_list;                    /**< Bigints currently used. */
+    bigint *free_list;                      /**< Bigints not used. */
+    bigint *bi_radix;                       /**< The radix used. */
+    bigint *bi_mod[BIGINT_NUM_MODS];        /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    bigint *bi_RR_mod_m[BIGINT_NUM_MODS];   /**< R^2 mod m */
+    bigint *bi_R_mod_m[BIGINT_NUM_MODS];    /**< R mod m */
+    comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bigint *bi_mu[BIGINT_NUM_MODS];         /**< Storage for mu */
+#endif
+    bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+    bigint **g;                 /**< Used by sliding-window. */
+    int window;                 /**< The size of the sliding window */
+    int active_count;           /**< Number of active bigints. */
+    int free_count;             /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    uint8_t use_classical;      /**< Use classical reduction. */
+#endif
+    uint8_t mod_offset;         /**< The mod offset we are using */
+} BI_CTX;
+
+#if !defined(U_BOOT)
+#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b))  /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */
+
+#endif
diff --git a/Network/ADB/crypto.h b/Network/ADB/crypto.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/crypto.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#define CONFIG_SSL_CERT_VERIFICATION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "bigint_impl.h"
+#include "bigint.h"
+
+#ifndef STDCALL
+#define STDCALL
+#endif
+#ifndef EXP_FUNC
+#define EXP_FUNC
+#endif
+
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE) 
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+/**************************************************************************
+ * AES declarations 
+ **************************************************************************/
+
+#define AES_MAXROUNDS			14
+#define AES_BLOCKSIZE           16
+#define AES_IV_SIZE             16
+
+typedef struct aes_key_st 
+{
+    uint16_t rounds;
+    uint16_t key_size;
+    uint32_t ks[(AES_MAXROUNDS+1)*8];
+    uint8_t iv[AES_IV_SIZE];
+} AES_CTX;
+
+typedef enum
+{
+    AES_MODE_128,
+    AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key, 
+        const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, 
+        uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    uint8_t x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations 
+ **************************************************************************/
+
+#define SHA1_SIZE   20
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct 
+{
+    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+    uint32_t Length_Low;            /* Message length in bits */
+    uint32_t Length_High;           /* Message length in bits */
+    uint16_t Message_Block_Index;   /* Index into message block array   */
+    uint8_t Message_Block[64];      /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
+
+/**************************************************************************
+ * MD2 declarations 
+ **************************************************************************/
+
+#define MD2_SIZE 16
+
+typedef struct
+{
+    unsigned char cksum[16];    /* checksum of the data block */
+    unsigned char state[48];    /* intermediate digest state */
+    unsigned char buffer[16];   /* data block being processed */
+    int left;                   /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations 
+ **************************************************************************/
+
+#define MD5_SIZE    16
+
+typedef struct 
+{
+  uint32_t state[4];        /* state (ABCD) */
+  uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  uint8_t buffer[64];       /* input buffer */
+} MD5_CTX;
+
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
+
+/**************************************************************************
+ * HMAC declarations 
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RSA declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    bigint *m;              /* modulus */
+    bigint *e;              /* public exponent */
+    bigint *d;              /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+    bigint *p;              /* p as in m = pq */
+    bigint *q;              /* q as in m = pq */
+    bigint *dP;             /* d mod (p-1) */
+    bigint *dQ;             /* d mod (q-1) */
+    bigint *qInv;           /* q^-1 mod p */
+#endif
+    int num_octets;
+    BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+        );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+        int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * RNG declarations 
+ **************************************************************************/
+EXP_FUNC void STDCALL RNG_initialize(void);
+EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
diff --git a/Network/ADB/os_int.h b/Network/ADB/os_int.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/os_int.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+/**
+ * @file os_int.h
+ *
+ * Ensure a consistent bit size 
+ */
+
+#ifndef HEADER_OS_INT_H
+#define HEADER_OS_INT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(U_BOOT)
+#ifdef CONFIG_PLATFORM_SOLARIS
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif /* Not Solaris */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
diff --git a/Network/ADB/os_port.h b/Network/ADB/os_port.h
new file mode 100644
--- /dev/null
+++ b/Network/ADB/os_port.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+/**
+ * @file os_port.h
+ *
+ * Some stuff to minimise the differences between windows and linux/unix
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "os_int.h"
+#if !defined(U_BOOT)
+#include <stdio.h>
+#endif
+
+#define STDCALL
+#define EXP_FUNC
+
+#if !defined(U_BOOT)
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#endif
+
+#define SOCKET_READ(A,B,C)      read(A,B,C)
+#define SOCKET_WRITE(A,B,C)     write(A,B,C)
+#define SOCKET_CLOSE(A)         if (A >= 0) close(A)
+#define TTY_FLUSH()
+
+#if 0
+/* some functions to mutate the way these work */
+#define malloc(A)       ax_malloc(A)
+#ifndef realloc
+#define realloc(A,B)    ax_realloc(A,B)
+#endif
+#define calloc(A,B)     ax_calloc(A,B)
+#endif
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); 
+
+#ifdef CONFIG_PLATFORM_LINUX
+void exit_now(const char *format, ...) __attribute((noreturn));
+#else
+void exit_now(const char *format, ...);
+#endif
+
+/* Mutexing definitions */
+#if defined(CONFIG_SSL_CTX_MUTEXING)
+#if defined(WIN32)
+#define SSL_CTX_MUTEX_TYPE          HANDLE
+#define SSL_CTX_MUTEX_INIT(A)       A=CreateMutex(0, FALSE, 0)
+#define SSL_CTX_MUTEX_DESTROY(A)    CloseHandle(A)
+#define SSL_CTX_LOCK(A)             WaitForSingleObject(A, INFINITE)
+#define SSL_CTX_UNLOCK(A)           ReleaseMutex(A)
+#else 
+#include <pthread.h>
+#define SSL_CTX_MUTEX_TYPE          pthread_mutex_t
+#define SSL_CTX_MUTEX_INIT(A)       pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A)    pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A)             pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A)           pthread_mutex_unlock(&A)
+#endif
+#else   /* no mutexing */
+#define SSL_CTX_MUTEX_INIT(A)
+#define SSL_CTX_MUTEX_DESTROY(A)
+#define SSL_CTX_LOCK(A)
+#define SSL_CTX_UNLOCK(A)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
diff --git a/Network/ADB/rsa.c b/Network/ADB/rsa.c
new file mode 100644
--- /dev/null
+++ b/Network/ADB/rsa.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * 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 the axTLS project nor the names of its 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.
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#if defined(TEXT_BASE)
+#define U_BOOT
+#endif
+
+#if !defined(TEXT_BASE)
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#else
+#include <common.h>
+#include <malloc.h>
+#endif
+#include "os_port.h"
+#include "crypto.h"
+
+void RSA_priv_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+    )
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx;
+    RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+    rsa_ctx = *ctx;
+    bi_ctx = rsa_ctx->bi_ctx;
+    rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+    bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+    rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+    rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+    rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+    rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+    rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+    bi_permanent(rsa_ctx->dP);
+    bi_permanent(rsa_ctx->dQ);
+    bi_permanent(rsa_ctx->qInv);
+    bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+    bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len)
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx;
+
+    if (*ctx)   /* if we load multiple certs, dump the old one */
+        RSA_free(*ctx);
+
+    bi_ctx = bi_initialize();
+    *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+    rsa_ctx = *ctx;
+    rsa_ctx->bi_ctx = bi_ctx;
+    rsa_ctx->num_octets = mod_len;
+    rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+    bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+    rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+    bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+    BI_CTX *bi_ctx;
+    if (rsa_ctx == NULL)                /* deal with ptrs that are null */
+        return;
+
+    bi_ctx = rsa_ctx->bi_ctx;
+
+    bi_depermanent(rsa_ctx->e);
+    bi_free(bi_ctx, rsa_ctx->e);
+    bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+    if (rsa_ctx->d)
+    {
+        bi_depermanent(rsa_ctx->d);
+        bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+        bi_depermanent(rsa_ctx->dP);
+        bi_depermanent(rsa_ctx->dQ);
+        bi_depermanent(rsa_ctx->qInv);
+        bi_free(bi_ctx, rsa_ctx->dP);
+        bi_free(bi_ctx, rsa_ctx->dQ);
+        bi_free(bi_ctx, rsa_ctx->qInv);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+    }
+
+    bi_terminate(bi_ctx);
+    free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return  The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, 
+                            uint8_t *out_data, int is_decryption)
+{
+    const int byte_size = ctx->num_octets;
+    int i, size;
+    bigint *decrypted_bi, *dat_bi;
+    uint8_t *block = (uint8_t *)malloc(byte_size);
+
+    memset(out_data, 0, byte_size); /* initialise */
+
+    /* decrypt */
+    dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    decrypted_bi = is_decryption ?  /* decrypt or verify? */
+            RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else   /* always a decryption */
+    decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+    /* convert to a normal block */
+    bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+    i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+    {
+        while (block[i++] == 0xff && i < byte_size);
+
+        if (block[i-2] != 0xff)
+            i = byte_size;     /*ensure size is 0 */   
+    }
+    else                    /* PKCS1.5 encryption padding is random */
+#endif
+    {
+        while (block[i++] && i < byte_size);
+    }
+    size = byte_size - i;
+
+    /* get only the bit we want */
+    if (size > 0)
+        memcpy(out_data, &block[i], size);
+
+    free(block);
+    return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+#ifdef CONFIG_BIGINT_CRT
+    return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);
+#else
+    BI_CTX *ctx = c->bi_ctx;
+    ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx) 
+{
+    if (rsa_ctx == NULL)
+        return;
+
+    printf("-----------------   RSA DEBUG   ----------------\n");
+    printf("Size:\t%d\n", rsa_ctx->num_octets);
+    bi_print("Modulus", rsa_ctx->m);
+    bi_print("Public Key", rsa_ctx->e);
+    bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+    c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing)
+{
+    int byte_size = ctx->num_octets;
+    int num_pads_needed = byte_size-in_len-3;
+    bigint *dat_bi, *encrypt_bi;
+
+    /* note: in_len+11 must be > byte_size */
+    out_data[0] = 0;     /* ensure encryption block is < modulus */
+
+    if (is_signing)
+    {
+        out_data[1] = 1;        /* PKCS1.5 signing pads with "0xff"'s */
+        memset(&out_data[2], 0xff, num_pads_needed);
+    }
+    else /* randomize the encryption padding with non-zero bytes */   
+    {
+        out_data[1] = 2;
+        // NOT USED - get_random_NZ(num_pads_needed, &out_data[2]);
+    }
+
+    out_data[2+num_pads_needed] = 0;
+    memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+    /* now encrypt it */
+    dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+    encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : 
+                              RSA_public(ctx, dat_bi);
+    bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+
+    /* save a few bytes of memory */
+    bi_clear_cache(ctx->bi_ctx);
+    return byte_size;
+}
+
+#endif  /* CONFIG_SSL_CERT_VERIFICATION */
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/adb.cabal b/adb.cabal
new file mode 100644
--- /dev/null
+++ b/adb.cabal
@@ -0,0 +1,43 @@
+-- Initial adb.cabal generated by cabal init.  For further documentation, 
+-- see http://haskell.org/cabal/users-guide/
+
+name:                adb
+version:             0.1.0.0
+synopsis:            Android Debug Bridge (ADB) protocol
+-- description:         
+license:             BSD3
+license-file:        LICENSE
+author:              Stephen Blackheath
+maintainer:          adb.protocol.stephen@blacksapphire.com
+-- copyright:           
+category:            Network
+build-type:          Simple
+extra-source-files:  programs/generate-rsa-key.hs
+                     programs/adb-shell.hs
+                     Network/ADB/os_port.h
+                     Network/ADB/crypto.h
+                     Network/ADB/adb_auth_private_key.h
+                     Network/ADB/adb_auth.h
+                     Network/ADB/bigint_impl.h
+                     Network/ADB/os_int.h
+                     Network/ADB/adb.h
+                     Network/ADB/bigint.h
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Network.ADB.Transport,
+                       Network.ADB.Client,
+                       Network.ADB.Server,
+                       Network.ADB.Socket
+  other-modules:       Network.ADB.Common
+  other-extensions:    ScopedTypeVariables, FlexibleContexts, OverloadedStrings, ForeignFunctionInterface, EmptyDataDecls
+  build-depends:       base >=4.6 && <4.8,
+                       mtl >=2.1 && <2.2,
+                       bytestring >=0.10,
+                       network >=2.4,
+                       containers >=0.5,
+                       cereal >=0.4
+  c-sources:           Network/ADB/adb_auth.c
+                       Network/ADB/bigint.c
+                       Network/ADB/rsa.c
+  default-language:    Haskell2010
diff --git a/programs/adb-shell.hs b/programs/adb-shell.hs
new file mode 100644
--- /dev/null
+++ b/programs/adb-shell.hs
@@ -0,0 +1,148 @@
+-- This program talks to a locally running Android Virtual Device, giving you a
+-- shell.
+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
+import Control.Applicative
+import Control.Concurrent
+import Control.Exception
+import Control.Monad.Error
+import qualified Data.ByteString.Char8 as B
+import Data.List
+import Network.ADB.Client
+import Network.ADB.Server
+import Network.ADB.Socket
+import Network.Socket
+import Prelude hiding (read)
+import qualified Prelude
+import System.Environment
+import System.Exit
+import System.IO
+import System.Posix.Terminal
+import System.Posix.Types
+
+
+main = withSocketsDo $ do
+    args <- getArgs
+    let def_host = "localhost"
+        def_port = "5555"
+        def_uri = "shell:"
+        (host, port, uri) = case args of
+            [] -> (def_host, def_port, def_uri)
+            [host] -> (host, def_port, def_uri)
+            [host, port] -> (host, port, def_uri)
+            (host:port:uri:_) -> (host, port, B.pack uri)
+    putStrLn $ "  Usage is: adb-shell {host {port {uri}}}      (client connection)"
+    putStrLn $ "            adb-shell --server port            (test server)"
+    putStrLn $ "    where { } means 'optional'"
+    putStrLn ""
+    if host == "--server" then do
+        let localAddresses = ["*"]   -- On Windows this should be ["", "localhost"]
+        ais <- concat <$> forM localAddresses (\addr ->
+            getAddrInfo (Just $ AddrInfo {
+                addrFlags = [AI_PASSIVE],
+                addrFamily = AF_UNSPEC,
+                addrSocketType = Stream,
+                addrProtocol = 0,
+                addrAddress = SockAddrInet 0 0,
+                addrCanonName = Nothing
+              }) (Just addr) (Just port)
+          )
+        forM_ (nub ais) $ \ai -> do
+            ss <- socket (addrFamily ai) (addrSocketType ai) (addrProtocol ai)
+            setSocketOption ss ReusePort 1
+              `catch` \(exc :: IOException) ->
+                return ()  -- ignore failure on Windows
+            when (addrFamily ai == AF_INET6) $ setSocketOption ss IPv6Only 1
+            bind ss (addrAddress ai)
+            listen ss 50
+            putStrLn $ "listening on port "++port++" and uri "++show uri
+            _ <- forkIO $ forever $ do
+                (s, _) <- accept ss
+                _ <- forkIO $ do
+                    let tra = socketTransport s
+                    _ <- runErrorT $ withServerSession tra "device::" $ \ses -> do
+                        withAccept ses $ \descriptor ->
+                            if descriptor /= uri
+                                then Nothing
+                                else Just $ \tra -> do
+                                    liftIO $ do
+                                        hPutStrLn stdout "incoming connection started"
+                                        hFlush stdout
+                                    terminal tra
+                    return ()
+                  `finally` sClose s
+                return ()
+            return ()
+        forever $ threadDelay 10000000
+      else do
+        putStrLn $ "connecting to "++host++":"++port++" and uri "++show uri
+        putStrLn ""
+        putStrLn "Default port 5555 is used by a local Android emulator:"
+        putStrLn "  Make sure you enable USB debugging in your emulator, which you'll"
+        putStrLn "  find under '{ } Developer options'"
+        putStrLn "  press ctrl-D or 'exit' to quit"
+        putStrLn ""
+        let hints = defaultHints { addrSocketType = Stream }
+        ais <- getAddrInfo (Just hints) (Just host) (Just port)
+        mSocket <- foldM (\mSocket ai -> do
+                case mSocket of
+                    Nothing -> do
+                        s <- socket (addrFamily ai) (addrSocketType ai) (addrProtocol ai)
+                        do
+                            connect s (addrAddress ai)
+                            return (Just s)
+                          `catch` \(exc :: IOException) -> do
+                            sClose s
+                            return Nothing
+                    Just _ -> return mSocket
+            ) Nothing ais
+        case mSocket of
+            Nothing -> do
+                hPutStrLn stderr $ "failed to connect to "++host++":"++port
+                exitFailure
+            Just skt -> do
+                let stra = socketTransport skt
+                ee <- runErrorT $ do
+                    withClientSession stra $ \ses -> do
+                        --let uri = "tcp:5000"   -- Connect to a localhost socket on the Android device
+                        withConnect ses uri $ \tra -> terminal tra
+                case ee of
+                    Left err -> putStrLn $ "FAILED: "++show err
+                    Right () -> return ()
+
+terminal :: Transport (ErrorT TransportError IO) -> ErrorT TransportError IO ()
+terminal tra = do
+    attrs <- liftIO $ do
+        --hSetEcho stdin False
+        hSetBuffering stdin NoBuffering
+        attrs <- getTerminalAttributes (Fd 0)
+        let attrs' = attrs `withoutMode` EnableEcho
+                           `withoutMode` ProcessInput
+                           `withoutMode` ProcessOutput
+                           `withoutMode` MapCRtoLF
+                           `withoutMode` IgnoreBreak
+                           `withoutMode` IgnoreCR
+                           `withoutMode` MapLFtoCR
+                           `withoutMode` EchoLF
+                           `withoutMode` ExtendedFunctions
+                           `withoutMode` KeyboardInterrupts
+        setTerminalAttributes (Fd 0) attrs' Immediately
+        return attrs
+    writeThr <- liftIO $ forkIO $ do
+        runErrorT $ forever $ do
+            l <- liftIO $ B.hGetSome stdin 1024
+            write tra l
+        return ()
+    -- Need to lift and unlift to use finally, if we don't want to
+    -- use some fancy package like 'exceptions' to do this for us.
+    ee <- liftIO $ runErrorT (forever $ do
+            x <- read tra 1024
+            liftIO $ do
+                B.hPutStr stdout x
+                hFlush stdout
+        ) `finally` do
+            killThread writeThr
+            setTerminalAttributes (Fd 0) attrs Immediately
+    case ee of
+        Left err -> throwError err
+        Right () -> return ()
+
diff --git a/programs/generate-rsa-key.hs b/programs/generate-rsa-key.hs
new file mode 100644
--- /dev/null
+++ b/programs/generate-rsa-key.hs
@@ -0,0 +1,92 @@
+-- Requires RSA package
+--
+-- Write the output of this program to Network/ADB/adb_auth_private_key.h
+import Crypto.Random
+import Codec.Crypto.RSA
+import Data.Bits
+import Data.Char
+import Data.List
+import Data.Maybe
+import Numeric
+import Data.Int
+import Data.Word
+
+
+public_n :: PublicKey -> Integer
+public_n k = extract "public_n = " (show k)
+
+public_e :: PublicKey -> Integer
+public_e k = extract "public_e = " (show k)
+
+private_d :: PrivateKey -> Integer
+private_d k = extract "private_d = " (show k)
+
+extract :: String -> String -> Integer
+extract n [] = error $ "can't extract "++show n
+extract n h | n `isPrefixOf` h = read $ takeWhile isDigit (drop (length n) h)
+extract n (_:h) = extract n h
+
+main :: IO ()
+main = do
+    g <- newGenIO :: IO SystemRandom
+    let (pub, priv, _) = generateKeyPair g 2048
+    putStr $ dumpBigInt "public_n" (public_n pub)
+    putStr $ dumpBigInt "public_e" (public_e pub)
+    putStr $ dumpBigInt "private_d" (private_d priv)
+    let rsaNumBytes = 256
+        rsaNumWords = rsaNumBytes `div` 4
+        r32 = 2^32
+        r = 2 ^ (rsaNumWords * 32)
+        rr = (r^2) `mod` public_n pub
+        rem = public_n pub `mod` r32
+        n0inv =
+            let one = fromMaybe (error "no modular inverse") $ rem `modInv` r32
+            in  fromIntegral (-one) .&. (2^32 - 1) :: Int32
+    --putStrLn $ show rem ++ " -> " ++ show (rem `modInv` 32)
+    putStr $ dumpRSAKey rsaNumWords n0inv (public_n pub) rr (public_e pub)
+
+dumpRSAKey rsaNumWords n0inv n rr e =
+    "const RSAPublicKey public_key = {\n" ++
+    "    "++show rsaNumWords++",\n" ++
+    "    "++show n0inv++",\n" ++
+    "    {"++(intercalate "," . map show . toWords $ n)++"},\n" ++
+    "    {"++(intercalate "," . map show . toWords $ rr)++"},\n" ++
+    "    "++show e++"\n"++
+    "};\n"
+
+toWords :: Integer -> [Int32]
+toWords i = go i
+  where
+    go i | i == 0 = []
+    go i = let (hi, lo) = i `divMod` (2^32)
+           in  fromIntegral lo : go hi
+
+-- Extended Euclidean algorithm.  Given non-negative a and b, return x, y and g
+-- such that ax + by = g, where g = gcd(a,b).  Note that x or y may be negative.
+gcdExt a 0 = (1, 0, a)
+gcdExt a b = let (q, r) = a `quotRem` b
+                 (s, t, g) = gcdExt b r
+             in (t, s - q * t, g)
+ 
+-- Given a and m, return Just x such that ax = 1 mod m.  If there is no such x
+-- return Nothing.
+modInv a m = let (i, _, g) = gcdExt a m
+             in if g == 1 then Just (mkPos i) else Nothing
+  where mkPos x = if x < 0 then x + m else x
+ 
+dumpBigInt :: String -> Integer -> String
+dumpBigInt name i =
+    "const uint8_t "++name++"[] = {\n"++
+    hex ++ "\n" ++
+    "};\n"++
+    "const int "++name++"_length = "++show n++";\n\n" 
+  where
+    bytes = toBytes i :: [Word8]
+    n = length bytes
+    hex = intercalate "," .
+          map (\x -> "0x"++showHex x "") $ bytes
+    toBytes i = reverse (go i)
+      where
+        go i | i == 0 = []
+        go i = let (hi, lo) = i `divMod` 256
+               in  fromIntegral lo : go hi
