|
@ -8,10 +8,12 @@ import ( |
|
|
"crypto/rsa" |
|
|
"crypto/rsa" |
|
|
"crypto/sha512" |
|
|
"crypto/sha512" |
|
|
"encoding/pem" |
|
|
"encoding/pem" |
|
|
|
|
|
"fmt" |
|
|
"hash" |
|
|
"hash" |
|
|
|
|
|
|
|
|
"git.tovijaeschke.xyz/tovi/Envelope/Backend/Database" |
|
|
"git.tovijaeschke.xyz/tovi/Envelope/Backend/Database" |
|
|
"git.tovijaeschke.xyz/tovi/Envelope/Backend/Models" |
|
|
"git.tovijaeschke.xyz/tovi/Envelope/Backend/Models" |
|
|
|
|
|
"git.tovijaeschke.xyz/tovi/Envelope/Backend/Util" |
|
|
"github.com/gofrs/uuid" |
|
|
"github.com/gofrs/uuid" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
@ -39,27 +41,17 @@ func PKCS5Padding(ciphertext []byte, blockSize int, after int) []byte { |
|
|
return append(ciphertext, padtext...) |
|
|
return append(ciphertext, padtext...) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func seedMessage(primaryUser, secondaryUser Models.User, threadID uuid.UUID, i int) error { |
|
|
|
|
|
|
|
|
func generateAesKey() (*pem.Block, cipher.BlockMode) { |
|
|
var ( |
|
|
var ( |
|
|
messageKey Models.Message |
|
|
|
|
|
messageData Models.MessageData |
|
|
|
|
|
|
|
|
|
|
|
block cipher.Block |
|
|
|
|
|
mode cipher.BlockMode |
|
|
|
|
|
pemBlock *pem.Block |
|
|
pemBlock *pem.Block |
|
|
|
|
|
block cipher.Block |
|
|
|
|
|
|
|
|
plaintext string |
|
|
|
|
|
ciphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
bKey []byte |
|
|
|
|
|
bIV []byte |
|
|
|
|
|
bPlaintext []byte |
|
|
|
|
|
|
|
|
bKey []byte |
|
|
|
|
|
bIV []byte |
|
|
|
|
|
|
|
|
err error |
|
|
err error |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
plaintext = "Test Message" |
|
|
|
|
|
|
|
|
|
|
|
bKey = make([]byte, 32) |
|
|
bKey = make([]byte, 32) |
|
|
_, err = rand.Read(bKey) |
|
|
_, err = rand.Read(bKey) |
|
|
if err != nil { |
|
|
if err != nil { |
|
@ -70,7 +62,6 @@ func seedMessage(primaryUser, secondaryUser Models.User, threadID uuid.UUID, i i |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
bPlaintext = PKCS5Padding([]byte(plaintext), aes.BlockSize, len(plaintext)) |
|
|
|
|
|
|
|
|
|
|
|
pemBlock = &pem.Block{ |
|
|
pemBlock = &pem.Block{ |
|
|
Type: "AES KEY", |
|
|
Type: "AES KEY", |
|
@ -82,53 +73,256 @@ func seedMessage(primaryUser, secondaryUser Models.User, threadID uuid.UUID, i i |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ciphertext = make([]byte, len(bPlaintext)) |
|
|
|
|
|
|
|
|
return pemBlock, cipher.NewCBCEncrypter(block, bIV) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func seedMessage( |
|
|
|
|
|
primaryUser Models.User, |
|
|
|
|
|
primaryUserThreadKey, secondaryUserThreadKey string, |
|
|
|
|
|
thread Models.MessageThread, |
|
|
|
|
|
i int, |
|
|
|
|
|
) error { |
|
|
|
|
|
var ( |
|
|
|
|
|
message Models.Message |
|
|
|
|
|
messageData Models.MessageData |
|
|
|
|
|
|
|
|
|
|
|
messagePemBlock *pem.Block |
|
|
|
|
|
messageMode cipher.BlockMode |
|
|
|
|
|
|
|
|
|
|
|
plaintext string |
|
|
|
|
|
dataCiphertext []byte |
|
|
|
|
|
senderIdCiphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
bPlaintext []byte |
|
|
|
|
|
bSenderIdPlaintext []byte |
|
|
|
|
|
|
|
|
|
|
|
err error |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
plaintext = "Test Message" |
|
|
|
|
|
bPlaintext = PKCS5Padding([]byte(plaintext), aes.BlockSize, len(plaintext)) |
|
|
|
|
|
bSenderIdPlaintext = PKCS5Padding(primaryUser.ID.Bytes(), aes.BlockSize, len(primaryUser.ID.Bytes())) |
|
|
|
|
|
|
|
|
|
|
|
dataCiphertext = make([]byte, len(bPlaintext)) |
|
|
|
|
|
senderIdCiphertext = make([]byte, len(bSenderIdPlaintext)) |
|
|
|
|
|
|
|
|
mode = cipher.NewCBCEncrypter(block, bIV) |
|
|
|
|
|
|
|
|
messagePemBlock, messageMode = generateAesKey() |
|
|
|
|
|
|
|
|
mode.CryptBlocks(ciphertext, bPlaintext) |
|
|
|
|
|
|
|
|
messageMode.CryptBlocks(dataCiphertext, bPlaintext) |
|
|
|
|
|
messageMode.CryptBlocks(senderIdCiphertext, bSenderIdPlaintext) |
|
|
|
|
|
|
|
|
messageData = Models.MessageData{ |
|
|
messageData = Models.MessageData{ |
|
|
Data: ciphertext, |
|
|
|
|
|
|
|
|
Data: dataCiphertext, |
|
|
|
|
|
SenderID: senderIdCiphertext, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
messageKey = Models.Message{ |
|
|
|
|
|
UserID: primaryUser.ID, |
|
|
|
|
|
|
|
|
message = Models.Message{ |
|
|
MessageData: messageData, |
|
|
MessageData: messageData, |
|
|
MessageType: "sender", |
|
|
|
|
|
RelationalUserId: encryptWithPublicKey(secondaryUser.ID.Bytes(), decodedPublicKey), |
|
|
|
|
|
SymmetricKey: string(pem.EncodeToMemory(pemBlock)), |
|
|
|
|
|
|
|
|
SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(messagePemBlock), decodedPublicKey), |
|
|
|
|
|
MessageThreadKey: primaryUserThreadKey, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = Database.CreateMessage(&message) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The symmetric key would be encrypted with secondary users public key in production
|
|
|
|
|
|
// But due to using the same pub/priv key pair for all users, we will just duplicate it
|
|
|
|
|
|
message = Models.Message{ |
|
|
|
|
|
MessageDataID: message.MessageDataID, |
|
|
|
|
|
SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(messagePemBlock), decodedPublicKey), |
|
|
|
|
|
MessageThreadKey: secondaryUserThreadKey, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = Database.CreateMessage(&message) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return Database.CreateMessage(&messageKey) |
|
|
|
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func seedMessageThread(threadPemBlock *pem.Block, threadMode cipher.BlockMode) (Models.MessageThread, error) { |
|
|
|
|
|
var ( |
|
|
|
|
|
messageThread Models.MessageThread |
|
|
|
|
|
|
|
|
|
|
|
name string |
|
|
|
|
|
bNamePlaintext []byte |
|
|
|
|
|
nameCiphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
err error |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
name = "Test Conversation" |
|
|
|
|
|
|
|
|
|
|
|
bNamePlaintext = PKCS5Padding([]byte(name), aes.BlockSize, len(name)) |
|
|
|
|
|
nameCiphertext = make([]byte, len(bNamePlaintext)) |
|
|
|
|
|
|
|
|
|
|
|
threadMode.CryptBlocks(nameCiphertext, bNamePlaintext) |
|
|
|
|
|
|
|
|
|
|
|
messageThread = Models.MessageThread{ |
|
|
|
|
|
Name: nameCiphertext, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = Database.CreateMessageThread(&messageThread) |
|
|
|
|
|
return messageThread, err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func seedUpdateMessageThreadUsers( |
|
|
|
|
|
userJson string, |
|
|
|
|
|
threadPemBlock *pem.Block, |
|
|
|
|
|
threadMode cipher.BlockMode, |
|
|
|
|
|
messageThread Models.MessageThread, |
|
|
|
|
|
) (Models.MessageThread, error) { |
|
|
|
|
|
var ( |
|
|
|
|
|
bUsersPlaintext []byte |
|
|
|
|
|
usersCiphertext []byte |
|
|
|
|
|
err error |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
bUsersPlaintext = PKCS5Padding([]byte(userJson), aes.BlockSize, len(userJson)) |
|
|
|
|
|
usersCiphertext = make([]byte, len(bUsersPlaintext)) |
|
|
|
|
|
|
|
|
|
|
|
threadMode.CryptBlocks(usersCiphertext, bUsersPlaintext) |
|
|
|
|
|
|
|
|
|
|
|
messageThread.Users = usersCiphertext |
|
|
|
|
|
err = Database.UpdateMessageThread(&messageThread) |
|
|
|
|
|
return messageThread, err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func seedMessageThreadUser( |
|
|
|
|
|
user Models.User, |
|
|
|
|
|
threadID uuid.UUID, |
|
|
|
|
|
messageThreadKey string, |
|
|
|
|
|
threadPemBlock *pem.Block, |
|
|
|
|
|
threadMode cipher.BlockMode, |
|
|
|
|
|
) (Models.MessageThreadUser, error) { |
|
|
|
|
|
var ( |
|
|
|
|
|
messageThreadUser Models.MessageThreadUser |
|
|
|
|
|
|
|
|
|
|
|
bThreadIdPlaintext []byte |
|
|
|
|
|
threadIdCiphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
bKeyPlaintext []byte |
|
|
|
|
|
keyCiphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
bAdminPlaintext []byte |
|
|
|
|
|
adminCiphertext []byte |
|
|
|
|
|
|
|
|
|
|
|
err error |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
bThreadIdPlaintext = PKCS5Padding(threadID.Bytes(), aes.BlockSize, len(threadID.String())) |
|
|
|
|
|
threadIdCiphertext = make([]byte, len(bThreadIdPlaintext)) |
|
|
|
|
|
|
|
|
|
|
|
bKeyPlaintext = PKCS5Padding([]byte(messageThreadKey), aes.BlockSize, len(messageThreadKey)) |
|
|
|
|
|
keyCiphertext = make([]byte, len(bKeyPlaintext)) |
|
|
|
|
|
|
|
|
|
|
|
bAdminPlaintext = PKCS5Padding([]byte("true"), aes.BlockSize, len("true")) |
|
|
|
|
|
adminCiphertext = make([]byte, len(bAdminPlaintext)) |
|
|
|
|
|
|
|
|
|
|
|
threadMode.CryptBlocks(threadIdCiphertext, bThreadIdPlaintext) |
|
|
|
|
|
threadMode.CryptBlocks(keyCiphertext, bKeyPlaintext) |
|
|
|
|
|
threadMode.CryptBlocks(adminCiphertext, bAdminPlaintext) |
|
|
|
|
|
|
|
|
|
|
|
messageThreadUser = Models.MessageThreadUser{ |
|
|
|
|
|
UserID: user.ID, |
|
|
|
|
|
MessageThreadID: threadIdCiphertext, |
|
|
|
|
|
MessageThreadKey: keyCiphertext, |
|
|
|
|
|
Admin: adminCiphertext, |
|
|
|
|
|
SymmetricKey: encryptWithPublicKey(pem.EncodeToMemory(threadPemBlock), decodedPublicKey), |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = Database.CreateMessageThreadUser(&messageThreadUser) |
|
|
|
|
|
return messageThreadUser, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func SeedMessages() { |
|
|
func SeedMessages() { |
|
|
var ( |
|
|
var ( |
|
|
primaryUser Models.User |
|
|
|
|
|
secondaryUser Models.User |
|
|
|
|
|
threadID uuid.UUID |
|
|
|
|
|
i int |
|
|
|
|
|
err error |
|
|
|
|
|
|
|
|
messageThread Models.MessageThread |
|
|
|
|
|
threadPemBlock *pem.Block |
|
|
|
|
|
threadMode cipher.BlockMode |
|
|
|
|
|
|
|
|
|
|
|
primaryUser Models.User |
|
|
|
|
|
primaryUserThreadKey string |
|
|
|
|
|
secondaryUser Models.User |
|
|
|
|
|
secondaryUserThreadKey string |
|
|
|
|
|
|
|
|
|
|
|
userJson string |
|
|
|
|
|
|
|
|
|
|
|
thread Models.MessageThread |
|
|
|
|
|
i int |
|
|
|
|
|
err error |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
threadPemBlock, threadMode = generateAesKey() |
|
|
|
|
|
messageThread, err = seedMessageThread(threadPemBlock, threadMode) |
|
|
|
|
|
primaryUserThreadKey = Util.RandomString(32) |
|
|
|
|
|
secondaryUserThreadKey = Util.RandomString(32) |
|
|
|
|
|
|
|
|
primaryUser, err = Database.GetUserByUsername("testUser") |
|
|
primaryUser, err = Database.GetUserByUsername("testUser") |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_, err = seedMessageThreadUser( |
|
|
|
|
|
primaryUser, |
|
|
|
|
|
messageThread.ID, |
|
|
|
|
|
primaryUserThreadKey, |
|
|
|
|
|
threadPemBlock, |
|
|
|
|
|
threadMode, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
secondaryUser, err = Database.GetUserByUsername("testUser2") |
|
|
secondaryUser, err = Database.GetUserByUsername("testUser2") |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
threadID, err = uuid.NewV4() |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
|
_, err = seedMessageThreadUser( |
|
|
|
|
|
secondaryUser, |
|
|
|
|
|
messageThread.ID, |
|
|
|
|
|
secondaryUserThreadKey, |
|
|
|
|
|
threadPemBlock, |
|
|
|
|
|
threadMode, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
userJson = fmt.Sprintf( |
|
|
|
|
|
` |
|
|
|
|
|
[ |
|
|
|
|
|
{ |
|
|
|
|
|
"id": "%s", |
|
|
|
|
|
"username": "%s", |
|
|
|
|
|
"admin": "true" |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
"id": "%s", |
|
|
|
|
|
"username": "%s", |
|
|
|
|
|
"admin": "true" |
|
|
} |
|
|
} |
|
|
|
|
|
] |
|
|
|
|
|
`, |
|
|
|
|
|
primaryUser.ID.String(), |
|
|
|
|
|
primaryUser.Username, |
|
|
|
|
|
secondaryUser.ID.String(), |
|
|
|
|
|
secondaryUser.Username, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
messageThread, err = seedUpdateMessageThreadUsers( |
|
|
|
|
|
userJson, |
|
|
|
|
|
threadPemBlock, |
|
|
|
|
|
threadMode, |
|
|
|
|
|
messageThread, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
for i = 0; i <= 20; i++ { |
|
|
for i = 0; i <= 20; i++ { |
|
|
err = seedMessage(primaryUser, secondaryUser, threadID, i) |
|
|
|
|
|
|
|
|
err = seedMessage( |
|
|
|
|
|
primaryUser, |
|
|
|
|
|
primaryUserThreadKey, |
|
|
|
|
|
secondaryUserThreadKey, |
|
|
|
|
|
thread, |
|
|
|
|
|
i, |
|
|
|
|
|
) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|