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;
}