Android 上的 XML SOAP 签名

2024-01-08

我需要在 Android 应用程序中签署 XML SOAP 请求。

我做了一些研究,似乎没有框架可以在 Android 上做到这一点。

有人设法做到这一点吗?


经过几周的尝试和测试,我终于成功地在 Android 上进行了手动 XML 签名。 这是代码:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;

import javax.crypto.Cipher;

import android.util.Log;

/**
 * Generates Sha1withRSA XML signatures.
 */
public final class XmlSigner {

  /** Log tag. */
  private static final String LOG_TAG = "XmlSigner";

  /**
   * DER encoded ASN.1 identifier for SHA1 digest: "1.3.14.3.2.26".
   */
  private static final byte[] DER_SHA1_DIGEST_IDENTIFIER = new byte[]{48, 33, 48, 9, 6, 5, 43, 14,
      3, 2, 26, 5, 0, 4, 20};

  /** The characters needed for base 64 encoding. */
  private static final char[] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();

  /**
   * Hide constructor.
   */
  private XmlSigner() {

  }

  /**
   * Generates Sha1withRSA XML signature for the specified XML content and
   * private key.
   * 
   * @param xml the XML content
   * @param privateKey the private key to generate the signature
   * @return the whole signature node XML string that should be inserted
   * somewhere in the XML
   * @throws XmlSignerException if the signature XML can not be generated
   */
  public static String generateXmlSignature(String xml, PrivateKey privateKey) throws Throwable {

    try {
      // get canonized XML
      int soapBodyStart = xml.indexOf("<soap:Body>");
      int soapBodyEnd = xml.indexOf("</soap:Body>");
      String bodyXml = xml.substring(soapBodyStart + 12, soapBodyEnd - 1);

      // get bytes from the XML
      byte[] xmlBytes = bodyXml.getBytes("UTF-8");

      // calculate SHA256 digest from the XML bytes
      byte[] xmlDigestBytes = sha1Digest(xmlBytes);

      // encode the XML digest to base64 string
      String base64XmlDigest = base64encode(xmlDigestBytes, false);

      // generate SignedInfo node to be signed with signature
      String signedInfo = "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">"
          + "<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">"
          + "</ds:CanonicalizationMethod><ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\">"
          + "</ds:SignatureMethod><ds:Reference URI=\"\"><ds:Transforms>"
          + "<ds:Transform Algorithm=\"http://www.w3.org/2002/06/xmldsig-filter2\">"
          + "<ds:XPath xmlns:ds=\"http://www.w3.org/2002/06/xmldsig-filter2\" Filter=\"intersect\">"
          + "/soap:Envelope/soap:Body/*</ds:XPath></ds:Transform>"
          + "<ds:Transform xmlns:ds=\"http://www.w3.org/2002/06/xmldsig-filter2\" "
          + "Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></ds:Transform>"
          + "</ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\">"
          + "</ds:DigestMethod><ds:DigestValue>" + base64XmlDigest
          + "</ds:DigestValue></ds:Reference></ds:SignedInfo>";

      // get the bytes from SignedInfo that will be signed
      byte[] signedInfoBytes = signedInfo.getBytes("UTF-8");

      // calculate SHA1 digest of the signed info bytes
      byte[] signedInfoSha1Digest = sha1Digest(signedInfoBytes);

      // encode the digest identifier and the SHA1 digest in DER format
      byte[] signedInfoDerSha1Digest = mergeArrays(DER_SHA1_DIGEST_IDENTIFIER, signedInfoSha1Digest);

      // initialize RSA cipher with the parameters from the private key
      Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
      cipher.init(Cipher.ENCRYPT_MODE, privateKey);

      // encrypt the DER encoded SHA1 digest of signed info
      byte[] signatureBytes = cipher.doFinal(signedInfoDerSha1Digest);

      // encode the signature bytes into base64 string
      String base64RsaSignature = base64encode(signatureBytes, true);

      // generate the whole signature node XML string
      String signature = "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis"
          + "-200401-wss-wssecurity-secext-1.0.xsd\">"
          + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">" + signedInfo
          + "<ds:SignatureValue>" + base64RsaSignature
          + "</ds:SignatureValue></ds:Signature></wsse:Security>";

      return signature;
    } catch (Throwable e) {
      Log.e(LOG_TAG, "Error generating signature for XML", e);
      throw e;
    }
  }

  /**
   * Merges two byte arrays in one.
   * 
   * @param array1 the first array
   * @param array2 the second array
   * @return merged array
   */
  public static byte[] mergeArrays(byte[] array1, byte[] array2) {
    byte[] temp = new byte[array1.length + array2.length];
    System.arraycopy(array1, 0, temp, 0, array1.length);
    System.arraycopy(array2, 0, temp, array1.length, array2.length);
    return temp;
  }

  /**
   * Generates SHA-1 digest of the provided data.
   * 
   * @param data the data to digest
   * @return SHA-1 digest of the provided data.
   */
  public static byte[] sha1Digest(byte[] data) {
    MessageDigest mdSha1 = null;
    try {
      mdSha1 = MessageDigest.getInstance("SHA-1");
    } catch (NoSuchAlgorithmException e1) {
      Log.e(LOG_TAG, "Error initializing SHA1 message digest");
    }
    mdSha1.update(data);
    byte[] sha1hash = mdSha1.digest();
    return sha1hash;
  }


  /**
   * Generates SHA-256 digest of the provided data.
   * 
   * @param data the data to digest
   * @return SHA-256 digest of the provided data.
   */
  public static byte[] sha256Digest(byte[] data) {
    MessageDigest mdSha256 = null;
    try {
      mdSha256 = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e1) {
      Log.e(LOG_TAG, "Error initializing SHA1 message digest");
    }
    mdSha256.update(data);
    byte[] sha256hash = mdSha256.digest();
    return sha256hash;
  }

  /**
   * Encoded byte arrays into Base64 strings.
   * 
   * @param data the byte array to encode
   * @param wrapLines <code>true</code> to add \r\n
   * @return base64 encoded string
   */
  public static String base64encode(byte[] data, boolean wrapLines) {
    int length = data.length;
    StringBuilder sb = new StringBuilder(length * 3 / 2);
    int end = length - 3;
    int i = 0;
    int n = 0;

    while (i <= end) {
      int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8)
          | (((int) data[i + 2]) & 0x0ff);

      sb.append(CHARS[(d >> 18) & 63]);
      sb.append(CHARS[(d >> 12) & 63]);
      sb.append(CHARS[(d >> 6) & 63]);
      sb.append(CHARS[d & 63]);

      i += 3;

      if (n++ >= 14) {
        n = 0;
        if (wrapLines) {
          sb.append("\r\n");
        }
      }
    }

    if (i == length - 2) {
      int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8);
      sb.append(CHARS[(d >> 18) & 63]);
      sb.append(CHARS[(d >> 12) & 63]);
      sb.append(CHARS[(d >> 6) & 63]);
      sb.append("=");
    } else if (i == length - 1) {
      int d = (((int) data[i]) & 0x0ff) << 16;

      sb.append(CHARS[(d >> 18) & 63]);
      sb.append(CHARS[(d >> 12) & 63]);
      sb.append("==");
    }

    return sb.toString();
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 上的 XML SOAP 签名 的相关文章

随机推荐

  • 幂律与其他分布的比较

    我正在使用 Jeff Alstott 的 Python powerlaw 包来尝试使我的数据符合幂律 Jeff 的软件包基于 Clauset 等人讨论幂律的论文 首先 我的数据的一些详细信息 它是离散的 字数数据 它严重向左倾斜 高偏度 I
  • 如何在不阅读的情况下获取文件中的行数[重复]

    这个问题在这里已经有答案了 可能的重复 如何快速统计行数 https stackoverflow com questions 6101367 how to count lines fast 我有一些文件逐行包含数据 我想获取文件中的行数以向
  • 通过比较 2 个列表/行的相似度进行图像旋转匹配 OpenCV Python

    我拿一个模板 并从中抽取 8 个点 现在为 36 个 每个小点都是一个掩模 我从那个小点区域中取平均值 然后将它们添加到列表中 它最终看起来像这样 203 176 160 174 185 185 152 136 131 131 131 13
  • 在 Groovy 中计算赋值表达式

    我有这样的表达 def expr anything something 就我而言 上面的字符串来自网络服务 但它可能来自任何地方 我想对此进行评估 以便最终得到具有 某物 值的变量 anything 这样 assert anything s
  • 为什么克隆的存储库比获取的存储库大 10 倍?

    我们有一个远程仓库 其大小已经爆炸 1 4G 到 14G 我们正在尝试找出此存储库大小增加的原因并解决问题 在这个过程中我们注意到 git clone 和 git fetch 之间的显着差异 如果我们克隆仓库 克隆的仓库也是 14G git
  • 发布 Google Apps 脚本库

    我对如何发布新库有点困惑 我为 Google Apps 脚本创建了一个我认为非常酷且有用的库 google api client https docs google com macros library versions d M5CBUAH
  • 在缩放模式 Picturebox 中平移矩形位置会导致负 Y 坐标

    我正在使用以下类参考 在缩放模式 Picturebox 中平移矩形位置 https stackoverflow com questions 53800328 translate rectangle position in zoom mode
  • 如何在 Angular 2 中正确从 http.get 中提取 JSON 数据?

    我似乎无法使用 json 文件中的信息为视图创建一个变量 但我已经很接近了 我可以回显中的信息 subscribe chain 但它不会将其设置为变量 它们只是未定义 我做错了什么 我只想将 json 文件加载到组件视图中的变量中 在 An
  • Maven 组装子模块多模块

    您好 我需要从主目录中的多模块项目中组装 jar 让我们有一个这样的结构 MASTER pom A3 pom A1 jar A2 jar B3 pom B1 jar B2 jar 我想要实现的是将MASTER中的所有jar包模块进行组装 j
  • 使用“new”实例化时到底发生了什么?

    让我们考虑以下代码 class a public var1 function disp echo this gt var1 obj1 new a echo br After instantiation into obj1 br xdebug
  • 使用 Espresso 单击 RecyclerView 项目内的视图

    如何使用 Espresso 单击某个视图中的特定视图回收视图物品 我知道我可以使用以下命令单击位置 0 处的项目 onView withId R id recyclerView perform RecyclerViewActions act
  • 如何使用 Perl 在文件中查找扩展 ASCII 字符?

    如何使用 Perl 在文件中查找扩展 ASCII 字符 谁能拿到剧本吗 提前致谢 自从延长ASCII http en wikipedia org wiki ASCII角色有价值128 及以上 http www asciitable com
  • 如何使用 jar 打包将 React webapp 集成到 Spring Boot 应用程序中

    我们正在开发一个 React Web 应用程序和一个 Spring Boot 应用程序 使用 Maven 构建 React 应用程序 在 npm 上 和启动应用程序是单独运行的 但现在是时候将它们集成起来并将其放入 QA staging 中
  • 为什么仍然可以插入不存在的外键?

    mysql gt create table products id integer unsigned auto increment primary key Query OK 0 rows affected 0 05 sec mysql gt
  • Electron 应用程序名称不变

    我正在使用电子打包器打包我的应用程序 但没有更改其名称 并且仍然显示 Electron 它应该使用productName in my package json但它没有改变 即使我制作了安装程序 安装的应用程序的名称 快捷方式和进程仍然是El
  • Android 2.2 wifi热点API

    我需要在 Android 2 2 Froyo 中进行什么 API 调用来创建 Wifi 热点 如网络共享和便携式热点设置项中所示 您可以致电 private boolean setWifiApEnabled WifiConfiguratio
  • 如果屏幕锁定,单击暂停按钮时 avplayer 不会暂停

    如果应用程序正在播放音频并且手机屏幕被锁定 则控制屏幕如下所示 我无法对 avplayer 执行任何操作 在我的应用程序委托中 我实现了 BOOL application UIApplication application didFinis
  • 无法正确 memcpy 一个 char 数组来构造

    所以我有一个称为数据包的构造 struct Packet unsigned int packet type wchar t packet length 128 wchar t file name 256 wchar t template n
  • Scala 中 NonFatal 和 Exception 的区别

    In 本文 https tersesystems com 2012 12 27 error handling in scala 据说 如果你想捕捉通常发生的 一切 那么使用 非致命 import scala util control Non
  • Android 上的 XML SOAP 签名

    我需要在 Android 应用程序中签署 XML SOAP 请求 我做了一些研究 似乎没有框架可以在 Android 上做到这一点 有人设法做到这一点吗 经过几周的尝试和测试 我终于成功地在 Android 上进行了手动 XML 签名 这是