概述
App Inventor 2没有内置加密组件,但可以通过以下方式实现文本加密:
| 方案 | 安全级别 | 实现方式 |
|---|---|---|
| Caesar密码(字符偏移) | ⭐ | 积木块直接实现 |
| XOR异或加密 | ⭐⭐ | 积木块实现 |
| Base64编码 | ⭐(非加密) | WebView/积木块 |
| SHA-256哈希 | ⭐⭐⭐(不可逆) | WebView |
| AES加密 | ⭐⭐⭐⭐⭐ | WebView + CryptoJS |
方案一:Caesar密码(凯撒密码)
最简单的加密方式,将每个字符偏移固定位数。
加密
定义 Caesar加密(原文, 偏移量) 返回 密文
设 密文 = ""
设 i = 1
当 i ≤ 文本长度(原文)
设 字符 = 文本第i个字符(原文)
设 ASCII码 = 文本转ASCII码(字符)
设 加密码 = ASCII码 + 偏移量
如果 加密码 > 126
设 加密码 = 加密码 - 94 ' 可打印ASCII范围
设 密文 = 密文 & ASCII码转文本(加密码)
设 i = i + 1
返回 密文
解密
定义 Caesar解密(密文, 偏移量) 返回 原文
返回 Caesar加密(密文, 0 - 偏移量) ' 反向偏移
使用示例
当 按钮_加密.被点击
设 偏移量 = 文本转数字(输入框_偏移量.文本)
设 加密结果 = Caesar加密(输入框_原文.文本, 偏移量)
标签_密文.文本 = 加密结果
当 按钮_解密.被点击
设 偏移量 = 文本转数字(输入框_偏移量.文本)
设 解密结果 = Caesar解密(输入框_密文.文本, 偏移量)
标签_原文.文本 = 解密结果
方案二:XOR异或加密
比Caesar更安全,使用密钥进行异或运算。
定义 XOR加密(原文, 密钥) 返回 密文
设 密文 = ""
设 密钥长度 = 文本长度(密钥)
设 i = 1
当 i ≤ 文本长度(原文)
设 原字符 = 文本转ASCII码(文本第i个字符(原文))
设 密钥字符 = 文本转ASCII码(文本第((i-1)模密钥长度+1)个字符(密钥))
设 异或结果 = 原字符 XOR 密钥字符 ' 使用位运算积木块
设 密文 = 密文 & 文本转十六进制(异或结果) & " "
设 i = i + 1
返回 密文
定义 XOR解密(密文, 密钥) 返回 原文
设 原文 = ""
设 十六进制列表 = 分割文本(密文, " ")
设 密钥长度 = 文本长度(密钥)
设 i = 1
当 i ≤ 列表长度(十六进制列表)
设 加密字节 = 十六进制转数字(列表第i项(十六进制列表))
设 密钥字符 = 文本转ASCII码(文本第((i-1)模密钥长度+1)个字符(密钥))
设 解密字节 = 加密字节 XOR 密钥字符
设 原文 = 原文 & ASCII码转文本(解密字节)
设 i = i + 1
返回 原文
注意:XOR加密的特性是
加密(加密(原文, 密钥), 密钥) = 原文,即加密和解密用同一个函数。
方案三:Base64编码
Base64不是加密,只是编码转换,但可以隐藏明文内容。
使用WebView
当 按钮_Base64编码.被点击
调用 WebView1.运行JavaScript(
"window.AppInventor.setWebViewString(btoa(unescape(encodeURIComponent('" & 输入框_文本.文本 & "'))))")
当 按钮_Base64解码.被点击
调用 WebView1.运行JavaScript(
"window.AppInventor.setWebViewString(decodeURIComponent(escape(atob('" & 输入框_文本.文本 & "'))))")
当 WebView1.WebView字符串改变(值)
标签_结果.文本 = 值
方案四:SHA-256哈希(推荐用于密码存储)
SHA-256是单向哈希,不可逆,适合密码存储验证。
HTML文件(crypto.html)
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
<script>
setInterval(function() {
var data = window.AppInventor.getWebViewString();
if (data && data !== "") {
try {
var parts = data.split("|||");
if (parts[0] === "sha256") {
window.AppInventor.setWebViewString("SHA:" + CryptoJS.SHA256(parts[1]).toString());
} else if (parts[0] === "aes_encrypt") {
var encrypted = CryptoJS.AES.encrypt(parts[1], parts[2]).toString();
window.AppInventor.setWebViewString("ENC:" + encrypted);
} else if (parts[0] === "aes_decrypt") {
var decrypted = CryptoJS.AES.decrypt(parts[1], parts[2]).toString(CryptoJS.enc.Utf8);
window.AppInventor.setWebViewString("DEC:" + decrypted);
} else if (parts[0] === "hmac") {
var hmac = CryptoJS.HmacSHA256(parts[1], parts[2]).toString();
window.AppInventor.setWebViewString("HMAC:" + hmac);
}
} catch(e) {
window.AppInventor.setWebViewString("ERROR:" + e.message);
}
}
}, 100);
</script>
</body>
</html>
App Inventor使用
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/crypto.html"
' SHA-256哈希
当 按钮_哈希.被点击
设 WebView1.WebView字符串 = "sha256|||" & 输入框_原文.文本
' AES加密
当 按钮_AES加密.被点击
设 WebView1.WebView字符串 = "aes_encrypt|||" & 输入框_原文.文本 & "|||" & 输入框_密钥.文本
' AES解密
当 按钮_AES解密.被点击
设 WebView1.WebView字符串 = "aes_decrypt|||" & 输入框_密文.文本 & "|||" & 输入框_密钥.文本
当 WebView1.WebView字符串改变(值)
如果 值 以 "SHA:" 开头
标签_哈希结果.文本 = 替换文本(值, "SHA:", "")
否则 如果 值 以 "ENC:" 开头
标签_加密结果.文本 = 替换文本(值, "ENC:", "")
否则 如果 值 以 "DEC:" 开头
标签_解密结果.文本 = 替换文本(值, "DEC:", "")
实战案例:加密记事本
功能需求
- 用户输入笔记内容
- 使用AES加密后保存到TinyDB
- 读取时解密显示
- 密码验证使用SHA-256
积木块代码
设 用户密码哈希 = ""
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/crypto.html"
' 检查是否已设置密码
设 保存的哈希 = TinyDB1.获取值("password_hash", "")
如果 保存的哈希 = ""
标签_状态.文本 = "首次使用,请设置密码"
否则
标签_状态.文本 = "请输入密码登录"
' 设置密码
当 按钮_设置密码.被点击
设 WebView1.WebView字符串 = "sha256|||" & 输入框_密码.文本
' 保存加密笔记
当 按钮_保存.被点击
设 WebView1.WebView字符串 = "aes_encrypt|||" & 输入框_笔记.文本 & "|||" & 输入框_密码.文本
' 读取加密笔记
当 按钮_读取.被点击
设 加密笔记 = TinyDB1.获取值("encrypted_note", "")
如果 加密笔记 ≠ ""
设 WebView1.WebView字符串 = "aes_decrypt|||" & 加密笔记 & "|||" & 输入框_密码.文本
当 WebView1.WebView字符串改变(值)
如果 值 以 "SHA:" 开头
设 用户密码哈希 = 替换文本(值, "SHA:", "")
调用 TinyDB1.存储值("password_hash", 用户密码哈希)
标签_状态.文本 = "✅ 密码已设置"
否则 如果 值 以 "ENC:" 开头
设 加密数据 = 替换文本(值, "ENC:", "")
调用 TinyDB1.存储值("encrypted_note", 加密数据)
标签_状态.文本 = "✅ 笔记已加密保存"
否则 如果 值 以 "DEC:" 开头
设 解密笔记 = 替换文本(值, "DEC:", "")
输入框_笔记.文本 = 解密笔记
标签_状态.文本 = "✅ 笔记已解密"
否则 如果 值 以 "ERROR:" 开头
标签_状态.文本 = "❌ 解密失败,密码错误?"
加密方案对比
| 方案 | 可逆 | 安全性 | 用途 |
|---|---|---|---|
| Caesar | ✅ | ⭐ | 教学、简单隐藏 |
| XOR | ✅ | ⭐⭐ | 简单加密、学习 |
| Base64 | ✅ | ⭐ | 编码转换,非加密 |
| SHA-256 | ❌ | ⭐⭐⭐ | 密码哈希、数据校验 |
| AES | ✅ | ⭐⭐⭐⭐⭐ | 数据加密、通信加密 |
常见问题
Q1: 加密后的中文显示乱码?
确保使用UTF-8编码处理。WebView方案中CryptoJS默认支持UTF-8。积木块方案需要处理多字节字符(中文字符占3个字节)。
Q2: WebView加载CryptoJS需要网络?
CDN方式需要网络。可以将crypto-js.min.js下载后放到Assets中,使用本地引用:
<script src="file:///android_asset/crypto-js.min.js"></script>
Q3: AES加密的密钥有多长?
CryptoJS支持128/192/256位密钥。传入的密钥字符串会被自动处理。建议使用至少16字符的密钥。
总结
- 密码存储 → SHA-256哈希
- 数据加密 → AES(WebView + CryptoJS)
- 简单隐藏 → Caesar或XOR
- 编码转换 → Base64
版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。
扫码添加客服咨询