使用公钥验证签名

曼努埃尔·勒杜克(Manuel Leduc):

我有一个外部服务,在定义的事件发生后会给我回电,并用其私钥签署他的请求。

我已经存储了如下公钥:

-----BEGIN PUBLIC KEY-----
........................................
-----END PUBLIC KEY-----

因此,我的工作是通过验证签名来检查请求的内容是否未更改。

这是我的算法:

// 1 - reading public key :
Scanner scanner = new Scanner( new File( keyPath ) );


//            encodedPublicKey.toString( );
StringBuilder sb = new StringBuilder( );
while ( scanner.hasNextLine( ) )
{
    sb.append( scanner.nextLine( ) );
    sb.append( '\n' );
}

byte[] encodedPublicKey = sb.toString( ).getBytes( "utf-8" );

// 2 - loading public key in a relevant object :
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( publicKeyBytes );

KeyFactory keyFactory = KeyFactory.getInstance( "DSA" );

PublicKey publicKey = keyFactory.generatePublic( publicKeySpec );

// 3 - verifying content with signature and content :
Signature sig = Signature.getInstance( "SHA1withDSA" );
sig.initVerify( publicKey );
sig.update( message.getBytes( ) );
ret = sig.verify( sign.getBytes( ) );

但是目前,我的算法已停止在此消息的“ PublicKey publicKey = keyFactory.generatePublic(publicKeySpec)”步骤处:

java.security.spec.InvalidKeySpecException: Inappropriate key specification: invalid key format

那么,如何以java api接受的方式加载密钥?

曼努埃尔·勒杜克(Manuel Leduc):

其实我已经找到了解决方案。

问题在于以正确的方式加载公钥文件。

我将bouncycastle库添加到我的依赖项中:

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.47</version>
</dependency>

它提供了PemReader,它允许读取和加载未认证的公共密钥。

这是我的实用程序类:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import org.bouncycastle.util.io.pem.PemReader;
import org.castor.util.Base64Decoder;

import fr.paris.lutece.portal.service.util.AppLogService;


/**
 * Classe d'aide à l'interfacage avec le service paybox.
 *
 * Toutes les informations parameterables sont sous la forme paybox.*
 */
public final class PayboxUtil
{

    /** The Constant CHARSET. */
    private static final String CHARSET = "utf-8";

    /** The Constant ENCRYPTION_ALGORITHM. */
    private static final String ENCRYPTION_ALGORITHM = "RSA";

    /** The Constant HASH_ENCRIPTION_ALGORITHM. */
    private static final String HASH_ENCRYPTION_ALGORITHM = "SHA1withRSA";

    /**
     * constructeur privé pour classe statique.
     */
    private PayboxUtil(  )
    {
    }

    /**
     * Controle si une signature est bien celle du message à l'aide de la clé
     * publique de l'emmeteur?.
     *
     * @param message le message
     * @param sign la signature
     * @param keyPath le chemin vers la clé publique.
     * @return true si la signature est bien celle du message avec la clé privé
     *         attendue.
     */
    public static boolean checkSign( String message, String sign, String keyPath )
    {
        boolean ret = false;

        try
        {
            ret = PayboxUtil.verify( message, sign, PayboxUtil.getKey( keyPath ) );
        }
        catch ( final FileNotFoundException e )
        {
            AppLogService.error( e );
        }
        catch ( final IOException e )
        {
            AppLogService.error( e );
        }
        catch ( final NoSuchAlgorithmException e )
        {
            AppLogService.error( e );
        }
        catch ( final InvalidKeySpecException e )
        {
            AppLogService.error( e );
        }
        catch ( final InvalidKeyException e )
        {
            AppLogService.error( e );
        }
        catch ( final SignatureException e )
        {
            AppLogService.error( e );
        }

        return ret;
    }


    /**
     * Récupère la clé publique à partir du chemin passé en paramètre.
     *
     * @param keyPath le chemin vers la clé.
     * @return la clé publique
     * @throws NoSuchAlgorithmException the no such algorithm exception
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws InvalidKeySpecException the invalid key spec exception
     */
    private static PublicKey getKey( String keyPath )
        throws NoSuchAlgorithmException, IOException, InvalidKeySpecException
    {
        final KeyFactory keyFactory = KeyFactory.getInstance( PayboxUtil.ENCRYPTION_ALGORITHM );
        final PemReader reader = new PemReader( new FileReader( keyPath ) );
        final byte[] pubKey = reader.readPemObject(  ).getContent(  );
        final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( pubKey );

        return keyFactory.generatePublic( publicKeySpec );
    }

    /**
     * effectue la vérification du message en fonction de la signature et de la
     * clé.
     *
     * @param message le message
     * @param sign la signature
     * @param publicKey la clé publique.
     * @return true, if successful
     * @throws NoSuchAlgorithmException the no such algorithm exception
     * @throws InvalidKeyException the invalid key exception
     * @throws SignatureException the signature exception
     * @throws UnsupportedEncodingException the unsupported encoding exception
     */
    private static boolean verify( String message, String sign, PublicKey publicKey )
        throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException
    {
        final Signature sig = Signature.getInstance( PayboxUtil.HASH_ENCRYPTION_ALGORITHM );
        sig.initVerify( publicKey );
        sig.update( message.getBytes( PayboxUtil.CHARSET ) );

        final byte[] bytes = Base64Decoder.decode( URLDecoder.decode( sign, PayboxUtil.CHARSET ) );

        return sig.verify( bytes );
    }
}

您只需要将签名内容,签名和密钥路径传递给checkSign方法即可完成所有工作。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用公钥验证端点签名JWT

使用公钥节点验证签名

仅使用公钥验证签名(C#)

使用.pem格式的公钥在Xcode中进行签名验证

Java使用公钥验证xml数字签名

验证公钥与私钥签名是否匹配

尽管使用了正确的公钥和签名文件,但未验证签名

ECDSA使用Java的公钥和签名在C#中验证签名

当我使用gpg验证签名的文档时,它如何知道要使用的公钥?

公钥可以用于解密(验证)使用私钥加密(签名)的文档吗?

Golang:验证x509证书是否使用与指定公钥相对应的私钥签名

使用C#中的公钥验证用RS256算法签名的JWT

如何使用x509公钥来验证已签名/已哈希的Alexa请求正文?

验证 JWT.io 签名 OneLogin ID Token 时使用什么公钥

在Apache Nifi中使用公钥进行RSA数字签名验证

如何使用Google的公钥手动验证JWT的签名?

无法验证签名,因为公钥不可用

如何验证给定哈希和公钥的数字签名?

带有公钥的Microsoft Graph AccessToken签名验证

如何针对特定的公钥验证gpg签名的文件?

如何使用公钥验证 ECDSA?

如何使用 rsa 公钥验证文件

验证Veracrypt的公钥

如何使用我的https公钥证书对消息签名?

使用公钥令牌签名DLL程序集

无法验证内核签名“ gpg:无法检查签名:未找到公钥”

iTextSharp中的Pades LTV验证抛出公钥,该公钥不提供用于根CA证书的证书签名

如何使用公钥在本地验证Keycloak访问令牌

Node JS JWT使用Google的公钥验证令牌