ExWapp.AppState.Crypto (ExWapp v0.1.2)

Copy Markdown View Source

Cryptographic primitives for WhatsApp App State Sync.

Implements key expansion, AES-256-CBC encrypt/decrypt, and MAC computation matching whatsmeow's appstate/keys.go and appstate/hash.go.

Summary

Functions

Compute content/value MAC: first 32 bytes of HMAC-SHA512.

Compute index MAC: HMAC-SHA256(index_key, index_json).

Compute patch MAC: HMAC-SHA256(patch_mac_key, snapshot_mac || value_macs... || version_u64 || collection_name).

Compute snapshot MAC: HMAC-SHA256(snapshot_mac_key, hash_state || version_u64 || collection_name).

Decrypt AES-256-CBC ciphertext and remove PKCS7 padding.

Encrypt plaintext with AES-256-CBC + PKCS7 padding.

Expand a 32-byte app state key into 5 sub-keys (160 bytes total) via HKDF-SHA256.

Types

expanded_keys()

@type expanded_keys() :: %{
  index: binary(),
  value_encryption: binary(),
  value_mac: binary(),
  snapshot_mac: binary(),
  patch_mac: binary()
}

Functions

compute_content_mac(operation, encrypted_content, key_id, mac_key)

@spec compute_content_mac(non_neg_integer(), binary(), binary(), binary()) :: binary()

Compute content/value MAC: first 32 bytes of HMAC-SHA512.

Data = operation_byte || key_id || encrypted_content || big_endian_u64(len(key_id)+1)

Operation byte = SyncdOperation value + 1 (SET=0 → byte 1, REMOVE=1 → byte 2).

Matches whatsmeow generateContentMAC() in hash.go:94-98.

compute_index_mac(index_json, index_key)

@spec compute_index_mac(binary(), binary()) :: binary()

Compute index MAC: HMAC-SHA256(index_key, index_json).

Matches whatsmeow concatAndHMAC(sha256.New, keys.Index, indexBytes) in encode.go:300.

compute_patch_mac(snapshot_mac, value_macs, version, collection_name, patch_mac_key)

@spec compute_patch_mac(binary(), [binary()], non_neg_integer(), binary(), binary()) ::
  binary()

Compute patch MAC: HMAC-SHA256(patch_mac_key, snapshot_mac || value_macs... || version_u64 || collection_name).

Matches whatsmeow generatePatchMAC() in hash.go:82-92.

compute_snapshot_mac(hash_state, version, collection_name, snapshot_mac_key)

@spec compute_snapshot_mac(binary(), non_neg_integer(), binary(), binary()) ::
  binary()

Compute snapshot MAC: HMAC-SHA256(snapshot_mac_key, hash_state || version_u64 || collection_name).

Matches whatsmeow HashState.generateSnapshotMAC() in hash.go:78-80.

decrypt_cbc(ciphertext, key, iv)

@spec decrypt_cbc(binary(), binary(), binary()) :: {:ok, binary()} | {:error, term()}

Decrypt AES-256-CBC ciphertext and remove PKCS7 padding.

Matches whatsmeow cbcutil.Decrypt().

encrypt_cbc(plaintext, key, iv \\ nil)

@spec encrypt_cbc(binary(), binary(), binary() | nil) :: {binary(), binary()}

Encrypt plaintext with AES-256-CBC + PKCS7 padding.

When iv is nil, generates a random 16-byte IV. Returns {iv, ciphertext}.

Matches whatsmeow cbcutil.Encrypt().

expand_keys(key_data)

@spec expand_keys(binary()) :: expanded_keys()

Expand a 32-byte app state key into 5 sub-keys (160 bytes total) via HKDF-SHA256.

Matches whatsmeow expandAppStateKeys() in appstate/keys.go:81-84.