RSA Cryptography

Left-side: the output of C# code in LINQPad

RSA Highlights

  • The plaintext‘s length must be less than or equal to the modulus’s size minus 88-bit padding, while OAEP padding typically adds 42 bytes. (1960 bits at most, given a 2048-bit modulus)
  • The ciphertext’s length equals the modulus’s size (p x q). (A 128-bit plaintext generates a 2048-bit ciphertext, given a 2048-bit modulus)
  • Because the size of hash values and symmetric keys is typically less than 512 bits, asymmetric cryptography is suitable for key exchange and digital signatures.
  • However, because of the lack of forward secrecy support, RSA nowadays is deemed inappropriate for key exchange.
  • “Forward secrecy (FS), also known as perfect forward secrecy (PFS), is a feature of specific key-agreement protocols that gives assurances that session keys will not be compromised even if long-term secrets used in the session key exchange are compromised.” (Wikipedia)

PKCS #1

         RSAPublicKey ::= SEQUENCE {
             modulus           INTEGER,  -- n
             publicExponent    INTEGER   -- e
         }

         RSAPrivateKey ::= SEQUENCE {
             version           Version,
             modulus           INTEGER,  -- n
             publicExponent    INTEGER,  -- e
             privateExponent   INTEGER,  -- d
             prime1            INTEGER,  -- p
             prime2            INTEGER,  -- q
             exponent1         INTEGER,  -- d mod (p-1)
             exponent2         INTEGER,  -- d mod (q-1)
             coefficient       INTEGER,  -- (inverse of q) mod p
             otherPrimeInfos   OtherPrimeInfos OPTIONAL
         }

Sample Code

The following is a snippet of C# code in LINQPad that demonstrates RSA Cryptography:

System
System.Security.Cryptography

void Main()
{
	string message = 
	"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"+
	"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"+
	"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"+
	"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF01234";
	(message.Length * 8).Dump("message.Length"); //1960 bits
	
	RSAParameters key = RsaEncryption.GenerateKey(2048);
	key.Dump("Key per PKCS #1");

	var encryptedData = RsaEncryption.Encrypt(message, key);
	(encryptedData.Length * 8).Dump("encryptedData.Length");
	
	var decryptedData = RsaEncryption.Decrypt(encryptedData, key);
	(decryptedData.Length * 8).Dump("decryptedData.Length");
	
	/*
	string encryptedMessage = Convert.ToBase64String(encryptedData);
	string decryptedMessage = Encoding.UTF8.GetString(RsaEncryption.Decrypt(encryptedData, key));
	Console.WriteLine("Encrypted message: " + encryptedMessage);
	Console.WriteLine("Decrypted message: " + decryptedMessage);
	*/

	//Digital Signature
	var hash = Sha256Hash.ComputeHash(message);
	BitConverter.ToString(hash).Dump("hash");
	(hash.Length * 8).Dump("hash.Length");
	
	var signature = DigitalSignature.Sign(hash, key);
	bool verified = DigitalSignature.Verify(hash, signature, key);

	(signature.Length * 8).Dump("signature.Length");
	verified.Dump("verified");
	//Console.WriteLine("Signature: " + signature);
	//Console.WriteLine("Verified: " + verified);
}

// Define other methods and classes here
public class Sha256Hash
{
	public static byte[] ComputeHash(string message)
	{
		byte[] hashValue;
		using (SHA256 sha256 = SHA256.Create())
		{
			hashValue = sha256.ComputeHash(Encoding.UTF8.GetBytes(message));
		}

		return hashValue;
	}
}

public class RsaEncryption
{
	public static byte[] Encrypt(string message, RSAParameters key)
	{
		byte[] encryptedData;
		using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
		{
			rsa.ImportParameters(key);
			encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(message), false);
		}

		return encryptedData;
	}

	public static byte[] Decrypt(byte[] ciphertext, RSAParameters key)
	{
		byte[] decryptedData;
		using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
		{
			rsa.ImportParameters(key);
			decryptedData = rsa.Decrypt(ciphertext, false);
		}

		return decryptedData;
	}

	public static RSAParameters GenerateKey(int keySzie)
	{
		RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySzie);
		return rsa.ExportParameters(true);
	}
}

public class DigitalSignature
{
	public static byte[] Sign(byte[] hash, RSAParameters key)
	{
		byte[] signature;
		using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
		{
			rsa.ImportParameters(key);
			signature = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
		}

		return signature;
	}

	public static bool Verify(byte[] hash, byte[] signature, RSAParameters key)
	{
		using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
		{
			rsa.ImportParameters(key);
			return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), signature);
		}
	}
}

References

Leave a Reply