PHP與JAVA的簽名與驗籤比較

  最近在做一個項目,由於我們的開發語言是php,業務方的語言是java,進行簽名和驗籤時兩邊需要保持一致,這就要求兩邊的簽名和驗籤方法完全相同,摸索了一天,總算是明白兩種開發語言在該知識點上的不同之處。
  
1 PHP簽名與驗籤
  首先直接上php代碼,代碼已經經過驗證,可以直接運行,如下:

<?php
class RsaUtil {
    /**
     * 獲取簽名
     * @param string $strData 加密數據
     * @param string $privateKey 私鑰
     * @return string $signature 簽名
     */
    static function sign($strData, $privateKey) {
        if (!openssl_get_privatekey($privateKey)) {
            echo 'encryptTaiping openssl_get_privatekey failed.';
            return false;
        }
        $signature = '';
        if (!openssl_sign($strData, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
            echo 'openssl_sign failed.';
            return false;
        }
        $signature = base64_encode($signature);
        return $signature;
    }

    /**
     *
     * RSA驗籤
     * @param string $strData 驗籤數據
     * @param string $signature 簽名
     * @return boolean true-成功 false-失敗
     */
    static function verify($strData, $signature, $publicKey) {
        if (!openssl_get_publickey($publicKey)) {
            echo 'verifyTaiping openssl_get_publickey failed.';
            return false;
        }
        $base64Signature = base64_decode($signature);
        if (!openssl_verify($strData, $base64Signature, $publicKey, OPENSSL_ALGO_SHA256)) {
            echo 'openssl_verify failed.';
            return false;
        }
        return true;
    }
}

$privateKey = '-----BEGIN RSA PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJXlLTA3tgArTApBu
KO9W8oIZq2p8AnZkx/6/2OCD/KMMRk7oUwev820ePBeT3J1IsKNsmgWLqsJ07J0SM
h/aVy7HBX6KPxueCilxa8yPFCdB0ZcLogFhN+2Rt6U0xGzRQ6WithR0XWZ6/aw4MX
xoioUzdkFGoExrsC/bTBLcWW3AgMBAAECgYAxVtJdALmDrLzG04M3QmkoQ0Oo/jro
wxlOeYv+8RzWtZaju6EIMUbpKvJ0DFcSUcQzTfjfkg2idwWbw/MBLA891mNO2P2qq
nKEq2leHlQN3PwH216nYfJ/24qiIi3lv1D9/H3QZ+qvq0e6m2gQMSbrAygPN3eNTY
3NUj6tqT2foQJBAPak9EiVZJ4wzD4KHGaC9rKWIst2j3Db5JBH2jsf73GI2yQcrZw
ceIR0mGREDxRA5VQkPw+YV63378ExwWSzgOsCQQCblLzRkIL5LtR6jb9rktoFqqlK
3K3nqTJs7sNCxZmgc14/EkGd42sLyi3kJhgdPHpqU9gmIZnoaAgCUIKyZFtlAkB9k
DSczxFOR2FzJAqZVYrqF+zW0CDuP8P4f9vlxbhMgHOvyrnHg+cG56S9Rri2guM9Fs
bT1aatdk+kdwQRlCDJAkA7WdViOLfOKXBDRFnWxtHHQaCNf3wUGPa0ma0BhvIhRIG
am/NOMRiACePR2jpuxMiKUWvut/jHsRAFGgOR3DkFAkAX6tPWaLK7vUPoydjX97y0
N5bPEaAyKhRn/U4IzoH8wgkbNQ+ktxZ8FLP5cUJOOlBtoCePbk52UexV4TqpZK++
-----END RSA PRIVATE KEY-----';
$publicKey = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCV5S0wN7YAK0wKQbijvVvKCGatqf
AJ2ZMf+v9jgg/yjDEZO6FMHr/NtHjwXk9ydSLCjbJoFi6rCdOydEjIf2lcuxwV+ij8
bngopcWvMjxQnQdGXC6IBYTftkbelNMRs0UOlorYUdF1mev2sODF8aIqFM3ZBRqBMa
7Av20wS3FltwIDAQAB
-----END PUBLIC KEY-----';

$textData = 'hello world!';
$strSignature = RsaUtil::sign($textData, $privateKey);
echo '簽名:' . $strSignature . "\n";
$bolVerify = RsaUtil::verify($textData, $strSignature, $publicKey);
echo '驗籤:' . $bolVerify . "\n";

  輸出結果爲:
  這裏寫圖片描述
  
2 JAVA簽名與驗籤
  下面在上java代碼前,有個小問題需要說明一下,java程序中需要包含base64的jar庫,該庫可以在該地址下載:http://download.csdn.net/download/yx0628/5842065,具體導入jar庫的方法,網上很多,我就不多介紹了,下面直接上代碼:

import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import it.sauronsoftware.base64.Base64;

public class RsaUtil {
    //RSA簽名 
    //text:待簽名的數據,privateKeyData:第三方的私鑰
    private static byte[] sign(final byte[] text, final byte[] privateKeyData) throws GeneralSecurityException {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyData);
        KeyFactory keyFactory       = KeyFactory.getInstance("RSA");
        PrivateKey privateKey       = keyFactory.generatePrivate(keySpec);
        Signature signatureChecker  = Signature.getInstance("SHA256WITHRSA");
        signatureChecker.initSign(privateKey);
        signatureChecker.update(text);
        return signatureChecker.sign();
    }

    //RSA驗簽名檢查 
    //text:待簽名數據,signedText:簽名值,publicKeyData:開發商公鑰
    private static boolean verify(final byte[] text, final byte[] signedText, final byte[] publicKeyData) throws GeneralSecurityException {
        X509EncodedKeySpec keySpec  = new X509EncodedKeySpec(publicKeyData);
        KeyFactory keyFactory       = KeyFactory.getInstance("RSA");
        PublicKey publicKey         = keyFactory.generatePublic(keySpec);
        Signature signatureChecker  = Signature.getInstance("SHA256WITHRSA");
        signatureChecker.initVerify(publicKey);
        signatureChecker.update(text);
        return signatureChecker.verify(signedText);
    }

    public static void main(String args[]) throws GeneralSecurityException, RuntimeException {
        String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJXlLTA3tgArTApBuKO9W8oIZq2p8AnZkx/6/2OCD/KMMRk7oUwev820ePBeT3J1IsKNsmgWLqsJ07J0SMh/aVy7HBX6KPxueCilxa8yPFCdB0ZcLogFhN+2Rt6U0xGzRQ6WithR0XWZ6/aw4MXxoioUzdkFGoExrsC/bTBLcWW3AgMBAAECgYAxVtJdALmDrLzG04M3QmkoQ0Oo/jrowxlOeYv+8RzWtZaju6EIMUbpKvJ0DFcSUcQzTfjfkg2idwWbw/MBLA891mNO2P2qqnKEq2leHlQN3PwH216nYfJ/24qiIi3lv1D9/H3QZ+qvq0e6m2gQMSbrAygPN3eNTY3NUj6tqT2foQJBAPak9EiVZJ4wzD4KHGaC9rKWIst2j3Db5JBH2jsf73GI2yQcrZwceIR0mGREDxRA5VQkPw+YV63378ExwWSzgOsCQQCblLzRkIL5LtR6jb9rktoFqqlK3K3nqTJs7sNCxZmgc14/EkGd42sLyi3kJhgdPHpqU9gmIZnoaAgCUIKyZFtlAkB9kDSczxFOR2FzJAqZVYrqF+zW0CDuP8P4f9vlxbhMgHOvyrnHg+cG56S9Rri2guM9FsbT1aatdk+kdwQRlCDJAkA7WdViOLfOKXBDRFnWxtHHQaCNf3wUGPa0ma0BhvIhRIGam/NOMRiACePR2jpuxMiKUWvut/jHsRAFGgOR3DkFAkAX6tPWaLK7vUPoydjX97y0N5bPEaAyKhRn/U4IzoH8wgkbNQ+ktxZ8FLP5cUJOOlBtoCePbk52UexV4TqpZK++";
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCV5S0wN7YAK0wKQbijvVvKCGatqfAJ2ZMf+v9jgg/yjDEZO6FMHr/NtHjwXk9ydSLCjbJoFi6rCdOydEjIf2lcuxwV+ij8bngopcWvMjxQnQdGXC6IBYTftkbelNMRs0UOlorYUdF1mev2sODF8aIqFM3ZBRqBMa7Av20wS3FltwIDAQAB";

        String textData = "hello world!";   
        byte[] base64PrivateKey = Base64.decode(privateKey.getBytes()); 
        byte[] base64PublicKey  = Base64.decode(publicKey.getBytes()); 

        byte[] signBytes = RsaUtil.sign(textData.getBytes(), base64PrivateKey);
        String strSignature = new String(Base64.encode(signBytes));
        System.out.println("簽名:  " + strSignature);
        boolean bolVerify = verify(textData.getBytes(), signBytes, base64PublicKey);
        System.out.println("驗籤:  " + bolVerify);
    }
}

  輸出結果爲(截取部分):
  這裏寫圖片描述
  
3 比較
  兩種語言生成的簽名完全相同,但是生成簽名和驗籤的過程中,有個明顯的不同之處,即java進行簽名和驗籤前,需要將key進行Base64.decode(),這個在php中不需要(我們用php,開始業務方給我們java的簽名和驗籤示例時,看到java對key進行Base64.decode(),我以爲php也需要對key進行相同處理,結果加密和驗籤一直失敗)。然後對於簽名和驗籤的算法,php中用到的是OPENSSL_ALGO_SHA256,對應的是java中的SHA256WITHRSA,這個需要自己查閱資料才能知道哈。
  

發佈了21 篇原創文章 · 獲贊 14 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章