#import "CommitPacket.h" @implementation CommitPacket @synthesize agreementSpecId, authSpecId, cipherSpecId, dhPart2HelloCommitment, h2, hashSpecId, sasSpecId, zid; #define ZID_LENGTH 12 #define HASH_SPEC_LENGTH 4 #define CIPHER_SPEC_LENGTH 4 #define AUTH_SPEC_LENGTH 4 #define AGREE_SPEC_LENGTH 4 #define SAS_SPEC_LENGTH 4 #define COMMIT_LENGTH 32 #define HASH_SPEC_OFFSET HASH_CHAIN_ITEM_LENGTH + ZID_LENGTH #define CIPHER_SPEC_OFFSET HASH_SPEC_OFFSET + HASH_SPEC_LENGTH #define AUTH_SPEC_OFFSET CIPHER_SPEC_OFFSET + CIPHER_SPEC_LENGTH #define AGREE_SPEC_OFFSET AUTH_SPEC_OFFSET + AUTH_SPEC_LENGTH #define SAS_SPEC_OFFSET AGREE_SPEC_OFFSET + AGREE_SPEC_LENGTH #define COMMIT_OFFSET SAS_SPEC_OFFSET + SAS_SPEC_LENGTH +(CommitPacket*) commitPacketWithDefaultSpecsAndKeyAgreementProtocol:(id)keyAgreementProtocol andHashChain:(HashChain*)hashChain andZid:(Zid*)zid andCommitmentToHello:(HelloPacket*)hello andDhPart2:(DhPacket*)dhPart2 { require(keyAgreementProtocol != nil); require(hashChain != nil); require(zid != nil); require(hello != nil); require(dhPart2 != nil); NSData* dhPart2Data = [[dhPart2 embeddedIntoHandshakePacket] dataUsedForAuthentication]; NSData* helloData = [[hello embeddedIntoHandshakePacket] dataUsedForAuthentication]; return [CommitPacket commitPacketWithHashChainH2:hashChain.h2 andZid:zid andHashSpecId:COMMIT_DEFAULT_HASH_SPEC_ID andCipherSpecId:COMMIT_DEFAULT_CIPHER_SPEC_ID andAuthSpecId:COMMIT_DEFAULT_AUTH_SPEC_ID andAgreeSpecId:keyAgreementProtocol.getId andSasSpecId:COMMIT_DEFAULT_SAS_SPEC_ID andDhPart2HelloCommitment:@[dhPart2Data, helloData].ows_concatDatas.hashWithSha256 andHmacKey:hashChain.h1]; } +(CommitPacket*) commitPacketWithHashChainH2:(NSData*)h2 andZid:(Zid*)zid andHashSpecId:(NSData*)hashSpecId andCipherSpecId:(NSData*)cipherSpecId andAuthSpecId:(NSData*)authSpecId andAgreeSpecId:(NSData*)agreeSpecId andSasSpecId:(NSData*)sasSpecId andDhPart2HelloCommitment:(NSData*)dhPart2HelloCommitment andHmacKey:(NSData*)hmacKey { require(h2 != nil); require(zid != nil); require(hashSpecId != nil); require(cipherSpecId != nil); require(authSpecId != nil); require(agreeSpecId != nil); require(sasSpecId != nil); require(dhPart2HelloCommitment != nil); require(hmacKey != nil); require(h2.length == HASH_CHAIN_ITEM_LENGTH); require(hashSpecId.length == HASH_SPEC_LENGTH); require(cipherSpecId.length == CIPHER_SPEC_LENGTH); require(authSpecId.length == AUTH_SPEC_LENGTH); require(agreeSpecId.length == AGREE_SPEC_LENGTH); require(sasSpecId.length == SAS_SPEC_LENGTH); CommitPacket* p = [CommitPacket new]; p->h2 = h2; p->zid = zid; p->hashSpecId = hashSpecId; p->cipherSpecId = cipherSpecId; p->authSpecId = authSpecId; p->agreementSpecId = agreeSpecId; p->sasSpecId = sasSpecId; p->dhPart2HelloCommitment = dhPart2HelloCommitment; p->embedding = [p embedInHandshakePacketAuthenticatedWith:hmacKey]; return p; } -(HandshakePacket*) embedInHandshakePacketAuthenticatedWith:(NSData*)hmacKey { require(hmacKey != nil); requireState(h2.length == HASH_CHAIN_ITEM_LENGTH); requireState(hashSpecId.length == HASH_SPEC_LENGTH); requireState(cipherSpecId.length == CIPHER_SPEC_LENGTH); requireState(authSpecId.length == AUTH_SPEC_LENGTH); requireState(agreementSpecId.length == AGREE_SPEC_LENGTH); requireState(sasSpecId.length == SAS_SPEC_LENGTH); NSData* payload = @[ h2, zid.getData, hashSpecId, cipherSpecId, authSpecId, agreementSpecId, sasSpecId, dhPart2HelloCommitment ].ows_concatDatas; return [[HandshakePacket handshakePacketWithTypeId:HANDSHAKE_TYPE_COMMIT andPayload:payload] withHmacAppended:hmacKey]; } -(void) verifyCommitmentAgainstHello:(HelloPacket*)hello andDhPart2:(DhPacket*)dhPart2 { require(hello != nil); require(dhPart2 != nil); NSData* expected = [[@[ [[dhPart2 embeddedIntoHandshakePacket] dataUsedForAuthentication], [[hello embeddedIntoHandshakePacket] dataUsedForAuthentication]] ows_concatDatas] hashWithSha256]; checkOperation([dhPart2HelloCommitment isEqualToData_TimingSafe:expected]); } -(void) verifyMacWithHashChainH1:(NSData*)hashChainH1 { checkOperation([[hashChainH1 hashWithSha256] isEqualToData_TimingSafe:h2]); [embedding withHmacVerifiedAndRemoved:hashChainH1]; } +(NSData*) getH2FromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(0, HASH_CHAIN_ITEM_LENGTH)]; } +(Zid*) getZidFromPayload:(NSData*)payload { return [Zid zidWithData:[payload subdataWithRange:NSMakeRange(HASH_CHAIN_ITEM_LENGTH, ZID_LENGTH)]]; } +(NSData*) getHashSpecIdFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(HASH_SPEC_OFFSET, HASH_SPEC_LENGTH)]; } +(NSData*) getCipherSpecIdFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(CIPHER_SPEC_OFFSET, CIPHER_SPEC_LENGTH)]; } +(NSData*) getAuthSpecIdFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(AUTH_SPEC_OFFSET, AUTH_SPEC_LENGTH)]; } +(NSData*) getAgreeSpecIdFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(AGREE_SPEC_OFFSET, AGREE_SPEC_LENGTH)]; } +(NSData*) getSasSpecIdFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(SAS_SPEC_OFFSET, SAS_SPEC_LENGTH)]; } +(NSData*) getCommitmentFromPayload:(NSData*)payload { return [payload subdataWithRange:NSMakeRange(COMMIT_OFFSET, COMMIT_LENGTH)]; } +(CommitPacket*) commitPacketParsedFromHandshakePacket:(HandshakePacket*)handshakePacket { require(handshakePacket != nil); checkOperation([[handshakePacket typeId] isEqualToData:HANDSHAKE_TYPE_COMMIT]); NSData* payload = [handshakePacket payload]; checkOperation(payload.length == COMMIT_OFFSET + COMMIT_LENGTH + HANDSHAKE_TRUNCATED_HMAC_LENGTH); CommitPacket* p = [CommitPacket new]; p->h2 = [self getH2FromPayload:payload]; p->zid = [self getZidFromPayload:payload]; p->hashSpecId = [self getHashSpecIdFromPayload:payload]; p->cipherSpecId = [self getCipherSpecIdFromPayload:payload]; p->authSpecId = [self getAuthSpecIdFromPayload:payload]; p->agreementSpecId = [self getAgreeSpecIdFromPayload:payload]; p->sasSpecId = [self getSasSpecIdFromPayload:payload]; p->dhPart2HelloCommitment = [self getCommitmentFromPayload:payload]; p->embedding = handshakePacket; return p; } -(HandshakePacket*) embeddedIntoHandshakePacket { return embedding; } @end