pebaikan decription

This commit is contained in:
2025-09-03 05:35:12 +07:00
parent bb5f3876ec
commit 1ab7687e68
3 changed files with 209 additions and 167 deletions

View File

@@ -11,6 +11,9 @@ import (
"errors"
"io"
"log"
"unicode/utf16"
lzstring "github.com/daku10/go-lz-string"
)
func min(a, b int) int {
@@ -23,7 +26,7 @@ func min(a, b int) int {
// ResponseVclaim decrypts the encrypted response from VClaim API
func ResponseVclaim(encrypted string, key string) (string, error) {
log.Println("ResponseVclaim: Starting decryption process")
log.Printf("ResponseVclaim: Encrypted string: %s", encrypted)
log.Printf("ResponseVclaim: Encrypted string length: %d", len(encrypted))
// Pad the base64 string if needed
if len(encrypted)%4 != 0 {
@@ -31,81 +34,177 @@ func ResponseVclaim(encrypted string, key string) (string, error) {
for i := 0; i < padding; i++ {
encrypted += "="
}
log.Printf("ResponseVclaim: Padded encrypted string: %s", encrypted)
}
// Decode base64
cipherText, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
log.Printf("ResponseVclaim: Failed to decode base64: %v", err)
return "", err
}
log.Printf("ResponseVclaim: Base64 decoded successfully, length: %d", len(cipherText))
hash := sha256.Sum256([]byte(key))
block, err := aes.NewCipher(hash[:])
if err != nil {
log.Printf("ResponseVclaim: Failed to create AES cipher: %v", err)
return "", err
}
if len(cipherText) < aes.BlockSize {
log.Println("ResponseVclaim: CipherText too short")
return "", errors.New("cipherText too short")
}
iv := hash[:aes.BlockSize]
// Create AES cipher
hash := sha256.Sum256([]byte(key))
block, err := aes.NewCipher(hash[:])
if err != nil {
return "", err
}
// Try both IV methods
// Method 1: IV from hash (current approach)
if result, err := tryDecryptWithHashIV(cipherText, block, hash[:aes.BlockSize]); err == nil {
log.Printf("ResponseVclaim: Success with hash IV method")
return result, nil
}
// Method 2: IV from cipherText (standard approach)
if result, err := tryDecryptWithCipherIV(cipherText, block); err == nil {
log.Printf("ResponseVclaim: Success with cipher IV method")
return result, nil
}
return "", errors.New("all decryption methods failed")
}
func tryDecryptWithHashIV(cipherText []byte, block cipher.Block, iv []byte) (string, error) {
if len(cipherText)%aes.BlockSize != 0 {
log.Println("ResponseVclaim: CipherText not multiple of block size")
return "", errors.New("cipherText is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(cipherText, cipherText)
log.Println("ResponseVclaim: AES decryption completed")
decrypted := make([]byte, len(cipherText))
mode.CryptBlocks(decrypted, cipherText)
// cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
cipherText = helper.RemovePKCS7Padding(cipherText)
log.Printf("ResponseVclaim: PKCS7 padding removed, length: %d", len(cipherText))
// Remove PKCS7 padding
decrypted = helper.RemovePKCS7Padding(decrypted)
log.Printf("tryDecryptWithHashIV: Decryption completed, length: %d", len(decrypted))
var data string
return tryAllDecompressionMethods(decrypted)
}
// Try gzip decompression first
reader, err := gzip.NewReader(bytes.NewReader(cipherText))
func tryDecryptWithCipherIV(cipherText []byte, block cipher.Block) (string, error) {
if len(cipherText) < aes.BlockSize {
return "", errors.New("cipherText too short for IV extraction")
}
// Extract IV from first block
iv := cipherText[:aes.BlockSize]
cipherData := cipherText[aes.BlockSize:]
if len(cipherData)%aes.BlockSize != 0 {
return "", errors.New("cipher data is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(cipherData))
mode.CryptBlocks(decrypted, cipherData)
// Remove PKCS7 padding
decrypted = helper.RemovePKCS7Padding(decrypted)
log.Printf("tryDecryptWithCipherIV: Decryption completed, length: %d", len(decrypted))
return tryAllDecompressionMethods(decrypted)
}
func tryAllDecompressionMethods(data []byte) (string, error) {
log.Printf("tryAllDecompressionMethods: Attempting decompression, data length: %d", len(data))
// Method 1: Check if it's already valid JSON
if isValidJSON(data) {
log.Println("tryAllDecompressionMethods: Data is valid JSON, returning as-is")
return string(data), nil
}
// Method 2: Try gzip decompression
if result, err := tryGzipDecompression(data); err == nil && len(result) > 0 {
log.Println("tryAllDecompressionMethods: Gzip decompression successful")
return result, nil
}
// Method 3: Try LZ-string decompression methods
if result, err := tryLZStringMethods(data); err == nil && len(result) > 0 {
log.Println("tryAllDecompressionMethods: LZ-string decompression successful")
return result, nil
}
// Method 4: Return as plain text
result := string(data)
if len(result) > 0 {
log.Printf("tryAllDecompressionMethods: Using decrypted data as plain text, length: %d", len(result))
return result, nil
}
return "", errors.New("all decompression methods failed")
}
func isValidJSON(data []byte) bool {
if len(data) == 0 {
return false
}
firstChar := data[0]
return firstChar == '{' || firstChar == '['
}
func tryGzipDecompression(data []byte) (string, error) {
reader, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
log.Printf("ResponseVclaim: Gzip decompression failed: %v, trying LZ-string decompression", err)
// Try lz-string decompression using helper function
data, err := helper.StringDecrypt(key, string(cipherText))
if err != nil || len(data) == 0 {
log.Printf("ResponseVclaim: Helper StringDecrypt failed or empty: %v, trying without decompression", err)
// Try without decompression
data = string(cipherText)
log.Printf("ResponseVclaim: Using decrypted data without decompression, data length: %d", len(data))
} else {
log.Printf("ResponseVclaim: Helper StringDecrypt successful, data length: %d, data: %s", len(data), data[:min(100, len(data))])
}
} else {
defer reader.Close()
decompressed, err := io.ReadAll(reader)
if err != nil {
log.Printf("ResponseVclaim: Failed to read gzip decompressed data: %v, trying LZ-string decompression", err)
// Try lz-string decompression using helper function
data, err := helper.StringDecrypt(key, string(cipherText))
if err != nil || len(data) == 0 {
log.Printf("ResponseVclaim: Helper StringDecrypt failed or empty: %v, using data without decompression", err)
data = string(cipherText)
log.Printf("ResponseVclaim: Using decrypted data without decompression, data length: %d", len(data))
} else {
log.Printf("ResponseVclaim: Helper StringDecrypt successful, data length: %d", len(data))
}
} else {
data = string(decompressed)
log.Printf("ResponseVclaim: Gzip decompression successful, data length: %d", len(data))
return "", err
}
defer reader.Close()
decompressed, err := io.ReadAll(reader)
if err != nil {
return "", err
}
return string(decompressed), nil
}
func tryLZStringMethods(data []byte) (string, error) {
dataStr := string(data)
// Method 1: DecompressFromEncodedURIComponent
if result, err := lzstring.DecompressFromEncodedURIComponent(dataStr); err == nil && len(result) > 0 {
return result, nil
}
// Method 2: DecompressFromBase64
if result, err := lzstring.DecompressFromBase64(dataStr); err == nil && len(result) > 0 {
return result, nil
}
// Method 3: DecompressFromUTF16 (with proper conversion)
if utf16Data, err := stringToUTF16(dataStr); err == nil {
if result, err := lzstring.DecompressFromUTF16(utf16Data); err == nil && len(result) > 0 {
return result, nil
}
}
log.Printf("ResponseVclaim: Final data length: %d, data: %s", len(data), data[:min(100, len(data))])
log.Println("ResponseVclaim: Decryption process completed successfully")
return data, nil
// Method 4: Try with base64 decoding first
if decoded, err := base64.StdEncoding.DecodeString(dataStr); err == nil {
if result, err := lzstring.DecompressFromEncodedURIComponent(string(decoded)); err == nil && len(result) > 0 {
return result, nil
}
}
return "", errors.New("all LZ-string methods failed")
}
// stringToUTF16 converts string to []uint16 for UTF16 decompression
func stringToUTF16(s string) ([]uint16, error) {
if len(s) == 0 {
return nil, errors.New("empty string")
}
// Convert string to runes first
runes := []rune(s)
// Convert runes to UTF16
utf16Data := utf16.Encode(runes)
return utf16Data, nil
}