← Alle berichten

Versleutelde data delen via korte media

Op deze pagina

Grote hoeveelheden data delen via korte media zoals QR-codes of NFC-tags is lastig. De data moet versleuteld zijn voor de vertrouwelijkheid, maar nuttige data in een kleine ruimte proppen is moeilijk.

Ik zocht een manier om data veilig te delen via een kort medium, met een ontvanger bij wie ik vooraf geen vertrouwensrelatie heb.

Terwijl ik hieraan werkte, liet ik me inspireren door het Signal Protocol en het Noise Protocol Framework.

Beide protocollen combineren symmetrische en asymmetrische versleuteling. Zo halen ze een hoog beveiligingsniveau en houden ze de hoeveelheid data die je moet overdragen klein.

Ik wilde hetzelfde bereiken, maar zonder asymmetrische versleuteling. Ik wilde de data versleutelen met een symmetrische sleutel en die sleutel peer-to-peer delen via het korte medium. Daarnaast wilde ik een gecentraliseerde tussenpartij die de versleutelde data opslaat en een token geeft.

Dit lijkt in sommige opzichten op Secure Multi-Party Computation.

Ik kwam uit op een protocol dat ik het Tokenized Encrypted Payload Sharing (TEPS) protocol noem. Hieronder heb ik het beschreven. Ik twijfel over mijn aanpak, dus ik hoor graag wat je ervan vindt.

Tokenized Encrypted Payload Sharing (TEPS)

Dit is een techniek om data te versleutelen die tijdelijk bij een tussenpartij staat. De tussenpartij krijgt de data niet te zien, maar we vertrouwen haar wel om de data te tokeniseren. De client versleutelt de data met een symmetrische sleutel en haalt de data met het token weer op bij de tussenpartij. Daarna ontsleutelt de client de data met dezelfde symmetrische sleutel. De techniek is handig om grote hoeveelheden data te delen via korte media zoals QR-codes of NFC-tags.

Een voorbeeld is een mobiele telefoon die veel data deelt met een andere mobiele telefoon. De afzender versleutelt de data en stuurt ze naar een tussenpartij. De tussenpartij slaat de versleutelde data op en geeft een token terug. De afzender deelt het token en de symmetrische sleutel met de ontvanger via een kort medium zoals een QR-code of NFC-tag. De ontvanger haalt de versleutelde data met het token op bij de tussenpartij. Daarna ontsleutelt de ontvanger de data met dezelfde symmetrische sleutel. De ontvanger kan het token en de symmetrische sleutel ook delen met een andere partij, zodat die de data kan ophalen.

Specificatie

1. Inleiding

Dit is een specificatie van het TEPS-protocol. Het protocol beschrijft hoe je versleutelde data deelt via een tussenpartij en hoe je het token en de symmetrische sleutel peer-to-peer deelt.

2. Terminologie

  • Intermediary (tussenpartij): Een vertrouwde, gecentraliseerde server die de data opslaat en een token geeft.
  • Symmetric Encryption Key (symmetrische sleutel): Een willekeurige symmetrische sleutel waarmee je de data versleutelt.
  • Token: Een unieke ID waarmee je de data bij de tussenpartij ophaalt.
  • Client: De entiteit die de data versleutelt en naar de tussenpartij stuurt. (bijv. een mobiele telefoon)
  • Share Medium: Het medium waarmee je het token en de symmetrische sleutel tussen clients overdraagt. (bijv. een QR-code, NFC-tag, enzovoort)

3. Protocol

3.1 Overzicht

De client genereert een willekeurige symmetrische sleutel en versleutelt daarmee de data. Daarna stuurt de client de versleutelde data naar de tussenpartij in ruil voor een token. De tussenpartij slaat de versleutelde data en het token op en geeft het token terug aan de client. De client combineert het token en de symmetrische sleutel en deelt die met de ontvangende client via het Share Medium (bijv. een QR-code, NFC-tag, enzovoort). De ontvanger haalt de versleutelde data met het token op bij de tussenpartij. Daarna ontsleutelt de ontvangende client de data met de symmetrische sleutel.

In sommige gevallen kan de ontvanger de informatie doorgeven aan een andere partij, maar dat valt buiten deze specificatie.

3.2 Proces

3.2.1 Symmetrische sleutel genereren

De client genereert een willekeurige symmetrische sleutel. Daarmee versleutel je de data. Later combineer je de sleutel met het token van de tussenpartij om peer-to-peer te delen. De symmetrische sleutel mag elke lengte hebben, maar houd hem bij voorkeur op een formaat dat past bij het Share Medium.

// Generate a 32 byte symmetric key
symmetricKey := make([]byte, 32)

if _, err := rand.Read(symmetricKey); err != nil {
  panic(err)
}

3.2.2 Data versleutelen

De client versleutelt de data met de symmetrische sleutel, met het AES-256-algoritme (of iets vergelijkbaars).

Bijvoorbeeld:

// Encrypt the data using the symmetric key
block, err := aes.NewCipher(symmetricKey)

if err != nil {
  panic(err)
}

gcm, err := cipher.NewGCM(block)

if err != nil {
  panic(err)
}

nonce := make([]byte, gcm.NonceSize())

if _, err = rand.Read(nonce); err != nil {
  panic(err)
}

ciphertext := gcm.Seal(nonce, nonce, data, nil)

3.2.3 Data naar de tussenpartij sturen

De client stuurt de versleutelde data naar de tussenpartij in ruil voor een Token.

Bijvoorbeeld:

POST /data HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 123

{
  "data": "encrypted data"
}

In code:

// Submit the encrypted data to the intermediary
req, err := http.NewRequest("POST", "https://api.example.com/data", bytes.NewBuffer(ciphertext))

if err != nil {
  panic(err)
}

req.Header.Set("Content-Type", "application/json")

resp, err := http.DefaultClient.Do(req)

if err != nil {
  panic(err)
}

defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)

if err != nil {
  panic(err)
}

var data map[string]interface{}

if err := json.Unmarshal(body, &data); err != nil {
  panic(err)
}

lookupID := data["lookup_id"].(string)

3.2.4 Data opslaan en token genereren

De tussenpartij slaat de versleutelde data op en genereert een willekeurig token. Met dat token haal je de data op bij de tussenpartij. Het token mag elke lengte hebben, maar houd het bij voorkeur op een formaat dat past bij het Share Medium.

Daarna geeft de tussenpartij het token terug aan de client.

Bijvoorbeeld:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123

{
  "lookup_id": "random token"
}

In code:

// Store the encrypted data and generate a token
lookupID := uuid.New().String()

if err := storeData(lookupID, ciphertext); err != nil {
  panic(err)
}

// Return the token to the client
resp, err := json.Marshal(map[string]interface{}{
  "lookup_id": lookupID,
})

if err != nil {
  panic(err)
}

w.Header().Set("Content-Type", "application/json")
w.Write(resp)

3.2.5 Data laten verlopen (optioneel)

De tussenpartij kan de data na een bepaalde tijd laten verlopen. Ze mag daarvoor elke methode gebruiken.

Sla de vervaldatum op bij de data:

{
  "data": "encrypted data",
  "expiry_date": "2023-07-19T21:12:43+10:00"
}

Verwijder verlopen data met een cron job.

3.2.6 Token en symmetrische sleutel combineren

De client combineert het token en de symmetrische sleutel. De client bepaalt zelf hoe ze het gecombineerde token en de sleutel verpakt, zolang de methode past bij het Share Medium en de ontvangende client.

In deze specificatie combineren we het token en de symmetrische sleutel in dit formaat:

<lookup_id><symmetric_key>

3.2.7 Token en symmetrische sleutel delen

De client deelt het token en de symmetrische sleutel met de ontvangende client via het Share Medium (bijv. een QR-code, NFC-tag, enzovoort).

3.2.8 Data ophalen bij de tussenpartij

De ontvangende client haalt de versleutelde data met het token op bij de tussenpartij.

Bijvoorbeeld:

GET /data/<lookup_id> HTTP/1.1
Host: api.example.com
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123

{
  "data": "encrypted data"
}

In code:

// Retrieve the encrypted data from the intermediary
resp, err := http.Get(fmt.Sprintf("https://api.example.com/data/%s", lookupID))

if err != nil {
  panic(err)
}

defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)

if err != nil {
  panic(err)
}

var data map[string]interface{}

if err := json.Unmarshal(body, &data); err != nil {
  panic(err)
}

ciphertext := data["data"].(string)

3.2.9 Data ontsleutelen

De ontvangende client ontsleutelt de data met de symmetrische sleutel.

Bijvoorbeeld:

// Decrypt the data using the symmetric key
block, err := aes.NewCipher(symmetricKey)

if err != nil {
  panic(err)
}

gcm, err := cipher.NewGCM(block)

if err != nil {
  panic(err)
}

nonceSize := gcm.NonceSize()

nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)

if err != nil {
  panic(err)
}

Verzoek om feedback

Ik hoor graag wat je van dit protocol vindt. Neem gerust contact met me op als je feedback hebt.

Bedankt voor het lezen!