An authenticated encryption cipher based on the ChaCha20 stream cipher and the Poly1305 message authentication code (MAC). Available in TLS as an alternative to AES and as a replacement for the older RC4 stream cipher.
A basic implementation based on the code from the linked pages:
# chacha20poly1305.tcl -- # # Implementation of the ChaCha20-Poly1305 authenticated cipher. # # Copyright (c) 2018 Neil Madden. # License: Tcl-style package require Tcl 8.6 if {[info exists argv0] && [file tail [info script]] eq [file tail $argv0]} { ::tcl::tm::path add [file dirname [info script]] } package require chacha20 1.0.0 package require poly1305 1.0.0 package provide chacha20poly1305 1.0.0 namespace eval ::chacha20poly1305 { namespace export encrypt decrypt namespace ensemble create proc genkey {key nonce} { set state [chacha20::block [chacha20::initialState $key 0 $nonce] 0] binary format i8 $state } proc encrypt {key message args} { array set options { -nonce "" -assocdata "" } array set options $args set nonce $options(-nonce) if {[string length $nonce] != 12} { error "nonce must be 12 bytes" } set assocData $options(-assocdata) unset options(-assocdata) set ciphertext [::chacha20 encrypt $key $message {*}[array get options] -counter 1] set tag [mac $key $nonce $assocData $ciphertext] return $ciphertext$tag } proc mac {key nonce assocData ciphertext} { set macKey [genkey $key $nonce] #puts "subkey = [binary encode hex $macKey]" set padding1 [padding $assocData] set padding2 [padding $ciphertext] set lengths [binary format ww [string length $assocData] [string length $ciphertext]] set macInput "$assocData$padding1$ciphertext$padding2$lengths" #puts [binary encode hex $macInput] return [::poly1305 compute $macKey $macInput] } proc decrypt {key ciphertext args} { array set options { -nonce "" -assocdata "" } array set options $args set nonce $options(-nonce) if {[string length $nonce] != 12} { error "nonce must be 12 bytes" } set assocData $options(-assocdata) unset options(-assocdata) set suppliedTag [string range $ciphertext end-15 end] set ciphertext [string range $ciphertext 0 end-16] set computedTag [mac $key $nonce $assocData $ciphertext] if {![poly1305::equals $computedTag $suppliedTag]} { error "invalid authentication tag" } return [chacha20 decrypt $key $ciphertext {*}[array get options] -counter 1] } proc padding {input} { set padLen [expr {(16 - ([string length $input] & 15)) & 15}] string repeat \x00 $padLen } } ##### TESTS ##### # if {![info exists argv0] || [file tail [info script]] ne [file tail $argv0]} { # Not running as main script so return to avoid running tests below return } proc fromHex hex { regsub -all {\s+} $hex {} hex regsub -all {:} $hex {} hex regsub -all {..} $hex {\x\0} hex subst $hex } proc assertEqual {a b {msg ""}} { if {$a ne $b} { puts "FAIL - assertion failed: expecting '[binary encode hex $a]' to equal '[binary encode hex $b]' $msg" } else { puts "PASS - $msg" } } set key [fromHex {80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f}] set nonce [fromHex {00 00 00 00 00 01 02 03 04 05 06 07}] assertEqual [chacha20poly1305::genkey $key $nonce] [fromHex { 8a d5 a0 8b 90 5f 81 cc 81 50 40 27 4a b2 94 71 a8 33 b6 37 e3 fd 0d a5 08 db b8 e2 fd d1 a6 46 }] "poly1305 subkey generation" set message "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." set aad [fromHex {50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7}] set nonce [fromHex {07 00 00 00 40 41 42 43 44 45 46 47}] set ctAndTag [chacha20poly1305 encrypt $key $message -assocdata $aad -nonce $nonce] set ciphertext [string range $ctAndTag 0 end-16] set tag [string range $ctAndTag end-15 end] assertEqual $ciphertext [fromHex { d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2 a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6 3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b 1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36 92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58 fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc 3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b 61 16 }] "ChaPoly AEAD - ciphertext test vector" assertEqual $tag [fromHex {1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91}] "ChaPoly AEAD - authentication tag" set decrypted [chacha20poly1305 decrypt $key $ctAndTag -assocdata $aad -nonce $nonce] assertEqual $decrypted $message "ChaPoly AEAD - roundtrip" # vim: ft=tcl