Skip to content

arrorLabArts/auroprint-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

auroprint-go

Go library for server-side verification of auroprint device fingerprints.

Installation

go get github.com/arrorLabArts/auroprint-go

Usage

package main

import (
    "context"
    "log"
    "time"

    "github.com/arrorLabArts/auroprint-go"
)

func main() {
    ctx := context.Background()

    // Request from Flutter client
    req := auroprint.Request{
        Payload:          `{"did":"device123","ts":1700000000,"nonce":"abc123"}`,
        Signature:        "base64signature...",
        PublicKey:        "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
        AttestationChain: []string{"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"},
        IntegrityToken:   "optional-play-integrity-token",
    }

    // Verify the request
    result := auroprint.Verify(ctx, req, &auroprint.VerifyOptions{
        PlayIntegrityPackageName: "com.yourapp.package",
    })

    if !result.Valid {
        log.Fatal("Verification failed:", result.Error)
    }

    // Use the verified payload
    deviceID := result.Payload.DeviceID
    nonce := result.Payload.Nonce
    timestamp := result.Payload.Timestamp

    // Application-specific anti-replay checks
    if time.Now().Unix()-timestamp > 30 {
        log.Fatal("Request expired")
    }

    // Check nonce against your store (Redis, database, etc.)
    // ...

    log.Printf("Verified device: %s, nonce: %s", deviceID, nonce)
}

What It Verifies

  1. Signature - Proves the payload was signed by the private key holder
  2. Attestation Chain (Android) - Proves the key is hardware-backed (TEE) and signed by Google
  3. Play Integrity (optional) - Proves real device, unmodified app from Play Store
    • Device integrity (not rooted/emulator)
    • App integrity (Play Store recognized)
    • Optional: Nonce validation (prevents replay attacks)
    • Optional: Timestamp validation (ensures token freshness)

What It Returns

  • DeviceID - Unique device identifier
  • Nonce - Random value for anti-replay protection
  • Timestamp - When the fingerprint was generated

What You Must Implement

For Auroprint Payload Anti-Replay

You must implement these checks on the auroprint payload:

  1. Check the timestamp is within acceptable window (e.g., 30 seconds)
  2. Store and check nonces to prevent replay attacks
  3. Implement rate limiting per device ID

For Play Integrity Anti-Replay (Optional but Recommended)

The library now supports optional Play Integrity anti-replay protection:

  • Nonce validation: Set PlayIntegrityExpectedNonce to verify the token was generated for your specific request
  • Timestamp validation: Set PlayIntegrityMaxAgeSeconds to ensure token freshness (recommended: 60 seconds)
  • Duplicate prevention: Optionally track used tokens in your application (Redis, database, etc.)

Options

opts := &auroprint.VerifyOptions{
    // Skip attestation chain verification
    SkipAttestationVerification: false,

    // Required if using Play Integrity
    PlayIntegrityPackageName: "com.yourapp.package",

    // Service account credentials for Play Integrity API
    // If empty, uses default credentials
    GoogleCredentialsJSON: []byte(`{...}`),

    // Optional: Expected nonce for Play Integrity token
    // If set, validates token nonce matches (prevents replay attacks)
    PlayIntegrityExpectedNonce: "server-generated-nonce-123",

    // Optional: Maximum age in seconds for Play Integrity token
    // If > 0, validates token timestamp is within this window
    // Recommended: 60 seconds
    PlayIntegrityMaxAgeSeconds: 60,
}

Play Integrity Anti-Replay Example

For maximum security with Play Integrity, use nonce and timestamp validation:

import (
    "context"
    "crypto/rand"
    "encoding/base64"
)

// 1. Generate a unique nonce for this request
func generateNonce() string {
    b := make([]byte, 32)
    rand.Read(b)
    return base64.URLEncoding.EncodeToString(b)
}

func handleRequest(ctx context.Context, req auroprint.Request) {
    // 2. Generate nonce (you should have sent this to client earlier)
    expectedNonce := generateNonce()
    // In practice, send this to client first, client includes it in Play Integrity request

    // 3. Verify with anti-replay protection
    result := auroprint.Verify(ctx, req, &auroprint.VerifyOptions{
        PlayIntegrityPackageName:   "com.yourapp.package",
        PlayIntegrityExpectedNonce: expectedNonce,
        PlayIntegrityMaxAgeSeconds: 60, // Token must be < 60 seconds old
    })

    if !result.Valid {
        log.Printf("Verification failed: %v", result.Error)
        return
    }

    // 4. Optional: Track used tokens to prevent duplicate use
    // trackUsedToken(req.IntegrityToken)

    log.Printf("Verified device: %s", result.Payload.DeviceID)
}

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages