forked from External/grumble
Throw the code out there. :)
This commit is contained in:
commit
73ab596ae6
27 changed files with 3565 additions and 0 deletions
6
pkg/cryptstate/Makefile
Normal file
6
pkg/cryptstate/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG = cryptstate
|
||||
GOFILES = cryptstate.go
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
360
pkg/cryptstate/cryptstate.go
Normal file
360
pkg/cryptstate/cryptstate.go
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
// Grumble - an implementation of Murmur in Go
|
||||
// Copyright (c) 2010 The Grumble Authors
|
||||
// The use of this source code is goverened by a BSD-style
|
||||
// license that can be found in the LICENSE-file.
|
||||
|
||||
package cryptstate
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/rand"
|
||||
"os"
|
||||
)
|
||||
|
||||
const AESBlockSize = 16
|
||||
const DecryptHistorySize = 0x100
|
||||
|
||||
type CryptState struct {
|
||||
RawKey [AESBlockSize]byte
|
||||
EncryptIV [AESBlockSize]byte
|
||||
DecryptIV [AESBlockSize]byte
|
||||
decryptHistory [DecryptHistorySize]byte
|
||||
|
||||
Good int
|
||||
Late int
|
||||
Lost int
|
||||
Resync int
|
||||
|
||||
RemoteGood int
|
||||
RemoteLate int
|
||||
RemoteLost int
|
||||
RemoteResync int
|
||||
|
||||
cipher *aes.Cipher
|
||||
}
|
||||
|
||||
func New() (cs *CryptState, err os.Error) {
|
||||
cs = new(CryptState)
|
||||
|
||||
for i := 0; i < DecryptHistorySize; i++ {
|
||||
cs.decryptHistory[i] = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptState) GenerateKey() (err os.Error) {
|
||||
rand.Read(cs.RawKey[0:])
|
||||
rand.Read(cs.EncryptIV[0:])
|
||||
rand.Read(cs.DecryptIV[0:])
|
||||
|
||||
cs.cipher, err = aes.NewCipher(cs.RawKey[0:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptState) SetKey(key []byte, eiv []byte, div[]byte) (err os.Error) {
|
||||
if copy(cs.RawKey[0:], key[0:]) != AESBlockSize {
|
||||
err = os.NewError("Unable to copy key")
|
||||
return
|
||||
}
|
||||
|
||||
if copy(cs.EncryptIV[0:], eiv[0:]) != AESBlockSize {
|
||||
err = os.NewError("Unable to copy EIV")
|
||||
return
|
||||
}
|
||||
|
||||
if copy(cs.DecryptIV[0:], div[0:]) != AESBlockSize {
|
||||
err = os.NewError("Unable to copy DIV")
|
||||
return
|
||||
}
|
||||
|
||||
cs.cipher, err = aes.NewCipher(cs.RawKey[0:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptState) Decrypt(src, dst []byte) (err os.Error) {
|
||||
if len(src) < 4 {
|
||||
err = os.NewError("Crypted length too short to decrypt")
|
||||
return
|
||||
}
|
||||
|
||||
plain_len := len(src) - 4
|
||||
if len(dst) != plain_len {
|
||||
err = os.NewError("plain_len and src len mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
var saveiv [AESBlockSize]byte
|
||||
var tag [AESBlockSize]byte
|
||||
var ivbyte byte
|
||||
var restore bool
|
||||
lost := 0
|
||||
late := 0
|
||||
|
||||
ivbyte = src[0]
|
||||
restore = false
|
||||
|
||||
if copy(saveiv[0:], cs.DecryptIV[0:]) != AESBlockSize {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
|
||||
if byte(cs.DecryptIV[0] + 1) == ivbyte {
|
||||
// In order as expected
|
||||
if ivbyte > cs.DecryptIV[0] {
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
} else if ivbyte < cs.DecryptIV[0] {
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
for i := 1; i < AESBlockSize; i++ {
|
||||
cs.DecryptIV[i] += 1
|
||||
if cs.DecryptIV[i] > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = os.NewError("invalid ivbyte")
|
||||
}
|
||||
} else {
|
||||
// Out of order or repeat
|
||||
var diff int
|
||||
diff = int(ivbyte - cs.DecryptIV[0])
|
||||
if diff > 128 {
|
||||
diff = diff - 256
|
||||
} else if diff < -128 {
|
||||
diff = diff + 256
|
||||
}
|
||||
|
||||
if ivbyte < cs.DecryptIV[0] && diff > -30 && diff < 0 {
|
||||
// Late packet, but no wraparound
|
||||
late = 1
|
||||
lost = -1
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
restore = true
|
||||
} else if ivbyte > cs.DecryptIV[0] && diff > -30 && diff < 0 {
|
||||
// Last was 0x02, here comes 0xff from last round
|
||||
late = 1
|
||||
lost = -1
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
for i := 1; i < AESBlockSize; i++ {
|
||||
cs.DecryptIV[0] -= 1
|
||||
if cs.DecryptIV[0] > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
restore = true
|
||||
} else if ivbyte > cs.DecryptIV[0] && diff > 0 {
|
||||
// Lost a few packets, but beyond that we're good.
|
||||
lost = int(ivbyte - cs.DecryptIV[0] - 1)
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
} else if ivbyte < cs.DecryptIV[0] && diff > 0 {
|
||||
// Lost a few packets, and wrapped around
|
||||
lost = int(256 - int(cs.DecryptIV[0]) + int(ivbyte) - 1)
|
||||
cs.DecryptIV[0] = ivbyte
|
||||
for i := 1; i < AESBlockSize; i++ {
|
||||
cs.DecryptIV[0] += 1
|
||||
if cs.DecryptIV[0] > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = os.NewError("No matching ivbyte")
|
||||
return
|
||||
}
|
||||
|
||||
if cs.decryptHistory[cs.DecryptIV[0]] == cs.DecryptIV[0] {
|
||||
if copy(cs.DecryptIV[0:], saveiv[0:]) != AESBlockSize {
|
||||
err = os.NewError("Failed to copy AESBlockSize bytes")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cs.OCBDecrypt(src[4:], dst[0:], cs.DecryptIV[0:], tag[0:])
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
if tag[i] != src[i+1] {
|
||||
if copy(cs.DecryptIV[0:], saveiv[0:]) != AESBlockSize {
|
||||
err = os.NewError("Error while trying to recover from error")
|
||||
return
|
||||
}
|
||||
err = os.NewError("tag mismatch")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cs.decryptHistory[cs.DecryptIV[0]] = cs.DecryptIV[0]
|
||||
|
||||
if restore {
|
||||
if copy(cs.DecryptIV[0:], saveiv[0:]) != AESBlockSize {
|
||||
err = os.NewError("Error while trying to recover IV")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cs.Good += 1
|
||||
cs.Late += late
|
||||
cs.Lost += lost
|
||||
|
||||
// restart timer
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptState) Encrypt(src, dst []byte) {
|
||||
var tag [AESBlockSize]byte
|
||||
|
||||
// First, increase our IV
|
||||
for i := 0; i < AESBlockSize; i++ {
|
||||
cs.EncryptIV[i] += 1;
|
||||
if cs.EncryptIV[i] > 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cs.OCBEncrypt(src, dst[4:], cs.EncryptIV[0:], tag[0:])
|
||||
|
||||
dst[0] = cs.EncryptIV[0]
|
||||
dst[1] = tag[0];
|
||||
dst[2] = tag[1];
|
||||
dst[3] = tag[2];
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func zeros(block []byte) {
|
||||
for i := 0; i < AESBlockSize; i++ {
|
||||
block[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func xor(dst []byte, a []byte, b []byte) {
|
||||
for i := 0; i < AESBlockSize; i++ {
|
||||
dst[i] = a[i] ^ b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func times2(block []byte) {
|
||||
carry := (block[0] >> 7) & 0x1
|
||||
for i := 0; i < AESBlockSize-1; i++ {
|
||||
block[i] = (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
|
||||
}
|
||||
block[AESBlockSize-1] = (block[AESBlockSize-1] << 1) ^ (carry * 135)
|
||||
}
|
||||
|
||||
func times3(block []byte) {
|
||||
carry := (block[0] >> 7) & 0x1;
|
||||
for i := 0; i < AESBlockSize-1; i++ {
|
||||
block[i] ^= (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
|
||||
}
|
||||
block[AESBlockSize-1] ^= ((block[AESBlockSize-1] << 1) ^ (carry * 135))
|
||||
}
|
||||
|
||||
func (cs *CryptState) OCBEncrypt(src []byte, dst []byte, nonce []byte, tag []byte) (err os.Error) {
|
||||
var delta [AESBlockSize]byte
|
||||
var checksum [AESBlockSize]byte
|
||||
var tmp [AESBlockSize]byte
|
||||
var pad [AESBlockSize]byte
|
||||
off := 0
|
||||
|
||||
cs.cipher.Encrypt(cs.EncryptIV[0:], delta[0:])
|
||||
zeros(checksum[0:])
|
||||
|
||||
remain := len(src)
|
||||
for remain > AESBlockSize {
|
||||
times2(delta[0:])
|
||||
xor(tmp[0:], delta[0:], src[off:off+AESBlockSize])
|
||||
cs.cipher.Encrypt(tmp[0:], tmp[0:])
|
||||
xor(dst[off:off+AESBlockSize], delta[0:], tmp[0:])
|
||||
xor(checksum[0:], checksum[0:], src[off:off+AESBlockSize])
|
||||
remain -= AESBlockSize
|
||||
off += AESBlockSize
|
||||
}
|
||||
|
||||
times2(delta[0:])
|
||||
zeros(tmp[0:])
|
||||
num := remain * 8
|
||||
tmp[AESBlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
|
||||
tmp[AESBlockSize-1] = uint8(num & 0xff)
|
||||
xor(tmp[0:], tmp[0:], delta[0:])
|
||||
cs.cipher.Encrypt(tmp[0:], pad[0:])
|
||||
copied := copy(tmp[0:], src[off:])
|
||||
if copied != remain {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
if copy(tmp[copied:], pad[copied:]) != (AESBlockSize-remain) {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
xor(checksum[0:], checksum[0:], tmp[0:])
|
||||
xor(tmp[0:], pad[0:], tmp[0:])
|
||||
if copy(dst[off:], tmp[0:]) != remain {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
|
||||
times3(delta[0:])
|
||||
xor(tmp[0:], delta[0:], checksum[0:])
|
||||
cs.cipher.Encrypt(tmp[0:], tag[0:])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptState) OCBDecrypt(encrypted []byte, plain []byte, nonce []byte, tag []byte) (err os.Error) {
|
||||
var checksum [AESBlockSize]byte
|
||||
var delta [AESBlockSize]byte
|
||||
var tmp [AESBlockSize]byte
|
||||
var pad [AESBlockSize]byte
|
||||
off := 0
|
||||
|
||||
cs.cipher.Encrypt(nonce[0:], delta[0:])
|
||||
zeros(checksum[0:])
|
||||
|
||||
remain := len(encrypted)
|
||||
for remain > AESBlockSize {
|
||||
times2(delta[0:])
|
||||
xor(tmp[0:], delta[0:], encrypted[off:off+AESBlockSize])
|
||||
cs.cipher.Decrypt(tmp[0:], tmp[0:])
|
||||
xor(plain[off:off+AESBlockSize], delta[0:], tmp[0:])
|
||||
xor(checksum[0:], checksum[0:], plain[off:off+AESBlockSize])
|
||||
off += AESBlockSize
|
||||
remain -= AESBlockSize
|
||||
}
|
||||
|
||||
times2(delta[0:])
|
||||
zeros(tmp[0:])
|
||||
num := remain * 8
|
||||
tmp[AESBlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
|
||||
tmp[AESBlockSize-1] = uint8(num & 0xff)
|
||||
xor(tmp[0:], tmp[0:], delta[0:])
|
||||
cs.cipher.Encrypt(tmp[0:], pad[0:])
|
||||
for i := 0; i < AESBlockSize; i++ {
|
||||
tmp[i] = 0
|
||||
}
|
||||
copied := copy(tmp[0:remain], encrypted[off:off+remain])
|
||||
if copied != remain {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
xor(tmp[0:], tmp[0:], pad[0:])
|
||||
xor(checksum[0:], checksum[0:], tmp[0:])
|
||||
copied = copy(plain[off:off+remain], tmp[0:remain])
|
||||
if copied != remain {
|
||||
err = os.NewError("Copy failed")
|
||||
return
|
||||
}
|
||||
|
||||
times3(delta[0:])
|
||||
xor(tmp[0:], delta[0:], checksum[0:])
|
||||
cs.cipher.Encrypt(tmp[0:], tag[0:])
|
||||
|
||||
return
|
||||
}
|
||||
147
pkg/cryptstate/cryptstate_test.go
Normal file
147
pkg/cryptstate/cryptstate_test.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package cryptstate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BlockCompare(a []byte, b []byte) (match bool) {
|
||||
if len(a) != len(b) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
match = true
|
||||
return
|
||||
}
|
||||
|
||||
func TestTimes2(t *testing.T) {
|
||||
msg := [AESBlockSize]byte{
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
}
|
||||
expected := [AESBlockSize]byte{
|
||||
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b,
|
||||
}
|
||||
|
||||
times2(msg[0:])
|
||||
if BlockCompare(msg[0:], expected[0:]) == false {
|
||||
t.Errorf("times2 produces invalid output: %v, expected: %v", msg, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimes3(t *testing.T) {
|
||||
msg := [AESBlockSize]byte{
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
}
|
||||
expected := [AESBlockSize]byte {
|
||||
0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85,
|
||||
}
|
||||
|
||||
times3(msg[0:])
|
||||
if BlockCompare(msg[0:], expected[0:]) == false {
|
||||
t.Errorf("times3 produces invalid output: %v, expected: %v", msg, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestZeros(t *testing.T) {
|
||||
var msg [AESBlockSize]byte
|
||||
zeros(msg[0:])
|
||||
for i := 0; i < len(msg); i++ {
|
||||
if msg[i] != 0 {
|
||||
t.Errorf("zeros does not zero slice.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestXor(t *testing.T) {
|
||||
msg := [AESBlockSize]byte{
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
}
|
||||
var out [AESBlockSize]byte
|
||||
xor(out[0:], msg[0:], msg[0:])
|
||||
for i := 0; i < len(out); i++ {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("XOR broken")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
msg := [15]byte {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
}
|
||||
key := [AESBlockSize]byte {
|
||||
0x96, 0x8b, 0x1b, 0x0c, 0x53, 0x1e, 0x1f, 0x80, 0xa6, 0x1d, 0xcb, 0x27, 0x94, 0x09, 0x6f, 0x32,
|
||||
}
|
||||
eiv := [AESBlockSize]byte {
|
||||
0x1e, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a,
|
||||
}
|
||||
div := [AESBlockSize]byte {
|
||||
0x73, 0x99, 0x9d, 0xa2, 0x03, 0x70, 0x00, 0x96, 0xef, 0x55, 0x06, 0x7a, 0x8b, 0xbe, 0x00, 0x07,
|
||||
}
|
||||
expected := [19]byte {
|
||||
0x1f, 0xfc, 0xdd, 0xb4, 0x68, 0x13, 0x68, 0xb7, 0x92, 0x67, 0xca, 0x2d, 0xba, 0xb7, 0x0d, 0x44, 0xdf, 0x32, 0xd4,
|
||||
}
|
||||
expected_eiv := [AESBlockSize]byte {
|
||||
0x1f, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a,
|
||||
}
|
||||
|
||||
cs, err := New()
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
|
||||
out := make([]byte, 19)
|
||||
cs.SetKey(key[0:], eiv[0:], div[0:])
|
||||
cs.Encrypt(msg[0:], out[0:])
|
||||
|
||||
if BlockCompare(out[0:], expected[0:]) == false {
|
||||
t.Errorf("Mismatch in output")
|
||||
}
|
||||
|
||||
if BlockCompare(cs.EncryptIV[0:], expected_eiv[0:]) == false {
|
||||
t.Errorf("EIV mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
key := [AESBlockSize]byte {
|
||||
0x96, 0x8b, 0x1b, 0x0c, 0x53, 0x1e, 0x1f, 0x80, 0xa6, 0x1d, 0xcb, 0x27, 0x94, 0x09, 0x6f, 0x32,
|
||||
}
|
||||
eiv := [AESBlockSize]byte {
|
||||
0x1e, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a,
|
||||
}
|
||||
div := [AESBlockSize]byte {
|
||||
0x73, 0x99, 0x9d, 0xa2, 0x03, 0x70, 0x00, 0x96, 0xef, 0x55, 0x06, 0x7a, 0x8b, 0xbe, 0x00, 0x07,
|
||||
}
|
||||
crypted := [19]byte {
|
||||
0x1f, 0xfc, 0xdd, 0xb4, 0x68, 0x13, 0x68, 0xb7, 0x92, 0x67, 0xca, 0x2d, 0xba, 0xb7, 0x0d, 0x44, 0xdf, 0x32, 0xd4,
|
||||
}
|
||||
expected := [15]byte {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
}
|
||||
post_div := [AESBlockSize]byte {
|
||||
0x1f, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a,
|
||||
}
|
||||
|
||||
cs, err := New()
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
|
||||
out := make([]byte, 15)
|
||||
cs.SetKey(key[0:], div[0:], eiv[0:])
|
||||
cs.Decrypt(crypted[0:], out[0:])
|
||||
|
||||
if BlockCompare(out[0:], expected[0:]) == false {
|
||||
t.Errorf("Mismatch in output")
|
||||
}
|
||||
|
||||
if BlockCompare(cs.DecryptIV[0:], post_div[0:]) == false {
|
||||
t.Errorf("Mismatch in DIV")
|
||||
}
|
||||
}
|
||||
322
pkg/cryptstate/testgen/CryptState.cpp
Normal file
322
pkg/cryptstate/testgen/CryptState.cpp
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/* Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
- Neither the name of the Mumble Developers nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements OCB-AES128.
|
||||
* In the US, OCB is covered by patents. The inventor has given a license
|
||||
* to all programs distributed under the GPL.
|
||||
* Mumble is BSD (revised) licensed, meaning you can use the code in a
|
||||
* closed-source program. If you do, you'll have to either replace
|
||||
* OCB with something else or get yourself a license.
|
||||
*/
|
||||
|
||||
#include "CryptState.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace MumbleClient {
|
||||
|
||||
CryptState::CryptState() {
|
||||
for (int i = 0; i < 0x100; i++)
|
||||
decrypt_history[i] = 0;
|
||||
|
||||
bInit = false;
|
||||
uiGood = uiLate = uiLost = uiResync = 0;
|
||||
uiRemoteGood = uiRemoteLate = uiRemoteLost = uiRemoteResync = 0;
|
||||
}
|
||||
|
||||
bool CryptState::isValid() const {
|
||||
return bInit;
|
||||
}
|
||||
|
||||
void CryptState::genKey() {
|
||||
RAND_bytes(raw_key, AES_BLOCK_SIZE);
|
||||
RAND_bytes(encrypt_iv, AES_BLOCK_SIZE);
|
||||
RAND_bytes(decrypt_iv, AES_BLOCK_SIZE);
|
||||
AES_set_encrypt_key(raw_key, 128, &encrypt_key);
|
||||
AES_set_decrypt_key(raw_key, 128, &decrypt_key);
|
||||
bInit = true;
|
||||
}
|
||||
|
||||
void CryptState::setKey(const unsigned char* rkey, const unsigned char* eiv, const unsigned char* div) {
|
||||
memcpy(raw_key, rkey, AES_BLOCK_SIZE);
|
||||
memcpy(encrypt_iv, eiv, AES_BLOCK_SIZE);
|
||||
memcpy(decrypt_iv, div, AES_BLOCK_SIZE);
|
||||
AES_set_encrypt_key(raw_key, 128, &encrypt_key);
|
||||
AES_set_decrypt_key(raw_key, 128, &decrypt_key);
|
||||
bInit = true;
|
||||
}
|
||||
|
||||
void CryptState::setDecryptIV(const unsigned char* iv) {
|
||||
memcpy(decrypt_iv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
const unsigned char* CryptState::getEncryptIV() const {
|
||||
return encrypt_iv;
|
||||
}
|
||||
|
||||
void CryptState::encrypt(const unsigned char* source, unsigned char* dst, unsigned int plain_length) {
|
||||
unsigned char tag[AES_BLOCK_SIZE];
|
||||
|
||||
// First, increase our IV.
|
||||
for (int i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
if (++encrypt_iv[i])
|
||||
break;
|
||||
|
||||
ocb_encrypt(source, dst+4, plain_length, encrypt_iv, tag);
|
||||
|
||||
dst[0] = encrypt_iv[0];
|
||||
dst[1] = tag[0];
|
||||
dst[2] = tag[1];
|
||||
dst[3] = tag[2];
|
||||
}
|
||||
|
||||
bool CryptState::decrypt(const unsigned char* source, unsigned char* dst, unsigned int crypted_length) {
|
||||
if (crypted_length < 4)
|
||||
return false;
|
||||
|
||||
unsigned int plain_length = crypted_length - 4;
|
||||
|
||||
unsigned char saveiv[AES_BLOCK_SIZE];
|
||||
unsigned char ivbyte = source[0];
|
||||
bool restore = false;
|
||||
unsigned char tag[AES_BLOCK_SIZE];
|
||||
|
||||
int lost = 0;
|
||||
int late = 0;
|
||||
|
||||
memcpy(saveiv, decrypt_iv, AES_BLOCK_SIZE);
|
||||
|
||||
if (((decrypt_iv[0] + 1) & 0xFF) == ivbyte) {
|
||||
// In order as expected.
|
||||
if (ivbyte > decrypt_iv[0]) {
|
||||
decrypt_iv[0] = ivbyte;
|
||||
} else if (ivbyte < decrypt_iv[0]) {
|
||||
decrypt_iv[0] = ivbyte;
|
||||
for (int i = 1;i < AES_BLOCK_SIZE; i++)
|
||||
if (++decrypt_iv[i])
|
||||
break;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// This is either out of order or a repeat.
|
||||
|
||||
int diff = ivbyte - decrypt_iv[0];
|
||||
if (diff > 128)
|
||||
diff = diff-256;
|
||||
else if (diff < -128)
|
||||
diff = diff+256;
|
||||
|
||||
if ((ivbyte < decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
|
||||
// Late packet, but no wraparound.
|
||||
late = 1;
|
||||
lost = -1;
|
||||
decrypt_iv[0] = ivbyte;
|
||||
restore = true;
|
||||
} else if ((ivbyte > decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
|
||||
// Last was 0x02, here comes 0xff from last round
|
||||
late = 1;
|
||||
lost = -1;
|
||||
decrypt_iv[0] = ivbyte;
|
||||
for (int i = 1; i < AES_BLOCK_SIZE; i++)
|
||||
if (decrypt_iv[i]--)
|
||||
break;
|
||||
restore = true;
|
||||
} else if ((ivbyte > decrypt_iv[0]) && (diff > 0)) {
|
||||
// Lost a few packets, but beyond that we're good.
|
||||
lost = ivbyte - decrypt_iv[0] - 1;
|
||||
decrypt_iv[0] = ivbyte;
|
||||
} else if ((ivbyte < decrypt_iv[0]) && (diff > 0)) {
|
||||
// Lost a few packets, and wrapped around
|
||||
lost = 256 - decrypt_iv[0] + ivbyte - 1;
|
||||
decrypt_iv[0] = ivbyte;
|
||||
for (int i = 1; i < AES_BLOCK_SIZE; i++)
|
||||
if (++decrypt_iv[i])
|
||||
break;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (decrypt_history[decrypt_iv[0]] == decrypt_iv[1]) {
|
||||
memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ocb_decrypt(source + 4, dst, plain_length, decrypt_iv, tag);
|
||||
|
||||
if (memcmp(tag, source + 1, 3) != 0) {
|
||||
memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
|
||||
return false;
|
||||
}
|
||||
decrypt_history[decrypt_iv[0]] = decrypt_iv[1];
|
||||
|
||||
if (restore)
|
||||
memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
|
||||
|
||||
uiGood++;
|
||||
uiLate += late;
|
||||
uiLost += lost;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__LP64__)
|
||||
|
||||
#define BLOCKSIZE 2
|
||||
#define SHIFTBITS 63
|
||||
typedef uint64_t subblock;
|
||||
|
||||
#ifdef __x86_64__
|
||||
static inline uint64_t SWAP64(register uint64_t __in) { register uint64_t __out; __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); return __out; }
|
||||
#else
|
||||
#define SWAP64(x) ((static_cast<uint64_t>(x) << 56) | \
|
||||
((static_cast<uint64_t>(x) << 40) & 0xff000000000000ULL) | \
|
||||
((static_cast<uint64_t>(x) << 24) & 0xff0000000000ULL) | \
|
||||
((static_cast<uint64_t>(x) << 8) & 0xff00000000ULL) | \
|
||||
((static_cast<uint64_t>(x) >> 8) & 0xff000000ULL) | \
|
||||
((static_cast<uint64_t>(x) >> 24) & 0xff0000ULL) | \
|
||||
((static_cast<uint64_t>(x) >> 40) & 0xff00ULL) | \
|
||||
((static_cast<uint64_t>(x) >> 56)))
|
||||
#endif
|
||||
|
||||
#define SWAPPED(x) SWAP64(x)
|
||||
|
||||
#else
|
||||
#define BLOCKSIZE 4
|
||||
#define SHIFTBITS 31
|
||||
typedef uint32_t subblock;
|
||||
#define SWAPPED(x) htonl(x)
|
||||
#endif
|
||||
|
||||
typedef subblock keyblock[BLOCKSIZE];
|
||||
|
||||
#define HIGHBIT (1<<SHIFTBITS);
|
||||
|
||||
|
||||
static void inline XOR(subblock* dst, const subblock* a, const subblock* b) {
|
||||
for (int i = 0; i < BLOCKSIZE; i++)
|
||||
dst[i] = a[i] ^ b[i];
|
||||
}
|
||||
|
||||
static void inline S2(subblock* block) {
|
||||
subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
|
||||
for (int i = 0; i < BLOCKSIZE - 1; i++)
|
||||
block[i] = SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i + 1]) >> SHIFTBITS));
|
||||
block[BLOCKSIZE - 1] = SWAPPED((SWAPPED(block[BLOCKSIZE - 1]) << 1) ^(carry * 0x87));
|
||||
}
|
||||
|
||||
static void inline S3(subblock* block) {
|
||||
subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
|
||||
for (int i = 0; i < BLOCKSIZE - 1; i++)
|
||||
block[i] ^= SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i + 1]) >> SHIFTBITS));
|
||||
block[BLOCKSIZE - 1] ^= SWAPPED((SWAPPED(block[BLOCKSIZE - 1]) << 1) ^(carry * 0x87));
|
||||
}
|
||||
|
||||
static void inline ZERO(keyblock &block) {
|
||||
for (int i = 0; i < BLOCKSIZE; i++)
|
||||
block[i] = 0;
|
||||
}
|
||||
|
||||
#define AESencrypt(src,dst,key) AES_encrypt(reinterpret_cast<const unsigned char *>(src),reinterpret_cast<unsigned char *>(dst), key);
|
||||
#define AESdecrypt(src,dst,key) AES_decrypt(reinterpret_cast<const unsigned char *>(src),reinterpret_cast<unsigned char *>(dst), key);
|
||||
|
||||
void CryptState::ocb_encrypt(const unsigned char* plain, unsigned char* encrypted, unsigned int len, const unsigned char* nonce, unsigned char* tag) {
|
||||
keyblock checksum, delta, tmp, pad;
|
||||
|
||||
// Initialize
|
||||
AESencrypt(nonce, delta, &encrypt_key);
|
||||
ZERO(checksum);
|
||||
|
||||
while (len > AES_BLOCK_SIZE) {
|
||||
S2(delta);
|
||||
XOR(tmp, delta, reinterpret_cast<const subblock *>(plain));
|
||||
AESencrypt(tmp, tmp, &encrypt_key);
|
||||
XOR(reinterpret_cast<subblock *>(encrypted), delta, tmp);
|
||||
XOR(checksum, checksum, reinterpret_cast<const subblock *>(plain));
|
||||
len -= AES_BLOCK_SIZE;
|
||||
plain += AES_BLOCK_SIZE;
|
||||
encrypted += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
S2(delta);
|
||||
ZERO(tmp);
|
||||
tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
|
||||
XOR(tmp, tmp, delta);
|
||||
AESencrypt(tmp, pad, &encrypt_key);
|
||||
memcpy(tmp, plain, len);
|
||||
memcpy(reinterpret_cast<unsigned char *>(tmp) + len, reinterpret_cast<const unsigned char *>(pad) + len, AES_BLOCK_SIZE - len);
|
||||
XOR(checksum, checksum, tmp);
|
||||
XOR(tmp, pad, tmp);
|
||||
memcpy(encrypted, tmp, len);
|
||||
|
||||
S3(delta);
|
||||
XOR(tmp, delta, checksum);
|
||||
AESencrypt(tmp, tag, &encrypt_key);
|
||||
}
|
||||
|
||||
void CryptState::ocb_decrypt(const unsigned char* encrypted, unsigned char* plain, unsigned int len, const unsigned char* nonce, unsigned char* tag) {
|
||||
keyblock checksum, delta, tmp, pad;
|
||||
|
||||
// Initialize
|
||||
AESencrypt(nonce, delta, &encrypt_key);
|
||||
ZERO(checksum);
|
||||
|
||||
while (len > AES_BLOCK_SIZE) {
|
||||
S2(delta);
|
||||
XOR(tmp, delta, reinterpret_cast<const subblock *>(encrypted));
|
||||
AESdecrypt(tmp, tmp, &decrypt_key);
|
||||
XOR(reinterpret_cast<subblock *>(plain), delta, tmp);
|
||||
XOR(checksum, checksum, reinterpret_cast<const subblock *>(plain));
|
||||
len -= AES_BLOCK_SIZE;
|
||||
plain += AES_BLOCK_SIZE;
|
||||
encrypted += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
S2(delta);
|
||||
ZERO(tmp);
|
||||
tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
|
||||
XOR(tmp, tmp, delta);
|
||||
AESencrypt(tmp, pad, &encrypt_key);
|
||||
memset(tmp, 0, AES_BLOCK_SIZE);
|
||||
memcpy(tmp, encrypted, len);
|
||||
XOR(tmp, tmp, pad);
|
||||
XOR(checksum, checksum, tmp);
|
||||
memcpy(plain, tmp, len);
|
||||
|
||||
S3(delta);
|
||||
XOR(tmp, delta, checksum);
|
||||
AESencrypt(tmp, tag, &encrypt_key);
|
||||
}
|
||||
|
||||
} // end namespace MumbleClient
|
||||
77
pkg/cryptstate/testgen/CryptState.h
Normal file
77
pkg/cryptstate/testgen/CryptState.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
- Neither the name of the Mumble Developers nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTSTATE_H
|
||||
#define _CRYPTSTATE_H
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
namespace MumbleClient {
|
||||
|
||||
class CryptState {
|
||||
public:
|
||||
unsigned char raw_key[AES_BLOCK_SIZE];
|
||||
unsigned char encrypt_iv[AES_BLOCK_SIZE];
|
||||
unsigned char decrypt_iv[AES_BLOCK_SIZE];
|
||||
unsigned char decrypt_history[0x100];
|
||||
|
||||
unsigned int uiGood;
|
||||
unsigned int uiLate;
|
||||
unsigned int uiLost;
|
||||
unsigned int uiResync;
|
||||
|
||||
unsigned int uiRemoteGood;
|
||||
unsigned int uiRemoteLate;
|
||||
unsigned int uiRemoteLost;
|
||||
unsigned int uiRemoteResync;
|
||||
|
||||
AES_KEY encrypt_key;
|
||||
AES_KEY decrypt_key;
|
||||
bool bInit;
|
||||
|
||||
public:
|
||||
CryptState();
|
||||
|
||||
bool isValid() const;
|
||||
void genKey();
|
||||
void setKey(const unsigned char* rkey, const unsigned char* eiv, const unsigned char* div);
|
||||
void setDecryptIV(const unsigned char* iv);
|
||||
const unsigned char* getEncryptIV() const;
|
||||
|
||||
void ocb_encrypt(const unsigned char* plain, unsigned char* encrypted, unsigned int len, const unsigned char* nonce, unsigned char* tag);
|
||||
void ocb_decrypt(const unsigned char* encrypted, unsigned char* plain, unsigned int len, const unsigned char* nonce, unsigned char* tag);
|
||||
|
||||
bool decrypt(const unsigned char* source, unsigned char* dst, unsigned int crypted_length);
|
||||
void encrypt(const unsigned char* source, unsigned char* dst, unsigned int plain_length);
|
||||
};
|
||||
|
||||
} // end namespace MumbleClient
|
||||
|
||||
#endif
|
||||
9
pkg/cryptstate/testgen/Makefile
Normal file
9
pkg/cryptstate/testgen/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
.PHONY: default
|
||||
default:
|
||||
g++ test.cpp CryptState.cpp -o test -lcrypto
|
||||
g++ test2.cpp CryptState.cpp -o test2 -lcrypto
|
||||
g++ test3.cpp CryptState.cpp -o test3 -lcrypto
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f test test2 test3
|
||||
1
pkg/cryptstate/testgen/README
Normal file
1
pkg/cryptstate/testgen/README
Normal file
|
|
@ -0,0 +1 @@
|
|||
C++ code for generating some of the test vectors used in cryptstate_test.go
|
||||
28
pkg/cryptstate/testgen/test.cpp
Normal file
28
pkg/cryptstate/testgen/test.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include "CryptState.h"
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned char msg[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
};
|
||||
|
||||
static void DumpBytes(unsigned char *bytes, unsigned int len, const char *name) {
|
||||
printf("unsigned char %s[] = { ", name);
|
||||
for (int i = 0; i < len; i++) {
|
||||
printf("0x%.2x, ", bytes[i]);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
MumbleClient::CryptState cs;
|
||||
cs.genKey();
|
||||
|
||||
DumpBytes(cs.raw_key, AES_BLOCK_SIZE, "rawkey");
|
||||
DumpBytes(cs.encrypt_iv, AES_BLOCK_SIZE, "encrypt_iv");
|
||||
DumpBytes(cs.decrypt_iv, AES_BLOCK_SIZE, "decrypt_iv");
|
||||
|
||||
unsigned char buf[19];
|
||||
cs.encrypt(msg, &buf[0], 15);
|
||||
|
||||
DumpBytes(buf, 19, "crypted");
|
||||
}
|
||||
36
pkg/cryptstate/testgen/test2.cpp
Normal file
36
pkg/cryptstate/testgen/test2.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "CryptState.h"
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned char msg[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
};
|
||||
|
||||
unsigned char rawkey[] = { 0x96, 0x8b, 0x1b, 0x0c, 0x53, 0x1e, 0x1f, 0x80, 0xa6, 0x1d, 0xcb, 0x27, 0x94, 0x09, 0x6f, 0x32, };
|
||||
unsigned char encrypt_iv[] = { 0x1e, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a, };
|
||||
unsigned char decrypt_iv[] = { 0x73, 0x99, 0x9d, 0xa2, 0x03, 0x70, 0x00, 0x96, 0xef, 0x55, 0x06, 0x7a, 0x8b, 0xbe, 0x00, 0x07, };
|
||||
unsigned char crypted[] = { 0x1f, 0xfc, 0xdd, 0xb4, 0x68, 0x13, 0x68, 0xb7, 0x92, 0x67, 0xca, 0x2d, 0xba, 0xb7, 0x0d, 0x44, 0xdf, 0x32, 0xd4, };
|
||||
|
||||
|
||||
static void DumpBytes(unsigned char *bytes, unsigned int len, const char *name) {
|
||||
printf("unsigned char %s[] = { ", name);
|
||||
for (int i = 0; i < len; i++) {
|
||||
printf("0x%.2x, ", bytes[i]);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
MumbleClient::CryptState cs;
|
||||
// cs.genKey();
|
||||
cs.setKey(rawkey, encrypt_iv, decrypt_iv);
|
||||
|
||||
DumpBytes(cs.raw_key, AES_BLOCK_SIZE, "rawkey");
|
||||
DumpBytes(cs.encrypt_iv, AES_BLOCK_SIZE, "encrypt_iv");
|
||||
DumpBytes(cs.decrypt_iv, AES_BLOCK_SIZE, "decrypt_iv");
|
||||
|
||||
unsigned char buf[19];
|
||||
cs.encrypt(msg, &buf[0], 15);
|
||||
|
||||
DumpBytes(buf, 19, "crypted");
|
||||
DumpBytes(cs.encrypt_iv, AES_BLOCK_SIZE, "post_eiv");
|
||||
}
|
||||
34
pkg/cryptstate/testgen/test3.cpp
Normal file
34
pkg/cryptstate/testgen/test3.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include "CryptState.h"
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned char msg[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
};
|
||||
|
||||
unsigned char rawkey[] = { 0x96, 0x8b, 0x1b, 0x0c, 0x53, 0x1e, 0x1f, 0x80, 0xa6, 0x1d, 0xcb, 0x27, 0x94, 0x09, 0x6f, 0x32, };
|
||||
unsigned char encrypt_iv[] = { 0x1e, 0x2a, 0x9b, 0xd0, 0x2d, 0xa6, 0x8e, 0x46, 0x26, 0x85, 0x83, 0xe9, 0x14, 0x2a, 0xff, 0x2a, };
|
||||
unsigned char decrypt_iv[] = { 0x73, 0x99, 0x9d, 0xa2, 0x03, 0x70, 0x00, 0x96, 0xef, 0x55, 0x06, 0x7a, 0x8b, 0xbe, 0x00, 0x07, };
|
||||
unsigned char crypted[] = { 0x1f, 0xfc, 0xdd, 0xb4, 0x68, 0x13, 0x68, 0xb7, 0x92, 0x67, 0xca, 0x2d, 0xba, 0xb7, 0x0d, 0x44, 0xdf, 0x32, 0xd4, };
|
||||
|
||||
static void DumpBytes(unsigned char *bytes, unsigned int len, const char *name) {
|
||||
printf("unsigned char %s[] = { ", name);
|
||||
for (int i = 0; i < len; i++) {
|
||||
printf("0x%.2x, ", bytes[i]);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
MumbleClient::CryptState cs;
|
||||
cs.setKey(rawkey, decrypt_iv, encrypt_iv);
|
||||
|
||||
DumpBytes(cs.raw_key, AES_BLOCK_SIZE, "rawkey");
|
||||
DumpBytes(cs.encrypt_iv, AES_BLOCK_SIZE, "encrypt_iv");
|
||||
DumpBytes(cs.decrypt_iv, AES_BLOCK_SIZE, "decrypt_iv");
|
||||
|
||||
unsigned char buf[15];
|
||||
cs.decrypt(crypted, &buf[0], 19);
|
||||
|
||||
DumpBytes(buf, 15, "plain");
|
||||
DumpBytes(cs.decrypt_iv, AES_BLOCK_SIZE, "post_div");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue