📄 sfs.cpp
字号:
/* * Copyright (c) 2001 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. Neither the name of the Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//* * sfs: Secure File Sharing */#ifdef WIN32#include <windows.h>#else#include <sys/time.h>#include <unistd.h>#endif#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <ptp/ptp.h>#include <ptp/id.h>#include <ptp/auth.h>#include <ptp/store.h>#include <ptp/collect.h>#include <ptp/net.h>#include <ptp/key.h>#include <ptp/rand.h>#include <ptp/debug.h>// Uncomment to build for performance testing//#define PERF_TEST 1const char *prog = NULL;#define STRLEN_CONST(x) (sizeof(x) - 1)#define STRNCMP_CONST(x, y) strncmp((x), (y), sizeof(y) - 1)#define SFS_DEFAULT_PORT 8080#define SFS_READ_SIZE 8192#define SFS_FLAGS_ROLL 0x1#define SFS_FLAGS_PLAINTEXT_XFER 0x2#define SFS_AUTH_URL "/auth"#define SFS_RESP_URL "/resp"#define SFS_SEARCH_URL "/search"/* * SFS network protocol * * Authentication: * HTTP PUT /auth | CERT * HTTP OK | CHAL | CERT * HTTP PUT /resp | RESP | CHAL | ENVELOPE(FLAGS) * HTTP OK | RESP | ENVELOPE(KEYID | SHADOW | KEY) * * Search: * HTTP PUT /search | KEYID | E(DATA) * HTTP OK | E(DATA) * * Get: * HTTP GET /KEYID/FILEID * HTTP OK | E(DATA) */struct Key:public PTP::List::Entry{ struct Shared { BYTE keyid[4]; BYTE shadow[4]; BYTE key[PTP::Key::KEY_SIZE]; }; BYTE id[PTP::Identity::KEY_SIZE]; PTP::Net::Ip ip; PTP::Net::Port port; unsigned long keyid; unsigned long shadow; int flags; Shared shared;};struct Response:public PTP::List::Entry{ int id; char *name; char *url;};struct TransferContext{ TransferContext(PTP::Net::Connection *conn, FILE *filep) :c(conn), fp(filep) {} PTP::Net::Connection *c; FILE *fp;};static Key *FindKey(PTP::List *keys, const PTP::Identity *ident, PTP::Net::Ip ip, PTP::Net::Port port){ BYTE id[PTP::Identity::KEY_SIZE]; if (ident) ident->GetKey(id); Key *key = NULL; keys->Lock(); PTP_LIST_FOREACH(Key, key, keys) { if (key->ip == ip && key->port == port && (!ident || memcmp(key->id, id, sizeof(id)) == 0)) break; } keys->Unlock(); return key;}static Key *CreateKey(PTP::List *keys, const PTP::Identity *id, PTP::Net::Ip ip, int flags){ static unsigned long keyid = 0; Key *key = FindKey(keys, id, ip, 0); if (!key) { key = new Key; id->GetKey(key->id); key->ip = ip; key->port = 0; key->keyid = 0; keys->Insert(key); flags |= SFS_FLAGS_ROLL; } if (flags & SFS_FLAGS_ROLL) { key->keyid = keyid++; PTP::Net::Set32(key->shared.keyid, key->keyid); PTP::Random::Fill((BYTE*) &key->shadow, sizeof(key->shadow)); PTP::Net::Set32(key->shared.shadow, key->shadow); PTP::Random::Fill(key->shared.key, sizeof(key->shared.key)); unsigned long shadow2 = 0; PTP::Random::Fill((BYTE*) &shadow2, sizeof(shadow2)); key->shadow ^= shadow2; } key->flags = (flags & ~SFS_FLAGS_ROLL); return key;}static Key *ImportKey(PTP::List *keys, const PTP::Identity *id, PTP::Net::Ip ip, PTP::Net::Port port, int flags, const Key::Shared *shared){ Key *key = FindKey(keys, id, ip, port); if (!key) { key = new Key; id->GetKey(key->id); key->ip = ip; key->port = port; key->keyid = PTP::Net::Get32(shared->keyid); key->shadow = PTP::Net::Get32(shared->shadow); memcpy(&key->shared, shared, sizeof(key->shared)); keys->Insert(key); } else { key->keyid = PTP::Net::Get32(shared->keyid); key->shadow = PTP::Net::Get32(shared->shadow); memcpy(&key->shared, shared, sizeof(key->shared)); } key->flags = (flags & ~SFS_FLAGS_ROLL); return key;}static Key *FindKey(PTP::List *keys, unsigned long keyid){ Key *key = NULL; keys->Lock(); PTP_LIST_FOREACH(Key, key, keys) { if (key->keyid == keyid) break; } keys->Unlock(); return key;}static voidDestroyKeys(PTP::List *keys){ Key *key = NULL; keys->Lock(); PTP_LIST_FOREACH(Key, key, keys) { keys->Remove(key, 0); delete key; } keys->Unlock();}static intInsertResponse(PTP::List *resps, int *count, char *start, char **end){ start = strstr(start, "HREF=\""); if (!start) return -1; start += STRLEN_CONST("HREF=\""); char *e = strchr(start, '"'); if (!e) return -1; int size = e - start; char *url = new char[size + 1]; memcpy(url, start, size); url[size] = '\0'; start = e + 2; e = strchr(start, '<'); if (!e) { delete [] url; return -1; } size = e - start; char *name = new char[size + 1]; memcpy(name, start, size); name[size] = '\0'; Response *resp = new Response; (*count)++; resp->id = *count; resp->name = name; resp->url = url; resps->Append(resp); if (end) *end = e + 1; return 0;}static Response *FindResponse(PTP::List *resps, int id){ Response *resp; resps->Lock(); PTP_LIST_FOREACH(Response, resp, resps) { if (resp->id == id) break; } resps->Unlock(); return resp;}static voidShowResponses(PTP::List *resps, int showid){ resps->Lock(); Response *resp; PTP_LIST_FOREACH(Response, resp, resps) { printf(" "); if (showid) printf("%d) ", resp->id); printf("%s (%s)\n", resp->name, resp->url); } resps->Unlock();}static voidDestroyResponses(PTP::List *resps){ resps->Lock(); Response *resp; PTP_LIST_FOREACH(Response, resp, resps) { resps->Remove(resp, 0); delete [] resp->name; delete [] resp->url; delete resp; } resps->Unlock();}static PTP::Net::Connection *Connect(const char *url){ PTP::Net::Port port; PTP::Net::Ip ip = PTP::Net::Lookup(url, &port, SFS_DEFAULT_PORT); if (!ip || !port) { printf("%s: invalid host `%s'.\n", prog, url); return NULL; } PTP::Net::Connection *c = new PTP::Net::Connection(PTP::Net::Connection::HTTP, ip, port); if (c->Open()) { printf("%s: connection to `%s' failed.\n", prog, url); delete c; return NULL; } return c;}static intInsert(PTP::Store *store, PTP::Identity *id){ PTP::Identity *local = store->Find(NULL, 1); if (local && strcmp(local->GetName(), id->GetName()) == 0) return 0; PTP::Identity *issuer = id; if (id && strcmp(id->GetName(), id->GetIssuerName()) != 0) issuer = store->Find(id->GetIssuerName()); if (!issuer || issuer->Verify(id) != 0) return -1; PTP::Identity *old = store->Find(id->GetName(), 0); if (old) store->Remove(old); store->Insert(id, 0); store->Save(); return 0;}static Key *Auth(PTP::Store *store, PTP::List *keys, PTP::Net::Connection *c, int flags){ if (!c) return NULL; Key *key = FindKey(keys, NULL, c->GetIp(), c->GetPort()); if (key) return key; const PTP::Identity *localId = store->Find(NULL, 1); int size = PTP::Store::Export(localId, 0, NULL, NULL, NULL); BYTE *buffer = new BYTE[size]; PTP::Store::Export(localId, 0, NULL, NULL, buffer); int st = c->WriteHttp("PUT", SFS_AUTH_URL, NULL, buffer, NULL, size); delete [] buffer; if (st) { c->Close(); return NULL; } buffer = c->ReadHttp(NULL, -1, NULL, &size); c->Close(); if (!buffer || size <= PTP::Authenticator::CHALLENGE_SIZE) { delete [] buffer; return NULL; } BYTE chal[PTP::Authenticator::CHALLENGE_SIZE]; memcpy(chal, buffer, sizeof(chal)); PTP::Identity *remoteId = PTP::Store::Import( buffer + sizeof(chal), size - sizeof(chal), NULL, NULL); delete [] buffer; if (!remoteId || Insert(store, remoteId)) { delete remoteId; return NULL; } BYTE fl = (BYTE) flags; size = PTP::Store::ExportEnvelope( &fl, sizeof(fl), NULL, remoteId, localId); size += (PTP::Authenticator::RESPONSE_SIZE + PTP::Authenticator::CHALLENGE_SIZE); buffer = new BYTE[size]; PTP::Authenticator auth(store); auth.Respond(chal, buffer); auth.Challenge(remoteId, 60, (void*) remoteId, buffer + PTP::Authenticator::RESPONSE_SIZE); PTP::Store::ExportEnvelope( &fl, sizeof(fl), buffer + PTP::Authenticator::RESPONSE_SIZE + PTP::Authenticator::CHALLENGE_SIZE, remoteId, localId); st = c->WriteHttp("PUT", SFS_RESP_URL, NULL, buffer, NULL, size); delete [] buffer; if (st) { c->Close(); delete remoteId; return NULL; } buffer = c->ReadHttp(NULL, -1, NULL, &size); c->Close(); if (!buffer || size <= PTP::Authenticator::RESPONSE_SIZE || auth.Verify(buffer) != remoteId || PTP::Store::ImportEnvelope( buffer + PTP::Authenticator::RESPONSE_SIZE, size - PTP::Authenticator::RESPONSE_SIZE, buffer, localId, remoteId) != sizeof(Key::Shared)) { delete [] buffer; delete remoteId; return NULL; } key = ImportKey(keys, remoteId, c->GetIp(), c->GetPort(), flags, (const Key::Shared*) buffer); delete [] buffer; delete remoteId; if (!key) return NULL; return key;}static intHandleAuth(PTP::Store *store, PTP::Authenticator *auth, PTP::List *keys, PTP::Net::Connection *c){ int size = 0; BYTE *buffer = c->ReadHttp(NULL, -1, NULL, &size); if (!buffer) return -1; const PTP::Identity *localId = store->Find(NULL, 1); PTP::Identity *remoteId = PTP::Store::Import(buffer, size, NULL, NULL); delete [] buffer; if (!remoteId) { c->Close(); return -1; } size = PTP::Authenticator::CHALLENGE_SIZE; size += PTP::Store::Export(localId, 0, NULL, NULL, NULL); buffer = new BYTE[size]; auth->Challenge(remoteId, 60, (void*) remoteId, buffer); PTP::Store::Export( localId, 0, NULL, NULL, buffer + PTP::Authenticator::CHALLENGE_SIZE); int st = c->WriteHttp(PTP::Net::HTTP_OK, NULL, buffer, NULL, size); delete [] buffer; c->Close(); if (st) return -1; return 0;}static intHandleResp(PTP::Store *store, PTP::Authenticator *auth, PTP::List *keys, PTP::Net::Connection *c){ int size = 0; BYTE *buffer = c->ReadHttp(NULL, -1, NULL, &size); if (!buffer) return -1; int esize = (size - PTP::Authenticator::RESPONSE_SIZE - PTP::Authenticator::CHALLENGE_SIZE); if (esize <= 0) { delete [] buffer; return -1; } const PTP::Identity *localId = store->Find(NULL, 1); PTP::Identity *remoteId = (PTP::Identity*) auth->Verify(buffer); if (!remoteId) { delete [] buffer; return -1; } BYTE resp[PTP::Authenticator::RESPONSE_SIZE]; memcpy(resp, buffer, sizeof(resp)); BYTE chal[PTP::Authenticator::CHALLENGE_SIZE]; memcpy(chal, buffer + sizeof(resp), sizeof(chal)); BYTE fl; if (PTP::Store::ImportEnvelope( buffer + (size - esize), esize, &fl, localId, remoteId) != sizeof(fl)) { delete remoteId; delete [] buffer; return -1; } int flags = (int) fl; delete [] buffer; Key *key = CreateKey(keys, remoteId, c->GetIp(), flags); if (!key) return -1; size = PTP::Store::ExportEnvelope( (BYTE*) &key->shared, sizeof(key->shared), NULL, remoteId, localId); size += PTP::Authenticator::RESPONSE_SIZE; buffer = new BYTE[size]; auth->Respond(chal, buffer); PTP::Store::ExportEnvelope( (BYTE*) &key->shared, sizeof(key->shared), buffer + PTP::Authenticator::RESPONSE_SIZE, remoteId, localId); delete remoteId; int st = c->WriteHttp(PTP::Net::HTTP_OK, NULL, buffer, NULL, size); delete [] buffer; c->Close(); if (st) return -1; return 0;}static intSearch(PTP::Net::Connection *c, Key *key, const char *str, PTP::List *resps){ DestroyResponses(resps); PTP::Key k(key->shared.key); int size = k.Encrypt(NULL, strlen(str), NULL); if (size <= 0) return -1; size += 4; BYTE *buffer = new BYTE[size]; memcpy(buffer, key->shared.keyid, 4); k.Encrypt((const BYTE*) str, strlen(str), buffer + 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -