working
This commit is contained in:
152
pkg/protocol/license.go
Normal file
152
pkg/protocol/license.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"filippo.io/edwards25519"
|
||||
)
|
||||
|
||||
// Root Key (compressed Edwards25519 point)
|
||||
var LicenseRootKeyBytes = [32]byte{
|
||||
0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c,
|
||||
0xfd, 0x8f, 0x68, 0xb3, 0xdc, 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec,
|
||||
0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,
|
||||
}
|
||||
|
||||
// ParseLicense and derive final Public Key
|
||||
func ParseLicenseAndDeriveKey(licenseData []byte) ([]byte, error) {
|
||||
// Header
|
||||
if len(licenseData) < 1 || licenseData[0] != 0x01 {
|
||||
return nil, errors.New("invalid license version")
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(licenseData[1:])
|
||||
|
||||
// Initialize current key with Root
|
||||
currentPoint, err := new(edwards25519.Point).SetBytes(LicenseRootKeyBytes[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load root key: %v", err)
|
||||
}
|
||||
|
||||
// Iterate blocks
|
||||
for reader.Len() > 0 {
|
||||
// Calculate Start Position
|
||||
bytesConsumed := (len(licenseData) - 1) - reader.Len()
|
||||
blockStartAbs := 1 + bytesConsumed
|
||||
|
||||
// Read KeyType
|
||||
_, err = reader.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read keyType failed: %v", err)
|
||||
}
|
||||
|
||||
// Read Public Key
|
||||
var pubKeyBytes [32]byte
|
||||
if _, err := reader.Read(pubKeyBytes[:]); err != nil {
|
||||
return nil, fmt.Errorf("read pubKey failed: %v", err)
|
||||
}
|
||||
|
||||
blockPubKey, err := new(edwards25519.Point).SetBytes(pubKeyBytes[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid block public key: %v", err)
|
||||
}
|
||||
|
||||
// Read Block Type
|
||||
blockType, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read blockType failed: %v", err)
|
||||
}
|
||||
|
||||
// Read Dates
|
||||
dates := make([]byte, 8)
|
||||
if _, err := reader.Read(dates); err != nil {
|
||||
return nil, fmt.Errorf("read dates failed: %v", err)
|
||||
}
|
||||
|
||||
// Parse Content
|
||||
switch blockType {
|
||||
case 0x00: // Intermediate
|
||||
// 4 bytes int
|
||||
tmp := make([]byte, 4)
|
||||
if _, err := reader.Read(tmp); err != nil {
|
||||
return nil, fmt.Errorf("read intermediate int failed: %v", err)
|
||||
}
|
||||
// String
|
||||
if _, err := readNullTerminatedString(reader); err != nil {
|
||||
return nil, fmt.Errorf("read intermediate string failed: %v", err)
|
||||
}
|
||||
case 0x01, 0x03: // Website / Code
|
||||
if _, err := readNullTerminatedString(reader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 0x02: // Server
|
||||
// 5 bytes
|
||||
tmp := make([]byte, 5)
|
||||
if _, err := reader.Read(tmp); err != nil {
|
||||
return nil, fmt.Errorf("read server data failed: %v", err)
|
||||
}
|
||||
if _, err := readNullTerminatedString(reader); err != nil {
|
||||
return nil, fmt.Errorf("read server string failed: %v", err)
|
||||
}
|
||||
case 0x20: // Box
|
||||
// Ephemeral blocks might be empty content
|
||||
if reader.Len() > 0 {
|
||||
if _, err := readNullTerminatedString(reader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
default:
|
||||
// Fallback
|
||||
}
|
||||
|
||||
// Calculate End for Hashing
|
||||
bytesConsumedAfter := (len(licenseData) - 1) - reader.Len()
|
||||
blockEndAbs := 1 + bytesConsumedAfter
|
||||
hashStart := blockStartAbs + 1
|
||||
|
||||
if blockEndAbs <= hashStart {
|
||||
return nil, errors.New("block too short for hashing")
|
||||
}
|
||||
|
||||
hashableData := licenseData[hashStart:blockEndAbs]
|
||||
|
||||
// Calculate SHA512 Hash
|
||||
hash := sha512.Sum512(hashableData)
|
||||
var scalarBytes [32]byte
|
||||
copy(scalarBytes[:], hash[:32]) // Take first 32 bytes
|
||||
|
||||
// Clamp the hash
|
||||
scalarBytes[0] &= 248
|
||||
scalarBytes[31] &= 127
|
||||
scalarBytes[31] |= 64
|
||||
|
||||
scalar, err := new(edwards25519.Scalar).SetBytesWithClamping(scalarBytes[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("scalar creation failed: %v", err)
|
||||
}
|
||||
|
||||
// Derive: current = current + (blockKey * hash)
|
||||
term := new(edwards25519.Point).ScalarMult(scalar, blockPubKey)
|
||||
currentPoint.Add(currentPoint, term)
|
||||
}
|
||||
|
||||
return currentPoint.Bytes(), nil
|
||||
}
|
||||
|
||||
func readNullTerminatedString(r *bytes.Reader) (string, error) {
|
||||
var data []byte
|
||||
for {
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if b == 0x00 {
|
||||
break
|
||||
}
|
||||
data = append(data, b)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
Reference in New Issue
Block a user