freeswitch/libs/libzrtp/src/zrtp_crypto_sas.c

746 lines
16 KiB
C

/*
* libZRTP SDK library, implements the ZRTP secure VoIP protocol.
* Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
* Contact: http://philzimmermann.com
* For licensing and other legal details, see the file zrtp_legal.c.
*
* Viktor Krykun <v.krikun at zfoneproject.com>
*/
#include "zrtp.h"
/* These 3-syllable words are no longer than 11 characters. */
extern uint8_t hash_word_list_odd[256][12];
/* These 2-syllable words are no longer than 9 characters. */
extern uint8_t hash_word_list_even[256][10];
/*----------------------------------------------------------------------------*/
/*
* copyright 2002, 2003 Bryce "Zooko" Wilcox-O'Hearn
* mailto:zooko@zooko.com
*
* See the end of this file for the free software, open source license (BSD-style).
*/
/**
* Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software to deal in this software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of this software, and to permit
* persons to whom this software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of this software.
*
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THIS SOFTWARE.
*/
zrtp_status_t b2a(zrtp_stringn_t *os, zrtp_stringn_t *result)
{
static const char chars[]="ybndrfg8ejkmcpqxot1uwisza345h769";
if (!os || !result) {
return zrtp_status_bad_param;
} else {
/* pointer into the os buffer, initially pointing to the "one-past-the-end" octet */
const uint8_t* osp = (uint8_t*)os->buffer + os->length;
/* pointer into the result buffer, initially pointing to the "one-past-the-end" quintet */
uint8_t* resp;
/* to hold up to 32 bits worth of the input */
uint32_t x = 0;
result->length = os->length*8;
result->length = (result->length % 5) ? ((result->length/5) + 1) : result->length/5;
/* pointer into the result buffer, initially pointing to the "one-past-the-end" quintet */
resp = (uint8_t*)result->buffer + result->length;
/* Now this is a real live Duff's device. You gotta love it. */
switch ((osp - (uint8_t*)os->buffer) % 5) {
case 0:
do {
x = *--osp;
*--resp = chars[x % 32]; /* The least sig 5 bits go into the final quintet. */
x /= 32; /* ... now we have 3 bits worth in x... */
case 4:
x |= ((uint32_t)(*--osp)) << 3; /* ... now we have 11 bits worth in x... */
*--resp = chars[x % 32];
x /= 32; /* ... now we have 6 bits worth in x... */
*--resp = chars[x % 32];
x /= 32; /* ... now we have 1 bits worth in x... */
case 3:
/* The 8 bits from the 2-indexed octet. So now we have 9 bits worth in x... */
x |= ((uint32_t)(*--osp)) << 1;
*--resp = chars[x % 32];
x /= 32; /* ... now we have 4 bits worth in x... */
case 2:
/* The 8 bits from the 1-indexed octet. So now we have 12 bits worth in x... */
x |= ((uint32_t)(*--osp)) << 4;
*--resp = chars[x%32];
x /= 32; /* ... now we have 7 bits worth in x... */
*--resp = chars[x%32];
x /= 32; /* ... now we have 2 bits worth in x... */
case 1:
/* The 8 bits from the 0-indexed octet. So now we have 10 bits worth in x... */
x |= ((uint32_t)(*--osp)) << 2;
*--resp = chars[x%32];
x /= 32; /* ... now we have 5 bits worth in x... */
*--resp = chars[x];
} while (osp > (const uint8_t *)os->buffer);
} /* switch ((osp - os.buf) % 5) */
return zrtp_status_ok;
}
}
/*----------------------------------------------------------------------------*/
static zrtp_status_t SAS32_compute( zrtp_sas_scheme_t *self,
zrtp_stream_t *stream,
zrtp_hash_t *hash,
uint8_t is_transferred )
{
zrtp_session_t *session = stream->session;
static const zrtp_string16_t sas_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SAS_STR);
zrtp_string64_t sas_digest = ZSTR_INIT_EMPTY(sas_digest);
zrtp_string8_t vad = ZSTR_INIT_EMPTY(vad);
ZSTR_SET_EMPTY(session->sas1);
ZSTR_SET_EMPTY(session->sas2);
if (!is_transferred && !stream->protocol) {
return zrtp_status_bad_param;
}
/*
* Generate SAS source as:
* sashash = KDF(ZRTPSess, "SAS", (ZIDi | ZIDr), 256)
*/
if (!is_transferred) {
_zrtp_kdf( stream,
ZSTR_GV(stream->protocol->cc->s0),
ZSTR_GV(sas_label),
ZSTR_GV(stream->protocol->cc->kdf_context),
ZRTP_HASH_SIZE,
ZSTR_GV(sas_digest));
/* Binary sas value is the leftmost ZRTP_SAS_DIGEST_LENGTH bytes */
zrtp_zstrncpy(ZSTR_GV(session->sasbin), ZSTR_GV(sas_digest), ZRTP_SAS_DIGEST_LENGTH);
} else {
zrtp_zstrcpy(ZSTR_GV(sas_digest), ZSTR_GV(session->sasbin));
}
/* Take the leftmost 20 bits from sas source and render bas32 value */
sas_digest.length = 3;
sas_digest.buffer[2] &= 0xF0;
if (zrtp_status_ok == b2a(ZSTR_GV(sas_digest), ZSTR_GV(vad)) && vad.length >= 4) {
zrtp_zstrncpy(ZSTR_GV(session->sas1), ZSTR_GV(vad), 4);
return zrtp_status_ok;
}
return zrtp_status_fail;
}
/*----------------------------------------------------------------------------*/
static zrtp_status_t SAS256_compute( zrtp_sas_scheme_t *self,
zrtp_stream_t *stream,
zrtp_hash_t *hash,
uint8_t is_transferred )
{
zrtp_session_t *session = stream->session;
ZSTR_SET_EMPTY(session->sas1);
ZSTR_SET_EMPTY(session->sas2);
if (!is_transferred && !stream->protocol) {
return zrtp_status_bad_param;
}
/*
* Generate SAS source as:
* sashash = KDF(ZRTPSess, "SAS", (ZIDi | ZIDr), 256)
*/
if (!is_transferred)
{
static const zrtp_string16_t sas_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SAS_STR);
zrtp_string64_t sas_digest = ZSTR_INIT_EMPTY(sas_digest);
_zrtp_kdf( stream,
ZSTR_GV(stream->protocol->cc->s0),
ZSTR_GV(sas_label),
ZSTR_GV(stream->protocol->cc->kdf_context),
ZRTP_HASH_SIZE,
ZSTR_GV(sas_digest));
/* Binary sas value is last ZRTP_SAS_DIGEST_LENGTH bytes */
zrtp_zstrncpy(ZSTR_GV(session->sasbin), ZSTR_GV(sas_digest), ZRTP_SAS_DIGEST_LENGTH);
}
zrtp_zstrcpyc(ZSTR_GV(session->sas1), (const char *)hash_word_list_even[(uint8_t)session->sasbin.buffer[0]]);
zrtp_zstrcpyc(ZSTR_GV(session->sas2), (const char *)hash_word_list_odd[(uint8_t)session->sasbin.buffer[1]]);
return zrtp_status_ok;
}
/*----------------------------------------------------------------------------*/
zrtp_status_t zrtp_defaults_sas(zrtp_global_t* zrtp)
{
zrtp_sas_scheme_t* base32 = zrtp_sys_alloc(sizeof(zrtp_sas_scheme_t));
zrtp_sas_scheme_t* base256 = zrtp_sys_alloc(sizeof(zrtp_sas_scheme_t));
if (!base32 || !base256) {
if (base32) {
zrtp_sys_free(base32);
}
if (base256) {
zrtp_sys_free(base256);
}
return zrtp_status_alloc_fail;
}
zrtp_memset(base32, 0, sizeof(zrtp_sas_scheme_t));
zrtp_memcpy(base32->base.type, ZRTP_B32, ZRTP_COMP_TYPE_SIZE);
base32->base.id = ZRTP_SAS_BASE32;
base32->base.zrtp = zrtp;
base32->compute = SAS32_compute;
zrtp_memset(base256, 0, sizeof(zrtp_sas_scheme_t));
zrtp_memcpy(base256->base.type, ZRTP_B256, ZRTP_COMP_TYPE_SIZE);
base256->base.id = ZRTP_SAS_BASE256;
base256->base.zrtp = zrtp;
base256->compute = SAS256_compute;
zrtp_comp_register(ZRTP_CC_SAS, base32, zrtp);
zrtp_comp_register(ZRTP_CC_SAS, base256, zrtp);
return zrtp_status_ok;
}
uint8_t hash_word_list_odd[256][12] = {
"adroitness",
"adviser",
"aftermath",
"aggregate",
"alkali",
"almighty",
"amulet",
"amusement",
"antenna",
"applicant",
"Apollo",
"armistice",
"article",
"asteroid",
"Atlantic",
"atmosphere",
"autopsy",
"Babylon",
"backwater",
"barbecue",
"belowground",
"bifocals",
"bodyguard",
"bookseller",
"borderline",
"bottomless",
"Bradbury",
"bravado",
"Brazilian",
"breakaway",
"Burlington",
"businessman",
"butterfat",
"Camelot",
"candidate",
"cannonball",
"Capricorn",
"caravan",
"caretaker",
"celebrate",
"cellulose",
"certify",
"chambermaid",
"Cherokee",
"Chicago",
"clergyman",
"coherence",
"combustion",
"commando",
"company",
"component",
"concurrent",
"confidence",
"conformist",
"congregate",
"consensus",
"consulting",
"corporate",
"corrosion",
"councilman",
"crossover",
"crucifix",
"cumbersome",
"customer",
"Dakota",
"decadence",
"December",
"decimal",
"designing",
"detector",
"detergent",
"determine",
"dictator",
"dinosaur",
"direction",
"disable",
"disbelief",
"disruptive",
"distortion",
"document",
"embezzle",
"enchanting",
"enrollment",
"enterprise",
"equation",
"equipment",
"escapade",
"Eskimo",
"everyday",
"examine",
"existence",
"exodus",
"fascinate",
"filament",
"finicky",
"forever",
"fortitude",
"frequency",
"gadgetry",
"Galveston",
"getaway",
"glossary",
"gossamer",
"graduate",
"gravity",
"guitarist",
"hamburger",
"Hamilton",
"handiwork",
"hazardous",
"headwaters",
"hemisphere",
"hesitate",
"hideaway",
"holiness",
"hurricane",
"hydraulic",
"impartial",
"impetus",
"inception",
"indigo",
"inertia",
"infancy",
"inferno",
"informant",
"insincere",
"insurgent",
"integrate",
"intention",
"inventive",
"Istanbul",
"Jamaica",
"Jupiter",
"leprosy",
"letterhead",
"liberty",
"maritime",
"matchmaker",
"maverick",
"Medusa",
"megaton",
"microscope",
"microwave",
"midsummer",
"millionaire",
"miracle",
"misnomer",
"molasses",
"molecule",
"Montana",
"monument",
"mosquito",
"narrative",
"nebula",
"newsletter",
"Norwegian",
"October",
"Ohio",
"onlooker",
"opulent",
"Orlando",
"outfielder",
"Pacific",
"pandemic",
"Pandora",
"paperweight",
"paragon",
"paragraph",
"paramount",
"passenger",
"pedigree",
"Pegasus",
"penetrate",
"perceptive",
"performance",
"pharmacy",
"phonetic",
"photograph",
"pioneer",
"pocketful",
"politeness",
"positive",
"potato",
"processor",
"provincial",
"proximate",
"puberty",
"publisher",
"pyramid",
"quantity",
"racketeer",
"rebellion",
"recipe",
"recover",
"repellent",
"replica",
"reproduce",
"resistor",
"responsive",
"retraction",
"retrieval",
"retrospect",
"revenue",
"revival",
"revolver",
"sandalwood",
"sardonic",
"Saturday",
"savagery",
"scavenger",
"sensation",
"sociable",
"souvenir",
"specialist",
"speculate",
"stethoscope",
"stupendous",
"supportive",
"surrender",
"suspicious",
"sympathy",
"tambourine",
"telephone",
"therapist",
"tobacco",
"tolerance",
"tomorrow",
"torpedo",
"tradition",
"travesty",
"trombonist",
"truncated",
"typewriter",
"ultimate",
"undaunted",
"underfoot",
"unicorn",
"unify",
"universe",
"unravel",
"upcoming",
"vacancy",
"vagabond",
"vertigo",
"Virginia",
"visitor",
"vocalist",
"voyager",
"warranty",
"Waterloo",
"whimsical",
"Wichita",
"Wilmington",
"Wyoming",
"yesteryear",
"Yucatan"
};
uint8_t hash_word_list_even[256][10] = {
"aardvark",
"absurd",
"accrue",
"acme",
"adrift",
"adult",
"afflict",
"ahead",
"aimless",
"Algol",
"allow",
"alone",
"ammo",
"ancient",
"apple",
"artist",
"assume",
"Athens",
"atlas",
"Aztec",
"baboon",
"backfield",
"backward",
"banjo",
"beaming",
"bedlamp",
"beehive",
"beeswax",
"befriend",
"Belfast",
"berserk",
"billiard",
"bison",
"blackjack",
"blockade",
"blowtorch",
"bluebird",
"bombast",
"bookshelf",
"brackish",
"breadline",
"breakup",
"brickyard",
"briefcase",
"Burbank",
"button",
"buzzard",
"cement",
"chairlift",
"chatter",
"checkup",
"chisel",
"choking",
"chopper",
"Christmas",
"clamshell",
"classic",
"classroom",
"cleanup",
"clockwork",
"cobra",
"commence",
"concert",
"cowbell",
"crackdown",
"cranky",
"crowfoot",
"crucial",
"crumpled",
"crusade",
"cubic",
"dashboard",
"deadbolt",
"deckhand",
"dogsled",
"dragnet",
"drainage",
"dreadful",
"drifter",
"dropper",
"drumbeat",
"drunken",
"Dupont",
"dwelling",
"eating",
"edict",
"egghead",
"eightball",
"endorse",
"endow",
"enlist",
"erase",
"escape",
"exceed",
"eyeglass",
"eyetooth",
"facial",
"fallout",
"flagpole",
"flatfoot",
"flytrap",
"fracture",
"framework",
"freedom",
"frighten",
"gazelle",
"Geiger",
"glitter",
"glucose",
"goggles",
"goldfish",
"gremlin",
"guidance",
"hamlet",
"highchair",
"hockey",
"indoors",
"indulge",
"inverse",
"involve",
"island",
"jawbone",
"keyboard",
"kickoff",
"kiwi",
"klaxon",
"locale",
"lockup",
"merit",
"minnow",
"miser",
"Mohawk",
"mural",
"music",
"necklace",
"Neptune",
"newborn",
"nightbird",
"Oakland",
"obtuse",
"offload",
"optic",
"orca",
"payday",
"peachy",
"pheasant",
"physique",
"playhouse",
"Pluto",
"preclude",
"prefer",
"preshrunk",
"printer",
"prowler",
"pupil",
"puppy",
"python",
"quadrant",
"quiver",
"quota",
"ragtime",
"ratchet",
"rebirth",
"reform",
"regain",
"reindeer",
"rematch",
"repay",
"retouch",
"revenge",
"reward",
"rhythm",
"ribcage",
"ringbolt",
"robust",
"rocker",
"ruffled",
"sailboat",
"sawdust",
"scallion",
"scenic",
"scorecard",
"Scotland",
"seabird",
"select",
"sentence",
"shadow",
"shamrock",
"showgirl",
"skullcap",
"skydive",
"slingshot",
"slowdown",
"snapline",
"snapshot",
"snowcap",
"snowslide",
"solo",
"southward",
"soybean",
"spaniel",
"spearhead",
"spellbind",
"spheroid",
"spigot",
"spindle",
"spyglass",
"stagehand",
"stagnate",
"stairway",
"standard",
"stapler",
"steamship",
"sterling",
"stockman",
"stopwatch",
"stormy",
"sugar",
"surmount",
"suspense",
"sweatband",
"swelter",
"tactics",
"talon",
"tapeworm",
"tempest",
"tiger",
"tissue",
"tonic",
"topmost",
"tracker",
"transit",
"trauma",
"treadmill",
"Trojan",
"trouble",
"tumor",
"tunnel",
"tycoon",
"uncut",
"unearth",
"unwind",
"uproot",
"upset",
"upshot",
"vapor",
"village",
"virus",
"Vulcan",
"waffle",
"wallet",
"watchword",
"wayside",
"willow",
"woodlark",
"Zulu"
};