KDF - Key Derive Function
KDF는 말 그대로 키를 파생하는 함수로, 난수 함수를 사용해서 마스터 키 또는 장치별 고유한 정보값으로 부터 비밀 키를 파생시키는 알고리즘이다.
"Recommendation for Key Derivation Using Pseudorandom Function"이라는 제목의 NIST SP 800-108 Rev.1 에 소개된 Counter Mode에서 KDF를 코드로 구현 해 봤다.
https://csrc.nist.gov/pubs/sp/800/108/r1/final
https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1.pdf
나는 PRF로 CMAC-AES 를 사용하여 예제를 작성했다.
typedef unsigned char uint8;
typedef uint8* (PFUNC_PRF)(uint *key, int nKey, uint8 Data, int nData);
int KDF(PFUNC_CMAC *pCmac, uint8 *Kin, int nKin, uint8 *Label, int nLabel, uint8 *Context, int nContext, int L, uint8 *Kout)
{
if(pCmac==NULL || Kin==NULL || Label==NULL || L<=0 || Kout==NULL)
return 1; //error: invalid parameter
//h - The length of the output of a single invocation of the PRF in bits
int h = 16; //digest size of cmac is 16
//r - The length of the binary representation of the counter i
int r = 8; //1byte, supports size of derived key = 128bits cmac output x 256 times loop
//1. n:=[L/h]
int n = (L+h-1)/h;
//2. If n > 2r−1, then output an error indicator and stop (i.e., skip steps 3, 4, and 5).
if(n > pow(long double)2, r)-1)
return 2; //error: exceed the count of repetitions
//3. result := ∅.
uint8* result = (uint8*)malloc(n*h);
memset(result, 0, n*h);
int pos = 0;
//4. For i = 1 to n, do
int nData = 1+nLabel+nContext+1+sizeof(L);
uint8 *inData = (uint8*)malloc(nData);
int seperator = 0x00;
for(int i=1; i<=n; i++) {
//a. K(i) := PRF (KIN, [i]2 || Label || 0x00 || Context || [L]2),
memcpy((void*)&inData[0], (void*)(uint8*)&i, sizeof(i));
memcpy((void*)&inData[1], Label, nLabel);
memcpy((void*)&inData[1+nLabel], (void*)&seperator, sizeof(seperator));
memcpy((void*)&inData[1+nLabel+1], Context, nContext);
memcpy((void*)&inData[1+nLabel+1+nContext], (void*)&L, sizeof(L));
uint8* K = pCmac(Kin, nKin, inData, nData);
//b. result := result || K(i).
memcpy((void*)&result[pos], k, h);
free(K);
pos = pos + h;
}
if(inData) { free(inData); inData=NULL; }
//5. KOUT := the leftmost L bits of result.
memcpy(Kout, result, L);
free(result);
return 0; //success
}
fn KDF(Kin: Box<[u8]>, Label: Box<[u8]>, Context: Box<[u8]>, L: u32, Kout: &mut Box<[u8]>) -> bool {
let h: u32 = 16;
let r: u32 = 8;
let n: u32 = (L+h-1)/h;
let binpow: u32 = 2;
let n_key: usize = mem::sizeo_of_val(&*Kin);
if n_key!=16 || n>binpow.pow(r)-1 {
println!("error: the size of input key must be 16 bytes.");
return false;
}
let mut pos: usize = 0;
let seperator: u8 = 0x000;
let byptes: [u8; 4] = unsafe { mem:transmute(L.to_le()) }; // or .to_be() according to endian
println!("loop n = {}", n);
for i in 1..n+1 {
let mut data: Vec<u8> = Vec::new();
data.push(i as u8);
data.append(&mut Label.clone(),into_vec());
data.push(seperator);
data.append(&mut Context.clone().into_vec());
data.append(&mut Vec::from(bytes));
let mut mac = Cmac::<Aes128>::new_from_slice(&Kin).unwrap();
mac.update(&data);
let fin = mac.finalize();
let bypts = fin.into_byptes();
for j in 0..h as usize {
if pos+j >= L as usize { break };
Kout[pos+j] = bytes[j];
}
pos = pos + h as usize;
}
return true;
}