package securitymdl import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "math/rand" "time" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/constantmdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl" "golang.org/x/crypto/bcrypt" ) // SetSecurityConfig will set security key and initializationVector func SetSecurityConfig(secKey []byte, initializationVector string) { loggermdl.LogDebug("SetSecurityConfig Started") SetIV(initializationVector) SetSecurityKey(secKey) loggermdl.LogDebug("SetSecurityConfig Ended") } // SetIV will set initializationVector func SetIV(initializationVector string) { loggermdl.LogDebug("SetIV Started") if initializationVector != "" { IV = initializationVector } loggermdl.LogDebug("SetIV Ended") } // SetSecurityKey will set Security key func SetSecurityKey(secKey []byte) { loggermdl.LogDebug("SetSecurityKey Started") if secKey != nil && len(secKey) != 1 { securityKey = secKey } loggermdl.LogDebug("SetSecurityKey Ended") } //AESEncrypt Encrypts given text func AESEncrypt(plainText, key []byte) ([]byte, error) { loggermdl.LogDebug("AESEncrypt Started") block, newCipherErr := aes.NewCipher(key) if errormdl.CheckErr(newCipherErr) != nil { loggermdl.LogError("error occured while calling aes.NewCipher() : ", errormdl.CheckErr(newCipherErr)) return nil, errormdl.CheckErr(newCipherErr) } padding := block.BlockSize() - len(plainText)%block.BlockSize() padtext := bytes.Repeat([]byte{byte(padding)}, padding) plainText = append(plainText, padtext...) cipherText := make([]byte, len(plainText)) ivBytes := []byte(IV) if ivBytes == nil || len(ivBytes) < 1 || len(ivBytes) != block.BlockSize() { loggermdl.LogError("IV length must equal block size") return nil, errormdl.Wrap("IV length must equal block size") } cbc := cipher.NewCBCEncrypter(block, ivBytes) cbc.CryptBlocks(cipherText, plainText) encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(plainText))) base64.StdEncoding.Encode(encodedData, cipherText) loggermdl.LogDebug("AESEncrypt Started") return encodedData, nil } //AESDecrypt Decrypts given cipher text func AESDecrypt(encodedData, key []byte) ([]byte, error) { loggermdl.LogDebug("AESDecrypt Started") decodedData := make([]byte, base64.StdEncoding.DecodedLen(len(encodedData))) n, decoreErr := base64.StdEncoding.Decode(decodedData, encodedData) if errormdl.CheckErr(decoreErr) != nil { loggermdl.LogError("error occured while calling base64.StdEncoding.Decode() : ", errormdl.CheckErr(decoreErr)) return nil, errormdl.CheckErr(decoreErr) } cipherText := decodedData[:n] block, newCipherErr := aes.NewCipher(key) if errormdl.CheckErr1(newCipherErr) != nil { loggermdl.LogError("error occured while calling aes.NewCipher : ", errormdl.CheckErr1(newCipherErr)) return nil, errormdl.CheckErr1(newCipherErr) } ivBytes := []byte(IV) if ivBytes == nil || len(ivBytes) < 1 || len(ivBytes) != block.BlockSize() { loggermdl.LogError("IV length must equal block size ") return nil, errormdl.Wrap("IV length must equal block size ") } cbc := cipher.NewCBCDecrypter(block, []byte(IV)) calculatedCipherSize := len(cipherText) % cbc.BlockSize() if errormdl.CheckInt1(calculatedCipherSize) != 0 { loggermdl.LogError("crypto/cipher: input not full blocks") return nil, errormdl.Wrap("crypto/cipher: input not full blocks") } cbc.CryptBlocks(cipherText, cipherText) length := len(cipherText) if errormdl.CheckInt(length) < 1 { loggermdl.LogError("length of cipherText is less than 1") return nil, errormdl.Wrap("length of cipherText is less than 1") } unpadding := int(cipherText[length-1]) difference := length - unpadding if errormdl.CheckInt2(difference) < 0 { return nil, errormdl.Wrap("length of (length - unpadding) is less than 0") } loggermdl.LogDebug("AESDecrypt Ended") return cipherText[:(length - unpadding)], nil } // //AESEncryptDefault method to encrypt with default config (securityKey) // func AESEncryptDefault(plainText []byte) ([]byte, error) { // loggermdl.LogDebug("AESEncryptDefault Started") // compressedText, compressionError := Compress(plainText) // if compressionError != nil { // return plainText, compressionError // } // loggermdl.LogDebug("AESEncryptDefault Started") // return AESEncrypt(compressedText, securityKey) // } // // AESDecryptDefault method to decrypt with default config (securityKey) // func AESDecryptDefault(encodedData []byte) ([]byte, error) { // loggermdl.LogDebug("AESDecryptDefault Started") // compressedText, decryptionError := AESDecrypt(encodedData, securityKey) // if decryptionError != nil { // return encodedData, decryptionError // } // byteArray, err := Decompress(compressedText) // if err != nil { // } // loggermdl.LogDebug("AESDecryptDefault Started") // return byteArray, nil // } // CreateSecurityKey generates random string of given length func CreateSecurityKey(keyLength int) (string, error) { if keyLength <= constantmdl.MAX_RANDOM_STRING_LENGTH { seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) b := make([]byte, keyLength) for i := range b { b[i] = constantmdl.CharSet[seededRand.Intn(keyLength)] } return string(b), nil } return "", errormdl.Wrap("length should be less than 256 bytes (2048 bits)") } // SaltPassword Salt using bcrypt creates saltedString of given string func SaltPassword(password string) (string, error) { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost) if errormdl.CheckErr(err) != nil { loggermdl.LogError("error occured while calling bcrypt.GenerateFromPassword() : ", errormdl.CheckErr(err)) return "", errormdl.CheckErr(err) } return string(hash), nil }