GCM Demo "Unfortunately, GCM demo has stopped"

本文解决了在运行Google Cloud Messaging (GCM) 示例应用时遇到的应用崩溃问题,并介绍了如何正确配置服务器URL以实现消息推送。

本文链接:http://blog.youkuaiyun.com/kongxx/article/details/8155913


今天在学习Google Cloud Messaging (GCM),在运行文档上使用的例子(http://developer.android.com/guide/google/gcm/demo.html)的时候,按照步骤设置好server和client之后,运行server和client之后,在模拟器上运行GCM Demo的时候总是出现"Unfortunately, GCM demo has stopped"错误,检查了一下,需要修改的地方都按照文档上的说明改了,还是出错。最后发现原来是选择的AVD有问题,开始使用的是"Android 4.1.2 - API Level 16",后来我把AVD换成"Google APIs (Google Inc.) - API Level 16"再运行client,就不会再出现上面的问题了


另外在测试的时候还发现一个问题,就是文档上给出了两种server选择,一种是“Using a standard web server”,在使用这种server选择的时候,按照文档上的说明配置client是可以运行的。但是如果使用“Using App Engine for Java”,需要将client中CommonUtilities.SERVER_URL改成“http://192.168.1.10:8080”,就是去掉其中的“/gcm-demo”,然后再运行,此时就可以通过“http://192.168.1.10:8080”来发送message了。


<think> 根据用户需求,用户需要Java中使用AES128-GCM进行加解密的示例代码。同时,用户引用了三段内容,其中提到了AES-GCM在Java中的实现以及一些注意事项,特别是关于认证标签(authTag)的处理。 关键点: 1. 用户需要AES128-GCM的示例代码。 2. 引用[2]提到Java中使用GCMParameterSpec,指定了认证标签长度(GCM_TAG_LENGTH)和nonce(iv)。 3. 引用[3]指出Node.js和Java在处理authTag时的差异:Java中authTag是拼接在加密结果中的(加密结果最后16位是authTag),而Node.js中可能需要分离。 因此,在实现Java AES-GCM加解密时,需要注意: - 使用GCMParameterSpec,指定认证标签长度(通常为128位,即16字节)。 - 在加密时,生成的认证标签(authTag)会附加在密文后面(即密文长度=明文长度+16字节)。 - 解密时,需要将密文拆分为实际密文和认证标签(最后16字节)。 步骤: 1. 生成密钥:使用KeyGenerator生成AES密钥,长度128位。 2. 加密: - 生成随机nonce(IV),长度建议12字节(推荐,也可以使用其他长度,但需要符合GCM规范)。 - 创建GCMParameterSpec,指定认证标签长度(128位)和nonce。 - 初始化Cipher为加密模式,传入密钥和GCMParameterSpec。 - 执行加密,得到密文数组。注意,加密结果包括密文和认证标签(附加在密文后面,共16字节)。 3. 解密: - 将密文拆分为实际密文和认证标签(最后16字节)。 - 使用相同的nonce(IV)和相同的认证标签长度创建GCMParameterSpec。 - 初始化Cipher为解密模式,传入密钥和GCMParameterSpec。 - 将实际密文(去掉最后16字节)传入进行解密,同时Cipher会验证认证标签。 注意:nonce(IV)在加密时随机生成,需要将其和密文一起传输给解密方。通常,我们将IV和密文(包含认证标签)一起存储或传输,常见的做法是先将IV放在密文前面,然后接着密文+认证标签。但根据引用[3]的描述,在Java中,认证标签是自动附加在密文后面的,所以整个加密结果为:IV(12字节)+ 密文(明文长度)+ 认证标签(16字节)。但注意,Java标准库中并不会自动将IV和密文拼接,需要我们自己处理。 因此,在加密后,我们将IV和加密后的数据(包括密文和认证标签)一起存储或传输。解密时,先提取前12字节(IV),然后剩余部分就是(密文+认证标签),再将剩余部分拆分为密文和认证标签(最后16字节为认证标签)。 但是,在Java中,我们使用Cipher类进行加密,加密后得到的是一个字节数组,这个数组已经包含了认证标签(附加在密文后面)。同时,我们使用IvParameterSpec(或GCMParameterSpec)传入的IV,并不会被自动保存。因此,我们需要将IV和密文(包含认证标签)一起保存。解密时,先读取IV,然后读取整个密文(包含认证标签),然后初始化Cipher时传入IV和认证标签长度(通过GCMParameterSpec),再将整个密文(包含认证标签)传入,Cipher会自动处理认证标签。 实际上,在解密时,我们传入的密文应该是加密时输出的整个字节数组(即密文+认证标签)。因为GCMParameterSpec已经指定了认证标签的长度,所以内部会按照这个长度从传入的密文数组的末尾提取认证标签进行验证。 因此,代码实现步骤: 加密: 1. 生成一个12字节的随机IV(使用SecureRandom)。 2. 创建GCMParameterSpec(128位认证标签,使用IV)。 3. 初始化Cipher(加密模式),使用密钥和GCMParameterSpec。 4. 加密数据,得到密文数组(这个数组包含认证标签)。 5. 将IV和密文数组(包含认证标签)组合在一起(例如,先写IV,再写密文数组)。这样,解密方可以先读取前12字节得到IV,剩余部分就是密文+认证标签。 解密: 1. 从输入数据中读取前12字节作为IV。 2. 剩余部分作为密文(包含认证标签)。 3. 创建GCMParameterSpec(128位认证标签,使用IV)。 4. 初始化Cipher(解密模式),使用密钥和GCMParameterSpec。 5. 解密剩余部分(密文+认证标签),得到原文。 注意:如果使用其他长度的IV,需要调整。GCM推荐使用12字节的IV(nonce),效率最高。 示例代码: </think> 以下是Java中使用AES-128-GCM加解密的完整示例代码及说明: ```java import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.ByteBuffer; import java.security.SecureRandom; import java.util.Base64; public class AESGCMExample { // 常量定义 private static final int GCM_IV_LENGTH = 12; // 推荐IV长度 private static final int GCM_TAG_LENGTH = 16; // 128位认证标签 private static final String ALGORITHM = "AES/GCM/NoPadding"; public static void main(String[] args) throws Exception { // 1. 生成密钥(实际应用中应从安全存储获取) SecretKey key = generateKey(128); // 2. 加密示例 String plainText = "Hello AES-GCM!"; byte[] encryptedData = encrypt(plainText.getBytes(), key); System.out.println("加密结果: " + Base64.getEncoder().encodeToString(encryptedData)); // 3. 解密示例 byte[] decryptedData = decrypt(encryptedData, key); System.out.println("解密结果: " + new String(decryptedData)); } // 生成AES密钥 public static SecretKey generateKey(int keySize) throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(keySize); return keyGenerator.generateKey(); } // 加密方法 public static byte[] encrypt(byte[] plaintext, SecretKey key) throws Exception { // 生成随机IV(推荐12字节) byte[] iv = new byte[GCM_IV_LENGTH]; SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(iv); // 初始化加密器 Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec); // 执行加密(结果包含:IV + 密文 + 认证标签) byte[] ciphertext = cipher.doFinal(plaintext); // 组合IV和密文(Java自动附加认证标签到密文末尾[^3]) ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + ciphertext.length); byteBuffer.put(iv); byteBuffer.put(ciphertext); return byteBuffer.array(); } // 解密方法 public static byte[] decrypt(byte[] encryptedData, SecretKey key) throws Exception { // 拆分数据:前12字节为IV,剩余为(密文+认证标签) ByteBuffer byteBuffer = ByteBuffer.wrap(encryptedData); byte[] iv = new byte[GCM_IV_LENGTH]; byteBuffer.get(iv); byte[] ciphertext = new byte[byteBuffer.remaining()]; byteBuffer.get(ciphertext); // 初始化解密器 Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec); // 执行解密(自动验证末尾的认证标签[^2]) return cipher.doFinal(ciphertext); } } ``` ### 关键说明: 1. **IV处理**: - 使用12字节随机IV(推荐长度) - 加密后IV附加在密文前部($IV_{12B} + Ciphertext + AuthTag_{16B}$) - 解密时先提取IV再处理剩余数据 2. **认证标签**: - 指定128位标签长度(`GCM_TAG_LENGTH=16`) - Java自动将标签附加到密文末尾[^3],解密时自动校验 3. **安全注意事项**: - **不要复用IV**:每次加密生成新IV - **密钥管理**:实际应用需使用密钥管理系统(如KeyStore) - **认证失败处理**:解密失败会抛出`AEADBadTagException`,需捕获处理 ### 执行流程: ```mermaid graph TD A[生成随机密钥] --> B[加密] B --> C[生成随机IV] C --> D[加密数据+生成认证标签] D --> E[组合IV+密文+标签] E --> F[传输/存储] F --> G[解密] G --> H[拆分IV和密文标签] H --> I[验证标签并解密] I --> J[返回明文] ``` ### 常见问题解决: 1. **认证失败**:检查密钥/IV是否匹配,数据是否篡改 2. **无效密钥**:确认使用相同长度的密钥(128位) 3. **IV长度错误**:确保使用12字节IV(`GCM_IV_LENGTH=12`) > **注意**:实际部署时应使用安全随机数生成器(`SecureRandom`),并遵循OWASP加密规范[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值