securitymdl.go 5.71 KiB
Newer Older
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
package securitymdl

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"math/rand"
	"time"
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/constantmdl"
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
	"golang.org/x/crypto/bcrypt"
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
)

// 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
}