Android内容提供商保护级别&;不同的键

Android内容提供商保护级别&;不同的键,android,key,android-contentprovider,signature,Android,Key,Android Contentprovider,Signature,我有一个应用程序在专业(付费)和免费(添加支持)版本。两个版本都使用相同的密钥存储进行签名,但每个版本都有自己的密钥别名 我想开发一个与这两个版本兼容的插件,通过内容提供商提供数据。数据是敏感的,所以我需要我的内容提供商只能从我的应用程序(专业版和免费版)访问 使用android:protectionLevel=“signature”的权限不起作用,因为免费版和专业版没有相同的签名:/。我想我应该用相同的密钥签署我的两个版本,但我认为Play Store上的每个应用都需要用自己的密钥签署 那么,

我有一个应用程序在专业(付费)和免费(添加支持)版本。两个版本都使用相同的密钥存储进行签名,但每个版本都有自己的密钥别名

我想开发一个与这两个版本兼容的插件,通过内容提供商提供数据。数据是敏感的,所以我需要我的内容提供商只能从我的应用程序(专业版和免费版)访问

使用android:protectionLevel=“signature”的权限不起作用,因为免费版和专业版没有相同的签名:/。我想我应该用相同的密钥签署我的两个版本,但我认为Play Store上的每个应用都需要用自己的密钥签署


那么,有人知道解决方案吗?有没有办法温和地要求谷歌更改我使用的钥匙(我可以证明我的身份,因为我没有松开钥匙),或者我被卡住了

编辑:我可以选择取消发布专业版(因为我现在很少下载),然后用与免费版相同的证书重新上传。如果我这样做,我是否需要更改它的包


提前感谢

签名
级别的权限很好,但相当不灵活:应用程序必须使用相同的签名密钥签名。在许多情况下,我们会希望检查另一个应用程序是否由预期的密钥签名,但该密钥不是我们的密钥。对你来说,你有两把钥匙。在其他情况下,可能会检查某些合作伙伴应用程序的签名,例如,确认您将要向用户发送的PayPal应用程序确实是PayPal应用程序,而不是取代PayPal应用程序的恶意软件

要验证另一个应用程序的签名,您可以使用
PackageManager
。例如,以下是from的当前版本:

/***
版权所有(c)2014 Commonware,LLC
根据Apache许可证2.0版(以下简称“许可证”)获得许可;你可以
除非符合许可证,否则不得使用此文件。你可以得到
许可证副本,位于
http://www.apache.org/licenses/LICENSE-2.0
除非适用法律要求或书面同意,软件
根据许可证进行的分发是按“原样”进行分发的,
无任何明示或暗示的保证或条件。
请参阅许可证以了解管理权限和权限的特定语言
许可证下的限制。
*/
包com.commonware.cwac.security;
导入android.content.Context;
导入android.content.pm.PackageManager;
导入android.content.pm.PackageManager.NameNotFoundException;
导入android.content.pm.Signature;
导入java.security.MessageDigest;
导入java.security.NoSuchAlgorithmException;
公共类签名{
公共静态字符串getOwnSignatureHash(Context-ctxt)
抛出NameNotFoundException,
NoSuchAlgorithmException{
return(getSignatureHash(ctxt,ctxt.getPackageName());
}
公共静态字符串getSignatureHash(上下文ctxt,字符串packageName)
抛出NameNotFoundException,
NoSuchAlgorithmException{
MessageDigest md=MessageDigest.getInstance(“SHA-256”);
签名信号=
ctxt.getPackageManager()
.getPackageInfo(packageName,PackageManager.GET_签名)。签名[0];
return(tohextringwithcolons(md.digest(sig.toByteArray())));
}
//基于https://stackoverflow.com/a/2197650/115145
公共静态字符串ToHexstringWithColon(字节[]字节){
字符[]六边形=
{'0','1','2','3','4','5','6','7','8','9','A','B',
‘C’、‘D’、‘E’、‘F’};
char[]hexChars=新字符[(bytes.length*3)-1];
INTV;
对于(int j=0;j
我使用
PackageManager
获取给定包的
签名
,给定其应用程序ID。尽管名称不同,
签名
实际上是用于对应用程序签名的密钥对的公钥。
getSignatureHash()
的输出是一组以冒号分隔的十六进制字符对,表示公钥的SHA256哈希。。。与使用Java 7+
keytool
命令获得的值相同

在您的情况下,您正在尝试动态确定传入的操作是否来自所需的应用程序,以及所需的应用程序是否正确(例如,与重新打包的恶意软件相比)。在您的情况下,
Binder.getCallingUid()
将为您提供触发代码的IPC的应用程序的Linux UID
PackageManager
can(忽略
android:sharedUserId
scenarios)。然后,您将看到该应用程序ID是否为预期值,如果是,请检查哈希签名密钥是否为预期值。如果其中一个测试失败,用挥舞手臂的机器人的话来说


一个重要的警告是,一些开发者将通过重新签署应用程序的渠道发布应用程序。这里最值得注意的是亚马逊Android应用商店,亚马逊有意将你的应用包装在他们自己的准DRM中,并使用他们代表你生成的密钥对该应用进行签名。这与您在其他地方必须使用的密钥不同,因此可能需要比较多个有效的签名哈希。

“有没有办法温和地要求谷歌更改我使用的密钥”——谷歌不是限制因素。Android本身将无法使用由不同签名密钥签名的更新来替换现有安装的应用程序。作为替代,fro
/***
  Copyright (c) 2014 CommonsWare, LLC

  Licensed under the Apache License, Version 2.0 (the "License"); you may
  not use this file except in compliance with the License. You may obtain
  a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

package com.commonsware.cwac.security;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SignatureUtils {
  public static String getOwnSignatureHash(Context ctxt)
                                                        throws NameNotFoundException,
                                                        NoSuchAlgorithmException {
    return(getSignatureHash(ctxt, ctxt.getPackageName()));
  }

  public static String getSignatureHash(Context ctxt, String packageName)
                                                                         throws NameNotFoundException,
                                                                         NoSuchAlgorithmException {
    MessageDigest md=MessageDigest.getInstance("SHA-256");
    Signature sig=
        ctxt.getPackageManager()
            .getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];

    return(toHexStringWithColons(md.digest(sig.toByteArray())));
  }

  // based on https://stackoverflow.com/a/2197650/115145

  public static String toHexStringWithColons(byte[] bytes) {
    char[] hexArray=
        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
            'C', 'D', 'E', 'F' };
    char[] hexChars=new char[(bytes.length * 3) - 1];
    int v;

    for (int j=0; j < bytes.length; j++) {
      v=bytes[j] & 0xFF;
      hexChars[j * 3]=hexArray[v / 16];
      hexChars[j * 3 + 1]=hexArray[v % 16];

      if (j < bytes.length - 1) {
        hexChars[j * 3 + 2]=':';
      }
    }

    return new String(hexChars);
  }
}