【问题标题】:How to use OpenSSL to extend {D,E,N} RSA key to {D,E,N,p,q,etc.}?如何使用 OpenSSL 将 {D,E,N} RSA 密钥扩展为 {D,E,N,p,q,etc.}?
【发布时间】:2012-08-07 00:10:52
【问题描述】:

我有一个 RSA 密钥,由公共和私有因素以及模数 D 组成。(我目前正在生成并使用带有 JavaScript 库的密钥。)我想使用相同的密钥来执行加密和解密OpenSSL。我可以将我的因子插入 OpenSSL RSA 密钥,一切正常,但我想让 OpenSSL 计算它使用的辅助因子(如果可用)以加快操作。

我不确定在数学上是否可以从 {D,E,N} 回溯到这些因数,但如果可以,我想知道如何让 libopenssl 去做。

谢谢!

【问题讨论】:

    标签: c++ c cryptography openssl rsa


    【解决方案1】:

    从秘密 d 推导出 pq 的算法非常简单快速,尽管是概率性的。在Chapter 8 of "Handbook of applied cryptography",第 8.2.2 节或 Boneh 的文章 "Twenty Years of Attacks on the RSA Cryptosystem",第 205 页中对其进行了非常简要的解释。

    您可以首先找到该算法在高级语言中的实现(例如,在 Python 中,检查 PyCrypto 中的函数 rsa_construct)。从那里,您可以使用其multiprecision API 通过 OpenSSL 实现它。

    【讨论】:

    • 感谢 PyCrypto 链接——它似乎完全符合我的要求(尝试从 D & N 计算 P & Q)。我只希望有一个 OpenSSL 函数:RSA_augment_key( rsa )。我想我得写了!
    • 这里是执行此操作的代码,或多或少采用 OpenSSL 格式。 (也提交给 openssl-dev。)
    【解决方案2】:
    /* crypto/rsa/rsa_aug_key.c  -*- Mode: C; c-file-style: "eay" -*- */
    /* ====================================================================
     * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer. 
     *
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in
     *    the documentation and/or other materials provided with the
     *    distribution.
     *
     * 3. All advertising materials mentioning features or use of this
     *    software must display the following acknowledgment:
     *    "This product includes software developed by the OpenSSL Project
     *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
     *
     * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     *    endorse or promote products derived from this software without
     *    prior written permission. For written permission, please contact
     *    openssl-core@OpenSSL.org.
     *
     * 5. Products derived from this software may not be called "OpenSSL"
     *    nor may "OpenSSL" appear in their names without prior written
     *    permission of the OpenSSL Project.
     *
     * 6. Redistributions of any form whatsoever must retain the following
     *    acknowledgment:
     *    "This product includes software developed by the OpenSSL Project
     *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
     *
     * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     * OF THE POSSIBILITY OF SUCH DAMAGE.
     * ====================================================================
     */
    
    #include <openssl/bn.h>
    #include <openssl/err.h>
    #include <openssl/rsa.h>
    
    /*
     * If key has d, e and n, but not p, q, dmp1, dmq1 and iqmp, try
     * to calculate these extra factors.  Return 1 on success or 0
     * on failure.  (The key may still be useable even if this fails.)
     */
    int RSA_augment_key(RSA *key)
    {
        int      spotted;
        BN_CTX  *ctx;
        BIGNUM  *ktot;
        BIGNUM  *t;
        BIGNUM  *tmp;
        BIGNUM  *a;
        BIGNUM  *two;
        BIGNUM  *l00;
        BIGNUM  *cand;
        BIGNUM  *k;
        BIGNUM  *n_1;
    
        if (!key || !key->d || !key->e || !key->n) return 0;
    
        spotted = 0;
    
        ctx    = BN_CTX_new( );
        ktot   = BN_new( );
        t      = BN_new( );
        tmp    = BN_new( );
        a      = 0; BN_dec2bn( &a,   "2" );
        two    = 0; BN_dec2bn( &two, "2" );
        l00    = 0; BN_dec2bn( &l00, "100" );
        cand   = BN_new( );
        k      = BN_new( );
        n_1    = BN_new( ); if (!BN_sub( n_1, key->n, BN_value_one( ) )) goto fail;
    
    /* Python-code comments from PyCrypto
    // ------------------------------------------------------------------
    //      # Compute factors p and q from the private exponent d.
    //      # We assume that n has no more than two factors.
    //      # See 8.2.2(i) in Handbook of Applied Cryptography.
    //      ktot = d*e-1*/
    
        if (!BN_mul( tmp, key->d, key->e, ctx ))    goto fail;
        if (!BN_sub( ktot, tmp, BN_value_one( ) ))  goto fail;
    
    /*      # The quantity d*e-1 is a multiple of phi(n), even,
    //      # and can be represented as t*2^s.
    //      t = ktot */
    
        if (!BN_copy( t, ktot ))                    goto fail;
    
    /*      while t%2==0:
    //          t=divmod(t,2)[0] */
    
        while (!BN_is_odd( t ))
            if (!BN_rshift1( t, t ))                goto fail;
    
    /*      # Cycle through all multiplicative inverses in Zn.
    //      # The algorithm is non-deterministic, but there is a 50% chance
    //      # any candidate a leads to successful factoring.
    //      # See "Digitalized Signatures and Public Key Functions as Intractable
    //      # as Factorization", M. Rabin, 1979
    //      spotted = 0
    //      a = 2
    
    //      while not spotted and a<100: */
        while (!spotted && BN_cmp( a, l00 ) < 0) {
    
    /*          k = t */
            if (!BN_copy( k, t ))                   goto fail;
    
    /*          # Cycle through all values a^{t*2^i}=a^k
    //          while k<ktot: */
            while (BN_cmp( k, ktot ) < 0) {
    
    /*              cand = pow(a,k,n) */
                if (!BN_mod_exp( cand, a, k, key->n, ctx ))         goto fail;
    
    /*              # Check if a^k is a non-trivial root of unity (mod n)
    //              if cand!=1 and cand!=(n-1) and pow(cand,2,n)==1: */
                if (BN_cmp( cand, BN_value_one( ) ) && BN_cmp( cand, n_1 )) {
                    if (!BN_mod_exp( tmp, cand, two, key->n, ctx )) goto fail;
                    if (BN_cmp( tmp, BN_value_one( )) == 0) {
    /*                  # We have found a number such that (cand-1)(cand+1)=0 (mod n).
    //                  # Either of the terms divides n.
    //                  obj.p = GCD(cand+1,n)
    //                  spotted = 1
    //                  break */
                        key->p = BN_new( );
                        if (!BN_add( tmp, cand, BN_value_one( ) ))  goto fail;
                        if (!BN_gcd( key->p, tmp, key->n, ctx ))    goto fail;
                        spotted = 1;
                        break;
                    }
                }
    
    //              k = k*2
                if (!BN_lshift1( k, k ))          goto fail;
            }
    
    /*          # This value was not any good... let's try another!
    //          a = a+2 */
            if (!BN_add( a, a, two ))               goto fail;
        }
    
        if (!spotted) {
            /* Unable to compute factors P and Q from exponent D */
            goto fail;
        }
    
        key->q = BN_new( );
        if (!BN_div( key->q, tmp, key->n, key->p, ctx ))    goto fail;
        if (!BN_is_zero( tmp )) {
            /* Curses!  Tricked with a bogus P! */
            goto fail;
        }
    
        key->dmp1 = BN_new( );
        key->dmq1 = BN_new( );
        key->iqmp = BN_new( );
    
        if (!BN_sub( tmp, key->p, BN_value_one( ) ))            goto fail;
        if (!BN_mod( key->dmp1, key->d, tmp, ctx ))             goto fail;
        if (!BN_sub( tmp, key->q, BN_value_one( ) ))            goto fail;
        if (!BN_mod( key->dmq1, key->d, tmp, ctx ))             goto fail;
        if (!BN_mod_inverse( key->iqmp, key->q, key->p, ctx ))  goto fail;
    
        if (RSA_check_key( key ) == 1)                          goto cleanup;
    
      fail:
        BN_free( key->p );     key->p = 0;
        BN_free( key->q );     key->q = 0;
        BN_free( key->dmp1 );  key->dmp1 = 0;
        BN_free( key->dmq1 );  key->dmq1 = 0;
        BN_free( key->iqmp );  key->iqmp = 0;
        spotted = 0;
    
      cleanup:
        BN_free( k );
        BN_free( cand );
    
        BN_free( n_1 );
        BN_free( l00 );
        BN_free( two );
    
        BN_free( a );
    
        BN_free( tmp );
        BN_free( t );
        BN_free( ktot );
    
        BN_CTX_free( ctx );
    
        return spotted;
    }
    

    【讨论】:

    • 注意:在 Python 中,a=b 将名称 a 绑定到名称 b 所指的任何对象。不涉及复制。内存中同一对象的两个名称。 BN_copy(a, b) 似乎不是该语义的良好近似。
    • 例如,您可以使用BN_rshift1(t, t)BN_lshift1(k, k)
    • 我不会说 Python,这是我第一次涉足 OpenSSL,所以代码可能不是最理想的。但是,BN 都是通过指针进行操作的,并且文档非常清楚,只有特定标识的操作才能有操作数作为结果。您会认为 rshift 和 lshift 会,但我认为它们不在列表中。无论如何,我预防性地使用了 BN_copy:我认为仅仅分配指针会导致内存泄漏。
    • the man page 明确表示:“对于移位函数,r 和 a 可能是同一个变量。”除了轮班操作之外,其他BN_copy() 调用似乎是合理的。
    【解决方案3】:

    难题。要从 n 中找到 pq,您需要分解 n,这很难。鉴于您知道 de,您可以改为寻找 de-1 的大因数,即 phi(n)。一旦你有了它,你就可以利用 n - phi(n) = p + q - 1 用于 RSA 密钥,从而找到 pq

    所以流程大致是:

    • 尝试在 de-1 = x phi(n) 中猜测 x。对于 RSA,正弦 e = 65537,这应该不会太糟糕 - x 必须在 50000..200000 左右的范围内,所以它应该只需要 100K 左右的试用分区。

    • 现在找到 y = (p + q)/2 = (n + phi(n) + 1)/2 和 z = sqrt(yy - n),这给了你 p = y+zq = yz

    相对简单,但没有内置的方式来使用 openssl 或我知道的任何其他库。

    【讨论】:

      猜你喜欢
      • 2014-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-03
      • 2013-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多