none
Помощь в портировании класса RSA для RDP с Java на C#. RRS feed

  • Вопрос

  • Прошу помочь в портировании имплиментации RSA шифрования для протокола RDP с Java на C#.

    Класс: msdn

    Проблема в разности классов BigIntiger.

    Вот что выводит в итоге Java (и никак не получается получить подобные значения на C#):

    Client random:
    
    0xff 0xee 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xff 
    
    Encrypted client random:
    
    0xc0 0x12 0x96 0x66 0xbe 0x28 0x60 0x7b 
    0xb0 0xb4 0x03 0xfe 0xda 0x38 0x6a 0xb9 
    0x39 0x9d 0x10 0xa2 0x76 0xb8 0x8b 0x4c 
    0xe4 0x25 0x9a 0x22 0x9e 0xe0 0x01 0x34 
    0xd4 0xc1 0x37 0x38 0xb7 0xef 0x50 0x09 
    0x55 0xc5 0xb3 0x35 0x17 0x9e 0xbd 0x9e 
    0x45 0x93 0x3c 0xd8 0x5d 0xe6 0x7c 0xa9 
    0xc3 0x70 0x2e 0x18 0xf2 0x23 0x71 0x09 
    
    Decrypted client random:
    
    0xff 0xee 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
    0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xff 
    0x00 

    p.s. и кстати очень странно, почему в официальной документации от Microsoft пример на Java, а не на C++\C#\VB.NET



    7 апреля 2015 г. 22:10

Ответы

  • Вот, как то так:

    using System;
    using System.Numerics;
    
    namespace RdpRsaEncrypt
    {
    	class Program
    	{
    		//
    		// Print out the contents of a byte array in hexadecimal.
    		//
    		private static void PrintBytes(byte[] bytes)
    		{
    			int cBytes = bytes.Length;
    			int iByte = 0;
    
    			for (; ; )
    			{
    				for (int i = 0; i < 8; i++)
    				{
    					String hex = bytes[iByte++].ToString("X2");
    
    					Console.Write("0x" + hex + " ");
    					if (iByte >= cBytes)
    					{
    						Console.WriteLine();
    						return;
    					}
    				}
    				Console.WriteLine();
    			}
    		}
    
    		//
    		// Use RSA to encrypt data.
    		//
    		public static byte[] RsaEncrypt(
    			byte[] modulusBytes,
    			byte[] exponentBytes,
    			byte[] dataBytes
    			)
    		{
    			BigInteger modulus = new BigInteger(modulusBytes);
    			BigInteger exponent = new BigInteger(exponentBytes);
    			BigInteger data = new BigInteger(dataBytes);
    
    			//
    			// Perform RSA encryption: 
    			// ciphertext = plaintext^exponent % modulus.
    			//
    			BigInteger cipherText = BigInteger.ModPow(data, exponent, modulus);
    			return cipherText.ToByteArray();
    		}
    
    		//
    		// Use RSA to decrypt data.
    		//
    		public static byte[] RsaDecrypt(
    			byte[] modulusBytes,
    			byte[] privateExponentBytes,
    			byte[] encryptedDataBytes
    			)
    		{
    			BigInteger modulus = new BigInteger(modulusBytes);
    			BigInteger privateExponent = new BigInteger(privateExponentBytes);
    			BigInteger encryptedData = new BigInteger(encryptedDataBytes);
    
    			//
    			// Perform RSA encryption: 
    			// plaintext = ciphertext^privateExponent % modulus.
    			//
    			BigInteger decryptedData = BigInteger.ModPow(encryptedData, privateExponent, modulus);
    			return decryptedData.ToByteArray();
    		}
    
    
    		static void Main(string[] args)
    		{
    			//
    			// Modulus bytes obtained straight from the wire in the 
    			// proprietary certificate (in little endian format). 
    			// This is for a 512-bit key set.
    			//
    			byte[] modulusBytes = 
    			{        
    				(byte) 0x37, (byte) 0xa8, (byte) 0x70, (byte) 0xfe, 
    				(byte) 0x9a, (byte) 0xb9, (byte) 0xa8, (byte) 0x54,
    				(byte) 0xcb, (byte) 0x98, (byte) 0x79, (byte) 0x44, 
    				(byte) 0x7a, (byte) 0xb9, (byte) 0xeb, (byte) 0x38,
    				(byte) 0x06, (byte) 0xea, (byte) 0x26, (byte) 0xa1, 
    				(byte) 0x47, (byte) 0xea, (byte) 0x19, (byte) 0x70,
    				(byte) 0x5d, (byte) 0xf3, (byte) 0x52, (byte) 0x88, 
    				(byte) 0x70, (byte) 0x21, (byte) 0xb5, (byte) 0x9e,
    				(byte) 0x50, (byte) 0xb4, (byte) 0xe1, (byte) 0xf5, 
    				(byte) 0x1a, (byte) 0xd8, (byte) 0x2d, (byte) 0x51,
    				(byte) 0x4d, (byte) 0x1a, (byte) 0xad, (byte) 0x79, 
    				(byte) 0x7c, (byte) 0x89, (byte) 0x46, (byte) 0xb0,
    				(byte) 0xcc, (byte) 0x66, (byte) 0x74, (byte) 0x02, 
    				(byte) 0xd8, (byte) 0x28, (byte) 0x5d, (byte) 0x9d,
    				(byte) 0xd7, (byte) 0xca, (byte) 0xfc, (byte) 0x60, 
    				(byte) 0x0f, (byte) 0x38, (byte) 0xf9, (byte) 0xb3, 0
    			};
    
    			//
    			// Exponent bytes (in little endian order) obtained straight 
    			// from the wire (in the proprietary certificate).
    			//
    			byte[] exponentBytes = 
    			{        
    				(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00
    			};
    
    			//
    			// Private exponent of the private key generated by the 
    			// server (in little endian format).
    			//
    			byte[] privateExponentBytes = 
    			{
    				(byte) 0xc1, (byte) 0x07, (byte) 0xe7, (byte) 0xd4, 
    				(byte) 0xd3, (byte) 0x38, (byte) 0x8d, (byte) 0x36,
    				(byte) 0xf5, (byte) 0x9e, (byte) 0x8b, (byte) 0x96, 
    				(byte) 0x0d, (byte) 0x55, (byte) 0x65, (byte) 0x08,
    				(byte) 0x28, (byte) 0x25, (byte) 0xa3, (byte) 0x2e, 
    				(byte) 0xc7, (byte) 0x68, (byte) 0xd6, (byte) 0x44,
    				(byte) 0x85, (byte) 0x2d, (byte) 0x32, (byte) 0xf6, 
    				(byte) 0x72, (byte) 0xa8, (byte) 0x9b, (byte) 0xba,
    				(byte) 0x5e, (byte) 0x82, (byte) 0x82, (byte) 0xf0, 
    				(byte) 0x5c, (byte) 0x0c, (byte) 0xeb, (byte) 0x6b,
    				(byte) 0x12, (byte) 0x6a, (byte) 0xa7, (byte) 0x45, 
    				(byte) 0x15, (byte) 0xce, (byte) 0x41, (byte) 0xe0,
    				(byte) 0x03, (byte) 0xe5, (byte) 0xe6, (byte) 0x6d, 
    				(byte) 0xdf, (byte) 0xfd, (byte) 0x58, (byte) 0x61,
    				(byte) 0x0b, (byte) 0x07, (byte) 0xa4, (byte) 0x7b, 
    				(byte) 0xb3, (byte) 0xf3, (byte) 0x71, (byte) 0x94, 0
    			};
    
    			//
    			// Sample 32-byte client random.
    			//
    			byte[] clientRandomBytes = 
    			{
    				(byte) 0xff, (byte) 0xee, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, 0
    			};
    
    			Console.WriteLine("Client random:");
    			PrintBytes(clientRandomBytes);
    
    			//
    			// Perform encryption.
    			//
    			byte[] encryptedClientRandomBytes = RsaEncrypt(
    				modulusBytes,
    				exponentBytes,
    				clientRandomBytes
    				);
    
    			Console.WriteLine("Encrypted client random:");
    			PrintBytes(encryptedClientRandomBytes);
    
    			//
    			// Perform decryption.
    			//
    			byte[] decryptedClientRandomBytes = RsaDecrypt(
    				modulusBytes,
    				privateExponentBytes,
    				encryptedClientRandomBytes
    				);
    
    			Console.WriteLine("Decrypted client random:");
    			PrintBytes(decryptedClientRandomBytes);
    		}
    	}
    }
    

    Два важных замечания.

    1. В отличие от Java, конструктор BigInteger .NET не принимает параметр, определяющий знак числа. Поэтому, если требуется положительное, последний байт в массиве должен содержать 0 в старшем бите (я добавил дополнительный байт = 0).

    2. Значение BigInteger .NET располагается в памяти младшим байтом вперед (little endian). Поэтому его не требуется переворачивать перед шифрованием/дешифрованием.


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    8 апреля 2015 г. 11:58

Все ответы

  • Простите, если не по теме. А штатные средства шифрования библиотеки .NET Вам не подходят?

    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    8 апреля 2015 г. 10:33
  • Простите, если не по теме. А штатные средства шифрования библиотеки .NET Вам не подходят?

    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!


    Пробовал штатными средствами, не получилось из за моей ошибки (там в комментариях): link

    8 апреля 2015 г. 10:45
  • Вот, как то так:

    using System;
    using System.Numerics;
    
    namespace RdpRsaEncrypt
    {
    	class Program
    	{
    		//
    		// Print out the contents of a byte array in hexadecimal.
    		//
    		private static void PrintBytes(byte[] bytes)
    		{
    			int cBytes = bytes.Length;
    			int iByte = 0;
    
    			for (; ; )
    			{
    				for (int i = 0; i < 8; i++)
    				{
    					String hex = bytes[iByte++].ToString("X2");
    
    					Console.Write("0x" + hex + " ");
    					if (iByte >= cBytes)
    					{
    						Console.WriteLine();
    						return;
    					}
    				}
    				Console.WriteLine();
    			}
    		}
    
    		//
    		// Use RSA to encrypt data.
    		//
    		public static byte[] RsaEncrypt(
    			byte[] modulusBytes,
    			byte[] exponentBytes,
    			byte[] dataBytes
    			)
    		{
    			BigInteger modulus = new BigInteger(modulusBytes);
    			BigInteger exponent = new BigInteger(exponentBytes);
    			BigInteger data = new BigInteger(dataBytes);
    
    			//
    			// Perform RSA encryption: 
    			// ciphertext = plaintext^exponent % modulus.
    			//
    			BigInteger cipherText = BigInteger.ModPow(data, exponent, modulus);
    			return cipherText.ToByteArray();
    		}
    
    		//
    		// Use RSA to decrypt data.
    		//
    		public static byte[] RsaDecrypt(
    			byte[] modulusBytes,
    			byte[] privateExponentBytes,
    			byte[] encryptedDataBytes
    			)
    		{
    			BigInteger modulus = new BigInteger(modulusBytes);
    			BigInteger privateExponent = new BigInteger(privateExponentBytes);
    			BigInteger encryptedData = new BigInteger(encryptedDataBytes);
    
    			//
    			// Perform RSA encryption: 
    			// plaintext = ciphertext^privateExponent % modulus.
    			//
    			BigInteger decryptedData = BigInteger.ModPow(encryptedData, privateExponent, modulus);
    			return decryptedData.ToByteArray();
    		}
    
    
    		static void Main(string[] args)
    		{
    			//
    			// Modulus bytes obtained straight from the wire in the 
    			// proprietary certificate (in little endian format). 
    			// This is for a 512-bit key set.
    			//
    			byte[] modulusBytes = 
    			{        
    				(byte) 0x37, (byte) 0xa8, (byte) 0x70, (byte) 0xfe, 
    				(byte) 0x9a, (byte) 0xb9, (byte) 0xa8, (byte) 0x54,
    				(byte) 0xcb, (byte) 0x98, (byte) 0x79, (byte) 0x44, 
    				(byte) 0x7a, (byte) 0xb9, (byte) 0xeb, (byte) 0x38,
    				(byte) 0x06, (byte) 0xea, (byte) 0x26, (byte) 0xa1, 
    				(byte) 0x47, (byte) 0xea, (byte) 0x19, (byte) 0x70,
    				(byte) 0x5d, (byte) 0xf3, (byte) 0x52, (byte) 0x88, 
    				(byte) 0x70, (byte) 0x21, (byte) 0xb5, (byte) 0x9e,
    				(byte) 0x50, (byte) 0xb4, (byte) 0xe1, (byte) 0xf5, 
    				(byte) 0x1a, (byte) 0xd8, (byte) 0x2d, (byte) 0x51,
    				(byte) 0x4d, (byte) 0x1a, (byte) 0xad, (byte) 0x79, 
    				(byte) 0x7c, (byte) 0x89, (byte) 0x46, (byte) 0xb0,
    				(byte) 0xcc, (byte) 0x66, (byte) 0x74, (byte) 0x02, 
    				(byte) 0xd8, (byte) 0x28, (byte) 0x5d, (byte) 0x9d,
    				(byte) 0xd7, (byte) 0xca, (byte) 0xfc, (byte) 0x60, 
    				(byte) 0x0f, (byte) 0x38, (byte) 0xf9, (byte) 0xb3, 0
    			};
    
    			//
    			// Exponent bytes (in little endian order) obtained straight 
    			// from the wire (in the proprietary certificate).
    			//
    			byte[] exponentBytes = 
    			{        
    				(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00
    			};
    
    			//
    			// Private exponent of the private key generated by the 
    			// server (in little endian format).
    			//
    			byte[] privateExponentBytes = 
    			{
    				(byte) 0xc1, (byte) 0x07, (byte) 0xe7, (byte) 0xd4, 
    				(byte) 0xd3, (byte) 0x38, (byte) 0x8d, (byte) 0x36,
    				(byte) 0xf5, (byte) 0x9e, (byte) 0x8b, (byte) 0x96, 
    				(byte) 0x0d, (byte) 0x55, (byte) 0x65, (byte) 0x08,
    				(byte) 0x28, (byte) 0x25, (byte) 0xa3, (byte) 0x2e, 
    				(byte) 0xc7, (byte) 0x68, (byte) 0xd6, (byte) 0x44,
    				(byte) 0x85, (byte) 0x2d, (byte) 0x32, (byte) 0xf6, 
    				(byte) 0x72, (byte) 0xa8, (byte) 0x9b, (byte) 0xba,
    				(byte) 0x5e, (byte) 0x82, (byte) 0x82, (byte) 0xf0, 
    				(byte) 0x5c, (byte) 0x0c, (byte) 0xeb, (byte) 0x6b,
    				(byte) 0x12, (byte) 0x6a, (byte) 0xa7, (byte) 0x45, 
    				(byte) 0x15, (byte) 0xce, (byte) 0x41, (byte) 0xe0,
    				(byte) 0x03, (byte) 0xe5, (byte) 0xe6, (byte) 0x6d, 
    				(byte) 0xdf, (byte) 0xfd, (byte) 0x58, (byte) 0x61,
    				(byte) 0x0b, (byte) 0x07, (byte) 0xa4, (byte) 0x7b, 
    				(byte) 0xb3, (byte) 0xf3, (byte) 0x71, (byte) 0x94, 0
    			};
    
    			//
    			// Sample 32-byte client random.
    			//
    			byte[] clientRandomBytes = 
    			{
    				(byte) 0xff, (byte) 0xee, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
    				(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, 0
    			};
    
    			Console.WriteLine("Client random:");
    			PrintBytes(clientRandomBytes);
    
    			//
    			// Perform encryption.
    			//
    			byte[] encryptedClientRandomBytes = RsaEncrypt(
    				modulusBytes,
    				exponentBytes,
    				clientRandomBytes
    				);
    
    			Console.WriteLine("Encrypted client random:");
    			PrintBytes(encryptedClientRandomBytes);
    
    			//
    			// Perform decryption.
    			//
    			byte[] decryptedClientRandomBytes = RsaDecrypt(
    				modulusBytes,
    				privateExponentBytes,
    				encryptedClientRandomBytes
    				);
    
    			Console.WriteLine("Decrypted client random:");
    			PrintBytes(decryptedClientRandomBytes);
    		}
    	}
    }
    

    Два важных замечания.

    1. В отличие от Java, конструктор BigInteger .NET не принимает параметр, определяющий знак числа. Поэтому, если требуется положительное, последний байт в массиве должен содержать 0 в старшем бите (я добавил дополнительный байт = 0).

    2. Значение BigInteger .NET располагается в памяти младшим байтом вперед (little endian). Поэтому его не требуется переворачивать перед шифрованием/дешифрованием.


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    8 апреля 2015 г. 11:58