navneet83/Cross-platform-AES-encryption

Refactor - c#, android and web

Closed this issue · 0 comments

.NET changes (c#):

public class EncryptionService2
{
	private const int
		KeySize = 256,
		BlockSize = 128,
		KeyLength = 32,
		IvLength = 16;

	private static Encoding Encoding => Encoding.UTF8;

	public string Encrypt(string inputText, string encryptionKey, string initVector)
	{
		using var rijndaelAlgorithm = GetRijndaelAlgorithm(encryptionKey, initVector);
		using var encryptor = rijndaelAlgorithm.CreateEncryptor();

		var inputBytes = Encoding.GetBytes(inputText);

		return encryptor
			.TransformFinalBlock(inputBytes, 0, inputBytes.Length)
			.Run(Convert.ToBase64String);
	}

	public string Decrypt(string inputText, string encryptionKey, string initVector)
	{
		using var rijndaelAlgorithm = GetRijndaelAlgorithm(encryptionKey, initVector);
		using var decryptor = rijndaelAlgorithm.CreateDecryptor();

		var inputBytes = Convert.FromBase64String(inputText);

		return decryptor
			.TransformFinalBlock(inputBytes, 0, inputBytes.Length)
			.Run(Encoding.GetString);
	}

	private static RijndaelManaged GetRijndaelAlgorithm(string encryptionKey, string initVector)
	{
		var encryptionKeyBytes = Encoding.GetBytes(encryptionKey);
		var initVectorBytes = Encoding.GetBytes(initVector);

		var encryptionKeyArray = new byte[KeyLength];
		var initialVectorArray = new byte[IvLength];

		CopyBytes(encryptionKeyBytes, encryptionKeyArray);
		CopyBytes(initVectorBytes, initialVectorArray);

		return new RijndaelManaged
		{
			Mode = CipherMode.CBC,
			Padding = PaddingMode.PKCS7,
			KeySize = KeySize,
			BlockSize = BlockSize,
			Key = encryptionKeyArray,
			IV = initialVectorArray
		};
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static void CopyBytes(byte[] source, byte[] destination) =>
		Array.Copy(source, destination, Math.Min(source.Length, destination.Length));
}

Android changes (Kotlin):

class EncryptionService {
	fun encrypt(inputText: String, encryptionKey: String, initVector: String): String =
		getCipher(Cipher.ENCRYPT_MODE, encryptionKey, initVector)
			.doFinal(inputText.toByteArray(charset))
			.run { Base64.encodeToString(this, Base64.DEFAULT) }

	fun decrypt(inputText: String, encryptionKey: String, initVector: String): String {
		val decodedValue = inputText.toByteArray()
			.run { Base64.decode(this, Base64.DEFAULT) }

		return getCipher(Cipher.DECRYPT_MODE, encryptionKey, initVector)
			.doFinal(decodedValue)
			.run<ByteArray, String>(::String)
	}

	companion object {
		private const val keyLength = 32
		private const val ivLength = 16
		private val charset = Charsets.UTF_8

		private fun getCipher(mode: Int, encryptionKey: String, initVector: String): Cipher {
			val encryptionKeyBytes = encryptionKey.toByteArray(charset)
			val initVectorBytes = initVector.toByteArray(charset)

			val secretKeySpec = ByteArray(keyLength)
				.also { copyBytes(encryptionKeyBytes, it) }
				.run { SecretKeySpec(this, "AES") }

			val ivParameterSpec = ByteArray(ivLength)
				.also { copyBytes(initVectorBytes, it) }
				.run(::IvParameterSpec)

			return Cipher.getInstance("AES/CBC/PKCS5Padding")
				.apply { init(mode, secretKeySpec, ivParameterSpec) }
		}

		private fun copyBytes(source: ByteArray, destination: ByteArray) {
			System.arraycopy(source, 0, destination, 0, minOf(source.size, destination.size))
		}
	}
}

Web changes (TypeScript)

export default class EncryptionService {
	private static readonly KeySize = 32
	private static readonly IvSize = 16
	private readonly mAlgorithm = 'AES-256-CBC'

	encrypt(plainText: string, encryptionKey: string, initVector: string) {
		const [encryptionKeyArray, initVectorArray] = EncryptionService.getByteArrays(encryptionKey, initVector)

		const encryptor = Crypto.createCipheriv(this.mAlgorithm, encryptionKeyArray, initVectorArray)
		encryptor.setEncoding('base64')
		encryptor.write(plainText)
		encryptor.end()

		return encryptor.read()
	}

	decrypt(encryptedText: string, encryptionKey: string, initVector: string) {
		const [encryptionKeyArray, initVectorArray] = EncryptionService.getByteArrays(encryptionKey, initVector)

		const decryptor = Crypto.createDecipheriv(this.mAlgorithm, encryptionKeyArray, initVectorArray)
		
		return decryptor
			.update(encryptedText, 'base64', 'utf8')
			.concat(decryptor.final('utf8'))
	}

	private static getByteArrays(encryptionKey: string, initVector: string) {
		const encryptionKeyArray = new Uint8Array(EncryptionService.KeySize),
			initVectorArray = new Uint8Array(EncryptionService.IvSize)

		const textEncoder = new TextEncoder()
		textEncoder.encodeInto(encryptionKey, encryptionKeyArray)
		textEncoder.encodeInto(initVector, initVectorArray)

		return [encryptionKeyArray, initVectorArray] as const
	}
}