Announcement

Collapse
No announcement yet.

Using AES with .NET and Java

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using AES with .NET and Java

    I saw some confusion in earlier posts (AESSOCK - Decode on serversite) regarding the use of AESsocks on the Lantronix with clients in .NET or Java. I thought I might share some working code to help people out. Please note that there is a bug in 1.1.0.1 that affects socket closing with Java (recvAES stuck at 0 bytes).

    Your best bet is to plan on a 16byte block size. I manually pad all packets to 16bytes with 0's.

    .NET, this code is in C# but is easily ported to VB
    Set's up the encryption and sends the IV
    Code:
    aes_manager = new RijndaelManaged();
    aes_manager.KeySize = 128;
    
    aes_manager.Key = aes_keys;
    aes_manager.GenerateIV(); //Random IV to increase security
    
    aes_manager.Mode = CipherMode.CFB;
    aes_manager.Padding = PaddingMode.None;
    encryptor = aes_manager.CreateEncryptor();
    
    aes2 = new RijndaelManaged();
    aes2.KeySize = 128;
    aes2.Key = aes_keys;
    aes2.IV = aes_manager.IV;
    decryptor = aes_manager.CreateDecryptor();
    
    byte[] aes_IV = aes_manager.IV;
    tcp_client.GetStream().Write(aes_IV, 0, aes_IV.Length);
    tcp_client.GetStream().BeginRead(recv_bytes, 0, 1024, recv_callback, tcp_client);
    write_crypto_stream = new CryptoStream(tcp_client.GetStream(), encryptor, CryptoStreamMode.Write);
    Example .NET TX
    Code:
    Byte[] send_buffer = new byte[16];
    
    ZeroFill(send_buffer, 16);
    
    send_buffer[0] = 0x2E;
    send_buffer[1] = 0xFF;
    
    write_crypto_stream.Write(send_buffer, 0, send_buffer.Length);
    Example .NET receiving uses a TCPClient with asynchronous reading, waits until 16 bytes have arrived:
    Code:
    private void RecvHandler(IAsyncResult asyncResult)
    {
       int recv_len = tcp_client.GetStream().EndRead(asyncResult);
    
       if (tmp_bytes == null)
       {
          tmp_bytes = new byte[recv_len];
          Array.Copy(recv_bytes, tmp_bytes, recv_len);
       }
       else
       {
          byte[] holder = new byte[recv_len + tmp_bytes.Length];
          Array.Copy(tmp_bytes, holder, tmp_bytes.Length);
          Array.Copy(recv_bytes, 0, holder, tmp_bytes.Length, holder.Length - tmp_bytes.Length);
          tmp_bytes = holder;
       }
    
       while (tmp_bytes.Length >= 16)
       {
          ProcessBytes(tmp_bytes, 16);
          byte[] holder = new byte[tmp_bytes.Length - 16];
          Array.Copy(tmp_bytes, 16, holder, 0, holder.Length);
          tmp_bytes = holder;
       }
    
       tcp_client.GetStream().BeginRead(recv_bytes, 0, 1024, recv_callback, tcp_client);
       }
    
    private void ProcessBytes(byte[] new_data, int length)
    {
       MemoryStream ms = new MemoryStream(new_data, 0, length);
       read_crypto_stream = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
       byte[] dec_data_bytes = new byte[length];
       int decr_data_len = read_crypto_stream.Read(dec_data_bytes, 0, length);
       string s = ConvertToHex(default_encoder.GetString(dec_data_bytes));
       System.Diagnostics.Debug.WriteLine(s);
    }
    The Java code works in a similar fashion except the send and receive encryption is explicitly separate and must be connected using the same keys and IV:
    Code:
    _RemKonEdgeAESCipherEncryptor = Cipher.getInstance("AES/CFB/NoPadding");
    _RemKonEdgeAESCipherDecryptor = Cipher.getInstance("AES/CFB/NoPadding");
    _RemKonEdgeAESKeySpec = new SecretKeySpec(_RemKonEdgeAESKeyBytes, "AES");
    				_RemKonEdgeAESCipherEncryptor.init(Cipher.ENCRYPT_MODE, _RemKonEdgeAESKeySpec);
    IvParameterSpec AESiv = new IvParameterSpec(_RemKonEdgeAESCipherEncryptor.getIV());
    				_RemKonEdgeAESCipherDecryptor.init(Cipher.DECRYPT_MODE, _RemKonEdgeAESKeySpec, AESiv);
    current_sock = new Socket(current_ip_addr, current_ip_port);
    current_sock.setKeepAlive(true);
    System.out.println("Finished setting up AES");
    				
    current_input_stream = current_sock.getInputStream();
    current_output_stream = current_sock.getOutputStream();
    				
    //Send Encryption IV
    byte[] IV = AESiv.getIV();
    current_output_stream.write(IV);
    connection_init_done = true;
    Example TX with Java:
    Code:
    byte tx_array[] = new byte[16];
    byte[] enc_array;
    ZeroFill(tx_array, 16);
    done_polling = false;
    
    tx_array[0] = 77;
    tx_array[1] = 13;
    tx_array[2] = 10;
    enc_array = _RemKonEdgeAESCipherEncryptor.update(tx_array);
    current_output_stream.write(enc_array);
    Example receiving with Java, similar to the .NET you need to accumulate 16 bytes to avoid getting out of sync:
    Code:
    byte array1[] = null;
    byte array2[] = null;
    byte decdata[] = null;
    
    recv_length = current_input_stream.read(_RecvData, 0, BUFFER_SIZE);
    System.out.print(String.format("Received %d bytes\r\n", recv_length));
    						
    if (array1 == null)
    {
    	array1 = new byte[recv_length];
    	System.arraycopy(_RecvData, 0, array1, 0, recv_length);
    }
    else
    {
    	byte holder[] = new byte[recv_length + array1.length];
    	System.arraycopy(array1, 0, holder, 0, array1.length);
    	System.arraycopy(_RecvData, 0, holder, array1.length, holder.length - array1.length);
    	array1 = holder;
    }
    						
    while (array1.length >= 16)
    {
    	decdata = _RemKonEdgeAESCipherDecryptor.update(array1, 0, 16);  //Decoded data
    	ProcessDecodedBuffer(decdata, decdata.length);
    	byte holder[] = new byte[array1.length - 16];
    	System.arraycopy(array1, 16, holder, 0, array1.length - 16);
    	array1 = holder;
    }
Working...
X