FADE代码解析2

    从前面FADE代码解析1可以得知。Client中的main.c主要是通过判断agrc个数不同来做出判断。在进行到process(command)的时候,我们可以看到这个Client主要是将整个框架分为六个部分。主要框架如下所示:



这是主要的流程图,我们可以看到Client主要是由六大块组成的,其中GENSERCT(主要是使用RAND_bytes生成密钥,然后将其写到密钥文件secretFile中去就可以了)以及QUIT比较简单,就不进行详述了。接下来分成UPLOAD、DOWNLOAD、RENEW、REVOKE这四部分进行详述。

    在进行讲述函数之前,我先对.metadata文件的相关部署进行一个简要的解释,解释如图所示

                                    


1.    UPLOAD(fileName,policyName)

{


1.首先FILE *fp = fopen((path + '/' + filename + ".metadata").c_str(), "w");.metadata这个后缀的文件包含了文件的各种属性

2.生成data key=key:RAND_bytes(key, AES_BLOCK_SIZE);//产生一段随机数组作为密钥

3.声明一个k=key:并进行赋值:unsigned char k[AES_BLOCK_SIZE];memcpy(k, key, AES_BLOCK_SIZE);//key作为data key。K要根据policy进行加密
4.生成S key=Ki:RAND_bytes(ki, AES_BLOCK_SIZE);//S key

5.然后以Ki作为参数来形成aes,并对AES_set_encrypt_key(ki, 128, &aes)&&AES_cbc_encrypt(k, kki, AES_BLOCK_SIZE, &aes, iv, AES_ENCRYPT);//加密强度。(char *in,char *out,length,AES_KEY *key,char *ivec,enc).其中AES_ENCRYPT表示加密,其余值表示解密

6.k=[data key]s:    memcpy(k, kki, AES_BLOCK_SIZE);

7.将Ki进行分片,并进行策略加密生成新的Ki:ssss_split(AES_BLOCK_SIZE, reinterpret_cast<char *>(ki), reinterpret_cast<char *>(ki_shares), ssss_threshold, ssss_number);

for (int share = 0; share < ssss_number; ++share)//    其中ssss_number是总的片数,ssss_threshold是门槛片数,也就是只要集成的片数>ssss_threshold时,就可以完整的将Ki重现。
{
memcpy(ki, ki_shares + AES_BLOCK_SIZE * share, AES_BLOCK_SIZE);//spilt.其中ki参与了[data key]s的加密工作
PolicyForClient policy(subToken, share); //PolicyForClient(policyname,keymanageID)
if (!policy.encrypt(ki))//对ki进行policy处理,这样就可以表现出基于策略的加密方式,返回的是ki
{
fclose(fp);
return false;
}
fwrite(ki, sizeof(unsigned char), rsaSize, fp);//将分片Ki(经过policy加工后的)文件存放到文件中

8.将k=[data key]s 写到文件中:fwrite(k, sizeof(unsigned char), AES_BLOCK_SIZE, fp);//k=[data key]S

9.对filename进行加密:encrypt(filename, key);//key =data key
}

2.DOWNLOAD(filename){


1.首先遍历,查看文件是否存在:getFile(filename, ".fade");//遍历看是否存在

2.if (!checkHMAC(filename))//查看文件的HMAC是否正确。,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出

3.获取文件相关属性:getFile(filename, ".metadata");

4.FILE *fp = fopen((path + '/' + filename + ".metadata").c_str(), "r");打开文件

while (fgets(policyName, POLICY_NAME_LENGTH, fp))//fgets()会加上行尾的/n

{

policyName[strlen(policyName) - 1] = '\0';字符串格式

for (char *str = policyName; ; str = NULL)

{

token = strtok_r(str, sep, &savePtr);//对policyName字符串进行不断地截取

for (int share = 0; share < ssss_number; ++share)//密钥分成多少组?
    {
fread(key, sizeof(unsigned char), rsaSize, fp);
PolicyForClient    policy(token, share);// PolicyForClient(const string &policyname,int keyManagerID=0)
if (share_index < ssss_threshold && policy.decrypt(key))//门槛值,将密钥赋给key.类似于几个组合在一起就可以凑齐key
    {
/* use ssss to combine ki */
memcpy(ki_shares + AES_BLOCK_SIZE * share_index, key, AES_BLOCK_SIZE);//将密钥碎片组合起来
share_indices[share_index++] = share + 1;//position add 1
        }

    }
success = (share_index >= ssss_threshold);// notice if success
if (success)
        {
ssss_combine(AES_BLOCK_SIZE, reinterpret_cast<char *>(ki_shares), share_indices, reinterpret_cast<char *>(key), ssss_threshold);//combine one chunk
//生成完整的密钥key
Keychain *kc = new Keychain;
kc->key = key;
kc->next = keychain;
keychain = kc;//组成链表

            }
else
            {
fseek(fp, rsaSize, SEEK_CUR);//重新定位fp内部指针,使得可以从一个新的key来进行下一个policy
        }

    }//根据policyName将加密data key的密钥S解密出来了,其中S被分成几个部分

if (success)//将[data key]s中的S解密出来之后,将S密钥形成环,然后再进行data key解密
{
unsigned char kki[AES_BLOCK_SIZE];
fread(kki, sizeof(unsigned char), AES_BLOCK_SIZE, fp);
while (keychain)
{
AES_KEY aes;
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0, sizeof(iv));
//进行解密data key操作
AES_set_decrypt_key(keychain->key, 128, &aes) 
unsigned char k[AES_BLOCK_SIZE];
AES_cbc_encrypt(kki, k, AES_BLOCK_SIZE, &aes, iv, AES_DECRYPT);//进行data key解密
/*
void AES_cbc_encrypt
(const unsigned char *in, 
unsigned char *out,
const unsigned long length, 
const AES_KEY *key, //it will be changed during the encrypt&decrypt process, so it required to be reset each time 
unsigned char *ivec,   // salt, it will be changed during the encrypt&decrypt process, so it required to be reset each time 
const int enc //AES_ENCRYPT for encrypt and other values for descrypt);*/
memcpy(kki, k, AES_BLOCK_SIZE);//获取data 加密密钥data key
/*释放链表*/

Keychain *kc = keychain;
free(keychain->key);
keychain = keychain->next;
delete kc;
}
fclose(fp);
decrypt(filename, kki);//获取完整的data key,进而对filename进行相关的解密
return true;
}
}

不然的话就将生成的部分keychain释放。}

3.RENEW(fileName,policyName)

{

这个函数主要是使用新的策略取代旧的策略,所以我们需要做的就是更改策略所使用的区域

1.遍历文件:getFile(filename, ".metadata")

2.打开文件属性,并获取文件policyName:FILE *fp = fopen((path + '/' + filename + ".metadata").c_str(), "r");和fgets(oldPolicyName, POLICY_NAME_LENGTH, fp);

3.将S key进行恢复,然后使用新的策略进行加密

fread(key, sizeof(unsigned char), rsaSize * ssss_number, fp);//S key分成ssss_number几个部分。
for (int share = 0; share < ssss_number; ++share)
{
PolicyForClient oldPolicy(oldPolicyName, share);
oldPolicy.decrypt(key + rsaSize * share)//将S解密出来
PolicyForClient newPolicy(newPolicyName, share);
!newPolicy.encrypt(key + rsaSize * share)//对S进行加密
}这样的话就是用了新的策略将S key加密起来了

4.读出[data key]s:fread(k, sizeof(unsigned char), AES_BLOCK_SIZE, fp);

5.重新生成一个文件.metadata

三步走:使用newpolicyName取代oldpolicyName、使用新policy的加密后的S取代旧的,然后就是不变的[data key]S,全程S、data key没有改变,改变的只是policyName以及经过policyName处理的[S]policy

fp = fopen((path + '/' + filename + ".metadata").c_str(), "w");
fprintf(fp, "%s\n", newPolicyName);//nowPolicyName replace oldPolicyName
fwrite(key, sizeof(unsigned char), rsaSize * ssss_number, fp);//S key
fwrite(k, sizeof(unsigned char), AES_BLOCK_SIZE, fp);//[data key]s
}

4. REVOKE:吊销policyName,这个需要跟key manager进行交互,相对来说麻烦一点。跟key manager通过使用socket进行信息之间的传递


bool Client::revoke(const char *policyName)
{
for (int share = 0; share < ssss_number; ++share)
{
char kmid[11];
snprintf(kmid, sizeof(kmid), "%d", share);
remove((path + '/' + policyName + '.' + kmid + ".pubkey").c_str());//移走公钥?
}
PolicyForClient policy(policyName);
return policy.revoke();
}    

    接着进入policy.revoke函数进行相关policy删除:bool PolicyForClient::revoke() const{

    1.首先获取policyName,并用它来作为下一步的请求字符串request

    2.重点来了const int challengeLength = Client::instance()->interact(request, requestLength, response, RESPONSE_BUFFER_LENGTH, keyManagerID) - 1;在这里我们可以看到调用了Client::instance()->interact,跟前面我们分析的那个key manager中的interact是不是有点眼熟。眼熟那就对了,Client跟Key manager是通过interact中的socket进行联系的,也就是客户端与服务器之间的所有的操作都是通过interact来进行的,具体的就是通过socket来进行的。

    Client::instance()->interact{

    步骤跟前面key manager中的interact相类似,唯一的区别就是我们将数据发送过去,等待key manager进行处理,然后将处理结果发给Client::instance()->interact

    1.    socket地址初始化

    2.    建立socket以及跟key manager中的socket进行连接,为一下步的信息传递做铺垫

    3.    发送信息,这里面一般要发送两个信息,if (sendn(sockfd, &len, sizeof(len)) < 0 || sendn(sockfd, request, requestLength) < 0),一个是传输的数据长度,一个是实际信息量

    4.    然后等待key manager返回数据,在这里我们可以看到的就是responese以及len长度,这里是key manager处理的结果}

    在interact之后,我们获取了返回信息responese以及长度len,接下来要做的就是根据responese来进行处理。

            1).    如果*responese== EPHEMERIZER_RESPONSE_FAILED这说明操作失败,直接返回

            2).      如果*responese== EPHEMERIZER_RESPONSE_OK_CPABE,那么我们需要分开讨论{

                          1.    在/temp_cpabe.cpabe中:  FILE *fp = fopen((Client::instance()->getPath() + "/temp_cpabe.cpabe").c_str(), "w");    if (system(("cpabe-dec " + Client::instance()->getCpabePublicKeyFile() + ' ' + Client::instance()->getCpabePrivateKeyFile() + ' ' + Client::instance()->getPath() + "/temp_cpabe.cpabe").c_str()))  

                          2.    在/temp_cpabe中:fp = fopen((Client::instance()->getPath() + "/temp_cpabe").c_str(), "r");然后进行获取前面提到的len长度的信息,requestLength = fread(request + 4, 1, challengeLength, fp) + 4;然后再和key manager进行交互Client::instance()->interact(request, requestLength, response, RESPONSE_BUFFER_LENGTH, keyManagerID);//client request} 

            }    

}


转载于:https://my.oschina.net/gddyl/blog/124437

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值