【问题标题】:Convert a clientsecret into a private key将 clientsecret 转换为私钥
【发布时间】:2013-02-26 08:24:24
【问题描述】:

我正在使用 AppEngine 中的 Google Cloud Storage,并尝试使用 POST 表单将文件上传到 GCS。我遇到的问题是签署政策文件所需的步骤。我可以轻松地获取 client_secret,它是来自 API 控制台给我的 client_secrets.json 的字符串。但是,为了创建签名,我需要将该字符串转换为 PrivateKey 对象。这是我的代码的样子:

//create the policy document and encode it
String policyDocument = ...  //omitted for brevity
String encodedPolicy = Base64.encodeString(policyDocument);

//sign using SHA256 with RSA
String secretKey = ... //I fetch this from client_secrets.json
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(secretKey); //THIS IS THE PROBLEM!  
sig.update(encodedPolicy.getBytes("UTF-8"));        
String signature = new String(Base64.encode(sig.sign()));

//put the values in the request attributes so we can fetch them from a JSP
req.setAttribute("policy", encodedPolicy);
req.setAttribute("signature", signature);

如上所述,我的问题出在一行

sig.initSign(secretKey); //THIS IS THE PROBLEM!  

secretKey 是一个字符串。 Signature.initSign() 需要 PrivateKey 或其后代对象之一。如何将 client_secrets.json 中的字符串转换为可以传递 Signature.initSign 的 PrivateKey(或派生)对象?

任何帮助将不胜感激。谢谢

好的,这就是我现在的位置。我尝试了以下建议,所有文档都敦促我使用从 Google API 控制台下载的 client_secrets.json 文件中的 client_secret,不是服务帐户。此外,我正在尝试构建用户上传的示例,而不是服务帐户。

我在另一个页面上找到了以下代码:

public static String signPolicyDocument(String policyDocument, String secret) {     
try {
        Mac mac = Mac.getInstance("HmacSHA256");
        byte[] secretBytes = secret.getBytes();
        SecretKeySpec signingKey = new SecretKeySpec(secretBytes, "HmacSHA256");
        mac.init(signingKey);
        byte[] signedSecretBytes = mac.doFinal(policyDocument.getBytes());          
        return new String(Base64.encode(signedSecretBytes));
    } catch (InvalidKeyException e) {
        throw new RuntimeException(e);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }

它让我完成了整个过程......直到我提交结果表格。然后我得到以下回复:

The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

它在寻找什么签名方法?

【问题讨论】:

  • 您在使用 App Engine 吗?这个问题没有提到它,但它被标记为这样。
  • 我在 AppEngine 工作。我编辑了 OP 以反映这一事实。

标签: google-app-engine sha256 google-cloud-storage


【解决方案1】:

这是我认为你需要做的:

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
sig.initSign(privateKey);

keyBytes 变量应该包含一个带有 service account key file in itbyte[] 数组。

【讨论】:

  • 感谢您的回复。我发现了几个问题。首先:Google App Engine 的 Java 运行时环境不支持 sun.misc.BASE64Decoder。所以我试图用这个替换它:byte[] encodedKey = Base64.decode(key64);
  • 那没用;它抛出“Base64 编码数据中的非法字符”。所以我省略了解码步骤;我只是将密钥直接传递到密钥规范中。结果是 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : Detect early EOF
  • 你是对的,你应该使用Base64.decode。您是否在使用 client_secrets.json 的“client_secret”字段?它应该是有效的 base64。
  • 是的,我正在使用来自 client_secrets.json 的 client_secret。在调试窗口中,我验证了我从 json 中提取的 client_secret 与 Google API 控制台上的客户端密码完全匹配。当我传入 client_secret 时,它 Base64.decode 仍然会引发异常。
  • 为了确保,我生成了一个新的秘密并更新了 client_secrets.json。现在,Base64.decode 无异常执行,我可以将结果传递给 keySpec。但是当我到达keyFactory.generatePrivate(keySpec); 时出现以下错误:java.security.InvalidKeyException: IOException : Detect premature EOF
【解决方案2】:

这个问题的最终答案就像战争游戏的结论一样。正如 WOPR 所说,“一场奇怪的比赛……获胜的唯一方法就是不玩。”避免签署和政策文档以及所有废话,并使用 blobstore。

(见:https://developers.google.com/appengine/docs/java/blobstore/overview#using-blobstore-with-gcs

很容易实现;当您像这样创建临时 blobstore 上传 URL 时:

    //open the blobstore service and create the upload url
    BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();        
    String uploadUrl = bs.createUploadUrl("/display",
            UploadOptions.Builder.withGoogleStorageBucketName(bucket));

这种方法的缺点是对象名称将是您无法识别的字符串。您可以打开 blobstore 查看器并在 blobstore 中按文件名查看您的对象,但在 GCS 中,其对象名称将是 gobbledygook。 (可能是哈希?随机分配的 ID)?

【讨论】:

  • 如果有一种方法可以在您的代码中指定将对象保存到 GCS 时使用哪个对象名称,那么这种方法的完美之处就在于。有人知道怎么做吗?
  • 仍在完善这种方法。我发现的一个可能的解决方案是这样做:
  • 仍在完善这种方法。我找到的一个可能的解决方案是 1. 上传文件 2. 捕获 gobbledygook 文件名 3. 将 gobbledygook 文件名复制到您想要的任何文件名 4. 删除具有 gobbledygook 名称的文件 要制作副本,您要做的是发出 PUT添加了 x-goog-copy-source 标头的请求:developers.google.com/storage/docs/reference-headers#xgoogcopy
  • 你现在可能已经知道了,但是为了后代,你可以在上传处理程序中获取一个 FileInfo 对象,它上面有 gs_object_name...developers.google.com/appengine/docs/python/blobstore/…
【解决方案3】:

要将文件从 Appengine 上传到 GCS,您可以使用 blobstore Api。按照Using Blobstore with GCS 中描述的步骤操作。优点是不用担心按键,代码也简单很多。

【讨论】:

    猜你喜欢
    • 2013-07-17
    • 2012-01-07
    • 2011-10-22
    • 2023-03-20
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 2014-11-25
    • 2013-06-22
    相关资源
    最近更新 更多