The Algorithm

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