1 Star 0 Fork 0

wlhet / orago

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
auth_object.go 16.28 KB
一键复制 编辑 原始数据 按行查看 历史
wlhet 提交于 2023-02-10 15:17 . 对应 go-ora v2.5.27
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
package orago
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"crypto/sha512"
"encoding/hex"
"errors"
"fmt"
"strconv"
"strings"
"time"
"gitee.com/wlhet/orago/network"
"gitee.com/wlhet/orago/network/security"
)
// E infront of the variable means encrypted
type AuthObject struct {
EServerSessKey string
EClientSessKey string
EPassword string
ESpeedyKey string
ServerSessKey []byte
ClientSessKey []byte
KeyHash []byte
Salt string
pbkdf2ChkSalt string
pbkdf2VgenCount int
pbkdf2SderCount int
globalUniqueDBID string
usePadding bool
customHash bool
VerifierType int
tcpNego *TCPNego
}
// create authentication object through reading data from network
func newAuthObject(username string, password string, tcpNego *TCPNego, conn *Connection) (*AuthObject, error) {
session := conn.session
ret := new(AuthObject)
ret.tcpNego = tcpNego
ret.usePadding = false
ret.customHash = ret.tcpNego.ServerCompileTimeCaps[4]&32 != 0
loop := true
for loop {
messageCode, err := session.GetByte()
if err != nil {
return nil, err
}
switch messageCode {
//case 4:
// session.Summary, err = network.NewSummary(session)
// if err != nil {
// return nil, err
// }
// if session.HasError() {
// return nil, session.GetError()
// }
// loop = false
case 8:
dictLen, err := session.GetInt(4, true, true)
if err != nil {
return nil, err
}
for x := 0; x < dictLen; x++ {
key, val, num, err := session.GetKeyVal()
if err != nil {
return nil, err
}
if bytes.Compare(key, []byte("AUTH_SESSKEY")) == 0 {
if len(ret.EServerSessKey) == 0 {
ret.EServerSessKey = string(val)
}
} else if bytes.Compare(key, []byte("AUTH_VFR_DATA")) == 0 {
if len(ret.Salt) == 0 {
ret.Salt = string(val)
ret.VerifierType = num
}
} else if bytes.Compare(key, []byte("AUTH_PBKDF2_CSK_SALT")) == 0 {
if len(ret.pbkdf2ChkSalt) == 0 {
ret.pbkdf2ChkSalt = string(val)
if len(ret.pbkdf2ChkSalt) != 32 {
return nil, &network.OracleError{
ErrCode: 28041,
ErrMsg: "ORA-28041: Authentication protocol internal error",
}
}
}
} else if bytes.Compare(key, []byte("AUTH_PBKDF2_VGEN_COUNT")) == 0 {
if ret.pbkdf2VgenCount == 0 {
ret.pbkdf2VgenCount, err = strconv.Atoi(string(val))
if err != nil {
return nil, &network.OracleError{
ErrCode: 28041,
ErrMsg: "ORA-28041: Authentication protocol internal error",
}
}
if ret.pbkdf2VgenCount < 4096 || ret.pbkdf2VgenCount > 100000000 {
ret.pbkdf2VgenCount = 4096
}
}
} else if bytes.Compare(key, []byte("AUTH_PBKDF2_SDER_COUNT")) == 0 {
ret.pbkdf2SderCount, err = strconv.Atoi(string(val))
if ret.pbkdf2SderCount == 0 {
if err != nil {
return nil, &network.OracleError{
ErrCode: 28041,
ErrMsg: "ORA-28041: Authentication protocol internal error",
}
}
if ret.pbkdf2SderCount < 3 || ret.pbkdf2SderCount > 100000000 {
ret.pbkdf2SderCount = 3
}
}
}
}
//case 15:
// warning, err := network.NewWarningObject(conn.session)
// if err != nil {
// return nil, err
// }
// if warning != nil {
// fmt.Println(warning)
// }
//case 23:
// opCode, err := conn.session.GetByte()
// if err != nil {
// return nil, err
// }
// err = conn.getServerNetworkInformation(opCode)
// if err != nil {
// return nil, err
// }
default:
err = conn.readResponse(messageCode)
if err != nil {
return nil, err
}
if messageCode == 4 {
if session.HasError() {
return nil, session.GetError()
}
loop = false
}
//return nil, errors.New(fmt.Sprintf("message code error: received code %d and expected code is 8", messageCode))
}
}
if len(ret.EServerSessKey) != 64 && len(ret.EServerSessKey) != 96 {
return nil, errors.New("session key should be either 64, 96 bytes long")
}
var key []byte
var speedyKey []byte
padding := false
var err error
if ret.VerifierType == 2361 {
key, err = getKeyFromUserNameAndPassword(username, password)
if err != nil {
return nil, err
}
} else if ret.VerifierType == 6949 {
if ret.tcpNego.ServerCompileTimeCaps[4]&2 == 0 {
padding = true
}
result, err := hex.DecodeString(ret.Salt)
if err != nil {
return nil, err
}
result = append([]byte(password), result...)
hash := sha1.New()
_, err = hash.Write(result)
if err != nil {
return nil, err
}
key = hash.Sum(nil) // 20 byte key
key = append(key, 0, 0, 0, 0) // 24 byte key
} else if ret.VerifierType == 18453 {
salt, err := hex.DecodeString(ret.Salt)
if err != nil {
return nil, err
}
message := append(salt, []byte("AUTH_PBKDF2_SPEEDY_KEY")...)
speedyKey = generateSpeedyKey(message, []byte(password), ret.pbkdf2VgenCount)
buffer := append(speedyKey, salt...)
hash := sha512.New()
hash.Write(buffer)
key = hash.Sum(nil)[:32]
} else {
return nil, errors.New("unsupported verifier type")
}
// get the server session key
ret.ServerSessKey, err = decryptSessionKey(padding, key, ret.EServerSessKey)
if err != nil {
return nil, err
}
// note if serverSessKey length is less than the expected length according to verifier generate random one
// generate new key for client
ret.ClientSessKey = make([]byte, len(ret.ServerSessKey))
for {
_, err = rand.Read(ret.ClientSessKey)
if err != nil {
return nil, err
}
if !bytes.Equal(ret.ClientSessKey, ret.ServerSessKey) {
break
}
}
// encrypt the client key
ret.EClientSessKey, err = encryptSessionKey(padding, key, ret.ClientSessKey)
if err != nil {
return nil, err
}
// get the hash key form server and client session key
newKey, err := ret.generatePasswordEncKey()
if err != nil {
return nil, err
}
if ret.VerifierType == 18453 {
padding = false
} else {
padding = true
}
// encrypt the password
ret.EPassword, err = encryptPassword([]byte(password), newKey, true)
if err != nil {
return nil, err
}
if ret.VerifierType == 18453 {
ret.ESpeedyKey, err = encryptPassword(speedyKey, newKey, padding)
if err != nil {
return nil, err
}
}
return ret, nil
}
// write authentication data to network
func (obj *AuthObject) Write(connOption *network.ConnectionOption, mode LogonMode, session *network.Session) error {
var keys = make([]string, 0, 20)
var values = make([]string, 0, 20)
var flags = make([]uint8, 0, 20)
appendKeyVal := func(key, val string, f uint8) {
keys = append(keys, key)
values = append(values, val)
flags = append(flags, f)
}
index := 0
if len(obj.EClientSessKey) > 0 {
appendKeyVal("AUTH_SESSKEY", obj.EClientSessKey, 1)
index++
}
if len(obj.EPassword) > 0 {
appendKeyVal("AUTH_PASSWORD", obj.EPassword, 0)
index++
}
if len(obj.ESpeedyKey) > 0 {
appendKeyVal("AUTH_PBKDF2_SPEEDY_KEY", obj.ESpeedyKey, 0)
index++
}
appendKeyVal("AUTH_TERMINAL", connOption.ClientInfo.HostName, 0)
index++
appendKeyVal("AUTH_PROGRAM_NM", connOption.ClientInfo.ProgramName, 0)
index++
appendKeyVal("AUTH_MACHINE", connOption.ClientInfo.HostName, 0)
index++
appendKeyVal("AUTH_PID", fmt.Sprintf("%d", connOption.ClientInfo.PID), 0)
index++
appendKeyVal("AUTH_SID", connOption.ClientInfo.UserName, 0)
index++
appendKeyVal("AUTH_CONNECT_STRING", connOption.ConnectionData(), 0)
index++
appendKeyVal("SESSION_CLIENT_CHARSET", strconv.Itoa(int(obj.tcpNego.ServerCharset)), 0)
index++
appendKeyVal("SESSION_CLIENT_LIB_TYPE", "0", 0)
index++
appendKeyVal("SESSION_CLIENT_DRIVER_NAME", connOption.ClientInfo.DriverName, 0)
index++
appendKeyVal("SESSION_CLIENT_VERSION", "2.0.0.0", 0)
index++
appendKeyVal("SESSION_CLIENT_LOBATTR", "1", 0)
index++
_, offset := time.Now().Zone()
tz := ""
if offset == 0 {
tz = "00:00"
} else {
hours := int8(offset / 3600)
minutes := int8((offset / 60) % 60)
if minutes < 0 {
minutes = minutes * -1
}
tz = fmt.Sprintf("%+03d:%02d", hours, minutes)
}
appendKeyVal("AUTH_ALTER_SESSION",
fmt.Sprintf("ALTER SESSION SET NLS_LANGUAGE='AMERICAN' NLS_TERRITORY='AMERICA' TIME_ZONE='%s'\x00", tz), 1)
index++
if len(connOption.ProxyClientName) > 0 {
appendKeyVal("PROXY_CLIENT_NAME", connOption.ProxyClientName, 0)
index++
}
session.ResetBuffer()
session.PutBytes(3, 0x73, 0)
if len(connOption.UserID) > 0 {
session.PutBytes(1)
session.PutInt(len(connOption.UserID), 4, true, true)
} else {
session.PutBytes(0, 0)
}
// if proxy auth logonMode |= 0x400
if len(connOption.UserID) > 0 && len(obj.EPassword) > 0 {
mode |= UserAndPass
}
session.PutUint(int(mode|NoNewPass), 4, true, true)
session.PutBytes(1)
session.PutUint(index, 4, true, true)
session.PutBytes(1, 1)
if len(connOption.UserID) > 0 {
session.PutString(connOption.UserID)
}
for i := 0; i < index; i++ {
session.PutKeyValString(keys[i], values[i], flags[i])
}
return session.Write()
}
func generateSpeedyKey(buffer, key []byte, turns int) []byte {
mac := hmac.New(sha512.New, key)
mac.Write(append(buffer, 0, 0, 0, 1))
firstHash := mac.Sum(nil)
tempHash := make([]byte, len(firstHash))
copy(tempHash, firstHash)
for index1 := 2; index1 <= turns; index1++ {
//mac = hmac.New(sha512.New, []byte("ter1234"))
mac.Reset()
mac.Write(tempHash)
tempHash = mac.Sum(nil)
for index2 := 0; index2 < 64; index2++ {
firstHash[index2] = firstHash[index2] ^ tempHash[index2]
}
}
return firstHash
}
func getKeyFromUserNameAndPassword(username string, password string) ([]byte, error) {
username = strings.ToUpper(username)
password = strings.ToUpper(password)
extendString := func(str string) []byte {
ret := make([]byte, len(str)*2)
for index, char := range []byte(str) {
ret[index*2] = 0
ret[index*2+1] = char
}
return ret
}
buffer := append(extendString(username), extendString(password)...)
if len(buffer)%8 > 0 {
buffer = append(buffer, make([]byte, 8-len(buffer)%8)...)
}
key := []byte{1, 35, 69, 103, 137, 171, 205, 239}
DesEnc := func(input []byte, key []byte) ([]byte, error) {
ret := make([]byte, 8)
enc, err := des.NewCipher(key)
if err != nil {
return nil, err
}
for x := 0; x < len(input)/8; x++ {
for y := 0; y < 8; y++ {
ret[y] = uint8(int(ret[y]) ^ int(input[x*8+y]))
}
output := make([]byte, 8)
enc.Encrypt(output, ret)
copy(ret, output)
}
return ret, nil
}
key1, err := DesEnc(buffer, key)
if err != nil {
return nil, err
}
key2, err := DesEnc(buffer, key1)
if err != nil {
return nil, err
}
// function OSLogonHelper.Method1_bytearray (DecryptSessionKey)
return append(key2, make([]byte, 8)...), nil
}
// decrypt session key that come from the server
func decryptSessionKey(padding bool, encKey []byte, sessionKey string) ([]byte, error) {
result, err := hex.DecodeString(sessionKey)
if err != nil {
return nil, err
}
blk, err := aes.NewCipher(encKey)
if err != nil {
return nil, err
}
//if padding {
// result = PKCS5Padding(result, blk.BlockSize())
//}
enc := cipher.NewCBCDecrypter(blk, make([]byte, 16))
output := make([]byte, len(result))
enc.CryptBlocks(output, result)
cutLen := 0
if padding {
num := int(output[len(output)-1])
if num < enc.BlockSize() {
apply := true
for x := len(output) - num; x < len(output); x++ {
if output[x] != uint8(num) {
apply = false
break
}
}
if apply {
cutLen = int(output[len(output)-1])
}
}
}
return output[:len(output)-cutLen], nil
}
// encrypt session key that generated from the client
func encryptSessionKey(padding bool, encKey []byte, sessionKey []byte) (string, error) {
blk, err := aes.NewCipher(encKey)
if err != nil {
return "", err
}
enc := cipher.NewCBCEncrypter(blk, make([]byte, 16))
originalLen := len(sessionKey)
sessionKey = security.PKCS5Padding(sessionKey, blk.BlockSize())
//if padding {
//
//}
output := make([]byte, len(sessionKey))
enc.CryptBlocks(output, sessionKey)
if !padding {
return fmt.Sprintf("%X", output[:originalLen]), nil
}
return fmt.Sprintf("%X", output), nil
//cryptoServiceProvider.Mode = CipherMode.CBC;
//cryptoServiceProvider.KeySize = key.Length * 8;
//cryptoServiceProvider.BlockSize = O5LogonHelper.d;
//cryptoServiceProvider.Key = key;
//cryptoServiceProvider.IV = O5LogonHelper.f;
//numArray = cryptoServiceProvider.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length);
}
// encrypt user password
func encryptPassword(password, key []byte, padding bool) (string, error) {
buff1 := make([]byte, 0x10)
_, err := rand.Read(buff1)
if err != nil {
return "", nil
}
buffer := append(buff1, password...)
return encryptSessionKey(padding, key, buffer)
}
// generate encryption key for the password this depends on database verifier type
func (obj *AuthObject) generatePasswordEncKey() ([]byte, error) {
hash := md5.New()
key1 := obj.ServerSessKey
key2 := obj.ClientSessKey
start := 16
logonCompatibility := obj.tcpNego.ServerCompileTimeCaps[4]
if logonCompatibility&32 != 0 {
var keyBuffer string
var retKeyLen int
switch obj.VerifierType {
case 2361:
buffer := append(key2[:len(key2)/2], key1[:len(key1)/2]...)
keyBuffer = fmt.Sprintf("%X", buffer)
retKeyLen = 16
case 6949:
buffer := append(key2[:24], key1[:24]...)
keyBuffer = fmt.Sprintf("%X", buffer)
retKeyLen = 24
case 18453:
buffer := append(key2, key1...)
keyBuffer = fmt.Sprintf("%X", buffer)
retKeyLen = 32
default:
return nil, errors.New("unsupported verifier type")
}
df2key, err := hex.DecodeString(obj.pbkdf2ChkSalt)
if err != nil {
return nil, err
}
return generateSpeedyKey(df2key, []byte(keyBuffer), obj.pbkdf2SderCount)[:retKeyLen], nil
} else {
switch obj.VerifierType {
case 2361:
buffer := make([]byte, 16)
for x := 0; x < 16; x++ {
buffer[x] = key1[x+start] ^ key2[x+start]
}
_, err := hash.Write(buffer)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
case 6949:
buffer := make([]byte, 24)
for x := 0; x < 24; x++ {
buffer[x] = key1[x+start] ^ key2[x+start]
}
_, err := hash.Write(buffer[:16])
if err != nil {
return nil, err
}
ret := hash.Sum(nil)
hash.Reset()
_, err = hash.Write(buffer[16:])
if err != nil {
return nil, err
}
ret = append(ret, hash.Sum(nil)...)
return ret[:24], nil
default:
return nil, errors.New("unsupported verifier type")
}
}
}
//func (obj *AuthObject) VerifyResponse(response string) bool {
// key, err := decryptSessionKey(true, obj.KeyHash, response)
// if err != nil {
// fmt.Println(err)
// return false
// }
// //fmt.Printf("%#v\n", key)
// return bytes.Compare(key[16:], []byte{83, 69, 82, 86, 69, 82, 95, 84, 79, 95, 67, 76, 73, 69, 78, 84}) == 0
// //KZSR_SVR_RESPONSE = new byte[16]{ (byte) 83, (byte) 69, (byte) 82, (byte) 86, (byte) 69, (byte) 82, (byte) 95, (byte) 84, (byte) 79,
// //(byte) 95, (byte) 67, (byte) 76, (byte) 73, (byte) 69, (byte) 78, (byte) 84 };
//
//}
//func (obj *AuthObject) TestResponse(password, pbkdf2ChkSalt string, vGenCount, sDerCount int) error {
// padding := false
// obj.pbkdf2ChkSalt = pbkdf2ChkSalt
// obj.pbkdf2VgenCount = vGenCount
// obj.pbkdf2SderCount = sDerCount
// obj.tcpNego = &TCPNego{
// MessageCode: 0,
// ProtocolServerVersion: 0,
// ProtocolServerString: "",
// OracleVersion: 0,
// ServerCharset: 0,
// ServerFlags: 0,
// CharsetElem: 0,
// ServernCharset: 0,
// ServerCompileTimeCaps: []byte{0, 0, 0, 0, 32},
// ServerRuntimeCaps: nil,
// }
// salt, err := hex.DecodeString(obj.Salt)
// if err != nil {
// return err
// }
// message := append(salt, []byte("AUTH_PBKDF2_SPEEDY_KEY")...)
// speedyKey := generateSpeedyKey(message, []byte(password), obj.pbkdf2VgenCount)
//
// buffer := append(speedyKey, salt...)
// hash := sha512.New()
// hash.Write(buffer)
// key := hash.Sum(nil)[:32]
// obj.ServerSessKey, err = decryptSessionKey(padding, key, obj.EServerSessKey)
// if err != nil {
// return err
// }
// obj.ClientSessKey, err = decryptSessionKey(padding, key, obj.EClientSessKey)
// if err != nil {
// return err
// }
// newKey, err := obj.generatePasswordEncKey()
// if err != nil {
// return err
// }
// fmt.Println(decryptSessionKey(padding, newKey, obj.EPassword))
//
// obj.EPassword, err = encryptPassword([]byte(password), newKey, false)
// if err != nil {
// return err
// }
// obj.ESpeedyKey, err = encryptPassword(speedyKey, newKey, false)
// return err
//}
1
https://gitee.com/wlhet/orago.git
git@gitee.com:wlhet/orago.git
wlhet
orago
orago
v1.0.0

搜索帮助

53164aa7 5694891 3bd8fe86 5694891