To verify that the messages shown actually were the one written at that specific time, you can manually decrypt the messages yourself. The actual algorithm is shown here.
func serializeAndCompress(msg Message) ([]byte, error) {
// Include all necessary fields
data := map[string]string{
"author": msg.Author,
"header": msg.Header,
"password": msg.Password,
"createdDate": convertMillisToDateString(msg.WrittenDateMilli),
"revealDate": convertMillisToDateString(msg.RevealDateMilli),
"message": msg.Message,
}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
// Compress the data
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
if _, err := gz.Write(jsonData); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encryptData(data []byte, password string) ([]byte, error) {
// Derive a 32-byte key from the password
key := sha256.Sum256([]byte(password))
// Create a new AES cipher using the key
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
// Use AES in GCM mode
aesGCM, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
// Generate a random nonce
nonce := make([]byte, aesGCM.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
// Encrypt the data
cipherText := aesGCM.Seal(nil, nonce, data, nil)
// Combine nonce and ciphertext
encryptedData := append(nonce, cipherText...)
return encryptedData, nil
}
func encodeData(data []byte) string {
return base64.URLEncoding.EncodeToString(data)
}
func CreatePublishableMessage(msg Message) (string, string, error) {
// Serialize and compress the data
compressedData, err := serializeAndCompress(msg)
if err != nil {
return "", "", err
}
// Encrypt the data
encryptedData, err := encryptData(compressedData, msg.Password)
if err != nil {
return "", "", err
}
// Encode the encrypted data
encodedData := encodeData(encryptedData)
// Format the publishable message using msg.RevealDate
publishableMessage := fmt.Sprintf("Time Message | Reveal time: %s | %s", convertMillisToDateString(msg.RevealDateMilli), encodedData)
return publishableMessage, encodedData, nil
}
func DecryptPublishableMessage(encodedData, password string) (Message, error) {
var msg Message
// Decode the data
encryptedData, err := decodeData(encodedData)
if err != nil {
return msg, err
}
// Decrypt the data
compressedData, err := decryptData(encryptedData, password)
if err != nil {
return msg, err
}
// Decompress the data
jsonData, err := decompressData(compressedData)
if err != nil {
return msg, err
}
// Deserialize the JSON
if err := json.Unmarshal(jsonData, &msg); err != nil {
return msg, err
}
return msg, nil
}
func decodeData(encodedData string) ([]byte, error) {
return base64.URLEncoding.DecodeString(encodedData)
}
func decryptData(encryptedData []byte, password string) ([]byte, error) {
key := sha256.Sum256([]byte(password))
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
aesGCM, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := aesGCM.NonceSize()
if len(encryptedData) < nonceSize {
return nil, fmt.Errorf("invalid encrypted data")
}
nonce, cipherText := encryptedData[:nonceSize], encryptedData[nonceSize:]
data, err := aesGCM.Open(nil, nonce, cipherText, nil)
if err != nil {
return nil, err
}
return data, nil
}
func decompressData(data []byte) ([]byte, error) {
buf := bytes.NewBuffer(data)
gz, err := gzip.NewReader(buf)
if err != nil {
return nil, err
}
decompressedData, err := io.ReadAll(gz)
if err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return decompressedData, nil
}
func generateRandomID(length int) (string, error) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var result strings.Builder
for i := 0; i < length; i++ {
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", err
}
result.WriteByte(charset[index.Int64()])
}
return result.String(), nil
}
func convertMillisToDateString(milliseconds uint64) string {
// Convert milliseconds to seconds and nanoseconds
seconds := int64(milliseconds / 1000)
nanoseconds := int64((milliseconds % 1000) * 1e6)
// Create a time.Time object in UTC
t := time.Unix(seconds, nanoseconds).UTC()
// Format the time object to a readable string
return t.Format("2006-01-02 15:04:05 UTC")
}
Time Messages
Stated Today, Read Tomorrow