github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/third/kmgRadius/MSCHAPV2/crypto.go (about)

     1  package MSCHAPV2
     2  
     3  import (
     4  	"crypto"
     5  	_ "crypto/sha1"
     6  
     7  	_ "golang.org/x/crypto/md4"
     8  )
     9  
    10  var generateAuthenticatorResponseMagic1 = []byte{0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
    11  	0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
    12  	0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
    13  	0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}
    14  
    15  var generateAuthenticatorResponseMagic2 = []byte{0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
    16  	0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
    17  	0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
    18  	0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
    19  	0x6E}
    20  
    21  // RFC2759 section 8.7 page 9
    22  // return binary form of the result
    23  // in the hash example password is utf-16 encode.
    24  //    Password = "clientPass" 密码的输入格式比较奇怪.utf16?
    25  // 			   = 63 00 6C 00 69 00 65 00 6E 00
    26  // 				 74 00 50 00 61 00 73 00 73 00
    27  func GenerateAuthenticatorResponse(Password []byte, NTResponse [24]byte, PeerChallenge [16]byte,
    28  	AuthenticatorChallenge [16]byte, UserName []byte) [20]byte {
    29  	//TODO 解决中文密码的问题
    30  	utf16Password := make([]byte, len(Password)*2)
    31  	for i := range Password {
    32  		utf16Password[i*2] = Password[i]
    33  	}
    34  	/*
    35  	 * Hash the password with MD4
    36  	 */
    37  
    38  	PasswordHash := md4(utf16Password) //ntPasswordHash
    39  
    40  	/*
    41  	 * Now hash the hash
    42  	 */
    43  
    44  	PasswordHashHash := md4(PasswordHash) //hashNtPasswordHash
    45  
    46  	h := crypto.SHA1.New()
    47  	h.Write(PasswordHashHash)
    48  	h.Write(NTResponse[:])
    49  	h.Write(generateAuthenticatorResponseMagic1)
    50  	Digest := h.Sum(nil)
    51  
    52  	Challenge := challengeHash(PeerChallenge, AuthenticatorChallenge, UserName)
    53  
    54  	h = crypto.SHA1.New()
    55  	h.Write(Digest)
    56  	h.Write(Challenge)
    57  	h.Write(generateAuthenticatorResponseMagic2)
    58  	Digest = h.Sum(nil)
    59  
    60  	out := [20]byte{}
    61  	copy(out[:], Digest)
    62  	return out
    63  }
    64  
    65  // it is md4 hash
    66  func md4(Password []byte) []byte {
    67  	h := crypto.MD4.New()
    68  	h.Write(Password)
    69  	return h.Sum(nil)
    70  }
    71  
    72  func challengeHash(PeerChallenge [16]byte, AuthenticatorChallenge [16]byte, UserName []byte) []byte {
    73  	h := crypto.SHA1.New()
    74  	h.Write(PeerChallenge[:])
    75  	h.Write(AuthenticatorChallenge[:])
    76  	h.Write(UserName)
    77  	Digest := h.Sum(nil)
    78  
    79  	Challenge := make([]byte, 8)
    80  	copy(Challenge, Digest[:8])
    81  	return Challenge
    82  }
    83  
    84  var msCHAPV2GetSendAndRecvKeySHSpad1 = [40]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    85  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    86  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    87  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
    88  
    89  var msCHAPV2GetSendAndRecvKeySHSpad2 = [40]byte{0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    90  	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    91  	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    92  	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2}
    93  
    94  var msCHAPV2GetSendAndRecvKeyMagic1 = [27]byte{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
    95  	0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
    96  	0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}
    97  
    98  var msCHAPV2GetSendAndRecvKeyMagic2 = [84]byte{0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
    99  	0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
   100  	0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
   101  	0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
   102  	0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
   103  	0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
   104  	0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
   105  	0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
   106  	0x6b, 0x65, 0x79, 0x2e}
   107  
   108  var msCHAPV2GetSendAndRecvKeyMagic3 = [84]byte{0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
   109  	0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
   110  	0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
   111  	0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
   112  	0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
   113  	0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
   114  	0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
   115  	0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
   116  	0x6b, 0x65, 0x79, 0x2e}
   117  
   118  func msCHAPV2GetSendAndRecvKeyGetMasterKey(passwordHashHash []byte, NTResponse [24]byte) (masterkey [16]byte) {
   119  	// Secure Hash Standard Federal Information Processing Standards Publication 180-1 -> SHA1
   120  	h := crypto.SHA1.New()
   121  	h.Write(passwordHashHash)
   122  	h.Write(NTResponse[:])
   123  	h.Write(msCHAPV2GetSendAndRecvKeyMagic1[:])
   124  	Digest := h.Sum(nil)
   125  	copy(masterkey[:], Digest[:16])
   126  	return
   127  }
   128  
   129  func msCHAPV2GetSendAndRecvKeyGetAsymetricStartKey(masterkey [16]byte, sessionKeyLength int, IsSend bool, IsServer bool) (sessionKey []byte) {
   130  	var s [84]byte
   131  	if IsSend {
   132  		if IsServer {
   133  			s = msCHAPV2GetSendAndRecvKeyMagic3
   134  		} else {
   135  			s = msCHAPV2GetSendAndRecvKeyMagic2
   136  		}
   137  	} else {
   138  		if IsServer {
   139  			s = msCHAPV2GetSendAndRecvKeyMagic2
   140  		} else {
   141  			s = msCHAPV2GetSendAndRecvKeyMagic3
   142  		}
   143  	}
   144  	h := crypto.SHA1.New()
   145  	h.Write(masterkey[:])
   146  	h.Write(msCHAPV2GetSendAndRecvKeySHSpad1[:])
   147  	h.Write(s[:])
   148  	h.Write(msCHAPV2GetSendAndRecvKeySHSpad2[:])
   149  	Digest := h.Sum(nil)
   150  	sessionKey = Digest[:sessionKeyLength]
   151  	return sessionKey
   152  }
   153  
   154  // http://www.ietf.org/rfc/rfc3079.txt
   155  //    Password = "clientPass" 密码的输入格式已经修正
   156  // 			   = 63 00 6C 00 69 00 65 00 6E 00
   157  // 				 74 00 50 00 61 00 73 00 73 00
   158  func MsCHAPV2GetSendAndRecvKey(Password []byte, NTResponse [24]byte) (sendKey []byte, recvKey []byte) {
   159  	//TODO 解决中文密码的问题
   160  	utf16Password := make([]byte, len(Password)*2)
   161  	for i := range Password {
   162  		utf16Password[i*2] = Password[i]
   163  	}
   164  	PasswordHash := md4(utf16Password)
   165  	PasswordHashHash := md4(PasswordHash)
   166  
   167  	masterKey := msCHAPV2GetSendAndRecvKeyGetMasterKey(PasswordHashHash, NTResponse)
   168  	MasterSendKey := msCHAPV2GetSendAndRecvKeyGetAsymetricStartKey(masterKey, 16, true, true)
   169  	MasterReceiveKey := msCHAPV2GetSendAndRecvKeyGetAsymetricStartKey(masterKey, 16, false, true)
   170  
   171  	return MasterSendKey, MasterReceiveKey
   172  }