Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
7.2 KiB

  1. package Seeder
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/rand"
  7. "crypto/rsa"
  8. "crypto/sha512"
  9. "encoding/pem"
  10. "fmt"
  11. "hash"
  12. "git.tovijaeschke.xyz/tovi/Envelope/Backend/Database"
  13. "git.tovijaeschke.xyz/tovi/Envelope/Backend/Models"
  14. "git.tovijaeschke.xyz/tovi/Envelope/Backend/Util"
  15. "github.com/gofrs/uuid"
  16. )
  17. // EncryptWithPublicKey encrypts data with public key
  18. func encryptWithPublicKey(msg []byte, pub *rsa.PublicKey) []byte {
  19. var (
  20. hash hash.Hash
  21. )
  22. hash = sha512.New()
  23. ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, pub, msg, nil)
  24. if err != nil {
  25. panic(err)
  26. }
  27. return ciphertext
  28. }
  29. func PKCS5Padding(ciphertext []byte, blockSize int, after int) []byte {
  30. var (
  31. padding int
  32. padtext []byte
  33. )
  34. padding = (blockSize - len(ciphertext)%blockSize)
  35. padtext = bytes.Repeat([]byte{byte(padding)}, padding)
  36. return append(ciphertext, padtext...)
  37. }
  38. func generateAesKey() (*pem.Block, cipher.BlockMode) {
  39. var (
  40. pemBlock *pem.Block
  41. block cipher.Block
  42. bKey []byte
  43. bIV []byte
  44. err error
  45. )
  46. bKey = make([]byte, 32)
  47. _, err = rand.Read(bKey)
  48. if err != nil {
  49. panic(err)
  50. }
  51. bIV = make([]byte, 16)
  52. _, err = rand.Read(bIV)
  53. if err != nil {
  54. panic(err)
  55. }
  56. pemBlock = &pem.Block{
  57. Type: "AES KEY",
  58. Bytes: bKey,
  59. }
  60. block, err = aes.NewCipher(bKey)
  61. if err != nil {
  62. panic(err)
  63. }
  64. return pemBlock, cipher.NewCBCEncrypter(block, bIV)
  65. }
  66. func seedMessage(
  67. primaryUser Models.User,
  68. primaryUserThreadKey, secondaryUserThreadKey string,
  69. thread Models.MessageThread,
  70. i int,
  71. ) error {
  72. var (
  73. message Models.Message
  74. messageData Models.MessageData
  75. messagePemBlock *pem.Block
  76. messageMode cipher.BlockMode
  77. plaintext string
  78. dataCiphertext []byte
  79. senderIdCiphertext []byte
  80. bPlaintext []byte
  81. bSenderIdPlaintext []byte
  82. err error
  83. )
  84. plaintext = "Test Message"
  85. bPlaintext = PKCS5Padding([]byte(plaintext), aes.BlockSize, len(plaintext))
  86. bSenderIdPlaintext = PKCS5Padding(primaryUser.ID.Bytes(), aes.BlockSize, len(primaryUser.ID.Bytes()))
  87. dataCiphertext = make([]byte, len(bPlaintext))
  88. senderIdCiphertext = make([]byte, len(bSenderIdPlaintext))
  89. messagePemBlock, messageMode = generateAesKey()
  90. messageMode.CryptBlocks(dataCiphertext, bPlaintext)
  91. messageMode.CryptBlocks(senderIdCiphertext, bSenderIdPlaintext)
  92. messageData = Models.MessageData{
  93. Data: dataCiphertext,
  94. SenderID: senderIdCiphertext,
  95. }
  96. message = Models.Message{
  97. MessageData: messageData,
  98. SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(messagePemBlock), decodedPublicKey),
  99. MessageThreadKey: primaryUserThreadKey,
  100. }
  101. err = Database.CreateMessage(&message)
  102. if err != nil {
  103. return err
  104. }
  105. // The symmetric key would be encrypted with secondary users public key in production
  106. // But due to using the same pub/priv key pair for all users, we will just duplicate it
  107. message = Models.Message{
  108. MessageDataID: message.MessageDataID,
  109. SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(messagePemBlock), decodedPublicKey),
  110. MessageThreadKey: secondaryUserThreadKey,
  111. }
  112. err = Database.CreateMessage(&message)
  113. if err != nil {
  114. return err
  115. }
  116. return err
  117. }
  118. func seedMessageThread(threadPemBlock *pem.Block, threadMode cipher.BlockMode) (Models.MessageThread, error) {
  119. var (
  120. messageThread Models.MessageThread
  121. name string
  122. bNamePlaintext []byte
  123. nameCiphertext []byte
  124. err error
  125. )
  126. name = "Test Conversation"
  127. bNamePlaintext = PKCS5Padding([]byte(name), aes.BlockSize, len(name))
  128. nameCiphertext = make([]byte, len(bNamePlaintext))
  129. threadMode.CryptBlocks(nameCiphertext, bNamePlaintext)
  130. messageThread = Models.MessageThread{
  131. Name: nameCiphertext,
  132. }
  133. err = Database.CreateMessageThread(&messageThread)
  134. return messageThread, err
  135. }
  136. func seedUpdateMessageThreadUsers(
  137. userJson string,
  138. threadPemBlock *pem.Block,
  139. threadMode cipher.BlockMode,
  140. messageThread Models.MessageThread,
  141. ) (Models.MessageThread, error) {
  142. var (
  143. bUsersPlaintext []byte
  144. usersCiphertext []byte
  145. err error
  146. )
  147. bUsersPlaintext = PKCS5Padding([]byte(userJson), aes.BlockSize, len(userJson))
  148. usersCiphertext = make([]byte, len(bUsersPlaintext))
  149. threadMode.CryptBlocks(usersCiphertext, bUsersPlaintext)
  150. messageThread.Users = usersCiphertext
  151. err = Database.UpdateMessageThread(&messageThread)
  152. return messageThread, err
  153. }
  154. func seedMessageThreadUser(
  155. user Models.User,
  156. threadID uuid.UUID,
  157. messageThreadKey string,
  158. threadPemBlock *pem.Block,
  159. threadMode cipher.BlockMode,
  160. ) (Models.MessageThreadUser, error) {
  161. var (
  162. messageThreadUser Models.MessageThreadUser
  163. bThreadIdPlaintext []byte
  164. threadIdCiphertext []byte
  165. bKeyPlaintext []byte
  166. keyCiphertext []byte
  167. bAdminPlaintext []byte
  168. adminCiphertext []byte
  169. err error
  170. )
  171. bThreadIdPlaintext = PKCS5Padding(threadID.Bytes(), aes.BlockSize, len(threadID.String()))
  172. threadIdCiphertext = make([]byte, len(bThreadIdPlaintext))
  173. bKeyPlaintext = PKCS5Padding([]byte(messageThreadKey), aes.BlockSize, len(messageThreadKey))
  174. keyCiphertext = make([]byte, len(bKeyPlaintext))
  175. bAdminPlaintext = PKCS5Padding([]byte("true"), aes.BlockSize, len("true"))
  176. adminCiphertext = make([]byte, len(bAdminPlaintext))
  177. threadMode.CryptBlocks(threadIdCiphertext, bThreadIdPlaintext)
  178. threadMode.CryptBlocks(keyCiphertext, bKeyPlaintext)
  179. threadMode.CryptBlocks(adminCiphertext, bAdminPlaintext)
  180. messageThreadUser = Models.MessageThreadUser{
  181. UserID: user.ID,
  182. MessageThreadID: threadIdCiphertext,
  183. MessageThreadKey: keyCiphertext,
  184. Admin: adminCiphertext,
  185. SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(threadPemBlock), decodedPublicKey),
  186. }
  187. err = Database.CreateMessageThreadUser(&messageThreadUser)
  188. return messageThreadUser, err
  189. }
  190. func SeedMessages() {
  191. var (
  192. messageThread Models.MessageThread
  193. threadPemBlock *pem.Block
  194. threadMode cipher.BlockMode
  195. primaryUser Models.User
  196. primaryUserThreadKey string
  197. secondaryUser Models.User
  198. secondaryUserThreadKey string
  199. userJson string
  200. thread Models.MessageThread
  201. i int
  202. err error
  203. )
  204. threadPemBlock, threadMode = generateAesKey()
  205. messageThread, err = seedMessageThread(threadPemBlock, threadMode)
  206. primaryUserThreadKey = Util.RandomString(32)
  207. secondaryUserThreadKey = Util.RandomString(32)
  208. primaryUser, err = Database.GetUserByUsername("testUser")
  209. if err != nil {
  210. panic(err)
  211. }
  212. _, err = seedMessageThreadUser(
  213. primaryUser,
  214. messageThread.ID,
  215. primaryUserThreadKey,
  216. threadPemBlock,
  217. threadMode,
  218. )
  219. secondaryUser, err = Database.GetUserByUsername("testUser2")
  220. if err != nil {
  221. panic(err)
  222. }
  223. _, err = seedMessageThreadUser(
  224. secondaryUser,
  225. messageThread.ID,
  226. secondaryUserThreadKey,
  227. threadPemBlock,
  228. threadMode,
  229. )
  230. userJson = fmt.Sprintf(
  231. `
  232. [
  233. {
  234. "id": "%s",
  235. "username": "%s",
  236. "admin": "true"
  237. },
  238. {
  239. "id": "%s",
  240. "username": "%s",
  241. "admin": "true"
  242. }
  243. ]
  244. `,
  245. primaryUser.ID.String(),
  246. primaryUser.Username,
  247. secondaryUser.ID.String(),
  248. secondaryUser.Username,
  249. )
  250. messageThread, err = seedUpdateMessageThreadUsers(
  251. userJson,
  252. threadPemBlock,
  253. threadMode,
  254. messageThread,
  255. )
  256. for i = 0; i <= 20; i++ {
  257. err = seedMessage(
  258. primaryUser,
  259. primaryUserThreadKey,
  260. secondaryUserThreadKey,
  261. thread,
  262. i,
  263. )
  264. if err != nil {
  265. panic(err)
  266. }
  267. }
  268. }