First commit: Outline of tunnel encryption code
This commit is contained in:
		
							
								
								
									
										72
									
								
								tunnel/crypto.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								tunnel/crypto.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | package tunnel | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/aes" | ||||||
|  | 	"crypto/cipher" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Encrypt encrypts data and returns encrypted payload | ||||||
|  | func Encrypt(data []byte, key string) ([]byte, error) { | ||||||
|  | 	// generate a new AES cipher using our 32 byte key | ||||||
|  | 	c, err := aes.NewCipher(hash(key)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// gcm or Galois/Counter Mode, is a mode of operation | ||||||
|  | 	// for symmetric key cryptographic block ciphers | ||||||
|  | 	// - https://en.wikipedia.org/wiki/Galois/Counter_Mode | ||||||
|  | 	gcm, err := cipher.NewGCM(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// create a new byte array the size of the nonce | ||||||
|  | 	// NOTE: we might use smaller nonce size in the future | ||||||
|  | 	nonce := make([]byte, gcm.NonceSize()) | ||||||
|  | 	if _, err = io.ReadFull(rand.Reader, nonce); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// NOTE: we prepend the nonce to the payload | ||||||
|  | 	// we need to do this as we need the same nonce | ||||||
|  | 	// to decrypt the payload when receiving it | ||||||
|  | 	return gcm.Seal(nonce, nonce, data, nil), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Decrypt decrypts the payload and returns decrypted data | ||||||
|  | func Decrypt(data []byte, key string) ([]byte, error) { | ||||||
|  | 	// generate AES cipher for decrypting the message | ||||||
|  | 	c, err := aes.NewCipher(hash(key)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// we use GCM to encrypt the payload | ||||||
|  | 	gcm, err := cipher.NewGCM(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	nonceSize := gcm.NonceSize() | ||||||
|  | 	// NOTE: we need to parse out nonce from the payload | ||||||
|  | 	// we prepend the nonce to every encrypted payload | ||||||
|  | 	nonce, ciphertext := data[:nonceSize], data[nonceSize:] | ||||||
|  | 	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return plaintext, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // hash hahes the data into 32 bytes key and returns it | ||||||
|  | // hash uses sha256 to hash the passed in string. | ||||||
|  | func hash(key string) []byte { | ||||||
|  | 	hasher := sha256.New() | ||||||
|  | 	hasher.Write([]byte(key)) | ||||||
|  | 	return hasher.Sum(nil) | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								tunnel/crypto_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tunnel/crypto_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | package tunnel | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestEncrypt(t *testing.T) { | ||||||
|  | 	key := "tokenpassphrase" | ||||||
|  | 	data := []byte("supersecret") | ||||||
|  |  | ||||||
|  | 	cipherText, err := Encrypt(data, key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("failed to encrypt data: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// verify the cipherText is not the same as data | ||||||
|  | 	if bytes.Equal(data, cipherText) { | ||||||
|  | 		t.Error("encrypted data are the same as plaintext") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDecrypt(t *testing.T) { | ||||||
|  | 	key := "tokenpassphrase" | ||||||
|  | 	data := []byte("supersecret") | ||||||
|  |  | ||||||
|  | 	cipherText, err := Encrypt(data, key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("failed to encrypt data: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	plainText, err := Decrypt(cipherText, key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("failed to decrypt data: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// verify the plainText is the same as data | ||||||
|  | 	if !bytes.Equal(data, plainText) { | ||||||
|  | 		t.Error("decrypted data not the same as plaintext") | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user