Android 和 .NET 加密。






4.93/5 (15投票s)
本文将简要介绍如何在 Android 和 .NET 平台上进行基本的加密/解密,重点在于将加密数据从 Android 传递到 .NET。
来源
Github: https://github.com/Pavel-Durov/CodeProject-Android-and-NET-Encryption
直接
目录
前言
应将可能被他人窥探到的敏感数据进行加密。
什么是敏感信息由您决定。它可以是任何个人数据、您在网络上传输的图片、您的 GPS 位置等……
当敏感数据暴露在程序外部、发送到互联网或保存到本地文件系统时,它就处于危险之中。
本文并非关于安全,而是关于简单的加密/解密实现。
什么是加密?
加密算法可分为两大类:对称加密和非对称加密。两者各有优缺点。
对称加密
加密和解密都使用同一个共享密钥。该密钥在发送方和接收方之间共享。
为了加密消息,发送方使用共享密钥;接收方也必须使用相同的密钥来解密消息。
对称算法速度很快,但要求双方拥有一个独一无二的相同密钥,这在大系统中可能成为一个问题,因为密钥管理会非常复杂。
非对称加密(公钥密码学)
发送方和接收方使用不同的密钥来加密和解密消息,每个人都拥有一对密钥——公钥和私钥。
当发送方要加密消息时,他会使用接收方的公钥。然后接收方可以使用自己的私钥解密该消息。这种方法速度较慢,但在大型系统中密钥管理要容易得多。
Android 中的对称加密
在本例中,我们将使用 Android 的 SDK 类 Cipher 来进行加密/解密。
Cipher 类提供了对加密和解密密码实现(ciphers)的访问。更多信息请参阅
https://developer.android.com.cn/reference/javax/crypto/Cipher.html
CryptoHandler 类
我们的 Cipher 依赖于两个密钥,第一个是通过字符串传递给构造函数的密码短语,第二个是 16 字节的原始密钥。
//CryptoHandler constructor
 public CryptoHandler(String passphrase)
 {
     //decodes passd phrase to encrypted byte[]
     byte[] passwordKey = encodeDigest(passphrase);
     try
     {
       //_aesCipher instantiation passing transformation parameter
         _aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
     }
     catch (NoSuchAlgorithmException e)
     { //Invalid algorithm in passed transformation parameter
         Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e);
     }
     catch (NoSuchPaddingException e)
     { //Invalid padding in passed transformation parameter
         Log.e(TAG, "No such padding PKCS5", e);
     }
     //Encodes the passed password phrase to a byte[]
     //that will be stored in class private member of SecretKey type
     _secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM);
     //Creates a new IvParameterSpec instance with the bytes
     //from the specified buffer iv used as initialization vector.
     _ivParameterSpec = new IvParameterSpec(rawSecretKey);
 }
在我们的 CryptoHandler 类中,我们将使用 AES(高级加密标准)加密,您可以在这里阅读更多相关信息:
http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
AES 的实例化发生在下面这行代码中:
private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
_aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
我们调用了一个 Cipher 的静态方法,它返回一个 Cipher 类型的实例化对象(如果没有抛出异常)。
“AES/CBC/PKCS5Padding”(传递的字符串转换参数)
AES – 加密算法(高级加密标准)。
CBC – 一种反馈模式的名称(在我们的例子中是密码块链接)。
PKCS5Padding – 填充方案的名称。
CryptoHandler 类的方法
除了构造函数,我们的 CryptoHandler 类还有另外 3 个方法:
public byte[] Encrypt(byte[] clearData)
Encrypt 方法通过将 Cipher.ENCRYPT_MODE 常量传递给 init() 方法,将 _aesCipher 设置为加密模式。
public byte[] Decrypt(byte[] data)
Decrypt 方法做同样的事情,但传递的不是 Cipher.ENCRYPT_MODE,而是 Cipher.DECRYPT_MODE。
Decrypt 和 Encrypt 方法都调用 DoWork() 方法,它们之间唯一的区别在于各自设置的 Cipher 模式常量。
public byte[] DoWork(byte[] data)
调用 _aesCipher.doFinal(data) 方法并捕获异常。
private byte[] encodeDigest(String text)
 private static byte[] _rawSecretKey =
 {
       0x12, 0x00, 0x22, 0x55, 0x33, 0x78, 0x25, 0x11,
       0x33, 0x45, 0x00, 0x00, 0x34, 0x00, 0x23, 0x28
 };
此密钥必须在发送方和接收方之间共享,在我们的例子中,我们既是发送方也是接收方,所以我们使用相同的密钥实例进行加密和解密。
Android 实现
在 MainActivity 的布局中,您可以看到两个着色的区域,蓝色区域是输入要加密文本的地方,绿色区域仅用于显示。
当您按下“加密”按钮时,加密后的数据将被保存在内部文件系统中(您可以在文件文件夹下看到它),并在绿色视图中显示为乱码(这是原始明文的密文)。
*保存的数据将覆盖之前的数据,而不会追加到文件中的现有数据。
/**
 * Encrypts the String value that entered in the _tvMessage EditText View
* and saves is to file on local file system
* */
private void EncryptMessage()
{
     String message  = _tvMessage.getText().toString();
     if(message != null && message.length() > 0)
     {
          //performs text encryption
          byte[] bytes = _crypto.Encrypt(message.getBytes());
          //sets view value
          SetTextViewEncryptresult(bytes);
          //saves encrypted text to internal file
          _streamHandler.SaveTextFile
              (
                     FileStreamHandler.ENCRYPTED_TXT_FILENAME,
                     bytes
              );
     }     
}
*如果您不知道如何查看 Android 设备的内部数据,请参阅我的文章:
https://codeproject.org.cn/Articles/825304/Accessing-internal-data-on-Android-device
所有文件操作都通过 handlers 包中的 FileStreamHandler 执行。
有几个方法负责读取和写入内部文件。
当您点击 MainActivity 布局上的 Decrypt 按钮时,消息将从保存的文件中读取并以 Toast 消息的形式显示给您。
/**
 * Decrypt the message from saved local file content.
 * calls ShowToast() method
 * */
private void DecryptMessage()
{
       byte[] fileContent = _streamHandler
              .ReadFromLocalFile(FileStreamHandler.ENCRYPTED_TXT_FILENAME);            
       if(fileContent != null && fileContent.length > 0)
       {
              //preforms decryption of the fuile content
              byte[] decrypted = _crypto.Decrypt(fileContent);
             
              //Creates new String instance of passed byte[] as UTF-8
              String readableData = StringHandler.GetString(decrypted);
              String encrypted = StringHandler.GetString(fileContent);
              if(readableData != null && encrypted != null)
              {
                     //showing toast
                     ShowToast
                     (     
                           getString(R.string.msg_decrypted) + readableData,
                           getString(R.string.msg_encrypted) + encrypted
                     );
              }
       }
       else
       {      //if file not exist or file content is empty
              ShowToast(":(", "!");
       }
}
如果您点击了“解密”按钮并得到了类似这样的结果:

这意味着您已完成整个加密周期。
您输入了明文,将其编码为密文并保存到本地文件,然后读取该文件并将其解密为正常的、可读的文本。
在本例中,我们将密钥和密码短语作为硬编码值保存在 java 类中,但这并非最佳解决方案,因为它很容易通过逆向工程进行检查,因此请牢记这一点,并将密钥存储在安全的地方。
在 .NET 中解密 Android 消息
现在,我们将看到如何使用 C# 语言在 .NET 中解密在 Android 设备上加密的密文。由于我们使用的是标准加密,因此也可以在其他平台上进行。
我们将把之前在 Android 设备上保存的文件拉取到计算机上,并将其导入到 Visual Studio 中的基本控制台应用程序。
2. 接下来,我们将运行几个命令来授予文件权限并使用 pull 命令从设备获取文件。
*再次说明,如果您不理解,请参阅我关于 adb 工具和 Android 内部文件权限的文章。
https://codeproject.org.cn/Articles/825304/Accessing-internal-data-on-Android-device

由于我所有的 adb 命令都已成功执行,我现在可以在我的下载目录中浏览我的文件了。

现在我们将它导入到我们的 .NET 控制台应用程序中。
*请勿复制文本,我们处理的是二进制数据,将其作为字符串复制可能会改变其值!只需按原样复制文件。
在我们的 C# 控制台应用程序中,我们有一个 CryptoHandler 类,它基本上与 Android 上的相同。请注意,在 .NET 中,我们使用了两个 ICryptoTransform 实例作为解密和加密机制。这大致相同,因为在 Android 中我们使用了常量,而在 .NET 中我们使用了 RijndaelManaged .NET 类的工厂方法。
如果一切顺利,运行 C# 程序,您将看到与在 Android 设备上输入的相同消息。

摘要
我们已经成功地在 Android 和 .NET 应用程序中加密和解密了我们的简单消息。这可以作为客户端-服务器通信(Android 作为客户端,.NET 作为服务器)的一部分,用于处理文本或任何您想加密的其他二进制文件,只需处理网络上的数据传输即可,这部分我们并未涵盖。
不要随意运行和加密您手头的所有东西,尤其是在处理大型二进制文件时。这会降低您的应用程序效率,特别是当您要保护的数据实际上没有人感兴趣时。




