refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
105
modules/lagoon/laravel_decrypt.go
Normal file
105
modules/lagoon/laravel_decrypt.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package lagoon
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// laravelPayload is Laravel's Encrypter JSON body (iv/value/mac).
|
||||
type laravelPayload struct {
|
||||
IV string `json:"iv"`
|
||||
Value string `json:"value"`
|
||||
MAC string `json:"mac"`
|
||||
}
|
||||
|
||||
// DecryptLaravelPayload decrypts a Laravel AES-256-CBC+HMAC "encrypted" payload
|
||||
// (base64 JSON {iv,value,mac}) using the raw APP_KEY bytes.
|
||||
//
|
||||
// Cutover-import-only; never called from Encrypted's live Scan/Value path (D-10).
|
||||
func DecryptLaravelPayload(payloadJSON string, appKey []byte) ([]byte, error) {
|
||||
if len(appKey) != encryptedKeySize {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload key must be 32 bytes")
|
||||
}
|
||||
body, err := decodeLaravelJSON(payloadJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var payload laravelPayload
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload json: %w", err)
|
||||
}
|
||||
if payload.IV == "" || payload.Value == "" || payload.MAC == "" {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload missing iv, value, or mac")
|
||||
}
|
||||
wantMAC, err := hex.DecodeString(payload.MAC)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload mac: %w", err)
|
||||
}
|
||||
mac := hmac.New(sha256.New, appKey)
|
||||
_, _ = mac.Write([]byte(payload.IV + payload.Value))
|
||||
gotMAC := mac.Sum(nil)
|
||||
if !hmac.Equal(wantMAC, gotMAC) {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload mac mismatch")
|
||||
}
|
||||
iv, err := base64.StdEncoding.DecodeString(payload.IV)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload iv: %w", err)
|
||||
}
|
||||
ct, err := base64.StdEncoding.DecodeString(payload.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload value: %w", err)
|
||||
}
|
||||
if len(iv) != aes.BlockSize {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload iv length %d", len(iv))
|
||||
}
|
||||
if len(ct) == 0 || len(ct)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload ciphertext length %d", len(ct))
|
||||
}
|
||||
block, err := aes.NewCipher(appKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plain := make([]byte, len(ct))
|
||||
cipher.NewCBCDecrypter(block, iv).CryptBlocks(plain, ct)
|
||||
return pkcs7Unpad(plain, aes.BlockSize)
|
||||
}
|
||||
|
||||
func decodeLaravelJSON(payloadJSON string) ([]byte, error) {
|
||||
s := strings.TrimSpace(payloadJSON)
|
||||
if s == "" {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload is empty")
|
||||
}
|
||||
if decoded, err := base64.StdEncoding.DecodeString(s); err == nil {
|
||||
trimmed := strings.TrimSpace(string(decoded))
|
||||
if strings.HasPrefix(trimmed, "{") {
|
||||
return []byte(trimmed), nil
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(s, "{") {
|
||||
return []byte(s), nil
|
||||
}
|
||||
return nil, fmt.Errorf("lagoon: laravel payload is not base64 JSON")
|
||||
}
|
||||
|
||||
func pkcs7Unpad(b []byte, blockSize int) ([]byte, error) {
|
||||
if blockSize <= 0 || len(b) == 0 || len(b)%blockSize != 0 {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload padding")
|
||||
}
|
||||
pad := int(b[len(b)-1])
|
||||
if pad == 0 || pad > blockSize || pad > len(b) {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload padding")
|
||||
}
|
||||
for i := len(b) - pad; i < len(b); i++ {
|
||||
if int(b[i]) != pad {
|
||||
return nil, fmt.Errorf("lagoon: laravel payload padding")
|
||||
}
|
||||
}
|
||||
return b[:len(b)-pad], nil
|
||||
}
|
||||
Reference in New Issue
Block a user