Skip to content

Instantly share code, notes, and snippets.

@mayconvm
Created April 29, 2025 10:55
Show Gist options
  • Select an option

  • Save mayconvm/1b7b5aa82d6a6e7b81458c725f5e0e0d to your computer and use it in GitHub Desktop.

Select an option

Save mayconvm/1b7b5aa82d6a6e7b81458c725f5e0e0d to your computer and use it in GitHub Desktop.
Decode file from Whatsapp
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"strings"
)
//ref: https://github.com/sostenesapollo/baileys-decode-enc-by-url/blob/master/decode.py
func HKDF(key []byte, length int, appInfo []byte) []byte {
zeroSalt := make([]byte, 32)
h := hmac.New(sha256.New, zeroSalt)
h.Write(key)
prk := h.Sum(nil)
keyStream := make([]byte, 0, length)
keyBlock := make([]byte, 0)
blockIndex := uint8(1)
for len(keyStream) < length {
h := hmac.New(sha256.New, prk)
h.Write(keyBlock)
h.Write(appInfo)
h.Write([]byte{blockIndex})
keyBlock = h.Sum(nil)
blockIndex++
keyStream = append(keyStream, keyBlock...)
}
return keyStream[:length]
}
func AESUnpad(padded []byte) ([]byte, error) {
if len(padded) == 0 {
return nil, errors.New("empty padded data")
}
padLen := int(padded[len(padded)-1])
if padLen > len(padded) || padLen == 0 {
return nil, errors.New("invalid padding")
}
for i := len(padded) - padLen; i < len(padded); i++ {
if padded[i] != byte(padLen) {
return nil, errors.New("invalid padding")
}
}
return padded[:len(padded)-padLen], nil
}
func AESDecrypt(key, ciphertext, iv []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(ciphertext) < aes.BlockSize || len(ciphertext)%aes.BlockSize != 0 {
return nil, errors.New("ciphertext is not a multiple of the block size")
}
if len(iv) != aes.BlockSize {
return nil, errors.New("IV length must equal block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))
copy(plaintext, ciphertext)
mode.CryptBlocks(plaintext, plaintext)
return AESUnpad(plaintext)
}
func cleanBase64String(s string) string {
s = strings.ReplaceAll(s, " ", "")
s = strings.ReplaceAll(s, "\n", "")
s = strings.ReplaceAll(s, "\r", "")
return s
}
func DecryptMessage(mediaData []byte, mediaKeyBase64, typeMessageToDecode string) ([]byte, error) {
decodedMediaKey, err := base64.URLEncoding.DecodeString(cleanBase64String(mediaKeyBase64))
if err != nil {
return nil, fmt.Errorf("erro ao decodificar mediaKey: %w", err)
}
appInfo := []byte(typeMessageToDecode)
mediaKeyExpanded := HKDF(decodedMediaKey, 112, appInfo)
key := mediaKeyExpanded[16:48]
ciphertext := mediaData[:len(mediaData)-10]
iv := mediaKeyExpanded[:16]
return AESDecrypt(key, ciphertext, iv)
}
// DecryptMessage("file.enc", "<mediaKeyBase64>", "WhatsApp Audio Keys")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment