Browse Source

Merge pull request #348 from rod-hynes/master

Deterministic key derivation for OSL file keys
Rod Hynes 9 years ago
parent
commit
cafc3e3bbf
1 changed files with 25 additions and 9 deletions
  1. 25 9
      psiphon/common/osl/osl.go

+ 25 - 9
psiphon/common/osl/osl.go

@@ -823,11 +823,11 @@ func (config *Config) Pave(
 	return paveFiles, nil
 	return paveFiles, nil
 }
 }
 
 
-// makeOSLFileSpec creates a random OSL file key, splits it according
-// the the scheme's key splits, and sets the OSL ID as its first SLOK
-// ID. The returned key is used to encrypt the OSL payload and then
-// discarded; the key may be reassembled using the data in the KeyShares
-// tree, given sufficient SLOKs.
+// makeOSLFileSpec creates an OSL file key, splits it according to the
+// scheme's key splits, and sets the OSL ID as its first SLOK ID. The
+// returned key is used to encrypt the OSL payload and then discarded;
+// the key may be reassembled using the data in the KeyShares tree,
+// given sufficient SLOKs.
 func makeOSLFileSpec(
 func makeOSLFileSpec(
 	scheme *Scheme,
 	scheme *Scheme,
 	propagationChannelID string,
 	propagationChannelID string,
@@ -841,10 +841,16 @@ func makeOSLFileSpec(
 	firstSLOK := scheme.deriveSLOK(ref)
 	firstSLOK := scheme.deriveSLOK(ref)
 	oslID := firstSLOK.ID
 	oslID := firstSLOK.ID
 
 
-	fileKey, err := common.MakeSecureRandomBytes(KEY_LENGTH_BYTES)
-	if err != nil {
-		return nil, nil, common.ContextError(err)
-	}
+	// Note: previously, this was a random key. Now, the file key
+	// is derived from the master key and OSL ID. This deterministic
+	// derivation ensures that repeated paves of the same OSL
+	// with the same ID and same content yields the same MD5Sum
+	// to avoid wastful downloads.
+
+	fileKey := deriveKeyHKDF(
+		scheme.MasterKey,
+		[]byte("osl-file-key"),
+		oslID)
 
 
 	keyShares, err := divideKey(
 	keyShares, err := divideKey(
 		scheme,
 		scheme,
@@ -884,10 +890,20 @@ func divideKey(
 	var keyShares []*KeyShares
 	var keyShares []*KeyShares
 
 
 	for _, share := range shares {
 	for _, share := range shares {
+
+		// Note: for a fully deterministic pave, where the OSL registry
+		// is unchanged when no OSLs change, the share key would need
+		// to be derived (e.g., from the master key, OSL ID, key split
+		// index, and share index). However, since the OSL registry file
+		// content is nondeterministic in any case due to aspects of the
+		// Shamir secret splitting algorithm, there's no reason not to
+		// use a random key here.
+
 		shareKey, err := common.MakeSecureRandomBytes(KEY_LENGTH_BYTES)
 		shareKey, err := common.MakeSecureRandomBytes(KEY_LENGTH_BYTES)
 		if err != nil {
 		if err != nil {
 			return nil, common.ContextError(err)
 			return nil, common.ContextError(err)
 		}
 		}
+
 		if keySplitIndex > 0 {
 		if keySplitIndex > 0 {
 			keyShare, err := divideKey(
 			keyShare, err := divideKey(
 				scheme,
 				scheme,