Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update IKE #6

Merged
merged 33 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6c9251b
Update message.go and type.go
Aug 27, 2024
17d529a
Update decrypt and encrypt in security.go
Aug 28, 2024
666e82c
Add UT in security.go
Aug 28, 2024
b902794
Add sha256 and verifyIntegrity UT
Aug 29, 2024
cc8f1b4
Move security algo in internal folder to security folder
Aug 29, 2024
edac991
Modify IKESA and ChildSA transform types
Aug 29, 2024
1249413
Move types to message folder
Aug 29, 2024
e1a9e8a
Remove xfrm related code and modify ikeSA and childSA struct
Aug 29, 2024
e3766ce
Rename IKESA and ChildSA to IKESAKey and ChildSAKey
Aug 29, 2024
d9e0061
Remove logger and Remove priority in Algo struct
Aug 30, 2024
e7401d6
Modify encr init function name to NewCrypto
Sep 2, 2024
842edc9
Modify new ChildSAKey and IKESAKey function
Sep 2, 2024
cf70758
Pass Log as a parameter into the function in message.go
Sep 2, 2024
ec0650f
Move decrypt/encrypt related code to ike.go and add encode/decode fun…
Sep 3, 2024
c37759f
Add ike encode/decode UT
Sep 3, 2024
7f20dca
Fix lint error
Sep 3, 2024
43cd876
Modify NewIKESAKey function
Sep 3, 2024
83e1d68
Modify ESNType interface to ESN struct
Sep 3, 2024
2c893b2
Remove SPI in IKESAKey
Sep 4, 2024
84b606d
Modify ike decode to IkeMsgDecrypt due to application need to get IKE…
Sep 4, 2024
697410c
refactor codes
tim-ywliu Sep 6, 2024
31d6325
fix msg len check in GetSPI()
tim-ywliu Sep 6, 2024
1d57e26
add stringer for ikeSAKey
tim-ywliu Sep 6, 2024
ed3e517
Add parse IKE header function
Sep 11, 2024
720d048
Modify DecodeDecrypt function parameter
Sep 12, 2024
0a65e2a
Add UT in all IKE payload
Sep 12, 2024
f1a1290
Seperate IKE payload in message into an independent file
Sep 13, 2024
5bc2b12
Rename filename from Payload to payload in mesage folder
Sep 13, 2024
f90b68f
Modify IKESAKey String()
Sep 13, 2024
81e633a
Modify golangci and fix Gosec issue
Sep 16, 2024
e3a4e3d
Modify get TransfromID function to public function
Sep 16, 2024
21dc71d
Fix gosec issue
Sep 18, 2024
e4fb229
Fix golint error
Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 4 additions & 32 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,14 @@ module github.com/free5gc/ike
go 1.17

require (
github.com/antonfisher/nested-logrus-formatter v1.3.0
github.com/free5gc/logger_conf v1.0.0
github.com/free5gc/logger_util v1.0.0
github.com/sirupsen/logrus v1.7.0
github.com/vishvananda/netlink v1.1.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.3
)

require (
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/free5gc/path_util v1.0.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
224 changes: 2 additions & 222 deletions go.sum

Large diffs are not rendered by default.

290 changes: 290 additions & 0 deletions ike.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
package ike

import (
"crypto/hmac"

"github.com/pkg/errors"

"github.com/free5gc/ike/message"
"github.com/free5gc/ike/security"
)

func EncodeEncrypt(
ikeMsg *message.IKEMessage,
ikesaKey *security.IKESAKey,
role message.Role,
) ([]byte, error) {
if ikesaKey != nil {
err := encryptMsg(ikeMsg, ikesaKey, role)
if err != nil {
return nil, errors.Wrapf(err, "IKE encode encrypt")
}
}

msg, err := ikeMsg.Encode()
return msg, errors.Wrapf(err, "IKE encode")
}

// Before use this function, need to use IKEMessage.Encode first
// and get IKESA
func DecodeDecrypt(
msg []byte,
ikeHeader *message.IKEHeader,
ikesaKey *security.IKESAKey,
role message.Role,
) (*message.IKEMessage, error) {
ikeMsg := new(message.IKEMessage)
var err error

if ikeHeader == nil {
err = ikeMsg.Decode(msg)
if err != nil {
return nil, errors.Wrapf(err, "DecodeDecrypt()")
}
} else {
ikeMsg.IKEHeader = ikeHeader
err = ikeMsg.DecodePayload(msg[message.IKE_HEADER_LEN:])
if err != nil {
return nil, errors.Wrapf(err, "DecodeDecrypt()")
}
}

if ikeMsg.Payloads[0].Type() == message.TypeSK {
if ikesaKey == nil {
return nil, errors.Errorf("IKE decode decrypt: need ikesaKey to decrypt")
}
ikeMsg, err = decryptMsg(msg, ikeMsg, ikesaKey, role)
if err != nil {
return nil, errors.Wrapf(err, "IKE decode decrypt")
}
}

return ikeMsg, nil
}

func verifyIntegrity(
originData []byte,
checksum []byte,
ikesaKey *security.IKESAKey,
role message.Role,
) error {
expectChecksum, err := calculateIntegrity(ikesaKey, role, originData)
if err != nil {
return errors.Wrapf(err, "verifyIntegrity[%d]", ikesaKey.IntegInfo.TransformID())
}

// fmt.Printf("Calculated checksum:\n%s\nReceived checksum:\n%s",
// hex.Dump(expectChecksum), hex.Dump(checksum))
if !hmac.Equal(checksum, expectChecksum) {
return errors.Errorf("invalid checksum")
}
return nil
}

func calculateIntegrity(
ikesaKey *security.IKESAKey,
role message.Role,
originData []byte,
) ([]byte, error) {
outputLen := ikesaKey.IntegInfo.GetOutputLength()

var calculatedChecksum []byte
if role == message.Role_Initiator {
if ikesaKey.Integ_i == nil {
return nil, errors.Errorf("CalcIKEChecksum() : IKE SA have nil Integ_r")
}
ikesaKey.Integ_i.Reset()
if _, err := ikesaKey.Integ_i.Write(originData); err != nil {
return nil, errors.Wrapf(err, "CalcIKEChecksum()")
}
calculatedChecksum = ikesaKey.Integ_i.Sum(nil)
} else {
if ikesaKey.Integ_r == nil {
return nil, errors.Errorf("CalcIKEChecksum() : IKE SA have nil Integ_i")
}
ikesaKey.Integ_r.Reset()
if _, err := ikesaKey.Integ_r.Write(originData); err != nil {
return nil, errors.Wrapf(err, "CalcIKEChecksum()")
}
calculatedChecksum = ikesaKey.Integ_r.Sum(nil)
}

return calculatedChecksum[:outputLen], nil
}

func encryptPayload(
plainText []byte,
ikesaKey *security.IKESAKey,
role message.Role,
) ([]byte, error) {
var cipherText []byte
if role == message.Role_Initiator {
var err error
if cipherText, err = ikesaKey.Encr_i.Encrypt(plainText); err != nil {
return nil, errors.Wrapf(err, "encryptPayload()")
}
} else {
var err error
if cipherText, err = ikesaKey.Encr_r.Encrypt(plainText); err != nil {
return nil, errors.Wrapf(err, "encryptPayload()")
}
}

return cipherText, nil
}

func decryptPayload(
cipherText []byte,
ikesaKey *security.IKESAKey,
role message.Role,
) ([]byte, error) {
var plainText []byte
if role == message.Role_Initiator {
var err error
if plainText, err = ikesaKey.Encr_r.Decrypt(cipherText); err != nil {
return nil, errors.Wrapf(err, "decryptPayload()")
}
} else {
var err error
if plainText, err = ikesaKey.Encr_i.Decrypt(cipherText); err != nil {
return nil, errors.Wrapf(err, "decryptPayload()")
}
}

return plainText, nil
}

func decryptMsg(
msg []byte,
ikeMsg *message.IKEMessage,
ikesaKey *security.IKESAKey,
role message.Role,
) (*message.IKEMessage, error) {
// Check parameters
if ikesaKey == nil {
return nil, errors.Errorf("decryptMsg(): IKE SA is nil")
}
if msg == nil {
return nil, errors.Errorf("decryptMsg(): msg is nil")
}
if ikeMsg == nil {
return nil, errors.Errorf("decryptMsg(): IKE encrypted payload is nil")
}

// Check if the context contain needed data
if ikesaKey.IntegInfo == nil {
return nil, errors.Errorf("decryptMsg(): No integrity algorithm specified")
}
if ikesaKey.EncrInfo == nil {
return nil, errors.Errorf("decryptMsg(): No encryption algorithm specified")
}

if ikesaKey.Integ_i == nil {
return nil, errors.Errorf("decryptMsg(): No initiator's integrity key")
}
if ikesaKey.Encr_i == nil {
return nil, errors.Errorf("decryptMsg(): No initiator's encryption key")
}

var encryptedPayload *message.Encrypted
for _, ikePayload := range ikeMsg.Payloads {
switch ikePayload.Type() {
case message.TypeSK:
encryptedPayload = ikePayload.(*message.Encrypted)
default:
return nil, errors.Errorf(
"Get IKE payload (type %d), this payload will not be decode",
ikePayload.Type())
}
}

checksumLength := ikesaKey.IntegInfo.GetOutputLength()
// Checksum
checksum := encryptedPayload.EncryptedData[len(encryptedPayload.EncryptedData)-checksumLength:]

err := verifyIntegrity(msg[:len(msg)-checksumLength], checksum, ikesaKey, !role)
if err != nil {
return nil, errors.Wrapf(err, "decryptMsg(): verify integrity")
}

// Decrypt
encryptedData := encryptedPayload.EncryptedData[:len(encryptedPayload.EncryptedData)-checksumLength]
plainText, err := decryptPayload(encryptedData, ikesaKey, role)
if err != nil {
return nil, errors.Wrapf(err, "decryptMsg(): Error decrypting message")
}

var decryptedPayloads message.IKEPayloadContainer
err = decryptedPayloads.Decode(encryptedPayload.NextPayload, plainText)
if err != nil {
return nil, errors.Wrapf(err, "decryptMsg(): Decoding decrypted payload failed")
}

ikeMsg.Payloads.Reset()
ikeMsg.Payloads = append(ikeMsg.Payloads, decryptedPayloads...)
return ikeMsg, nil
}

func encryptMsg(
ikeMsg *message.IKEMessage,
ikesaKey *security.IKESAKey,
role message.Role,
) error {
if ikeMsg == nil {
return errors.Errorf("encryptMsg(): Response IKE message is nil")
}
if ikesaKey == nil {
return errors.Errorf("encryptMsg(): IKE SA is nil")
}
ikePayloads := ikeMsg.Payloads
// Check parameters
if len(ikePayloads) == 0 {
return errors.Errorf("encryptMsg(): No IKE payload to be encrypted")
}
// Check if the context contain needed data
if ikesaKey.IntegInfo == nil {
return errors.Errorf("encryptMsg(): No integrity algorithm specified")
}
if ikesaKey.EncrInfo == nil {
return errors.Errorf("encryptMsg(): No encryption algorithm specified")
}

if ikesaKey.Integ_r == nil {
return errors.Errorf("encryptMsg(): No responder's integrity key")
}
if ikesaKey.Encr_r == nil {
return errors.Errorf("encryptMsg(): No responder's encryption key")
}

checksumLength := ikesaKey.IntegInfo.GetOutputLength()

plainTextPayload, err := ikePayloads.Encode()
if err != nil {
return errors.Wrapf(err, "encryptMsg(): Encoding IKE payload failed.")
}

// Encrypting
encryptedData, err := encryptPayload(plainTextPayload, ikesaKey, role)
if err != nil {
return errors.Wrapf(err, "encryptMsg(): Error encrypting message")
}

encryptedData = append(encryptedData, make([]byte, checksumLength)...)
ikeMsg.Payloads.Reset()
sk := ikeMsg.Payloads.BuildEncrypted(ikePayloads[0].Type(), encryptedData)

// Calculate checksum
ikeMsgData, err := ikeMsg.Encode()
if err != nil {
return errors.Wrapf(err, "encryptMsg(): Encoding IKE message error")
}
checksumOfMessage, err := calculateIntegrity(ikesaKey, role,
ikeMsgData[:len(ikeMsgData)-checksumLength])
if err != nil {
return errors.Wrapf(err, "encryptMsg(): Error calculating checksum")
}
checksumField := sk.EncryptedData[len(sk.EncryptedData)-checksumLength:]
copy(checksumField, checksumOfMessage)

return nil
}
Loading
Loading