【问题标题】:Why JsonWebSignature with ECDH encryption algorithm give a different signature everytime?为什么带有 ECDH 加密算法的 JsonWebSignature 每次都给出不同的签名?
【发布时间】:2019-10-27 03:36:52
【问题描述】:

我想向 google FCM 发送请求以向浏览器发送推送请求以显示通知。

主要目标是使用带有 SHA256 的 ECDH 算法使用私钥对 JWT 有效负载进行签名,以获取 JWT 令牌。

我尝试使用 ECDH 算法对令牌进行签名,但每次我得到相同有效负载的不同签名。

这是我的代码的快照

提前致谢

    JwtClaims claims = new JwtClaims();
    claims.setAudience("https://fcm.googleapis.com");
    claims.setExpirationTime(NumericDate.fromSeconds(1560388318));
    claims.setSubject("mailto:admin@example.com");

    JsonWebSignature jws = new JsonWebSignature();
    jws.setHeader("typ", "JWT");
    jws.setHeader("alg", "ES256");
    jws.setPayload(claims.toJson());
    try {
        Key key = loadPrivateKey("-kmhPYsH6JKiFjG8C1cS9vx4bCz594yofAwTLa_SOEE");
        jws.setKey(key);
    } catch (NoSuchProviderException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    }
    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256);

    try {
        System.out.println(jws.getCompactSerialization());
    } catch (JoseException e) {
        e.printStackTrace();
    }

.

 public static PrivateKey loadPrivateKey(String encodedPrivateKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] decodedPrivateKey = base64Decode(encodedPrivateKey);

    // prime256v1 is NIST P-256
    ECParameterSpec params = ECNamedCurveTable.getParameterSpec("prime256v1");
    ECPrivateKeySpec prvkey = new ECPrivateKeySpec(new BigInteger(decodedPrivateKey), params);
    KeyFactory kf = KeyFactory.getInstance("ECDH");

    return kf.generatePrivate(prvkey);
   }

.

public static byte[] base64Decode(String base64Encoded) {
    if (base64Encoded.contains("+") || base64Encoded.contains("/")) {
        return BaseEncoding.base64().decode(base64Encoded);
    } else {
        return BaseEncoding.base64Url().decode(base64Encoded);
    }
}

我第一次尝试:

eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTU2MDM4ODMxOCwic3ViIjoibWFpbHRvOmFkbWluQGV4YW1wbGUuY29tIn0.MpGc0pKvXtDb94Ruq5lkQjqCqxFMkVAwzVervnH90RLArvGHUAZ_kO4VcecLhGfIXTCitBKb5M-EKsYR35IT0A P>

第二次获得:

eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTU2MDM4ODMxOCwic3ViIjoibWFpbHRvOmFkbWluQGV4YW1wbGUuY29tIn0.qEW0ci1BnXXUUjkfsQkdReznAyIDEPtygxV3B58Sl8v_gTlh8O4HHGzRtxsqdvL5UIJV06e_UJHYPOUDK_MF9A P>

【问题讨论】:

  • 您根本没有使用ECDH,您使用的是ECDSA,它是签名而不是加密。这些都是椭圆曲线算法,但它们是完全不同的算法。但是,它们确实使用相同的 keys(实际上是密钥对),这就是您的 KeyFactory for ECDH 起作用的原因。

标签: java push-notification jwt progressive-web-apps ecdh


【解决方案1】:

根据设计,数字加密签名应仅满足以下条件

应该可以通过相应的公钥进行验证。

如果您查看 Signature Generation algorithm 步骤 3,它会显示 Select a cryptographically secure random integer k from [1,n-1]. ,其中 n 是曲线的顺序(您现在可以忽略这个事实)。

然后计算(x1, y1) = k * G,其中G是椭圆曲线的生成点。然后,r = x1 mod n。这个 r 是签名的一部分。因此,通过更改kr 也会更改,因此签名会更改。

因此,对于每次签名生成,算法都会选择不同的参数,然后使用 is 来计算签名。 例如:

>>> from ecc import curves
>>> curve = curves.P256()
>>> pkey =  0x00c3f7c39a9be2418cd89a732e40d648b09fa0af9e909a4fb6864910144b5cbcdf
>>> s1 = c.sign(b'Hello', pkey)
(37527198291707833181859423619289327687028014812888685671525882103189540525356,7717531609084222009133798505588038563850333231389727023073200992747312618427)
>>> s2 = c.sign(b'Hello', pkey)
(55880701658034823360120047989457771316451459626784083177171213563603884569397,88917360761747520665103257272757357544674490240888454865713640275762122369837)
>>> s1 == s2
False

每次签名都不一样。

参考:

【讨论】:

  • 但是公钥会在没有随机整数的情况下验证密文吗?这是一个愚蠢的问题,但我们可以在没有随机整数的情况下做到这一点吗?在此先感谢队友
  • @Ridae:ECDSA(或 DSA)的随机 k 被有效地编码在验证者使用的签名的 r 部分中。如果您生成具有固定或重复 k 的 ECDSA(或 DSA)签名,他们将进行验证,但任何在不同数据上看到两个此类签名的对手都可以计算您的私钥,然后在他们想要的任何数据上伪造“您的”签名,这使得您的签名完全一文不值。这是比特币中的一个问题,其中一些错误导致重复-k签名,人们损失了很多钱。对于 多个 Qs,请参阅 crypto.SX security.SX bitcoin.SX 。
  • 是的,这就是整个想法..您不需要知道随机数..您只需要验证计算序列是否有效。你可以参考“ECDSA 和一个小证明”文章来了解验证是如何工作的。如果你对 ecc 内部没有一些经验,这有点过分了。但你可以感受一下。而且,就像其他人说的那样,您不应该使用可预测的随机数,因为.. 具有相同的 k 可能会泄漏私钥.. 参考文献中提到的该文档也有关于它将如何泄漏私钥的证据。
【解决方案2】:

ECDH 加密算法使用不同的安全随机数来计算每个签名生成的签名。 您可以指定此 Secure Random 以每次都获得相同的签名。 对于您的情况:

ProviderContext context = new ProviderContext();
context.setSecureRandom(new SecureRandom(SecureRandom.getSeed(0)));
jws.setProviderContext(context);

【讨论】:

  • s/ECDH 加密/ECDSA 签名/ 这将导致您的私钥被任何对手破解。
猜你喜欢
  • 2020-10-14
  • 2020-08-24
  • 2023-01-24
  • 2018-05-02
  • 2017-05-06
  • 1970-01-01
  • 2021-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多