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 }