Files
guoju0808/refer/bindingdemo(1).txt
T
2026-08-29 17:52:05 +08:00

148 lines
5.2 KiB
Plaintext

package com.bidding.supplier.security.openapi;
import com.alibaba.fastjson2.JSON;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* Supplier account API codec delivered to the customer for payload decryption
* and BCrypt password verification.
*/
public class BiddingSupplierAccountApiCodec
{
private static final String PROTOCOL = "BSA";
private static final String VERSION = "v1";
private static final int IV_LENGTH = 12;
private static final int GCM_TAG_BITS = 128;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final BCryptPasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
private final String keyId;
private final String prefix;
private final byte[] aesKey;
public BiddingSupplierAccountApiCodec(String keyId, String aesKeyBase64)
{
if (keyId == null || !keyId.matches("^[A-Za-z0-9_-]{1,32}$"))
{
throw new IllegalArgumentException("Invalid supplier account API key id");
}
try
{
this.aesKey = Base64.getDecoder().decode(aesKeyBase64 == null ? "" : aesKeyBase64.trim());
}
catch (IllegalArgumentException exception)
{
throw new IllegalArgumentException("Invalid supplier account API AES key", exception);
}
if (aesKey.length != 32)
{
throw new IllegalArgumentException("Supplier account API AES key must be 32 bytes");
}
this.keyId = keyId;
this.prefix = PROTOCOL + "." + VERSION + "." + keyId + ".";
}
public String decryptPayload(String payload)
{
try
{
String[] parts = parsePayload(payload);
byte[] iv = Base64.getUrlDecoder().decode(parts[3]);
byte[] ciphertextAndTag = Base64.getUrlDecoder().decode(parts[4]);
if (iv.length != IV_LENGTH || ciphertextAndTag.length <= GCM_TAG_BITS / 8)
{
throw new IllegalArgumentException("Invalid supplier account API payload");
}
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(aesKey, "AES"),
new GCMParameterSpec(GCM_TAG_BITS, iv));
return new String(cipher.doFinal(ciphertextAndTag), StandardCharsets.UTF_8);
}
catch (IllegalArgumentException exception)
{
throw exception;
}
catch (Exception exception)
{
throw new IllegalArgumentException("Unable to decrypt supplier account API payload", exception);
}
}
public <T> T decryptPayload(String payload, Class<T> targetType)
{
if (targetType == null)
{
throw new IllegalArgumentException("Target type is required");
}
return JSON.parseObject(decryptPayload(payload), targetType);
}
/**
* Generate a BCrypt hash for a new or changed customer-platform password.
*/
public String encodePassword(String rawPassword)
{
if (rawPassword == null)
{
throw new IllegalArgumentException("Raw password is required");
}
return PASSWORD_ENCODER.encode(rawPassword);
}
public boolean matchesPassword(String rawPassword, String bcryptPasswordHash)
{
if (rawPassword == null || bcryptPasswordHash == null || bcryptPasswordHash.isBlank())
{
return false;
}
try
{
return PASSWORD_ENCODER.matches(rawPassword, bcryptPasswordHash);
}
catch (IllegalArgumentException exception)
{
return false;
}
}
String encryptPayload(Object payload)
{
try
{
byte[] iv = new byte[IV_LENGTH];
SECURE_RANDOM.nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(aesKey, "AES"),
new GCMParameterSpec(GCM_TAG_BITS, iv));
byte[] ciphertextAndTag = cipher.doFinal(JSON.toJSONBytes(payload));
Base64.Encoder encoder = Base64.getUrlEncoder().withoutPadding();
return prefix + encoder.encodeToString(iv) + "." + encoder.encodeToString(ciphertextAndTag);
}
catch (Exception exception)
{
throw new IllegalStateException("Unable to encrypt supplier account API payload", exception);
}
}
private String[] parsePayload(String payload)
{
if (payload == null || !payload.startsWith(prefix))
{
throw new IllegalArgumentException("Invalid supplier account API payload");
}
String[] parts = payload.split("\\.", 5);
if (parts.length != 5 || !PROTOCOL.equals(parts[0]) || !VERSION.equals(parts[1])
|| !keyId.equals(parts[2]))
{
throw new IllegalArgumentException("Invalid supplier account API payload");
}
return parts;
}
}