-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This removes a lot of profile specific constants and insteads put them behind the profile. Key, Salt and TagLen need to be determined by the profile. Relates to #85
- Loading branch information
Showing
13 changed files
with
495 additions
and
341 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package srtp | ||
|
||
import ( | ||
"crypto/aes" | ||
"encoding/binary" | ||
) | ||
|
||
// All of these key derivation functions are AES-CM specific | ||
// in the future we have multiple implementations of each of these functions | ||
|
||
func generateSessionKey(label byte, masterKey, masterSalt []byte) ([]byte, error) { | ||
// https://tools.ietf.org/html/rfc3711#appendix-B.3 | ||
// The input block for AES-CM is generated by exclusive-oring the master salt with the | ||
// concatenation of the encryption key label 0x00 with (index DIV kdr), | ||
// - index is 'rollover count' and DIV is 'divided by' | ||
sessionKey := make([]byte, len(masterSalt)) | ||
copy(sessionKey, masterSalt) | ||
|
||
labelAndIndexOverKdr := []byte{label, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} | ||
for i, j := len(labelAndIndexOverKdr)-1, len(sessionKey)-1; i >= 0; i, j = i-1, j-1 { | ||
sessionKey[j] = sessionKey[j] ^ labelAndIndexOverKdr[i] | ||
} | ||
|
||
// then padding on the right with two null octets (which implements the multiply-by-2^16 operation, see Section 4.3.3). | ||
sessionKey = append(sessionKey, []byte{0x00, 0x00}...) | ||
|
||
//The resulting value is then AES-CM- encrypted using the master key to get the cipher key. | ||
block, err := aes.NewCipher(masterKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
block.Encrypt(sessionKey, sessionKey) | ||
return sessionKey, nil | ||
} | ||
|
||
func generateSessionSalt(label byte, saltLen int, masterKey, masterSalt []byte) ([]byte, error) { | ||
// https://tools.ietf.org/html/rfc3711#appendix-B.3 | ||
// The input block for AES-CM is generated by exclusive-oring the master salt with | ||
// the concatenation of the encryption salt label | ||
sessionSalt := make([]byte, len(masterSalt)) | ||
copy(sessionSalt, masterSalt) | ||
|
||
labelAndIndexOverKdr := []byte{label, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} | ||
for i, j := len(labelAndIndexOverKdr)-1, len(sessionSalt)-1; i >= 0; i, j = i-1, j-1 { | ||
sessionSalt[j] = sessionSalt[j] ^ labelAndIndexOverKdr[i] | ||
} | ||
|
||
// That value is padded and encrypted as above. | ||
sessionSalt = append(sessionSalt, []byte{0x00, 0x00}...) | ||
block, err := aes.NewCipher(masterKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
block.Encrypt(sessionSalt, sessionSalt) | ||
return sessionSalt[0:saltLen], nil | ||
} | ||
|
||
func generateSessionAuthTag(label byte, masterKey, masterSalt []byte) ([]byte, error) { | ||
// https://tools.ietf.org/html/rfc3711#appendix-B.3 | ||
// We now show how the auth key is generated. The input block for AES- | ||
// CM is generated as above, but using the authentication key label. | ||
sessionAuthTag := make([]byte, len(masterSalt)) | ||
copy(sessionAuthTag, masterSalt) | ||
|
||
labelAndIndexOverKdr := []byte{label, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} | ||
for i, j := len(labelAndIndexOverKdr)-1, len(sessionAuthTag)-1; i >= 0; i, j = i-1, j-1 { | ||
sessionAuthTag[j] = sessionAuthTag[j] ^ labelAndIndexOverKdr[i] | ||
} | ||
|
||
// That value is padded and encrypted as above. | ||
// - We need to do multiple runs at key size (20) is larger then source | ||
firstRun := append(sessionAuthTag, []byte{0x00, 0x00}...) | ||
secondRun := append(sessionAuthTag, []byte{0x00, 0x01}...) | ||
block, err := aes.NewCipher(masterKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
block.Encrypt(firstRun, firstRun) | ||
block.Encrypt(secondRun, secondRun) | ||
return append(firstRun, secondRun[:4]...), nil | ||
} | ||
|
||
// Generate IV https://tools.ietf.org/html/rfc3711#section-4.1.1 | ||
// where the 128-bit integer value IV SHALL be defined by the SSRC, the | ||
// SRTP packet index i, and the SRTP session salting key k_s, as below. | ||
// - ROC = a 32-bit unsigned rollover counter (ROC), which records how many | ||
// - times the 16-bit RTP sequence number has been reset to zero after | ||
// - passing through 65,535 | ||
// i = 2^16 * ROC + SEQ | ||
// IV = (salt*2 ^ 16) | (ssrc*2 ^ 64) | (i*2 ^ 16) | ||
func generateCounter(sequenceNumber uint16, rolloverCounter uint32, ssrc uint32, sessionSalt []byte) []byte { | ||
counter := make([]byte, 16) | ||
|
||
binary.BigEndian.PutUint32(counter[4:], ssrc) | ||
binary.BigEndian.PutUint32(counter[8:], rolloverCounter) | ||
binary.BigEndian.PutUint32(counter[12:], uint32(sequenceNumber)<<16) | ||
|
||
for i := range sessionSalt { | ||
counter[i] = counter[i] ^ sessionSalt[i] | ||
} | ||
|
||
return counter | ||
} |
Oops, something went wrong.