2010-01-19 72 views
19

Tôi đã tìm thấy nhiều ví dụ về cách mã hóa trong C# và một cặp cho Android, nhưng tôi đặc biệt đang tìm cách xử lý mã hóa (sử dụng một cái gì đó như AES, TripleDES, v.v. .) từ Android và cuối cùng sẽ được giải mã trong C#. Tôi tìm thấy một số example for encoding AES trong Android và encoding/decoding AES trong C# nhưng không chắc chắn nếu chúng tương thích (C# yêu cầu IV, không có gì được chỉ định cho điều này trong ví dụ Android). Ngoài ra, một khuyến nghị về một cách tốt để mã hóa chuỗi được mã hóa để truyền qua HTTP (Base64?) Sẽ hữu ích. Cảm ơn.Mã hóa tương thích giữa Android và C#

+0

Liên kết là chết. Bạn có thể vui lòng thêm đoạn mã bạn đã sử dụng cho Android không? –

Trả lời

38

Nhận trợ giúp từ http://oogifu.blogspot.com/2009/01/aes-in-java-and-c.html.

Đây là lớp Java của tôi:

package com.neocodenetworks.smsfwd; 

import java.security.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 
import android.util.Log; 

public class Crypto { 
    public static final String TAG = "smsfwd"; 

    private static Cipher aesCipher; 
    private static SecretKey secretKey; 
    private static IvParameterSpec ivParameterSpec; 

    private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding"; 
    private static String CIPHER_ALGORITHM = "AES"; 
    // Replace me with a 16-byte key, share between Java and C# 
    private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 

    private static String MESSAGEDIGEST_ALGORITHM = "MD5"; 

    public Crypto(String passphrase) { 
     byte[] passwordKey = encodeDigest(passphrase); 

     try { 
      aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); 
     } catch (NoSuchAlgorithmException e) { 
      Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e); 
     } catch (NoSuchPaddingException e) { 
      Log.e(TAG, "No such padding PKCS5", e); 
     } 

     secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM); 
     ivParameterSpec = new IvParameterSpec(rawSecretKey); 
    } 

    public String encryptAsBase64(byte[] clearData) { 
     byte[] encryptedData = encrypt(clearData); 
     return net.iharder.base64.Base64.encodeBytes(encryptedData); 
    } 

    public byte[] encrypt(byte[] clearData) { 
     try { 
      aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec); 
     } catch (InvalidKeyException e) { 
      Log.e(TAG, "Invalid key", e); 
      return null; 
     } catch (InvalidAlgorithmParameterException e) { 
      Log.e(TAG, "Invalid algorithm " + CIPHER_ALGORITHM, e); 
      return null; 
     } 

     byte[] encryptedData; 
     try { 
      encryptedData = aesCipher.doFinal(clearData); 
     } catch (IllegalBlockSizeException e) { 
      Log.e(TAG, "Illegal block size", e); 
      return null; 
     } catch (BadPaddingException e) { 
      Log.e(TAG, "Bad padding", e); 
      return null; 
     } 
     return encryptedData; 
    } 

    private byte[] encodeDigest(String text) { 
     MessageDigest digest; 
     try { 
      digest = MessageDigest.getInstance(MESSAGEDIGEST_ALGORITHM); 
      return digest.digest(text.getBytes()); 
     } catch (NoSuchAlgorithmException e) { 
      Log.e(TAG, "No such algorithm " + MESSAGEDIGEST_ALGORITHM, e); 
     } 

     return null; 
    } 
} 

tôi đã sử dụng http://iharder.sourceforge.net/current/java/base64/ cho mã hóa base64.

Dưới đây là C# tôi lớp:

using System; 
using System.Text; 
using System.Security.Cryptography; 

namespace smsfwdClient 
{ 
    public class Crypto 
    { 
     private ICryptoTransform rijndaelDecryptor; 
     // Replace me with a 16-byte key, share between Java and C# 
     private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 

     public Crypto(string passphrase) 
     { 
      byte[] passwordKey = encodeDigest(passphrase); 
      RijndaelManaged rijndael = new RijndaelManaged(); 
      rijndaelDecryptor = rijndael.CreateDecryptor(passwordKey, rawSecretKey); 
     } 

     public string Decrypt(byte[] encryptedData) 
     { 
      byte[] newClearData = rijndaelDecryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length); 
      return Encoding.ASCII.GetString(newClearData); 
     } 

     public string DecryptFromBase64(string encryptedBase64) 
     { 
      return Decrypt(Convert.FromBase64String(encryptedBase64)); 
     } 

     private byte[] encodeDigest(string text) 
     { 
      MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider(); 
      byte[] data = Encoding.ASCII.GetBytes(text); 
      return x.ComputeHash(data); 
     } 
    } 
} 

Tôi thực sự hy vọng điều này sẽ giúp người khác!

+7

Vâng ... Tôi thích khi mọi người trả lời câu hỏi kỹ thuật của tôi với "Oh, bạn nên làm điều đó" hoặc "Ồ, bạn nên làm điều này". Cảm ơn bạn đã thiết thực và rời khỏi lớp học của bạn. – kape123

+0

Tôi đã mã hóa nội dung tệp của mình bằng mã Java và đã lưu nội dung đã mã hóa thành encrypted.txt. Bây giờ tôi muốn giải mã nó bằng công cụ openssl bằng cách sử dụng lệnh này: openssl enc -d -a -p -aes-256-cbc -salt -in encrypted.txt -out decrypted.txt -pass pass: myPassword nhưng tôi gặp lỗi: số ma thuật xấu. Bất kỳ ý tưởng gì là sai? Ngay cả khi tôi loại bỏ tham số -salt khỏi lệnh, tôi vẫn nhận được lỗi tương tự. – uerceg

+0

@uerceg: Bạn sẽ muốn bắt đầu một câu hỏi mới cho điều đó. Giải pháp này không sử dụng OpenSSL vì vậy tôi không mong đợi rằng để làm việc. – Jess

1

Có thể không sao, miễn là chúng tôi khóa phím là giống nhau - 128 bit AES và chế độ mã hóa khối chính xác (CBC). Bạn có thể gặp vấn đề với đệm, nhưng điều đó khá dễ dàng để sắp xếp. Tôi đã gặp phải những vấn đề này với Java và Python gần đây, nhưng cuối cùng cũng có mọi thứ hoạt động. Base64 cho mã hóa phải được sử dụng tốt trên HTTP. Chúc may mắn!

1

Nếu bạn triển khai chính xác cùng một thuật toán (như AES) và chế độ (như CTR, CFB, CCM, v.v.) trên cả hai đầu, thì bản mã từ một đầu có thể được giải mã bằng đầu kia bất kể nền tảng.

Ví dụ về Android mà bạn liên kết với dường như sử dụng chế độ ECB và do đó không an toàn cho mục đích của bạn. Điều quan trọng là bạn hiểu được ý nghĩa của chế độ khối bạn chọn. Rất khó để có được mật mã sai ở cấp độ này, dẫn đến một hệ thống không an toàn như bạn nghĩ.

EDIT: Tôi lấy lại nó, nó không sử dụng ECB, nhưng cách nó tạo ra IV là không thực tế. Trong mọi trường hợp, quan điểm của tôi về sự hiểu biết về các tác động của các chế độ khối là viết tắt.

Bạn có thể bắt đầu với điều này wikipedia article. Cuốn sách của Bruce Schneier 'Practical Cryptography' cũng cực kỳ có giá trị đối với bất kỳ ai thực hiện bảo mật mật mã.

Để mã hóa chuỗi, nếu bạn phải chuyển đổi chuỗi thành văn bản ASCII Base64 là tốt như mọi cách, nhưng tôi khuyên bạn nên điều tra việc sử dụng HTTP PUT hoặc POST để phụ tùng cho bạn bước bổ sung này.

4

Trong mẫu C# mã nguồn được cung cấp, xem ra dòng này:

Encoding.ASCII.GetString(newClearData); 

UTF-8 là bảng mã mặc định dành cho Android, chuỗi để mã hóa (đặc biệt là ký tự phi ASCII như Trung Quốc) sẽ được thông qua C# giả sử UTF-8. Các văn bản trở nên tranh giành nếu giải mã trở lại chuỗi bằng cách sử dụng mã hóa ASCII. Đây là hình ảnh tốt hơn,

Encoding.UTF8.GetString(newClearData); 

Cảm ơn!

1

Hầu hết các ví dụ trên internet là triển khai yếu kém của AES. Để thực hiện được mạnh mẽ, IV ngẫu nhiên nên được sử dụng tất cả các thời gian và chìa khóa nên được băm.

Đối với an toàn hơn (ngẫu nhiên IV + phím băm) đa nền tảng (Android, iOS, C#) thực hiện AES xem câu trả lời của tôi ở đây - https://stackoverflow.com/a/24561148/2480840

Các vấn đề liên quan