package ciphersuite
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"fmt"
"github.com/pion/dtls/v2/pkg/protocol"
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
)
const (
gcmTagLength = 16
gcmNonceLength = 12
)
type GCM struct {
localGCM, remoteGCM cipher .AEAD
localWriteIV, remoteWriteIV []byte
}
func NewGCM (localKey , localWriteIV , remoteKey , remoteWriteIV []byte ) (*GCM , error ) {
localBlock , err := aes .NewCipher (localKey )
if err != nil {
return nil , err
}
localGCM , err := cipher .NewGCM (localBlock )
if err != nil {
return nil , err
}
remoteBlock , err := aes .NewCipher (remoteKey )
if err != nil {
return nil , err
}
remoteGCM , err := cipher .NewGCM (remoteBlock )
if err != nil {
return nil , err
}
return &GCM {
localGCM : localGCM ,
localWriteIV : localWriteIV ,
remoteGCM : remoteGCM ,
remoteWriteIV : remoteWriteIV ,
}, nil
}
func (g *GCM ) Encrypt (pkt *recordlayer .RecordLayer , raw []byte ) ([]byte , error ) {
payload := raw [recordlayer .HeaderSize :]
raw = raw [:recordlayer .HeaderSize ]
nonce := make ([]byte , gcmNonceLength )
copy (nonce , g .localWriteIV [:4 ])
if _ , err := rand .Read (nonce [4 :]); err != nil {
return nil , err
}
additionalData := generateAEADAdditionalData (&pkt .Header , len (payload ))
encryptedPayload := g .localGCM .Seal (nil , nonce , payload , additionalData )
r := make ([]byte , len (raw )+len (nonce [4 :])+len (encryptedPayload ))
copy (r , raw )
copy (r [len (raw ):], nonce [4 :])
copy (r [len (raw )+len (nonce [4 :]):], encryptedPayload )
binary .BigEndian .PutUint16 (r [recordlayer .HeaderSize -2 :], uint16 (len (r )-recordlayer .HeaderSize ))
return r , nil
}
func (g *GCM ) Decrypt (in []byte ) ([]byte , error ) {
var h recordlayer .Header
err := h .Unmarshal (in )
switch {
case err != nil :
return nil , err
case h .ContentType == protocol .ContentTypeChangeCipherSpec :
return in , nil
case len (in ) <= (8 + recordlayer .HeaderSize ):
return nil , errNotEnoughRoomForNonce
}
nonce := make ([]byte , 0 , gcmNonceLength )
nonce = append (append (nonce , g .remoteWriteIV [:4 ]...), in [recordlayer .HeaderSize :recordlayer .HeaderSize +8 ]...)
out := in [recordlayer .HeaderSize +8 :]
additionalData := generateAEADAdditionalData (&h , len (out )-gcmTagLength )
out , err = g .remoteGCM .Open (out [:0 ], nonce , out , additionalData )
if err != nil {
return nil , fmt .Errorf ("%w: %v" , errDecryptPacket , err )
}
return append (in [:recordlayer .HeaderSize ], out ...), nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .