Browse Source

fixed integrity checksum bug

Jonathan Turner 9 years ago
parent
commit
3ac81fb2b3
7 changed files with 30 additions and 50 deletions
  1. 1 1
      client/ASExchange.go
  2. 2 15
      client/client.go
  3. 0 1
      client/session.go
  4. 5 14
      crypto/EncryptionEngine.go
  5. 14 11
      crypto/aes-cts-hmac-sha1-96.go
  6. 7 7
      debug.go
  7. 1 1
      messages/KRBError.go

+ 1 - 1
client/ASExchange.go

@@ -29,7 +29,7 @@ func (cl *Client) ASExchange() error {
 		if err != nil {
 			return fmt.Errorf("Could not unmarshal data returned from KDC: %v", err)
 		}
-		if krberr.ErrorCode = errorcode.KDC_ERR_PREAUTH_REQUIRED {
+		if krberr.ErrorCode == errorcode.KDC_ERR_PREAUTH_REQUIRED {
 			//TODO put PA TIMESTAMP here
 		}
 		return krberr

+ 2 - 15
client/client.go

@@ -1,22 +1,9 @@
 package client
 
 import (
-	"bytes"
-	"encoding/hex"
-	"fmt"
-	"github.com/jcmturner/asn1"
-	"github.com/jcmturner/gokrb5/config"
-	"github.com/jcmturner/gokrb5/crypto"
-	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/keytab"
-	"github.com/jcmturner/gokrb5/messages"
-	"github.com/jcmturner/gokrb5/types"
-	"math/rand"
-	"net"
-	"os"
-	"time"
+	"github.com/jcmturner/gokrb5/config"
 )
-
 type Client struct {
 	Username string
 	Password string
@@ -51,7 +38,7 @@ func (cl *Client) WithKeytab(kt keytab.Keytab) *Client {
 	return cl
 }
 
-func (cl *Client) WithConfig(cfg config.Config) *Client {
+func (cl *Client) WithConfig(cfg *config.Config) *Client {
 	cl.Config = cfg
 	return cl
 }

+ 0 - 1
client/session.go

@@ -3,7 +3,6 @@ package client
 import (
 	"github.com/jcmturner/gokrb5/types"
 	"time"
-	"github.com/jcmturner/gokrb5/keytab"
 )
 
 

+ 5 - 14
crypto/EncryptionEngine.go

@@ -47,7 +47,7 @@ func GetEtype(id int) (EType, error) {
 
 // RFC3961: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
 // key - base key or protocol key. Likely to be a key from a keytab file
-// TODO usage - a constant
+// usage - a constant
 // n - block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
 // k - key length / key seed length in bits. Eg. for AES256 this value is 256
 // encrypt - the encryption function to use
@@ -131,7 +131,6 @@ func pkcs7Unpad(b []byte, m int) ([]byte, error) {
 
 func DecryptEncPart(key []byte, pe types.EncryptedData, etype EType, usage uint32) ([]byte, error) {
 	//Derive the key
-	//TODO need to consider PAdata for deriving key
 	k, err := etype.DeriveKey(key, GetUsageKe(usage))
 	if err != nil {
 		return nil, fmt.Errorf("Error deriving key: %v", err)
@@ -143,7 +142,7 @@ func DecryptEncPart(key []byte, pe types.EncryptedData, etype EType, usage uint3
 	}
 	//Verify checksum
 	if !etype.VerifyIntegrity(key, pe.Cipher, b, usage) {
-		return nil, errors.New("Error decrypting encrypted part: integrity verification failed")
+			return nil, errors.New("Error decrypting encrypted part: integrity verification failed")
 	}
 	//Remove the confounder bytes
 	b = b[etype.GetConfounderByteSize():]
@@ -222,15 +221,8 @@ func GetIntegrityHash(pt, key []byte, usage uint32, etype EType) ([]byte, error)
 		return nil, fmt.Errorf("Unable to derive key for checksum: %v", err)
 	}
 	mac := hmac.New(etype.GetHash, k)
-	//TODO do I need to append the ivz before taking the hash?
-	//ivz := make([]byte, etype.GetConfounderByteSize())
-	//pt = append(ivz, pt...)
-	//if r := len(pt)%etype.GetMessageBlockByteSize(); r != 0 {
-	//	t := make([]byte, etype.GetMessageBlockByteSize() - r)
-	//	pt = append(pt, t...)
-	//}
 	mac.Write(pt)
-	return mac.Sum(nil)[1:etype.GetHMACBitLength()/8], nil
+	return mac.Sum(nil)[:etype.GetHMACBitLength()/8], nil
 }
 
 func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype EType) bool {
@@ -240,16 +232,15 @@ func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype EType) bool {
 	//random confounder prefix and sufficient padding to bring it to a
 	//multiple of the message block size.  When the HMAC is computed, the
 	//key is used in the protocol key form.
-	h := ct[len(ct)-etype.GetHMACBitLength()/8+1:]
+	h := make([]byte, etype.GetHMACBitLength()/8)
+	copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
 	expectedMAC, _ := GetIntegrityHash(pt, key, usage, etype)
 	return hmac.Equal(h, expectedMAC)
 }
 
 /*
 Key Usage Numbers
-
 RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below.
-
 Kc = DK(base-key, usage | 0x99);
 Ke = DK(base-key, usage | 0xAA);
 Ki = DK(base-key, usage | 0x55);

+ 14 - 11
crypto/aes-cts-hmac-sha1-96.go

@@ -123,12 +123,15 @@ func AESCTSEncrypt(key, iv, message []byte, e EType) ([]byte, []byte, error) {
 }
 
 func AESCTSDecrypt(key, ciphertext []byte, e EType) ([]byte, error) {
+	// Copy the cipher text as golang slices even when passed by value to this method can result in the backing arrays of the calling code value being updated.
+	ct := make([]byte, len(ciphertext))
+	copy(ct, ciphertext)
 	if len(key) != e.GetKeyByteSize() {
 		return nil, fmt.Errorf("Incorrect keysize: expected: %v actual: %v", e.GetKeySeedBitLength(), len(key))
 
 	}
-	if len(ciphertext) < aes.BlockSize {
-		return nil, fmt.Errorf("Ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ciphertext))
+	if len(ct) < aes.BlockSize {
+		return nil, fmt.Errorf("Ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
 	}
 	// Configure the CBC
 	block, err := aes.NewCipher(key)
@@ -141,19 +144,19 @@ func AESCTSDecrypt(key, ciphertext []byte, e EType) ([]byte, error) {
 
 	//If ciphertext is multiple of blocksize we just need to swap back the last two blocks and then do CBC
 	//If the ciphertext is just one block we can't swap so we just decrypt
-	if len(ciphertext)%aes.BlockSize == 0 {
-		if len(ciphertext) > aes.BlockSize {
-			ciphertext, _ = swapLastTwoBlocks(ciphertext, aes.BlockSize)
+	if len(ct)%aes.BlockSize == 0 {
+		if len(ct) > aes.BlockSize {
+			ct, _ = swapLastTwoBlocks(ct, aes.BlockSize)
 		}
 		mode = cipher.NewCBCDecrypter(block, ivz)
-		message := make([]byte, len(ciphertext))
-		mode.CryptBlocks(message, ciphertext)
-		return message[:len(ciphertext)], nil
+		message := make([]byte, len(ct))
+		mode.CryptBlocks(message, ct)
+		return message[:len(ct)], nil
 	}
 
 	// Cipher Text Stealing (CTS) using CBC interface. Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
 	// Get ciphertext of the 2nd to last (penultimate) block (cpb), the last block (clb) and the rest (crb)
-	crb, cpb, clb, _ := tailBlocks(ciphertext, aes.BlockSize)
+	crb, cpb, clb, _ := tailBlocks(ct, aes.BlockSize)
 	iv := ivz
 	var message []byte
 	if crb != nil {
@@ -171,7 +174,7 @@ func AESCTSDecrypt(key, ciphertext []byte, e EType) ([]byte, error) {
 	mode = cipher.NewCBCDecrypter(block, ivz)
 	mode.CryptBlocks(pb, cpb)
 	// number of byte needed to pad
-	npb := aes.BlockSize - len(ciphertext)%aes.BlockSize
+	npb := aes.BlockSize - len(ct)%aes.BlockSize
 	//pad last block using the number of bytes needed from the tail of the plaintext 2nd to last (penultimate) block
 	clb = append(clb, pb[len(pb)-npb:]...)
 
@@ -189,7 +192,7 @@ func AESCTSDecrypt(key, ciphertext []byte, e EType) ([]byte, error) {
 	message = append(message, cpb...)
 
 	// Truncate to the size of the original cipher text
-	return message[:len(ciphertext)], nil
+	return message[:len(ct)], nil
 }
 
 func tailBlocks(b []byte, c int) ([]byte, []byte, []byte, error) {

+ 7 - 7
debug.go

@@ -40,7 +40,6 @@ const pa149rep= "6b8202f3308202efa003020105a10302010ba22e302c302aa103020113a2230
 func main() {
 
 NoPA()
-
 }
 
 func NoPA() {
@@ -73,17 +72,18 @@ func Fast (){
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Error marshalling AS_REQ: %v\n", err)
 	}
-	rb, err := client.SendToKDC(c, b)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "Error sending to KDC: %v\n", err)
-	}
-	var ar messages.ASRep
-	ar.Unmarshal(rb)
 	kb, _ := hex.DecodeString(ktab)
 	kt, err := keytab.Parse(kb)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "KT load err: %v\n\n", err)
 	}
+	cl := client.NewClientWithKeytab("testuser1", kt)
+	rb, err := cl.SendToKDC(b)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error sending to KDC: %v\n", err)
+	}
+	var ar messages.ASRep
+	ar.Unmarshal(rb)
 	err = ar.DecryptEncPartWithKeytab(kt)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "\nDecrypt err: %v\n", err)

+ 1 - 1
messages/KRBError.go

@@ -37,6 +37,6 @@ func (k *KRBError) Unmarshal(b []byte) error {
 	return nil
 }
 
-func (k *KRBError) Error() string {
+func (k KRBError) Error() string {
 	return fmt.Sprintf("KRB Error: %d - %s", k.ErrorCode, k.EText)
 }