iT邦幫忙

0

求救 統一金流API加解密 JAVA

  • 分享至 

  • xImage

求救
https://www.payuni.com.tw/docs/web/#/7/29

求救JAVA加解密範例 aes-256-gcm
壓出來始終跟範例不一樣
求高手指導

淺水員 iT邦大師 6 級 ‧ 2023-07-26 14:10:49 檢舉
我看錯,原來是要 java 的,但是官網只給 php
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
海綿寶寶
iT邦大神 1 級 ‧ 2023-07-26 16:17:41

Google到這篇提供參考看看
主程式不動,改改參數看看結果是否會相符

哈~AES裡面可以加自訂義字串~
版主要知道訂義字串編碼方式~
無法直接套用的~
如圖~
https://ithelp.ithome.com.tw/upload/images/20230727/200613690oxxWCI1Uu.png

0
純真的人
iT邦大師 1 級 ‧ 2023-07-26 22:52:58

這個跟我遇到藍新金流一樣~只有PHP範例~= =...
害我只好先架好PHP後~逐筆拆解每列編碼結果~(觀察二進位編碼010)
再用找網路範例(C# 轉 VB)~再去拆解逐筆AES編碼確認~
所以JAVA範例~你也要去找網路參考範例修改~

JAVA AES加解密範例
https://www.1ju.org/article/java-aes-encryption-decryption

找到解法了 我自問自答
/*

  • Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
  • Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
    */
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.util.Arrays;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    import javax.crypto.spec.GCMParameterSpec;
    import javax.crypto.spec.SecretKeySpec;

/**
*

  • @author boboboom
    */
    public class PayUni {
    public static void main(String[] args) {
    // 填入商店串接資訊
    String merID = "NPPA129180793";
    String hashKey = "12345678901234567890123456789012";// "uH9qCQ9rrv0aEgqxPBoqtcoWNLJb5Bpb";
    String hashIV = "1234567890123456";// "5lCWfCqsn81BJ3TL";

     // 建立請求參數
     Map<String, String> requestData = new HashMap<>();
     requestData.put("MerID"   , merID);
     requestData.put("Version" , "1.0");
    
     Map<String, String> data = new LinkedHashMap<>();
     data.put("MerID"      , "ABC");
     data.put("MerTradeNo" , "1658198662_93966");
     data.put("TradeAmt"   , "7017");
     data.put("Timestamp"  , "1658198662");
     data.put("ProdDesc"   , "商品說明");
     data.put("UsrMail"    , "a@presco.ws");
     data.put("ReturnURL"  , "http://lapi-epay.presco.com.tw/api/upp/return");
    
     StringBuilder sb = new StringBuilder();
     for (Map.Entry<String, String> entry : data.entrySet()) {
         sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
                 .append("&");
     }
     sb.deleteCharAt(sb.length() - 1);
    
     String encodedUrl = sb.toString();
     System.out.println("Origin:" + encodedUrl + "\r\n");
     // 產生加密字串
     String encryptInfo = encrypt(encodedUrl, hashKey, hashIV);
     System.out.println("EncryptInfo:" + encryptInfo + "\r\n");
     requestData.put("EncryptInfo", encryptInfo);
     // 產生 HashInfo
     String hashInfo = getTradeSha(encryptInfo, hashKey, hashIV);
     requestData.put("HashInfo", hashInfo);
     System.out.println("HashInfo:" + hashInfo + "\r\n");
     // 解密
     String decryptInfo = decrypt(encryptInfo, hashKey, hashIV);
     System.out.println("DecryptInfo:" + decryptInfo);
    
     getHtml(requestData);
    

    }

    public static String encrypt(String text, String key, String iv) {
    try {
    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv.getBytes(StandardCharsets.UTF_8));

         Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
         cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
         byte[] encryptedBytes = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
    
         byte[] encryptedInfo  = Arrays.copyOfRange(encryptedBytes, 0, encryptedBytes.length-16);
         byte[] tagInfo        = Arrays.copyOfRange(encryptedBytes, encryptedBytes.length-16, encryptedBytes.length);
    
         String encodeText  = Base64.getEncoder().encodeToString(encryptedInfo);
         String encodeTag   = Base64.getEncoder().encodeToString(tagInfo);
         String finalString = encodeText + ":::" + encodeTag;
         byte[] finalBytes  = finalString.getBytes(StandardCharsets.UTF_8);
         return bytesToHex(finalBytes);
     } catch (Exception e) {
         e.printStackTrace();
     }
     return null;
    

    }

    public static String decrypt(String text, String key, String iv) {
    try {
    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

         // Create SecretKeySpec
         SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
    
         // Create GCMParameterSpec
         GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv.getBytes(StandardCharsets.UTF_8));
    
         // Initialize Cipher for DECRYPT_MODE
         cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
    
         byte[] hexToByte  = hexStringToByteArray(text);
         String encryptStr = new String(hexToByte, StandardCharsets.UTF_8);
    
         String encryptInfo = encryptStr.split(":::")[0];
         byte[] encryptInfoBytes = Base64.getDecoder().decode(encryptInfo);
    
         String tagString   = encryptStr.split(":::")[1];
         byte[] tagStringBytes = Base64.getDecoder().decode(tagString);
    
         byte[] encryptData = new byte[encryptInfoBytes.length + tagStringBytes.length];
         System.arraycopy(encryptInfoBytes, 0, encryptData, 0, encryptInfoBytes.length);
         System.arraycopy(tagStringBytes, 0, encryptData, encryptInfoBytes.length, tagStringBytes.length);
    
         byte[] decodeInfo = cipher.doFinal(encryptData);
         String decodeInfoString = new String(decodeInfo, StandardCharsets.UTF_8);
         return decodeInfoString;
     } catch (Exception e) {
         e.printStackTrace();
     }
     return null;
    

    }
    public static byte[] hexStringToByteArray(String hex) {
    int len = hex.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
    data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
    + Character.digit(hex.charAt(i + 1), 16));
    }
    return data;
    }
    private static String bytesToHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
    sb.append(String.format("%02x", b));
    }
    return sb.toString();
    }

    public static String getTradeSha(String data, String key, String iv) {
    String sha256 = encrySha256(key + data + iv);
    return sha256.trim();
    }

    public static String encrySha256(String value) {
    try {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(value.getBytes());
    byte byteBuffer[] = messageDigest.digest();
    StringBuffer strHexString = new StringBuffer();
    for (int i = 0; i < byteBuffer.length; i++) {
    String hex = Integer.toHexString(0xff & byteBuffer[i]);
    if (hex.length() == 1) {
    strHexString.append('0');
    }
    strHexString.append(hex);
    }
    return strHexString.toString().toUpperCase();
    } catch (Exception e) {

     }
     return null;
    

    }

    public static String getHtml(Map<String, String> data) {
    StringBuilder sb = new StringBuilder();
    sb.append("<form id="Unipay" action="https://api.payuni.com.tw/api/upp" method="post">");
    for (Map.Entry<String, String> entry : data.entrySet()) {
    String keyA = entry.getKey();
    String valueA = entry.getValue();
    sb.append("<input type="hidden"name="" + keyA + "" value="" + valueA + "">");
    }
    sb.append("<script language="JavaScript">Unipay.submit()");
    sb.append("");

     try {
         BufferedWriter writer = new BufferedWriter(new FileWriter("payment.html"));
         writer.write(sb.toString());
         writer.close();
         System.out.println("payment.html file generated successfully.");
     } catch (IOException e) {
         e.printStackTrace();
     }
    
     return sb.toString();
    

    }
    }

恩~問題解決就好唷~加油!

我要發表回答

立即登入回答