Skip to content

Commit

Permalink
Add functionality for DLOC/LOC decryption of assignment and entry data
Browse files Browse the repository at this point in the history
Currently, we follow a naive approach. Both DecryptAssignmentData() and
DecryptEntryData() take a list of matched (by pi) DLOC/LOC ciphertexts and
encrypted assignment/entry data. We decrypt the DLOC/LOC ciphertexts to
get the (U, S, c_x), where x = a|e, tuples and then attempt to
interpolate all (U, S) pairs to find k. The problem is that if we are given one malformed
pair, the entire process fails. This is a problem that can easily be
fixed if we implement the smarter algorithm mentioned in the paper (see issue #5).

If we assume no malicious (U, S) pairs, then the process finds k and
correctly decrypts c_x to get the assignment/entry key that can be used
to decrypt the data given.

+ Update main.go to show this decryption process
  • Loading branch information
ymarcus93 committed Apr 7, 2020
1 parent df5c49f commit f7e4a6e
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 4 deletions.
193 changes: 193 additions & 0 deletions callisto/loc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package callisto

import (
"crypto/rsa"
"fmt"

ss "github.com/superarius/shamir"
ff "github.com/superarius/shamir/modular"

"github.com/vmihailenco/msgpack"

"github.com/ymarcus93/gallisto/encoding"
"github.com/ymarcus93/gallisto/encryption"
"github.com/ymarcus93/gallisto/shamir"
"github.com/ymarcus93/gallisto/types"
)

// DecryptAssignmentData decrypts a list of encrypted assignment data. It does
// this by finding a common k value amongst matched dlocData and attempting to
// decrypt encrypted assignment keys with this k. It then uses the decrypted
// assignment keys to decrypt all assignment data.
func DecryptAssignmentData(dlocCiphertexts [][]byte, encryptedAssignmentData []types.GCMCiphertext, dlocPrivateKey *rsa.PrivateKey) ([]types.AssignmentData, error) {
if len(dlocCiphertexts) != len(encryptedAssignmentData) {
return nil, fmt.Errorf("mismatch length between dlocCiphertexts and encrypted assignment data")
}

// Decrypt dloc ciphertexts
dlocData, err := decryptLOCCiphertexts(dlocCiphertexts, dlocPrivateKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt DLOC ciphertexts: %v", err)
}

// Validate
if !validateLOCData(dlocData, types.Director) {
return nil, fmt.Errorf("decrypted DLOC ciphertexts but found non-Director data")
}

// Find k
kAsBytes, err := findKValueFromLOCData(dlocData)
if err != nil {
return nil, fmt.Errorf("failed to find k value from DLOC ciphertexts: %v", err)
}

// Decrypt assignment data
assignmentDatas := make([]types.AssignmentData, len(dlocData))
for i, d := range dlocData {
k_a, err := encryption.DecryptAES(kAsBytes, d.EncryptedKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt EncryptedAssignmentDataKey at index %v: %v", i, err)
}
assignData, err := symDecryptAssignmentData(encryptedAssignmentData[i], k_a)
if err != nil {
return nil, fmt.Errorf("failed to decrypt assignment data at index %v: %v", i, err)
}
assignmentDatas[i] = assignData
}

return assignmentDatas, nil
}

// DecryptEntryData decrypts a list of encrypted entry data. It does this by
// finding a common k value amongst matched locData and attempting to decrypt
// encrypted entry keys with this k. It then uses the decrypted entry keys to
// decrypt all entry data.
func DecryptEntryData(locCiphertexts [][]byte, encryptedEntryData []types.GCMCiphertext, locPrivateKey *rsa.PrivateKey) ([]types.EntryData, error) {
if len(locCiphertexts) != len(encryptedEntryData) {
return nil, fmt.Errorf("mismatch length between locCiphertexts and encrypted entry data")
}

// Decrypt loc ciphertexts
locData, err := decryptLOCCiphertexts(locCiphertexts, locPrivateKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt LOC ciphertexts: %v", err)
}

// Validate
if !validateLOCData(locData, types.Counselor) {
return nil, fmt.Errorf("decrypted LOC ciphertexts but found non-Counselor data")
}

// Find k
kAsBytes, err := findKValueFromLOCData(locData)
if err != nil {
return nil, fmt.Errorf("failed to find k value from LOC ciphertexts: %v", err)
}

// Decrypt entry data
entryDatas := make([]types.EntryData, len(locData))
for i, d := range locData {
k_e, err := encryption.DecryptAES(kAsBytes, d.EncryptedKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt EncryptedEntryDataKey at index %v: %v", i, err)
}
entryData, err := symDecryptEntryData(encryptedEntryData[i], k_e)
if err != nil {
return nil, fmt.Errorf("failed to decrypt entry data at index %v: %v", i, err)
}
entryDatas[i] = entryData
}

return entryDatas, nil
}

func validateLOCData(data []types.LOCData, expectedLOCType types.LOCType) bool {
for _, d := range data {
if d.Type != expectedLOCType {
return false
}
}
return true
}

func decryptLOCCiphertexts(locCiphertexts [][]byte, privateKey *rsa.PrivateKey) ([]types.LOCData, error) {
// Decrypt ciphertexts to get all loc data
locData := make([]types.LOCData, len(locCiphertexts))
for i, c := range locCiphertexts {
decryptedCiphertext, err := decryptLOCCiphertext(c, privateKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt (D)LOC ciphertext at index %v: %v", i, err)
}
locData[i] = decryptedCiphertext
}

return locData, nil
}

func findKValueFromLOCData(locData []types.LOCData) ([]byte, error) {
// Form shamir (x,y) shares
shares := make([]*ss.Share, len(locData))
for i, d := range locData {
shares[i] = &ss.Share{
X: ff.IntFromBytes(d.U),
Y: ff.IntFromBytes(d.S),
}
}

// Find K Value (the key)
kAsElement, err := shamir.FindShamirKValue(shares)
if err != nil {
return nil, fmt.Errorf("failed to find k value: %v", err)
}
return kAsElement.Bytes(), nil
}

func decryptLOCCiphertext(locCiphertext []byte, privateKey *rsa.PrivateKey) (types.LOCData, error) {
// Decrypt ciphertext
dlocDataBytes, err := encryption.DecryptRSA(locCiphertext, privateKey)
if err != nil {
return types.LOCData{}, fmt.Errorf("failed to decrypt (D)LOC ciphertext: %v", err)
}

// Decode msgpack encoding of LOC data
dlocData, err := encoding.DecodeLOCData(dlocDataBytes)
if err != nil {
return types.LOCData{}, err
}

return dlocData, nil
}

func symDecryptAssignmentData(encryptedAssignmentData types.GCMCiphertext, assignmentDataKey []byte) (types.AssignmentData, error) {
// Decrypt assignment data
assignmentDataEncodedBytes, err := encryption.DecryptAES(assignmentDataKey, encryptedAssignmentData)
if err != nil {
return types.AssignmentData{}, fmt.Errorf("failed to decrypt assignment data: %v", err)
}

// Decode msgpack encoding
var decodedAssignmentData types.AssignmentData
err = msgpack.Unmarshal(assignmentDataEncodedBytes, &decodedAssignmentData)
if err != nil {
return types.AssignmentData{}, fmt.Errorf("failed to decode assignment data: %v", err)
}

return decodedAssignmentData, nil
}

func symDecryptEntryData(encryptedEntryData types.GCMCiphertext, entryDataKey []byte) (types.EntryData, error) {
// Decrypt entry data
assignmentDataEncodedBytes, err := encryption.DecryptAES(entryDataKey, encryptedEntryData)
if err != nil {
return types.EntryData{}, fmt.Errorf("failed to decrypt entry data: %v", err)
}

// Decode msgpack encoding
var decodedEntryData types.EntryData
err = msgpack.Unmarshal(assignmentDataEncodedBytes, &decodedEntryData)
if err != nil {
return types.EntryData{}, fmt.Errorf("failed to decode entry data: %v", err)
}

return decodedEntryData, nil
}
50 changes: 46 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"fmt"

"github.com/ymarcus93/gallisto/callisto"
Expand All @@ -10,7 +11,12 @@ import (
)

func main() {
callistoClient, err := callisto.NewCallistoClient(types.OPRF_CIPHERSUITE)
// Two callisto clients
callistoClientOne, err := callisto.NewCallistoClient(types.OPRF_CIPHERSUITE)
if err != nil {
panic(err)
}
callistoClientTwo, err := callisto.NewCallistoClient(types.OPRF_CIPHERSUITE)
if err != nil {
panic(err)
}
Expand All @@ -29,6 +35,7 @@ func main() {
panic(err)
}

// Generate DLOC/LOC keys
locKeys, err := encryption.GenerateRSAKeyPair()
if err != nil {
panic(err)
Expand All @@ -37,12 +44,12 @@ func main() {
if err != nil {
panic(err)
}

locPubKeys := types.LOCPublicKeys{
LOCPublicKey: locKeys.PublicKey,
DLOCPublicKey: dlocKeys.PublicKey,
}

// Callisto entry
entry := types.CallistoEntry{
EntryData: types.EntryData{
PerpetratorName: "Foo",
Expand All @@ -58,11 +65,46 @@ func main() {
},
}

// Compute two Callisto tuples of the same perp, but with two separate
// users. Because two users have reported the same perp, LOCs/DLOCs can
// decrypt
perpID := []byte("perpID")
tuple, err := callistoClient.CreateCallistoTuple(perpID, entry, locPubKeys, oprfServer)
tupleOne, err := callistoClientOne.CreateCallistoTuple(perpID, entry, locPubKeys, oprfServer)
if err != nil {
panic(err)
}
// Change the data slightly for user 2's report
entry.AssignmentData.VictimStateOfCurrentResidence = "BB"
entry.EntryData.PerpetratorTwitterUserName = "@bar"
tupleTwo, err := callistoClientTwo.CreateCallistoTuple(perpID, entry, locPubKeys, oprfServer)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", tupleOne)
fmt.Printf("%+v\n", tupleTwo)

// Sanity check pi values are the same
if !bytes.Equal(tupleOne.Pi, tupleTwo.Pi) {
panic("pi values are not equal")
}

dlocCiphertexts := [][]byte{tupleOne.DLOCCiphertext, tupleTwo.DLOCCiphertext}
encryptedAssignmentData := []types.GCMCiphertext{tupleOne.EncryptedAssignmentData, tupleTwo.EncryptedAssignmentData}
assignmentResults, err := callisto.DecryptAssignmentData(dlocCiphertexts, encryptedAssignmentData, dlocKeys.PrivateKey)
if err != nil {
panic(err)
}
for _, d := range assignmentResults {
fmt.Printf("%+v\n", d)
}

fmt.Printf("%+v\n", tuple)
locCiphertexts := [][]byte{tupleOne.LOCCiphertext, tupleTwo.LOCCiphertext}
encryptedEntryData := []types.GCMCiphertext{tupleOne.EncryptedEntryData, tupleTwo.EncryptedEntryData}
entryResults, err := callisto.DecryptEntryData(locCiphertexts, encryptedEntryData, locKeys.PrivateKey)
if err != nil {
panic(err)
}
for _, d := range entryResults {
fmt.Printf("%+v\n", d)
}
}

0 comments on commit f7e4a6e

Please sign in to comment.