diff --git a/apps/ios/SimpleXChat/SimpleX.h b/apps/ios/SimpleXChat/SimpleX.h index 56df7589a7..9d9ebfa040 100644 --- a/apps/ios/SimpleXChat/SimpleX.h +++ b/apps/ios/SimpleXChat/SimpleX.h @@ -22,3 +22,5 @@ extern char *chat_recv_msg(chat_ctrl ctl); extern char *chat_recv_msg_wait(chat_ctrl ctl, int wait); extern char *chat_parse_markdown(char *str); extern char *chat_parse_server(char *str); +extern void chat_encrypt_media(char *key, char *frame, int len); +extern void chat_decrypt_media(char *key, char *frame, int len); diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 1278a49897..8e8911f703 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -85,6 +85,7 @@ library Simplex.Chat.Migrations.M20230129_drop_chat_items_group_idx Simplex.Chat.Migrations.M20230206_item_deleted_by_group_member_id Simplex.Chat.Mobile + Simplex.Chat.Mobile.WebRTC Simplex.Chat.Options Simplex.Chat.ProfileGenerator Simplex.Chat.Protocol diff --git a/src/Simplex/Chat/Mobile.hs b/src/Simplex/Chat/Mobile.hs index 46e44570c7..2de9921b24 100644 --- a/src/Simplex/Chat/Mobile.hs +++ b/src/Simplex/Chat/Mobile.hs @@ -18,6 +18,7 @@ import Data.Functor (($>)) import Data.List (find) import qualified Data.List.NonEmpty as L import Data.Maybe (fromMaybe) +import Data.Word (Word8) import Database.SQLite.Simple (SQLError (..)) import qualified Database.SQLite.Simple as DB import Foreign.C.String @@ -29,6 +30,7 @@ import GHC.Generics (Generic) import Simplex.Chat import Simplex.Chat.Controller import Simplex.Chat.Markdown (ParsedMarkdown (..), parseMaybeMarkdownList) +import Simplex.Chat.Mobile.WebRTC import Simplex.Chat.Options import Simplex.Chat.Store import Simplex.Chat.Types @@ -63,6 +65,10 @@ foreign export ccall "chat_parse_markdown" cChatParseMarkdown :: CString -> IO C foreign export ccall "chat_parse_server" cChatParseServer :: CString -> IO CJSONString +foreign export ccall "chat_encrypt_media" cChatEncryptMedia :: CString -> Ptr Word8 -> CInt -> IO () + +foreign export ccall "chat_decrypt_media" cChatDecryptMedia :: CString -> Ptr Word8 -> CInt -> IO () + -- | check / migrate database and initialize chat controller on success cChatMigrateInit :: CString -> CString -> Ptr (StablePtr ChatController) -> IO CJSONString cChatMigrateInit fp key ctrl = do diff --git a/src/Simplex/Chat/Mobile/WebRTC.hs b/src/Simplex/Chat/Mobile/WebRTC.hs new file mode 100644 index 0000000000..09dfd940e7 --- /dev/null +++ b/src/Simplex/Chat/Mobile/WebRTC.hs @@ -0,0 +1,43 @@ +module Simplex.Chat.Mobile.WebRTC where + +import qualified Data.ByteString as B +import Data.ByteString.Internal (ByteString(PS), memcpy) +import Foreign.C (CInt, CString) +import Foreign.Ptr (Ptr, plusPtr) +import Foreign.ForeignPtr (newForeignPtr_) +import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) +import Control.Monad (when) +import Data.Word (Word8) + +cChatEncryptMedia :: CString -> Ptr Word8 -> CInt -> IO () +cChatEncryptMedia = cTransformMedia chatEncryptMedia + +cChatDecryptMedia :: CString -> Ptr Word8 -> CInt -> IO () +cChatDecryptMedia = cTransformMedia chatDecryptMedia + +cTransformMedia :: (ByteString -> ByteString -> ByteString) -> CString -> Ptr Word8 -> CInt -> IO () +cTransformMedia f cKey cFrame cFrameLen = do + key <- B.packCStringLen (cKey, 32) + frame <- getByteString cFrame cFrameLen + let frame' = f key frame + putByteString frame' cFrame cFrameLen +{-# INLINE cTransformMedia #-} + +chatEncryptMedia :: ByteString -> ByteString -> ByteString +chatEncryptMedia _key frame = frame + +chatDecryptMedia :: ByteString -> ByteString -> ByteString +chatDecryptMedia _key frame = frame + +getByteString :: Ptr Word8 -> CInt -> IO ByteString +getByteString p size = do + fp <- newForeignPtr_ p + pure $ PS fp 0 $ fromIntegral size +{-# INLINE getByteString #-} + +putByteString :: ByteString -> Ptr Word8 -> CInt -> IO () +putByteString bs@(PS fp offset _) to size = do + let len = B.length bs + p = unsafeForeignPtrToPtr fp `plusPtr` offset + when (len <= fromIntegral size) $ memcpy to p len +{-# INLINE putByteString #-}