65.9K
CodeProject 正在变化。 阅读更多。
Home

Android 和 .NET 加密。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (15投票s)

2014 年 10 月 7 日

CPOL

6分钟阅读

viewsIcon

51658

downloadIcon

1657

本文将简要介绍如何在 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 类。


//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 中的基本控制台应用程序。

好的,让我们创建文件并使用 adb 拉取它:

步骤

  1. 在蓝色区域输入消息,然后按 加密 按钮。

 

现在,我们的消息已被加密并保存到硬盘。

     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 作为服务器)的一部分,用于处理文本或任何您想加密的其他二进制文件,只需处理网络上的数据传输即可,这部分我们并未涵盖。

不要随意运行和加密您手头的所有东西,尤其是在处理大型二进制文件时。这会降低您的应用程序效率,特别是当您要保护的数据实际上没有人感兴趣时。

© . All rights reserved.