Merge branch 'release/0.2.0'

This commit is contained in:
Christian Basler 2015-07-03 14:48:33 +02:00
commit c557eafc36
84 changed files with 1724 additions and 16899 deletions

View File

@ -1,7 +1,7 @@
Jabit [![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) Jabit [![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit)
===== =====
A Java implementation for the Bitmessage protocol. To build, use command `gradle build`. Note that for some tests to run, a standard Bitmessage client needs to run on the same system, using port 8444 (the default port). A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`.
Please note that development is still heavily in progress, and I will break the database a lot until it's ready for prime time. Please note that development is still heavily in progress, and I will break the database a lot until it's ready for prime time.
@ -12,6 +12,7 @@ There are most probably some security issues, me programming this thing all by m
Project Status Project Status
-------------- --------------
Basically, everything needed for a working Bitmessage client is there: Basically, everything needed for a working Bitmessage client is there:
* Creating new identities (private addresses) * Creating new identities (private addresses)
* Adding contracts and subscriptions * Adding contracts and subscriptions
@ -22,3 +23,59 @@ Basically, everything needed for a working Bitmessage client is there:
* Initialise and manage a registry of Bitmessage network nodes * Initialise and manage a registry of Bitmessage network nodes
* An easy to use API * An easy to use API
* A command line demo application built using the API * A command line demo application built using the API
Setup
-----
Add Jabit as Gradle dependency:
```Gradle
compile 'ch.dissem.jabit:jabit-domain:0.2.0'
```
Unless you want to implement your own, also add the following:
```Gradle
compile 'ch.dissem.jabit:jabit-networking:0.2.0'
compile 'ch.dissem.jabit:jabit-repositories:0.2.0'
```
And if you want to import from or export to the Wallet Import Format (used by PyBitmessage) you might also want to add:
```Gradle
compile 'ch.dissem.jabit:jabit-wif:0.2.0'
```
Usage
-----
First, you'll need to create a `BitmessageContext`:
```Java
JdbcConfig jdbcConfig = new JdbcConfig();
BitmessageContext ctx = new BitmessageContext.Builder()
.addressRepo(new JdbcAddressRepository(jdbcConfig))
.inventory(new JdbcInventory(jdbcConfig))
.messageRepo(new JdbcMessageRepository(jdbcConfig))
.nodeRegistry(new MemoryNodeRegistry())
.networkHandler(new NetworkNode())
.build();
```
This creates a simple context using a H2 database that will be created in the user's home directory. Next you'll need to
start the context and decide what happens if a message arrives:
```Java
ctx.startup(new BitmessageContext.Listener() {
@Override
public void receive(Plaintext plaintext) {
// TODO: Notify the user
}
});
```
Then you might want to create an identity
```Java
BitmessageAddress identity = ctx.createIdentity(false, Pubkey.Feature.DOES_ACK);
```
or add some contacts
```Java
BitmessageAddress contact = new BitmessageAddress("BM-2cTarrmjMdRicKZ4qQ8A13JhoR3Uq6Zh5j");
address.setAlias("Chris");
ctx.addContact(contact);
```
to which you can send some messages
```Java
ctx.send(identity, contact, "Test", "Hello Chris, this is a message.");
```

View File

@ -1,11 +1,13 @@
allprojects { subprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
apply plugin: 'signing' apply plugin: 'signing'
sourceCompatibility = 1.7 sourceCompatibility = 1.7
group = 'ch.dissem.jabit' group = 'ch.dissem.jabit'
version = '0.1.2' version = '0.2.0'
ext.isReleaseVersion = !version.endsWith("SNAPSHOT")
repositories { repositories {
mavenCentral() mavenCentral()
@ -25,7 +27,55 @@ allprojects {
archives javadocJar, sourcesJar archives javadocJar, sourcesJar
} }
// signing { signing {
// sign configurations.archives required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") }
// } sign configurations.archives
}
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
if (!hasProperty('ossrhUsername')) {
ext.ossrhUsername = 'dummy'
ext.ossrhPassword = 'dummy'
}
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
pom.project {
name 'Jabit'
packaging 'jar'
url 'https://github.com/Dissem/Jabit'
scm {
connection 'scm:git:https://github.com/Dissem/Jabit.git'
developerConnection 'scm:git:git@github.com:Dissem/Jabit.git'
url 'https://github.com/Dissem/Jabit.git'
}
licenses {
license {
name 'The Apache License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
name 'Christian Basler'
email 'chrigu.meyer@gmail.com'
}
}
}
}
}
}
} }

View File

@ -2,6 +2,18 @@ plugins {
id "us.kirchmeier.capsule" version "1.0-rc1" id "us.kirchmeier.capsule" version "1.0-rc1"
} }
uploadArchives {
repositories {
mavenDeployer {
pom.project {
name 'Jabit Demo'
artifactId = 'jabit-demo'
description 'An example Bitmessage client using Jabit.'
}
}
}
}
task fatCapsule(type: FatCapsule) { task fatCapsule(type: FatCapsule) {
applicationClass 'ch.dissem.bitmessage.demo.Main' applicationClass 'ch.dissem.bitmessage.demo.Main'
} }
@ -10,6 +22,7 @@ dependencies {
compile project(':domain') compile project(':domain')
compile project(':networking') compile project(':networking')
compile project(':repositories') compile project(':repositories')
compile project(':wif')
compile 'org.slf4j:slf4j-simple:1.7.12' compile 'org.slf4j:slf4j-simple:1.7.12'
compile 'args4j:args4j:2.32' compile 'args4j:args4j:2.32'
testCompile 'junit:junit:4.11' testCompile 'junit:junit:4.11'

View File

@ -43,11 +43,10 @@ public class Application {
ctx = new BitmessageContext.Builder() ctx = new BitmessageContext.Builder()
.addressRepo(new JdbcAddressRepository(jdbcConfig)) .addressRepo(new JdbcAddressRepository(jdbcConfig))
.inventory(new JdbcInventory(jdbcConfig)) .inventory(new JdbcInventory(jdbcConfig))
.nodeRegistry(new JdbcNodeRegistry(jdbcConfig)) .nodeRegistry(new MemoryNodeRegistry())
.messageRepo(new JdbcMessageRepository(jdbcConfig)) .messageRepo(new JdbcMessageRepository(jdbcConfig))
.networkHandler(new NetworkNode()) .networkHandler(new NetworkNode())
.port(48444) .port(48444)
.streams(1)
.build(); .build();
ctx.startup(new BitmessageContext.Listener() { ctx.startup(new BitmessageContext.Listener() {

View File

@ -16,6 +16,16 @@
package ch.dissem.bitmessage.demo; package ch.dissem.bitmessage.demo;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.networking.NetworkNode;
import ch.dissem.bitmessage.repository.*;
import ch.dissem.bitmessage.wif.WifExporter;
import ch.dissem.bitmessage.wif.WifImporter;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import java.io.File;
import java.io.IOException; import java.io.IOException;
public class Main { public class Main {
@ -25,6 +35,40 @@ public class Main {
if (System.getProperty("org.slf4j.simpleLogger.logFile") == null) if (System.getProperty("org.slf4j.simpleLogger.logFile") == null)
System.setProperty("org.slf4j.simpleLogger.logFile", "./jabit.log"); System.setProperty("org.slf4j.simpleLogger.logFile", "./jabit.log");
CmdLineOptions options = new CmdLineOptions();
CmdLineParser parser = new CmdLineParser(options);
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
parser.printUsage(System.err);
}
if (options.exportWIF != null || options.importWIF != null) {
JdbcConfig jdbcConfig = new JdbcConfig();
BitmessageContext ctx = new BitmessageContext.Builder()
.addressRepo(new JdbcAddressRepository(jdbcConfig))
.inventory(new JdbcInventory(jdbcConfig))
.nodeRegistry(new MemoryNodeRegistry())
.messageRepo(new JdbcMessageRepository(jdbcConfig))
.networkHandler(new NetworkNode())
.port(48444)
.build();
if (options.exportWIF != null) {
new WifExporter(ctx).addAll().write(options.exportWIF);
}
if (options.importWIF != null) {
new WifImporter(ctx, options.importWIF).importAll();
}
} else {
new Application(); new Application();
} }
} }
private static class CmdLineOptions {
@Option(name = "-import", usage = "Import from keys.dat or other WIF file.")
private File importWIF;
@Option(name = "-export", usage = "Export to WIF file.")
private File exportWIF;
}
}

38
docs-de/.gitignore vendored
View File

@ -1,38 +0,0 @@
# Created by https://www.gitignore.io
### LaTeX ###
*.acn
*.acr
*.alg
*.aux
*.bbl
*.bcf
*.blg
*.dvi
*.fdb_latexmk
*.glg
*.glo
*.gls
*.idx
*.ilg
*.ind
*.ist
*.lof
*.log
*.lot
*.maf
*.mtc
*.mtc0
*.nav
*.nlo
*.out
*.pdfsync
*.ps
*.run.xml
*.snm
*.synctex.gz
*.toc
*.vrb
*.xdy
*.tdo

View File

@ -1,15 +0,0 @@
\section{Einführung}
\subsection{Was sind Metadaten?}
Metadaten sind informationen, welche als Nebeneffekte der eigentlichen Kommunikation auftreten. Wer schreibt wem? Wann? Über welchen Kanal?
Verschlüsselungstechnologien wie PGP oder S/MIME ermöglichen uns auf sichere Art und Weise Nachrichten vor neugierigen Augen zu schützen. Doch seit Edward Snowden den NSA-Skandal aufgedeckt hat wissen wir, dass Metadaten --- vor allem Informationen darüber wer mit wem kommuniziert -- genauso interessant und viel einfacher zu analysieren sind.
Es gibt einige Beispiele wie Sie durch Metadaten in Schwierigkeiten kommen können. Wenn Sie jemandem schreiben der in der IS ist, kann es durchaus sein, dass Sie das nächste mal nicht in die USA fliegen können. Die No-Fly-Liste kümmert sich dabei nicht darum dass Sie Journalist sind oder keine Ahnung hatten dass diese Person ein Terrorist war.
\subsection{Wie können wir Metadaten verstecken?}
Mit E-Mail können wir die Verbindung zu unserem Mail-Provider verschlüsseln und dieser wiederum die Verbindung mit dem Provider unseres Gesprächspartners. Dabei können wir nur hoffen, dass unser Anbieter und derjenige des Empfängers sowohl vertrauenswürdig als auch kompetent sind.\footnote{Gratis sollte er natürlich auch noch sein.}
Bei Bitmessage senden wir eine Nachricht an eine grosse Anzahl Teilnehmer, darunter den eigentlichen Empfänger. Die Nachricht ist dabei so verschlüsselt, dass nur der Besitzer des privaten Schlüssels diese lesen kann. Alle Teilnehmer versuchen nun, alle Meldungen zu entschlüsseln, um so die für sie bestimmten Nachrichten zu finden.

View File

@ -1,279 +0,0 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{bfh}[2015/04/21 Atricle Class for my BFH reports]
\DeclareOption{a4paper}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{11pt}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{oneside}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{titlepage}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\ExecuteOptions{a4paper,11pt,oneside}
\ProcessOptions
%\RequirePackage{cite}
%\RequirePackage[backend=bibtex]{biblatex}
% Literatur- und Bilderquellen trennen
%\defbibheading{lit}{\section*{Literature}}
%\defbibheading{pic}{\section*{Pictures}}
\LoadClass{scrartcl}
\RequirePackage{remreset}
\RequirePackage[utf8]{inputenc}
\RequirePackage{graphicx}
\RequirePackage{color}
\RequirePackage{lmodern}
\RequirePackage{url}
\RequirePackage{lastpage}
\RequirePackage{mathtools}
\RequirePackage{amsfonts}
%\RequirePackage{float}
\RequirePackage{textgreek}
%\RequirePackage{centernot}
\RequirePackage{hyphenat}
\RequirePackage[T1]{fontenc}
\RequirePackage[scaled]{helvet}
\RequirePackage{textcomp}
\RequirePackage{eurosym}
\RequirePackage{fancyhdr}
\RequirePackage{alltt}
\RequirePackage{verbatim}
\RequirePackage{aeguill}
%\RequirePackage{underscore}
\RequirePackage{ctable}
\RequirePackage[english,ngerman]{babel}
\RequirePackage{tabularx}
\RequirePackage{wrapfig}
\RequirePackage{ifthen}
\RequirePackage[usenames,dvipsnames,svgnames]{xcolor}
\RequirePackage{hyperref}
\RequirePackage{listings}
\RequirePackage{attachfile}
\RequirePackage{enumitem}
\RequirePackage{wasysym}
\RequirePackage[absolute]{textpos}
\definecolor{bfhblue}{rgb}{0.396,0.49,0.56} % Blue
\definecolor{bfhorange}{rgb}{0.961,0.753,0.196} % Orange
\definecolor{bfhorangelight}{RGB}{246,216,136} % Orange Light
\hypersetup{
linkcolor=blue, % color of internal links
citecolor=green, % color of links to bibliography
filecolor=blue, % color of file links
urlcolor=blue, % color of external links
colorlinks=true
}
\urlstyle{same}
\typearea{12}
%\bibliographystyle{alpha}
\setcounter{secnumdepth}{4}
\setlength{\parskip}{12pt}
\setlength{\parindent}{0pt}
\renewcommand{\familydefault}{\sfdefault}
%\let\oldtoc\tableofcontents
%\renewcommand{\tableofcontents} {
% \oldtoc
% \newpage
%}
\newcommand*{\tutor}[1]{\gdef\@tutor{#1}}
\renewcommand{\maketitle} {
\begin{titlepage}
\newlength{\unitlengthtmp}
\setlength{\unitlengthtmp}{\unitlength}
\setlength{\unitlength}{1mm}
\setlength{\TPHorizModule}{\textwidth}
\setlength{\TPVertModule}{\textheight}
%
% BFH Logo
\includegraphics[scale=1.25]{images/logo.pdf}
%
% Linien
\begin{textblock}{1}[0,0](0,0)
\begin{picture}(0,130)
\put(20,0){\color{bfhblue}\rule{\textwidth}{1.2mm}}
\put(20,40){\color{bfhblue}\rule{\textwidth}{1.2mm}} %28.5
\end{picture}
\end{textblock}
%
%Zentrierte Titel
\begin{flushleft}
\vspace*{4.08cm}
\textsf{\textbf{\noindent{\Huge{\textcolor{bfhblue}{\@title}}}}}\\[0.4cm]
\textsf{\huge{\textcolor{bfhblue}{\@subtitle}}}
%
%Angaben zum Dokument
\begin{vfill}
\begin{tabularx}{\textwidth}{lX}
\textsf{Autor} & \@author\\
\textsf{Betreuer} & \@tutor\\
% \textsf{Expert} & \textsf\DozentA\\
% \textsf{Studiengang} & \textsf{\Studiengang}\vspace{5pt}\\
% \textsf{Autoren} & \textsf\AutorA\\
% & \textsf\AutorB\vspace{5pt}\\
% \textsf{Betreuer} & \textsf\DozentA\\
% & \textsf\DozentB\vspace{5pt}\\
% \textsf{Experten} & \textsf\ExpertA\\
% & \textsf\ExpertB\vspace{5pt}\\
\textsf{Datum} & \textsf{\@date}\vspace{5pt}\\
% &\\
% &\\
% \multicolumn{2}{p{\columnwidth-\tabcolsep}}{\textsf{\input{titlepage/titlepage_info}}}\\
\end{tabularx}
\end{vfill}
\end{flushleft}
\setlength{\unitlength}{\unitlengthtmp}
\end{titlepage}
}
\pagestyle{fancy}
\fancyhf{}
\fancyfoot[R]{\hrule\thepage/\pageref{LastPage}}
\fancyfoot[L]{\hrule\today}
\fancyhead[L]{\@title}
\fancyhead[R]{
\includegraphics[height=1.5\baselineskip]{images/logo.png}
}
\addtolength{\headheight}{2\baselineskip}
\addtolength{\headheight}{0.61pt}
\lstset{
language=XML, % Code langugage
basicstyle=\ttfamily\scriptsize,
keywordstyle=\color{OliveGreen}, % Keywords font ('*' = uppercase)
stringstyle=\color{blue}, % String font
commentstyle=\color{gray}, % Comments font
numbers=left, % Line nums position
numberstyle=\tiny, % Line-numbers fonts
stepnumber=1, % Step between two line-numbers
numbersep=10pt, % How far are line-numbers from code
backgroundcolor=\color{BackgroundBlue}, % Choose background color
frame=none, % A frame around the code
tabsize=4, % Default tab size
captionpos=b, % Caption-position = bottom
breaklines=true, % Automatic line breaking?
breakatwhitespace=false, % Automatic breaks only at whitespace?
%showspaces=false, % Dont make spaces visible
%showtabs=false, % Dont make tabls visible
columns=fixed, % Column format
morekeywords={Server, Listener, GlobalNamingResources,
Resource, ResourceLink, Service, Connector, Engine,
Host, Context, Environment,
beans, bean, broker, destinationPolicy, policyMap,
policyEntries, policyEntry, dispatchPolicy,
strictOrderDispatchPolicy, subscriptionRecoveryPolicy,
lastImageSubscriptionRecoveryPolicy, managementContext,
persistenceAdapter, systemUsage, memoryUsage,
storeUsage, tempUsage, transportConnectors,
transportConnector, property, jetty, connectors,
nioConnector, handlers, webAppContext},
}
% Shows a listing and creates an attachment with the source
\newcommand{\attachlisting}[2][]{
\hspace{0.95\textwidth}
\attachfile[icon=Paperclip]{#2}
\vspace{-5ex}
\lstinputlisting[#1]{#2}
}
% 1 line number(s)
% 2 variable name
% 3 description
% 4 example values
\newcommand{\listinginfo}[4]{
\colorbox{WhiteSmoke}{
\parbox[t]{0.25\textwidth}{
\printifnotempty{#1}{\texttt{#1:}\\}
\textit{#2}
}
\parbox[t]{0.715\textwidth}{
\printifnotempty{#3}{#3
}
\printifnotempty{#4}{
\par
\vspace{1ex}
\colorbox{BackgroundBlue}{
\parbox{0.69\textwidth}{
\vspace{-2ex}
\ttfamily
\flushleft{#4}
}
}
\par
\vspace{0.5ex}
}
}
}
\par
\vspace{-1.7ex}
}
\newcommand{\printifnotempty}[2]{
\ifthenelse{\equal{#1}{}}{}{#2}
}
% Makes a red box that highlights errors or very important warnings
\newcommand{\errorbox}[1]{
\fcolorbox{Red}{LightPink}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/error.pdf}
\vspace{12pt}
\end{wrapfigure}
#1
}
}
}
% Makes a yellow box that highlights warnings
\newcommand{\warningbox}[1]{
\fcolorbox{Goldenrod}{LightYellow}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/warning.pdf}
\vspace{12pt}
\end{wrapfigure}
#1
}
}
}
% Makes a blue box that highlights special information
\newcommand{\infobox}[1]{
\fcolorbox{CornflowerBlue}{AliceBlue}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/info.pdf}
\end{wrapfigure}
#1
}
}
}
\RequirePackage{listings}
\definecolor{BackgroundBlue}{cmyk}{0.05,0,0,0}
\let\olditemize=\itemize
\def\itemize{
\olditemize
\setlength{\itemsep}{-1.5ex}
}
\newcommand{\leadingzero}[1]{\ifnum #1<10 0\the#1\else\the#1\fi}
%YYYY-MM-DD
\newcommand{\todayI}{\the\year-\leadingzero{\month}-\leadingzero{\day}}
\endinput

View File

@ -1,48 +0,0 @@
@ONLINE{wiki:protocol,
url = {https://bitmessage.org/wiki/Protocol_specification},
title = {Bitmessage Wiki: Protocol Specification},
publisher = {Bitmessage Wiki},
urldate = {2015-04-24},
author = {Warren, Jonathan 'Atheros' and Coe, Jonathan},
note = {\\ \url{https://bitmessage.org/wiki/Protocol_specification}},
year = {2015},
}
@ONLINE{wiki:prefixfilter,
url = {https://bitmessage.org/wiki/Scalability_through_Prefix_Filtering},
title = {Bitmessage Wiki: Scalability through Prefix Filtering},
publisher = {Bitmessage Wiki},
urldate = {2015-05-22},
author = {Coe, Jonathan},
note = {\\ \url{https://bitmessage.org/wiki/Scalability_through_Prefix_Filtering}},
year = {2015},
}
@ONLINE{forum:msg7871,
url = {https://bitmessage.org/forum/index.php?topic=3725.msg7871},
title = {A tweak to enable trust-less BM relay servers (and lightweight mobile clients)},
publisher = {Bitmessage Forum},
urldate = {2015-05-25},
author = {Dan Smith},
note = {\\ \url{https://bitmessage.org/forum/index.php?topic=3725.msg7871}},
year = {2014}
}
@ONLINE{issue:112,
url = {https://github.com/Bitmessage/PyBitmessage/issues/112},
title = {BigInv and ping/pong},
publisher = {github.com},
urldate = {2015-05-22},
author = {Warren, Jonathan 'Atheros' and ISibbol},
note = {\\ \url{https://github.com/Bitmessage/PyBitmessage/issues/112}},
year = {2015},
}
@ONLINE{xkcd:538,
url = {http://xkcd.com/538/},
title = {Security},
publisher = {xkcd.com},
urldate = {2015-05-25},
author = {Randall Munroe},
note = {\\ \url{http://xkcd.com/538/}}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

View File

@ -1,123 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="116.25"
height="67.5"
xml:space="preserve"
sodipodi:docname="logo.pdf"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="m 0,0 922.23,0 0,538.586 L 0,538.586 0,0 z"
id="path20" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview4"
showgrid="false"
inkscape:zoom="3.4962963"
inkscape:cx="58.125"
inkscape:cy="33.75"
inkscape:window-x="271"
inkscape:window-y="47"
inkscape:window-maximized="0"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="logo"
transform="matrix(1.25,0,0,-1.25,0,67.5)"><g
id="g12"
transform="scale(0.1,0.1)"><g
id="g14"><g
id="g16"
clip-path="url(#clipPath18)"><path
d="m 185.602,538.586 c 77.55,0 140.449,-62.867 140.449,-140.449 0,-52.102 -24.153,-97.317 -63.223,-121.828 -0.765,-0.485 -1.32,-1.211 -1.32,-2.161 0,-1.714 1.359,-2.152 1.453,-2.191 50.684,-19.617 82.488,-71.375 82.488,-131.484 C 345.449,62.875 282.535,0 204.977,0 L 19.4961,0.0390625 C 8.73047,0.0390625 0,8.77344 0,19.5156 L 0,519.094 c 0,10.769 8.73047,19.492 19.4961,19.492 l 166.1059,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path22" /><path
d="m 117.695,95.3672 c -2.476,0 -4.593,2.1172 -4.593,4.5937 l 0,112.6291 c 0,2.469 2.117,4.594 4.593,4.594 l 7.071,0 c 2.468,0 4.613,-2.125 4.613,-4.594 l 0,-49.895 43.844,0 0,49.895 c 0,2.469 2.121,4.594 4.593,4.594 l 7.071,0 c 2.472,0 4.593,-2.125 4.593,-4.594 l 0,-112.6291 c 0,-2.4765 -2.121,-4.5937 -4.593,-4.5937 l -7.071,0 c -2.472,0 -4.593,2.1172 -4.593,4.5937 l 0,48.4181 -43.844,0 0,-48.4181 c 0,-2.4765 -2.145,-4.5937 -4.613,-4.5937 l -7.071,0"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path24" /><path
d="m 117.227,321.836 c -2.477,0 -4.594,2.117 -4.594,4.594 l 0,112.644 c 0,2.473 2.117,4.614 4.594,4.614 l 67.757,0 c 2.473,0 4.594,-2.141 4.594,-4.614 l 0,-4.773 c 0,-2.477 -2.121,-4.594 -4.594,-4.594 l -56.078,0 0,-39.148 47.754,0 c 2.488,0 4.613,-2.121 4.613,-4.598 l 0,-4.789 c 0,-2.477 -2.125,-4.594 -4.613,-4.594 l -47.754,0 0,-50.148 c 0,-2.477 -2.121,-4.594 -4.593,-4.594 l -7.086,0"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path26" /><path
d="m 410.621,489.852 8.406,0 c 7.207,0 9.758,2.777 9.758,9.086 0,6.226 -2.324,9.082 -9.461,9.082 l -8.703,0 0,-18.168 z m -0.078,24.027 8.559,0 c 6.078,0 7.429,2.547 7.429,7.957 0,5.398 -1.726,8.184 -7.804,8.184 l -8.184,0 0,-16.141 z m -4.879,-29.805 c -1.051,0 -1.953,0.895 -1.953,1.953 l 0,47.821 c 0,1.047 0.902,1.953 1.953,1.953 l 13.285,0 c 10.891,0 14.864,-5.711 14.864,-13.821 0,-5.398 -1.348,-8.328 -6.301,-10.429 5.027,-1.422 8.633,-5.332 8.633,-12.985 0,-10.285 -6.758,-14.492 -16.372,-14.492 l -14.109,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path28" /><path
d="m 462.32,517.559 c -4.355,0 -7.054,-2.258 -7.586,-11.27 l 14.946,0 c 0,8.645 -1.953,11.27 -7.36,11.27 z m 0.825,-34.465 c -9.832,0 -15.391,5.703 -15.391,19.824 0,14.258 5.855,19.738 14.719,19.738 8.929,0 14.035,-5.097 14.035,-18.691 l 0,-1.348 c 0,-0.672 -0.528,-1.203 -1.199,-1.203 l -20.645,0 c 0.145,-10.281 2.402,-12.84 8.633,-12.84 3.226,0 5.332,0.977 7.277,2.332 0.906,0.676 2.18,0.449 2.781,-0.379 l 1.2,-1.57 c 0.601,-0.832 0.449,-2.113 -0.45,-2.707 -3.074,-2.176 -6.23,-3.156 -10.96,-3.156"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path30" /><path
d="m 491.531,484.074 c -1.047,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.906,1.946 1.953,1.946 l 1.125,0 c 1.129,0 2.106,-0.821 2.328,-1.946 l 0.676,-3.379 c 2.778,3.45 6.231,6.008 10.586,6.008 0.223,0 0.527,0 0.75,-0.078 0.305,-0.078 0.602,-0.371 0.527,-0.676 l -0.527,-5.254 c -0.07,-0.523 -0.601,-0.972 -1.199,-0.906 -0.375,0.078 -0.824,0.078 -1.203,0.078 -3.449,0 -5.781,-1.277 -8.559,-3.828 l 0,-25.672 c 0,-1.058 -0.898,-1.953 -1.949,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path32" /><path
d="m 521.055,484.074 c -1.051,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.902,1.946 1.953,1.946 l 1.125,0 c 1.125,0 2.101,-0.821 2.328,-1.875 l 0.597,-2.774 c 3.309,3.301 7.059,5.625 11.489,5.625 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.469 c 0,-1.058 -0.907,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.949,0.895 -1.949,1.953 l 0,25.446 c 0,4.281 -1.2,5.48 -4.578,5.48 -3.004,0 -6.383,-2.098 -9.086,-4.5 l 0,-26.426 c 0,-1.058 -0.903,-1.953 -1.95,-1.953 l -2.554,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path34" /><path
d="m 573.313,517.559 c -4.36,0 -7.059,-2.258 -7.586,-11.27 l 14.941,0 c 0,8.645 -1.953,11.27 -7.355,11.27 z m 0.824,-34.465 c -9.836,0 -15.391,5.703 -15.391,19.824 0,14.258 5.859,19.738 14.715,19.738 8.934,0 14.039,-5.097 14.039,-18.691 l 0,-1.348 c 0,-0.672 -0.527,-1.203 -1.199,-1.203 l -20.649,0 c 0.153,-10.281 2.407,-12.84 8.633,-12.84 3.231,0 5.328,0.977 7.281,2.332 0.907,0.676 2.18,0.449 2.782,-0.379 l 1.199,-1.57 c 0.601,-0.832 0.449,-2.113 -0.449,-2.707 -3.082,-2.176 -6.231,-3.156 -10.961,-3.156"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path36" /><path
d="m 602.527,484.074 c -1.047,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.906,1.946 1.953,1.946 l 1.125,0 c 1.129,0 2.106,-0.821 2.328,-1.946 l 0.676,-3.379 c 2.778,3.45 6.231,6.008 10.586,6.008 0.223,0 0.528,0 0.75,-0.078 0.305,-0.078 0.602,-0.371 0.528,-0.676 l -0.528,-5.254 c -0.07,-0.523 -0.597,-0.972 -1.199,-0.906 -0.375,0.078 -0.824,0.078 -1.203,0.078 -3.449,0 -5.781,-1.277 -8.559,-3.828 l 0,-25.672 c 0,-1.058 -0.898,-1.953 -1.949,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path38" /><path
d="m 406.41,394.07 c -1.051,0 -1.945,0.903 -1.945,1.953 l 0,47.825 c 0,1.047 0.894,1.953 1.945,1.953 l 21.852,0 c 1.051,0 1.949,-0.906 1.949,-1.953 l 0,-2.032 c 0,-1.043 -0.898,-1.953 -1.949,-1.953 l -16.895,0 0,-15.683 13.363,0 c 1.051,0 1.954,-0.91 1.954,-1.953 l 0,-2.032 c 0,-1.047 -0.903,-1.953 -1.954,-1.953 l -13.363,0 0,-22.219 c 0,-1.05 -0.898,-1.953 -1.949,-1.953 l -3.008,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path40" /><path
d="m 450.371,398.203 c 3.676,0 6.453,2.481 8.258,4.5 l 0,9.992 -2.25,0 c -9.465,0 -11.266,-2.402 -11.266,-7.89 0,-4.95 1.575,-6.602 5.258,-6.602 z m -0.824,-5.105 c -7.207,0 -11.34,3.972 -11.34,11.707 0,8.562 5.031,12.539 17.344,12.539 l 3.078,0 0,2.929 c 0,4.2 -0.527,6.758 -5.406,6.758 -3.227,0 -6.383,-1.133 -9.235,-2.558 -0.976,-0.45 -2.175,-0.071 -2.625,0.91 l -0.754,1.426 c -0.449,0.972 -0.078,2.175 0.899,2.703 3.379,1.797 7.285,3.144 12.387,3.144 7.359,0 11.187,-3.301 11.187,-11.328 l 0,-25.305 c 0,-1.05 -0.898,-1.953 -1.953,-1.953 l -1.121,0 c -1.129,0 -2.18,0.754 -2.481,1.875 l -0.523,1.875 c -2.18,-2.398 -5.332,-4.722 -9.457,-4.722"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path42" /><path
d="m 493.102,393.098 c -9.61,0 -14.942,6.304 -14.942,19.824 0,14.336 5.707,19.734 15.016,19.734 3.601,0 6.457,-0.82 9.16,-3 0.902,-0.672 0.977,-1.875 0.297,-2.703 l -1.203,-1.504 c -0.746,-0.82 -1.95,-0.898 -2.774,-0.222 -1.652,1.277 -3.23,1.953 -5.707,1.953 -5.703,0 -7.883,-2.473 -7.883,-14.258 0,-11.567 2.407,-14.348 8.411,-14.348 2.324,0 3.902,0.899 5.476,2.18 0.828,0.672 2.106,0.601 2.781,-0.227 l 1.352,-1.425 c 0.746,-0.75 0.676,-2.032 -0.152,-2.707 -2.473,-2.176 -5.555,-3.297 -9.832,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path44" /><path
d="m 517.891,394.07 c -1.051,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.902,1.953 1.953,1.953 l 2.554,0 c 1.047,0 1.95,-0.906 1.95,-1.953 l 0,-18.993 c 3.304,3.079 6.683,5.176 11.035,5.176 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.907,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.949,0.903 -1.949,1.953 l 0,25.454 c 0,4.277 -1.2,5.476 -4.579,5.476 -3.003,0 -6.382,-2.098 -9.085,-4.504 l 0,-26.426 c 0,-1.05 -0.903,-1.953 -1.95,-1.953 l -2.554,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path46" /><path
d="m 559.496,394.07 c -1.055,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.055,0 1.953,-0.906 1.953,-1.953 l 0,-18.993 c 3.305,3.079 6.684,5.176 11.035,5.176 5.403,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.902,-1.953 -1.953,-1.953 l -2.555,0 c -1.05,0 -1.953,0.903 -1.953,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.574,5.476 -3.004,0 -6.383,-2.098 -9.086,-4.504 l 0,-26.426 c 0,-1.05 -0.898,-1.953 -1.953,-1.953 l -2.551,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path48" /><path
d="m 612.621,398.203 c 5.707,0 8.41,3.074 8.41,14.641 0,11.629 -2.777,14.715 -8.48,14.715 -5.711,0 -8.41,-3.008 -8.41,-14.637 0,-11.567 2.777,-14.719 8.48,-14.719 z m 0,-5.105 c -9.16,0 -15.391,5.703 -15.391,19.824 0,14.109 6.086,19.734 15.243,19.734 9.16,0 15.465,-5.625 15.465,-19.734 0,-14.121 -6.157,-19.824 -15.317,-19.824"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path50" /><path
d="m 654.23,393.098 c -9.613,0 -14.945,6.304 -14.945,19.824 0,14.336 5.711,19.734 15.016,19.734 3.605,0 6.457,-0.82 9.16,-3 0.898,-0.672 0.977,-1.875 0.305,-2.703 l -1.203,-1.504 c -0.75,-0.82 -1.954,-0.898 -2.778,-0.222 -1.656,1.277 -3.226,1.953 -5.707,1.953 -5.703,0 -7.883,-2.473 -7.883,-14.258 0,-11.567 2.403,-14.348 8.41,-14.348 2.325,0 3.903,0.899 5.477,2.18 0.824,0.672 2.106,0.601 2.777,-0.227 l 1.356,-1.425 c 0.75,-0.75 0.672,-2.032 -0.152,-2.707 -2.477,-2.176 -5.555,-3.297 -9.833,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path52" /><path
d="m 679.023,394.07 c -1.05,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.903,1.953 1.953,1.953 l 2.555,0 c 1.051,0 1.945,-0.906 1.945,-1.953 l 0,-18.993 c 3.309,3.079 6.688,5.176 11.04,5.176 5.402,0 9.085,-2.773 9.085,-9.16 l 0,-27.473 c 0,-1.05 -0.906,-1.953 -1.953,-1.953 l -2.554,0 c -1.051,0 -1.95,0.903 -1.95,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.578,5.476 -3.004,0 -6.383,-2.098 -9.09,-4.504 l 0,-26.426 c 0,-1.05 -0.894,-1.953 -1.945,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path54" /><path
d="m 727.582,393.098 c -4.129,0 -8.105,1.343 -10.883,2.925 -0.902,0.598 -1.203,1.797 -0.679,2.707 l 0.832,1.426 c 0.519,0.977 1.722,1.27 2.625,0.75 2.628,-1.504 5.328,-2.398 8.41,-2.398 5.101,0 6.679,2.019 6.679,5.547 0,4.207 -1.953,5.027 -7.961,6.687 -5.253,1.426 -9.609,4.199 -9.609,11.629 0,5.481 3.531,10.285 11.789,10.285 3.602,0 6.309,-0.593 8.711,-1.57 0.977,-0.449 1.426,-1.652 0.977,-2.629 l -0.68,-1.504 c -0.449,-0.976 -1.578,-1.504 -2.625,-1.055 -2.18,0.977 -3.902,1.282 -6.16,1.282 -4.051,0 -5.926,-1.426 -5.926,-4.653 0,-3.535 1.57,-4.429 6.754,-5.855 5.777,-1.574 11.039,-3.828 11.039,-12.317 0,-7.8 -4.434,-11.257 -13.293,-11.257"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path56" /><path
d="m 766.797,393.098 c -9.609,0 -14.942,6.304 -14.942,19.824 0,14.336 5.708,19.734 15.016,19.734 3.602,0 6.453,-0.82 9.16,-3 0.899,-0.672 0.977,-1.875 0.301,-2.703 l -1.199,-1.504 c -0.754,-0.82 -1.953,-0.898 -2.778,-0.222 -1.656,1.277 -3.23,1.953 -5.71,1.953 -5.704,0 -7.879,-2.473 -7.879,-14.258 0,-11.567 2.402,-14.348 8.406,-14.348 2.324,0 3.902,0.899 5.48,2.18 0.825,0.672 2.106,0.601 2.778,-0.227 l 1.351,-1.425 c 0.754,-0.75 0.676,-2.032 -0.148,-2.707 -2.477,-2.176 -5.559,-3.297 -9.836,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path58" /><path
d="m 791.586,394.07 c -1.055,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.054,0 1.953,-0.906 1.953,-1.953 l 0,-18.993 c 3.305,3.079 6.683,5.176 11.035,5.176 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.902,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.953,0.903 -1.953,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.574,5.476 -3.004,0 -6.383,-2.098 -9.086,-4.504 l 0,-26.426 c 0,-1.05 -0.899,-1.953 -1.953,-1.953 l -2.551,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path60" /><path
d="m 840.68,393.098 c -5.41,0 -9.61,3.074 -9.61,9.605 l 0,27.031 c 0,1.047 0.899,1.946 1.95,1.946 l 2.55,0 c 1.051,0 1.953,-0.899 1.953,-1.946 l 0,-25 c 0,-4.429 1.5,-5.933 4.879,-5.933 3.004,0 6.231,2.027 9.008,4.512 l 0,26.421 c 0,1.047 0.903,1.946 1.953,1.946 l 2.555,0 c 1.051,0 1.949,-0.899 1.949,-1.946 l 0,-33.711 c 0,-1.05 -0.898,-1.953 -1.949,-1.953 l -1.129,0 c -1.129,0 -2.098,0.832 -2.328,1.875 l -0.602,2.785 c -3.148,-3.234 -6.754,-5.632 -11.179,-5.632"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path62" /><path
d="m 880,393.32 c -4.805,0 -6.832,2.559 -6.832,9.16 l 0,43.993 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.055,0 1.953,-0.906 1.953,-1.953 l 0,-45.196 c 0,-1.875 0.824,-2.625 2.625,-2.625 0.305,0 0.602,0 0.824,0.078 0.379,0 0.754,-0.222 0.828,-0.605 l 0.375,-2.18 c 0.227,-1.043 -0.449,-2.097 -1.5,-2.324 -0.902,-0.144 -1.879,-0.301 -2.777,-0.301"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path64" /><path
d="m 908.043,427.559 c -4.355,0 -7.059,-2.254 -7.582,-11.27 l 14.937,0 c 0,8.645 -1.953,11.27 -7.355,11.27 z m 0.824,-34.461 c -9.836,0 -15.39,5.703 -15.39,19.824 0,14.258 5.855,19.734 14.714,19.734 8.934,0 14.039,-5.097 14.039,-18.691 l 0,-1.348 c 0,-0.676 -0.527,-1.203 -1.199,-1.203 l -20.644,0 c 0.144,-10.281 2.402,-12.84 8.633,-12.84 3.226,0 5.332,0.977 7.281,2.332 0.902,0.676 2.176,0.449 2.777,-0.379 l 1.199,-1.574 c 0.602,-0.828 0.45,-2.105 -0.449,-2.703 -3.074,-2.18 -6.23,-3.152 -10.961,-3.152"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path66" /></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="130.34865"
height="67.32325"
xml:space="preserve"
sodipodi:docname="logo-en.svg"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="m 0,0 922.23,0 0,538.586 L 0,538.586 0,0 z"
id="path20"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="889"
inkscape:window-height="781"
id="namedview4"
showgrid="false"
inkscape:zoom="6.9925926"
inkscape:cx="64.932998"
inkscape:cy="68.072034"
inkscape:window-x="271"
inkscape:window-y="47"
inkscape:window-maximized="0"
inkscape:current-layer="g10"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="logo"
transform="matrix(1.25,0,0,-1.25,0,67.32325)"><path
inkscape:connector-curvature="0"
id="path22"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 18.5602,53.8586 c 7.755,0 14.0449,-6.2867 14.0449,-14.0449 0,-5.2102 -2.4153,-9.7317 -6.3223,-12.1828 -0.0765,-0.0485 -0.132,-0.1211 -0.132,-0.2161 0,-0.1714 0.1359,-0.2152 0.1453,-0.2191 5.0684,-1.9617 8.2488,-7.1375 8.2488,-13.1484 C 34.5449,6.2875 28.2535,0 20.4977,0 L 1.94961,0.00390625 C 0.873047,0.00390625 0,0.877344 0,1.95156 L 0,51.9094 c 0,1.0769 0.873047,1.9492 1.94961,1.9492 l 16.61059,0" /><path
inkscape:connector-curvature="0"
id="path24"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 11.7695,9.53672 c -0.2476,0 -0.4593,0.21172 -0.4593,0.45937 l 0,11.26291 c 0,0.2469 0.2117,0.4594 0.4593,0.4594 l 0.7071,0 c 0.2468,0 0.4613,-0.2125 0.4613,-0.4594 l 0,-4.9895 4.3844,0 0,4.9895 c 0,0.2469 0.2121,0.4594 0.4593,0.4594 l 0.7071,0 c 0.2472,0 0.4593,-0.2125 0.4593,-0.4594 l 0,-11.26291 c 0,-0.24765 -0.2121,-0.45937 -0.4593,-0.45937 l -0.7071,0 c -0.2472,0 -0.4593,0.21172 -0.4593,0.45937 l 0,4.84181 -4.3844,0 0,-4.84181 c 0,-0.24765 -0.2145,-0.45937 -0.4613,-0.45937 l -0.7071,0" /><path
inkscape:connector-curvature="0"
id="path26"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 11.7227,32.1836 c -0.2477,0 -0.4594,0.2117 -0.4594,0.4594 l 0,11.2644 c 0,0.2473 0.2117,0.4614 0.4594,0.4614 l 6.7757,0 c 0.2473,0 0.4594,-0.2141 0.4594,-0.4614 l 0,-0.4773 c 0,-0.2477 -0.2121,-0.4594 -0.4594,-0.4594 l -5.6078,0 0,-3.9148 4.7754,0 c 0.2488,0 0.4613,-0.2121 0.4613,-0.4598 l 0,-0.4789 c 0,-0.2477 -0.2125,-0.4594 -0.4613,-0.4594 l -4.7754,0 0,-5.0148 c 0,-0.2477 -0.2121,-0.4594 -0.4593,-0.4594 l -0.7086,0" /><text
xml:space="preserve"
style="font-size:11.55966663px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#467d97;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="40.459648"
y="-47.22646"
id="text3153"
sodipodi:linespacing="125%"
transform="scale(0.97670303,-1.0238527)"><tspan
sodipodi:role="line"
id="tspan3155"
x="40.459648"
y="-47.22646"
style="font-size:7.06424141px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#467d97;fill-opacity:1;font-family:News Gothic MT;-inkscape-font-specification:News Gothic MT">Bern University</tspan><tspan
sodipodi:role="line"
x="40.459648"
y="-38.396156"
id="tspan3157"
style="font-size:7.06424141px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#467d97;fill-opacity:1;font-family:News Gothic MT;-inkscape-font-specification:News Gothic MT">of Applied Sciences</tspan></text>
</g></svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="679.7655"
height="591.2851"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="ports_and_adapters.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="149.17872"
inkscape:cy="85.139761"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1632"
inkscape:window-height="1005"
inkscape:window-x="48"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-18.678419,-26.216821)">
<path
inkscape:transform-center-y="-23.12416"
inkscape:transform-center-x="10.947617"
d="m 465.92439,509.82496 c -1.78891,1.03067 -204.67101,0.84709 -206.45806,-0.18682 -1.78704,-1.03391 -103.06911,-176.82675 -103.06724,-178.89133 0.002,-2.06458 101.6019,-177.67385 103.39081,-178.70452 1.78892,-1.03067 204.67102,-0.84709 206.45806,0.18682 1.78705,1.0339 103.06912,176.82675 103.06725,178.89133 -0.002,2.06458 -101.6019,177.67384 -103.39082,178.70452 z"
inkscape:randomized="9.7491459e-16"
inkscape:rounded="0.01"
inkscape:flatsided="true"
sodipodi:arg2="1.5717012"
sodipodi:arg1="1.0481024"
sodipodi:r2="214.49513"
sodipodi:r1="206.45815"
sodipodi:cy="330.93362"
sodipodi:cx="362.85715"
sodipodi:sides="6"
id="path2997"
style="fill:#5fbcd3;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
sodipodi:type="star"
transform="matrix(1.645857,0,0,1.645857,-238.64982,-222.81004)" />
<path
sodipodi:type="star"
style="fill:#ffd42a;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="path2985"
sodipodi:sides="6"
sodipodi:cx="362.85715"
sodipodi:cy="330.93362"
sodipodi:r1="206.45815"
sodipodi:r2="214.49513"
sodipodi:arg1="1.0481024"
sodipodi:arg2="1.5717012"
inkscape:flatsided="true"
inkscape:rounded="0.01"
inkscape:randomized="9.7491459e-16"
d="m 465.92439,509.82496 c -1.78891,1.03067 -204.67101,0.84709 -206.45806,-0.18682 -1.78704,-1.03391 -103.06911,-176.82675 -103.06724,-178.89133 0.002,-2.06458 101.6019,-177.67385 103.39081,-178.70452 1.78892,-1.03067 204.67102,-0.84709 206.45806,0.18682 1.78705,1.0339 103.06912,176.82675 103.06725,178.89133 -0.002,2.06458 -101.6019,177.67384 -103.39082,178.70452 z"
inkscape:transform-center-x="6.6516253"
inkscape:transform-center-y="-14.049918"
transform="translate(-4.2959915,-9.0742422)" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="358.36584"
y="218.6479"
id="text2987"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="358.36584"
y="218.6479"
id="tspan2995"
style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">Application</tspan></text>
<text
sodipodi:linespacing="125%"
id="text2999"
y="94.647903"
x="359.22522"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
id="tspan3003"
y="94.647903"
x="359.22522"
sodipodi:role="line">Adapters</tspan></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="-100.75645"
y="246.52264"
id="text3042"
sodipodi:linespacing="125%"
transform="matrix(0.47970506,-0.8774298,0.8774298,0.47970506,0,0)"><tspan
sodipodi:role="line"
x="-100.75645"
y="246.52264"
id="tspan3044"
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique">Storage</tspan></text>
<text
transform="matrix(0.53345366,0.84582929,-0.84582929,0.53345366,0,0)"
sodipodi:linespacing="125%"
id="text3046"
y="-357.84464"
x="471.47845"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique"
y="-357.84464"
x="471.47845"
sodipodi:role="line"
id="tspan3050">Proof of Work</tspan></text>
<text
transform="matrix(-0.51536966,-0.85696798,0.85696798,-0.51536966,0,0)"
sodipodi:linespacing="125%"
id="text3054"
y="-85.847336"
x="-455.38437"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique"
id="tspan3056"
y="-85.847336"
x="-455.38437"
sodipodi:role="line">User Interface</tspan></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="92.095795"
y="-700.29236"
id="text3058"
sodipodi:linespacing="125%"
transform="matrix(-0.51365875,0.85799458,-0.85799458,-0.51365875,0,0)"><tspan
id="tspan3060"
sodipodi:role="line"
x="92.095795"
y="-700.29236"
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique">Network</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.7 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

View File

@ -1,188 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="432.34531"
height="100.50558"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="signature.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="252.2677"
inkscape:cy="-17.844674"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1632"
inkscape:window-height="1005"
inkscape:window-x="48"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-110.35921,-353.40277)">
<rect
y="399.45847"
x="185.46117"
height="31.314728"
width="253.52907"
id="rect3031"
style="fill:none;stroke:#000000" />
<rect
style="fill:none;stroke:#000000"
id="rect3029"
width="228.88622"
height="31.314728"
x="313.3183"
y="373.45847" />
<g
id="g3024"
transform="translate(-2.777866,0)">
<rect
y="387.68179"
x="113.13708"
height="30.304565"
width="74.751282"
id="rect2985"
style="fill:#467d97;fill-opacity:1;stroke:none" />
<text
sodipodi:linespacing="125%"
id="text2987"
y="407.88486"
x="125.55178"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ffffff;font-family:Consolas;-inkscape-font-specification:Consolas"
y="407.88486"
x="125.55178"
id="tspan2989"
sodipodi:role="line">nonce</tspan></text>
</g>
<g
id="g3019"
transform="translate(-1.7677265,0)">
<rect
style="fill:#aa0000;fill-opacity:1;stroke:none"
id="rect2991"
width="127.27923"
height="30.304565"
x="186.87822"
y="387.68179" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="220.4944"
y="407.88486"
id="text2993"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan2995"
x="220.4944"
y="407.88486"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ffffff;font-family:Consolas;-inkscape-font-specification:Consolas">header</tspan></text>
</g>
<g
id="g3014"
transform="translate(1.2627377,0)">
<rect
y="387.68179"
x="311.12698"
height="30.304565"
width="127.27923"
id="rect2997"
style="fill:#660080;fill-opacity:1;stroke:none" />
<text
sodipodi:linespacing="125%"
id="text2999"
y="407.88486"
x="340.09814"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ffffff;font-family:Consolas;-inkscape-font-specification:Consolas"
y="407.88486"
x="340.09814"
id="tspan3001"
sodipodi:role="line">payload</tspan></text>
</g>
<g
id="g3009"
transform="translate(3.2830548,0)">
<rect
style="fill:#217821;fill-opacity:1;stroke:none"
id="rect3003"
width="103.03555"
height="30.304565"
x="436.38589"
y="387.68179" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="447.86951"
y="407.88486"
id="text3005"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3007"
x="447.86951"
y="407.88486"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ffffff;font-family:Consolas;-inkscape-font-specification:Consolas">signatur</tspan></text>
</g>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="378.20868"
y="366.64789"
id="text3033"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3035"
x="378.20868"
y="366.64789">verschlüsselt</tspan></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="282.60217"
y="449.50504"
id="text3037"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3039"
x="282.60217"
y="449.50504">signiert</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

View File

@ -1,78 +0,0 @@
\documentclass{bfh}
\title{Project 2}
\subtitle{Bitmessage -- Communication Without Metadata}
\author{Christian Basler}
\tutor{Kai Brünnler}
\date{\today}
\begin{document}
\maketitle
\tableofcontents
\section{Synopsis}
TODO
% Section basics
\input{basics}
The protocol is described in detail in my Seminar paper.
\section{Goal}
At the moment, there aren't many implementations apart from the official clients. Especially two things are missing: a multi purpose Java library and a usable mobile client. My goal for my \textit{Project 2} is to create the library, to be used next semester as a starting point for an Android\textsuperscript{\texttrademark} client in my Bachelor Thesis.
\section{Issues}
TODO
\subsection{Unsigned Numbers}
Java doesn't support unsigned number types. While Java 8 has some helper classes to address this issue, my goal is to support Java 7, which is needed for Android development, so I wasn't able to leverage them.
\subsection{Proof of Work}
Proof of work is needed for a message to be distributed within the Bitmessage network. This is to protect both the network itself from denial of service attacks and the users from spam.
\section{Architecture}
\subsection{Ports and Adapters}
The library uses a ports and adapters architecture, which allows us to easily replace some implementations that might be platform dependent, such as storage or proof of work calculation.
\includegraphics[width=\textwidth]{images/ports_and_adapters.pdf}
The big advantage of this approach is that it's easy to test the core as well as each adapter by itself.
\subsection{Network Management}
\section{Usage}
TODO
\section{Discussion}
\appendix
\addcontentsline{toc}{section}{Appendix}
\section*{Appendix}
\renewcommand{\thesubsection}{\Alph{subsection}}
\subsection{JavaDoc Documentation}
\subsection{Literature}
\end{document}

View File

@ -1,11 +0,0 @@
@Comment{$ biblatex control file $}
@Comment{$ biblatex version 1.7 $}
Do not modify this file!
This is an auxiliary file used by the 'biblatex' package.
This file may safely be deleted. It will be recreated as
required.
@Control{biblatex-control,
options = {1.7:0:0:1:0:0:1:1:0:0:0:0:1:1:3:1:79:+},
}

Binary file not shown.

View File

@ -1,257 +0,0 @@
\documentclass{bfh}
\usepackage[numbers]{natbib}
\usepackage{xfrac}
\title{Informatikseminar}
\subtitle{Bitmessage -- Kommunikation ohne Metadaten}
\author{Christian Basler}
\tutor{Kai Brünnler}
\date{\today}
\newcommand{\msg}[1]{\textit{\textcolor{RedOrange}{#1}}}
\newcommand{\obj}[1]{\textbf{\textcolor{OliveGreen}{#1}}}
\newcommand{\node}[1]{\textbf{\textcolor{MidnightBlue}{#1}}}
\begin{document}
\maketitle
\tableofcontents
\newpage
% Section basics
\input{basics}
\newpage
\section{PyBitmessage}
PyBitmessage ist der Standard Bitmessage Client und, wie der Name andeutet, in Python implementiert. Der Client bietet zwar alle Funktionen von Bitmessage, die User Experience ist allerdings nicht ganz optimal. Insbesondere lassen sich Nachrichten nicht in Ordner verschieben oder mit Labels versehen.
\begin{figure}[h]
\centering
\includegraphics[width=0.8\textwidth]{images/PyBitmessage-Inbox.png}
\caption[PyBitmessage: Inbox]{Der Posteingang von PyBitmessage.}
\label{fig:inbox}
\end{figure}
Der Client ist ausserdem ziemlich langsam im Berechnen des Proof of Work. Auf einem MacBook Pro von 2012 kann es durchaus einige Minuten dauern bis eine Nachricht gesendet werden kann.
% \begin{figure}[h]
\begin{wrapfigure}{r}{0.5\textwidth}
\centering
\includegraphics[width=0.5\textwidth]{images/PyBitmessage-Send.png}
\caption[PyBitmessage: Senden]{Eine neue Nachricht erfassen.}
\label{fig:inbox}
\end{wrapfigure}
Wenn man die Funktionsweise des Protokolls sieht, liegt die Idee natürlich nicht weit Meldungen an mehrere Empfänger gleichzeitig senden zu wollen. Dies geht so, dass die Adresse selbst in einen privaten Schlüssel umgewandelt wird und so zum \textit{entschlüsseln} der Broadcasts benutzt werden kann. Entsprechend kann man beim Erfassen einer Nachricht wählen ob sie an einen bestimmten Empfänger gehen soll oder an alle, die unsere Broadcasts abonniert haben. Jeder, der die Adresse kennt kann dabei allerdings die darüber gesendeten Broadcasts lesen.
\newpage
\section{Protokoll}
Wir benutzen die folgende Konvention um zwischen verschiedenen Bestandteilen der Protokolls zu unterscheiden:
\begin{tabular}{@{}>{$}l<{$}l@{}}
\msg{version} & für Meldungen zwischen Netzwerkknoten \\
\obj{pubkey} & für Objekte welche im Netzwerk verteilt werden \\
\node{A} & für einzelne Netzwerkknoten \\
\end{tabular}
\subsection{Nomenklatur}
Es gibt einige Begriffe welche schnell verwechselt werden können. Es folgt eine Liste der verwirrendsten.
\subsubsection{message, msg}
Eine Nachricht oder \msg{message} wird von einem Netzwerkknoten zum anderen geschickt, z.B. um neue Objekte anzukündigen oder um die Verbindung aufzubauen.
Ein \obj{msg}-Objekt andererseits enthält die verschlüsselte Nachricht von einem Benutzer an einen anderen.
\subsubsection{payload}
Payload werden die Nutzdaten eines Protokolls genannt. Es gibt drei Arten von Payload:
\begin{enumerate}
\item Der Payload von Meldungen, z.B. \textit{Inventory Vectors}.
\item Der Payload von Objekten. Dieser wird im Netzwerk verteilt.\footnote{Und ist Teil vom Meldungs-Payload.}
\item Verschlüsselter Payload, der Chiffretext mit einigen Zusatzinformationen welche für die Entschlüsselung benötigt werden.\footnote{Dieser wiederum ist Teil vom Objekt-Payload.}
\end{enumerate}
\subsubsection{object}
Ein Objekt ist eine Art Meldung, deren Payload zwischen allen Netzwerkknoten verteilt wird. Manchmal wird auch nur der Payload gemeint. Um ein Objekt zu senden, wird ein \textit{Proof of Work} benötigt.
\subsection{Ablauf}
Der neu gestartete Netzwerkknoten \node{A} stellt die Verbindung zu einem zufälligen Knoten \node{B} aus seinem Knotenverzeichnis her und sendet eine \msg{version}-Meldung, die die aktuellste unterstützte Protokollversion ankündigt. Falls \node{B} die Version akzeptiert,\footnote{Eine Version wird normalerweise akzeptiert, wenn sie höher oder gleich der eigenen höchsten unterstützten Version ist. Knoten, welche eine experimentelle Protokollversion implementieren, können auch ältere Versionen akzeptieren.} antwortet er mit einer \msg{verack}-Meldung, gefolgt von der eigenen \msg{version} mit ihrer neusten unterstützten Protokollversion. Knoten \node{A} entscheidet nun ob er die Version von \node{B} akzeptiert und sendet in diesem Fall seine \msg{verack}-Meldung.
Wenn beide Knoten die Verbindung akzeptieren, senden sie je eine \msg{addr}-Meldung mit bis zu 1000 bekannten Knoten, gefolgt von einer oder mehreren \msg{inv}-Meldungen, welche alle bekannten gültigen Objekte mitteilt. Danach wird eine \msg{getdata}-Meldung für die noch fehlenden Objekte gesendet.
Auf \msg{getdata} antwortet der Knoten mit einer \msg{object}-Meldung, welche dann das angeforderte Objekt enthält.
Ein Knoten verbindet sich aktiv mit acht anderen Knoten und erlaubt beliebig viele eingehende Verbindungen. Wenn ein Benutzer an Knoten \node{A} ein neues Objekt erzeugt, wird es mittels \msg{inv}-Meldung bei acht der angebundenen Knoten angeboten. Diese fordern es an und bieten es wiederum bei acht Nachbarknoten an, bis es an alle Knoten verteilt ist.
\subsection{Meldungen}
Die Meldungen, Objekte und das Binärformat sind im Bitmessage-Wiki gut dokumentiert, die Beschreibungen hier sind deshalb darauf konzentriert um was es geht und wie man sie benutzt.\cite{wiki:protocol}
\subsubsection{version / verack}
Die \msg{version}-Meldung enthält die aktuellste vom Knoten unterstützte Protokollversion, die Streams für welche er sich interessiert und die unterstützten Features. Falls der andere Knoten akzeptiert, bestätigt er mittels \msg{verack}. Die Verbindung gilt als initialisiert wenn beide Knoten eine \msg{verack}-Meldung gesendet haben.
\subsubsection{addr}
Eine \msg{addr}-Meldung enthält bis zu 1000 bekannte Knoten mit deren IP-Adresse, Port, Stream und unterstützten Features. Die IP-Adressen werden dabei im IPv6-Format dargestellt, für IPv4-Adressen also 12 Bytes \texttt{00 00 00 00 00 00 00 00 00 00 FF FF}, gefolgt von den vier Bytes der IPv4-Adresse.
\subsubsection{inv}
Eine \msg{inv}-Meldung enthält die Hashes von bis zu 50000 gültigen Objekten. Falls das Inventar mehr Objekte enthält können mehrere Meldungen gesendet werden.
\subsubsection{getdata}
Die Meldung \msg{getdata} kann bis zu 50000 Objekte anfordern, indem es deren Hashes sendet.
\subsubsection{object}
Die \msg{object}-Meldung enthält ein angefordertes Objekt, das eines von folgenden sein kann:
\listinginfo{}{getpubkey}{Eine Aufforderung an eine Adresse, deren öffentlichen Schlüssel zu senden. Dieser wird benötigt um die Meldung an diese Adressen zu verschlüsseln.}{}
\listinginfo{}{pubkey}{Ein öffentlicher Schlüssel. Siehe \ref{subsec:addr} \nameref{subsec:addr}}{}
\listinginfo{}{msg}{Eine Nachricht an einen bestimmten Benutzer.}{}
\listinginfo{}{broadcast}{Eine Nachricht, welche auf eine spezielle Art verschlüsselt wird. So kann jeder, der die sendende Adresse kennt, sie entschlüsseln.}{}
\subsubsection{ping / pong / getbiginv}
Wer den Source Code von PyBitmessage untersucht, ist vielleicht über einige Meldungen irritiert, welche implementiert zu sein scheinen, aber nirgends in der offiziellen Spezifikation zu finden sind. \msg{Ping} bringt einen Knoten (sofern implementiert) dazu ein \msg{pong} zurückzusenden. \msg{Getbiginv} scheint dafür gedacht zu sein das ganze Inventar abzufragen. Verwendet werden diese Meldungen jedoch nirgends.\cite{issue:112}
\subsection{Adressen}
\label{subsec:addr}
\textit{BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h}: Adressen beginnen mit "BM-"{} und sind, genau wie Bitcoin-Adressen, Base58 codiert.\footnote{Dieses verwendet die Zeichen 1-9, A-Z und a-z ohne die leicht verwechselbaren Zeichen I, l, 0 and O.}
\listinginfo{}{version}{Adressversion. Version 1 wird vom Netzwerk nicht mehr unterstützt.}{0x02, 0x03 oder 0x04}
\listinginfo{}{stream}{Stream-Nummer. Im Moment wird praktisch nur Stream 1 verwendet.}{0x01}
\listinginfo{}{ripe}{Hash der aneinandergefügten öffentlichen Schlüssel zum Signieren und Verschlüsseln. Wichtig: in \obj{pubkey}-Objekten werden die Schlüssel ohne führendes 0x04 gesendet, doch um den Ripe zu berechnen muss dieses Byte vorangestellt werden. Da dies für fast alle Verwendungszwecke der Schlüssel nötig ist, lohnt es sich dies gleich beim Erstellen des Objekts zu machen.
Führende Nullen werden dabei weggelassen. Es wird ausserdem ein Schlüsselpaar gesucht, dessen Ripe mindestens eine führende Null hat.}{ripemd160(sha512(pubSigKey + pubEncKey))}
\listinginfo{}{checksum}{Die ersten vier Bytes eines doppelten SHA-512-Hashs der vorangehenden Daten.}{sha512(sha512(version + stream + ripe))}
\subsection{Verschlüsselung}
Bitmessage benutzt Elliptische-Kurven-Kryptographie sowohl zum Signieren als auch zum Verschlüsseln. Die Mathematik dahinter ist ziemlich kompliziert. Sie basiert jedoch auf dem bewährten Prinzip, eine mathematische Operation durchzuführen, welche in eine Richtung relativ einfach, jedoch sehr schwierig umzukehren ist. An Stelle der sonst üblichen zwei grossen Primzahlen werden hier ein Punkt auf der elliptischen Kurve mit einer sehr grossen Zahl multipliziert.\footnote{Falls Sie wissen möchten wie das genau geht, beginnen Sie auf \url{http://de.wikipedia.org/wiki/Elliptische_Kurve} und \url{http://de.wikipedia.org/wiki/Elliptic_Curve_Cryptography}. Falls Sie etwas machen möchten das funktioniert, verwenden Sie aber lieber eine Bibliothek wie Bouncy Casle, welche die harte Arbeit übernimmt.}
Der Vorteil von elliptischen Kurven ist einerseits, dass man keine grossen Primzahlen suchen muss, andererseits aber auch, dass die Schlüssel bei gleicher Verschlüsselungsstärke viel kürzer sein können.
Die Benutzerin, nennen wir sie Alice, benötigt ein Schlüsselpaar, welches aus dem privaten Schlüssel
$$k$$
besteht, der eine riesige\footnote{32 Bytes} Zufallszahl darstellt, und einem öffentlichen Schlüssel
$$K = G k$$
der einen Punkt auf der vorher definierten Kurve repräsentiert.\footnote{Bitmessage benutzt eine Kurve namens \textit{secp256k1}.} Beachten Sie bitte dass dies keine einfache Multiplikation ist, sondern die skalare Multiplikation eines Punktes auf der elliptischen Kurve. $G$ ist der Startpunkt für alle Operationen auf einer spezifischen Kurve.
Ein anderer Benutzer, Bob, kennt den öffentlichen Schlüssel. Um eine Nachricht zu verschlüsseln erstellt er das temporäre Schlüsselpaar
$$r$$
und
$$R = G r$$
Danach berechnet er
$$K r$$
benutzt den daraus folgenden Punkt um die Meldung zu verschlüsseln\footnote{Genaugenommen wird ein doppelter SHA-512-Hash über der X-Koordinate benutzt um den symmetrischen Schlüssel zu erzeugen.} und sendet $K$ zusammen mit der verschlüsselten Nachricht.
Wenn Alice die Meldung empfängt, benutzt sie die Tatsache dass
$$K r = G k r = G r k = R k$$
also berechnet sie einfach $R k$ um die Meldung zu entschlüsseln.
Die genaue von Bitmessage verwendete Methode wird Elliptic Curve Integrated Encryption Scheme oder ECIES genannt, welche auf Wikipedia detailliert beschrieben wird (\url{http://de.wikipedia.org/wiki/Elliptic_Curve_Integrated_Encryption_Scheme}).
\subsubsection{Signatur}
Um Objekte zu signieren verwendet Bitmessage Elliptic Curve Digital Signature Algorithm oder ECDSA. Dies ist etwas komplizierter als ECIES. Wenn Sie Details wissen möchten ist Wikipedia einmal mehr eine gute Anlaufstelle: \url{http://de.wikipedia.org/wiki/Elliptic_Curve_DSA}.
Ein interessantes Detail für potentielle Entwickler von Bitmessage-Clients --- vor allem wenn Sie es mit einem objektorientierten Ansatz machen möchten: die Signatur geht über alles aus dem Objekt-Header ohne das Nonce und alles aus dem Objekt-Payload ohne die Signatur selbst. Natürlich sind nicht alle Objekte signiert und die Signatur befindet sich im verschlüsselten Teil des Objekt-Payloads.\footnote{Mein Ansatz: zuerst denken, dann falsch implementieren, dann viel umschreiben.}
\begin{figure}[htp]
\centering
\includegraphics[width=0.7\textwidth]{images/signature.pdf}
\caption[Signatur: Datenstruktur]{Aufbau von signierten und verschlüsselten Daten}
\label{fig:signature}
\end{figure}
\newpage
\section{Probleme}
\subsection{Skalierbarkeit}
Bitmessage skaliert nicht.\footnote{Noch nicht.} Gibt es sehr wenige Benutzer, so gibt es auch keine Anonymität. Mit einer kleinen Anzahl von Benutzern ist es einfach (beispielsweise für die NSA), den Verkehr zwischen Knoten zu analysieren um herauszufinden wer wem schreiben könnte.
Mit vielen Benutzern wächst der benötigte Traffic und Speicherplatz quadratisch. Dies, weil es sowohl mehr Benutzer die eine Nachricht schreiben, als auch mehr mögliche Gesprächspartner für bestehende Benutzer gibt.
\subsubsection{Proof of Work}
Proof of Work erfüllt zwei Zwecke. Es hilft das Netzwerk zu schützen, indem es verhindert, dass einzelne Knoten es mit Objekten fluten. Andererseits schützt es auch den einzelnen Benutzer vor Spam. Es gibt einen minimal nötigen Proof of Work um Objekte im Netzwerk zu verteilen, doch der Benutzer kann für seine Adressen höhere Anforderungen stellen falls er mit Angeboten für billiges Viagra\texttrademark{} zugeschüttet wird. Der für eine Adresse nötige Proof of Work wird im \obj{pubkey}-Objekt mitgeteilt. Absender, welche in der Kontaktliste eines Benutzers sind, sollten keinen höheren Proof of Work machen müssen.
Die Schwierigkeit wird mittels Nachrichtenlänge und Lebensdauer berechnet, das heisst eine grössere Meldung oder eine welche länger im Netzwerk gespeichert wird kostet mehr beim Senden.
$$ d = \frac{2^{64}}{n (l + \frac{t l}{2^{16}})} $$
\begin{tabular}{@{}>{$}l<{$}l@{}}
d & Zielschwierigkeit \\
n & nötige Versuche pro Byte \\
l & Payload-Länge + Extra-Bytes (um es nicht zu einfach zu machen viele winzige Meldungen zu versenden) \\
t & Lebensdauer \\
\end{tabular}
Um den Proof of Work durchzuführen, muss ein Nonce\footnote{Number used once.} gefunden werden, so dass die ersten acht Bytes vom Hash des Objekts (inklusive Nonce) eine kleinere Zahl repräsentieren als die Zielschwierigkeit.
\subsubsection{Beschränkung der Meldungsgrösse}
Um zu verhindern dass bösarige Benutzer einzelne Knoten blockieren, dürfen Meldungen nicht grösser als 256 KiB sein. Wegen des Proof of Work sind grössere Nachrichten für den Normalgebrauch sowieso nicht praktikabel, aber sie könnten benutzt werden um Knoten mit Müll-Meldungen zu beschäftigen.
\subsubsection{Streams}
Die vorgesehene Lösung für das Skalierungsproblem ist, den Traffic -- genau genommen Adressen -- in Streams aufzuteilen. Ein Knoten liest nur auf denjenigen Streams, welche seine Adressen betreffen. Wenn er ein Objekt an einen anderen Stream schicken möchte, verbindet er sich einfach mit einem Knoten im gewünschten Stream, sendet sein Objekt und schliesst die Verbindung wieder. Wenn alle aktiven Streams voll sind, wird für neue Adressen ein neuer Stream verwendet.
Das ungelöste Problem ist herauszufinden, wann ein Stream voll ist. Ein weiteres Problem ist die Tatsache, dass --- während das Netzwerk wächst --- der Traffic auf den vollen Streams mitwächst, da es mehr Benutzer gibt welche jemandem auf dem vollen Stream schreiben möchten. Der Traffic auf dem vollen Stream wächst also linear mit der Netzwerkgrösse.
\subsubsection{Präfix-Filterung}
Jonathan Coe schlägt diesen interessanten Ansatz vor, den Traffic aufzuteilen. Dies würde ein Protokoll-Update erfordern, erlaubt aber eine viel genauere Kontrolle darüber, wie viel Traffic ein Knoten verarbeiten soll.\cite{wiki:prefixfilter}
\begin{figure}[h]
\centering
\includegraphics[width=\textwidth]{images/prefix-filter-binary-tree.pdf}
\caption[Präfix-Filter: Binärbaum]{Die Pefix-Länge geht bis 64, jedes der gelben Dreiecke stellt folglich einen Teilbaum der Höhe 61 dar.}
\label{fig:bintree}
\end{figure}
Anstelle von Streams stellen wir uns eine Adresse als Blatt eines Binärbaums der Höhe 65 vor. Die Position wird über die ersten 64 Bits des Ripe einer Adresse bestimmt. Eine Präfix-Lenge $n$ definiert den Teilbaum, ab welchem wir Meldungen lesen. Ein sendender Client setzt ein 64-Bit-Nonce, bei welchem die ersten $n$ Bits vom Ripe der Empfängeradresse kopiert und der Rest zufällig gesetzt wird.
Nehmen wir nun an, der Ripe von Bobs Adresse starte mit \texttt{00101001\ldots} und hat eine Präfix-Länge von 3. Alice sendet ihre Meldung mit dem Tag \texttt{00110100\ldots}. Die ersten drei Bits müssen gleich sein, aber der Rest ist zufällig gewählt. Bobs Client verarbeitet nun alle Meldungen welche seinem Präfix entsprechen, er muss also nur \sfrac{1}{8} des Gesamttraffics lesen.\footnote{Im Moment ist der Traffic insgesamt etwa 1 GiB im Monat.}
Wie Bitmessage populärer wird, wird es auch mehr und mehr Traffic generieren. Bob möchte deshalb möglicherweise seine Präfix-Länge auf 4 erhöhen, was den zu verarbeitenden Traffic weiter auf \sfrac{1}{16} des Gesamtvolumens reduziert. Um dies zu tun, publiziert er einfach seinen \obj{pubkey} mit seiner aktualisierten Präfix-Länge. Das heisst natürlich auch, dass entweder immer ein \obj{pubkey} publiziert sein muss, oder Alice muss wenigstens einmal online sein während der \obj{pubkey} publiziert ist. Andernfalls gibt es in unserem Szenario eine 50\% Chance dass die Nachricht Bob nicht erreicht.
Die Methode der Präfix-Filterung würde es zwar einem Smartphone-Client erlauben nur seine eigenen Meldungen zu verarbeiten,\footnote{Ein Präfix von 64 würde höchstwahrscheinlich bedeuten dass man auf dem Stream nur seine eigenen Meldungen erhählt.} aber damit würde man auch seine Anonymität beinahe komplett aufgeben.
\subsection{Forward Secrecy}
Offensichtlich ist es für einen Angreifer trivial alle (verschlüsselten) Objekte zu sammeln, welche durch das Bitmessage-Netzwerk verteilt werden --- sofern Speicherplatz kein Problem ist. Sollte dieser Angreifer irgendwie an den privaten Schlüssel eines Benutzers kommen, kann er alle gespeicherten Meldungen entschlüsseln, welche für diesen Benutzer bestimmt sind, und sich ausserdem als diesen ausgeben.\footnote{Das Letztere ist schwieriger wenn der Schlüssel durch eine Bruteforce-Attacke erworben wurde.}
Glaubhafte Abstreitbarkeit (plausible deniability) kann in einigen Szenarios dagegen helfen. Bei dieser Aktion --- auch "{}eine Adresse atomisieren"\footnote{"Nuking an address."} genannt --- wird der private Schlüssel anonym veröffentlicht.\footnote{Siehe \url{https://bitmessage.ch/nuked/} für ein Beispiel.}
Perfect Forward Secrecy scheint nicht praktikabel implementierbar zu sein, da man dazu vor dem Senden der eigentlichen Nachricht Informationen austauschen muss. Dies braucht wiederum Proof of Work um das Netzwerk zu schützen, was für den Sender die doppelte Arbeit bedeutet und die dreifache Zeit eine Nachricht zu senden --- falls beide Clients online sind. Der Austausch von Nachrichten würde so gut wie unmöglich wenn beide Benutzer nur sporadisch online sind.
\subsection{Mobile Client}
Es gibt zwar inzwischen einen Client für Android,\footnote{Bitseal: \url{https://play.google.com/store/apps/details?id=com.github.bitseal}} dieser benötigt jedoch sehr viel Traffic, der Proof of Work dauert ewig und die Batterie hält nicht sehr lange.
In PyBitmessage gibt es die Option, den Empfänger eindeutig identifizierbar zu machen. Dies würde es einem Server erlauben nur die relevanten Meldungen weiterzuleiten. Zwar gibt man dabei seine Anonymität auf, aber das ist immer noch besser als die Ansätze der E-Mail-Relays, wo der private Schlüssel gleich beim Server liegt.
Ein Ansatz, der Anonymität trotz unterstützendem Server erlaubt, schlug Dan Smith vor.\cite{forum:msg7871} Dabei wird ein drittes Schlüsselpaar generiert, mit dem der String "{}IDENTIFICATION"{} und einige zufällige Bytes verschlüsselt wird. Der Relay-Server muss dabei den privaten Identifikationsschlüssel erhalten --- soweit muss man ihm also noch vertrauen. Wenn er also mit Hilfe des Identifikationsschlüssels den Text "{}IDENTIFICATION"{} extrahieren kann, ist die Meldung für mich bestimmt und wird weitergeleitet.
Der Proof of Work schliesslich lässt sich sehr einfach auf einem Server erledigen. Mit einer optimierten Implementation sollte er aber auch auf einem modernen Smartphone in vernünftiger Zeit machbar sein. Die Geräte haben inzwischen oftmals mehr als vier Prozessorkerne und einen dedizierten Grafikchip, der sich ausgezeichnet zum parallelen Berechnen von Hashes eignet.
\newpage
\section{Diskussion}
Anonymität hat ihren Preis. Bei Bitmessage ist es Traffic, Speicherplatz und Rechenpower. Bei E-Mail ist es Vertrauen. Wenn wir unserem E-Mail-Provider nicht vertrauen können (wer kann das?), ist Bitmessage eine Alternative, wenn auch nicht vollständig ausgereift.
Ich finde die Idee eines Trustless-Protokolls\footnote{Ein Protokoll, das kein Vertrauen benötigt.} und Peer-To-Peer Netzwerke, die üblicherweise soche Protokolle verwenden, äusserst interessant. Zu Beginn war das Internet ein riesiges Netzwerk gleichberechtigter Teilnehmer, doch heutzutage scheint alles zu Google oder Facebook zu führen. P2P und Trustless-Protokolle geben uns ein Stück dieser Freiheit zurück, welche in der Cloud verlorengegangen ist.
Dass es nun einen P2P E-Mail-Ersatz gibt finde ich absolut grossartig. Ja, es skaliert nicht so gut wie E-Mail. Aber dank Proof of Work denke ich, dass wir kein mit E-Mail vergleichbares Spam-Problem haben, was den Traffic schon mal gut halbiert. Falls Bitmessage E-Mail jemals ersetzt, würde ein grosser Teil des E-Mail-Verkehrs wohl eher durch Instant-Messaging ersetzt. Vor allem Firmenintern, wo eine eigene Infrastruktur aufgebaut werden kann, muss nicht unbedingt Bitmessage verwendet werden.
\begin{figure}[htp]
\centering
\includegraphics[width=0.7\textwidth]{images/xkcd-security.png}
\caption[XKCD: Security]{\url{http://xkcd.com/538/}\nocite{xkcd:538}}
\label{fig:xkcd}
\end{figure}
\newpage
\bibliographystyle{plain}
\bibliography{bibliography}
\listoffigures
\end{document}

38
docs/.gitignore vendored
View File

@ -1,38 +0,0 @@
# Created by https://www.gitignore.io
### LaTeX ###
*.acn
*.acr
*.alg
*.aux
*.bbl
*.bcf
*.blg
*.dvi
*.fdb_latexmk
*.glg
*.glo
*.gls
*.idx
*.ilg
*.ind
*.ist
*.lof
*.log
*.lot
*.maf
*.mtc
*.mtc0
*.nav
*.nlo
*.out
*.pdfsync
*.ps
*.run.xml
*.snm
*.synctex.gz
*.toc
*.vrb
*.xdy
*.tdo

View File

@ -1,15 +0,0 @@
\section{Introduction}
\subsection{What is Metadata?}
While encryption technology like PGP or S/MIME provides a secure way to protect content from prying eyes, ever since Edward Snowdens whistleblowing we learned that metadata --- most notably information about who communicates with whom --- is equally interesting and much easier to analyze.
There are a few examples where meta data might be enough to get you in trouble. If you write to someoune in the IS, you might not be able to fly the next time you want to visit the U.S. The no-fly list doesn't care if you're a journalist, or had no clue that this person was a terrorist.
If Samsung knows Apple talks excessively with the sole producer of this nifty little sensor, they don't need the details --- the S7 will sport one of those, too. (Failing to see that Apple used it to build a car.)
\subsection{How Can We Hide Metadata?}
With e-mail, we can only prevent this by encrypting the connection to the server as well as between servers. Therefore we can only hope that both our and the recipient's e-mail provider are both trustworthy as well as competent.\footnote{Of course they should be free as well.}
With Bitmessage we send a message to a sufficiently large number of participants, with the intended recipient among them. Content is encrypted such as only the person in possesion of the private key can decrypt it. All participants try to do this in order to find their messages.

View File

@ -1,279 +0,0 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{bfh}[2015/04/21 Atricle Class for my BFH reports]
\DeclareOption{a4paper}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{11pt}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{oneside}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption{titlepage}{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}}
\ExecuteOptions{a4paper,11pt,oneside}
\ProcessOptions
%\RequirePackage{cite}
%\RequirePackage[backend=bibtex]{biblatex}
% Literatur- und Bilderquellen trennen
%\defbibheading{lit}{\section*{Literature}}
%\defbibheading{pic}{\section*{Pictures}}
\LoadClass{scrartcl}
\RequirePackage{remreset}
\RequirePackage[utf8]{inputenc}
\RequirePackage{graphicx}
\RequirePackage{color}
\RequirePackage{lmodern}
\RequirePackage{url}
\RequirePackage{lastpage}
\RequirePackage{mathtools}
\RequirePackage{amsfonts}
%\RequirePackage{float}
\RequirePackage{textgreek}
%\RequirePackage{centernot}
\RequirePackage{hyphenat}
\RequirePackage[T1]{fontenc}
\RequirePackage[scaled]{helvet}
\RequirePackage{textcomp}
\RequirePackage{eurosym}
\RequirePackage{fancyhdr}
\RequirePackage{alltt}
\RequirePackage{verbatim}
\RequirePackage{aeguill}
%\RequirePackage{underscore}
\RequirePackage{ctable}
\RequirePackage[english]{babel}
\RequirePackage{tabularx}
\RequirePackage{wrapfig}
\RequirePackage{ifthen}
\RequirePackage[usenames,dvipsnames,svgnames]{xcolor}
\RequirePackage{hyperref}
\RequirePackage{listings}
\RequirePackage{attachfile}
\RequirePackage{enumitem}
\RequirePackage{wasysym}
\RequirePackage[absolute]{textpos}
\definecolor{bfhblue}{rgb}{0.396,0.49,0.56} % Blue
\definecolor{bfhorange}{rgb}{0.961,0.753,0.196} % Orange
\definecolor{bfhorangelight}{RGB}{246,216,136} % Orange Light
\hypersetup{
linkcolor=blue, % color of internal links
citecolor=green, % color of links to bibliography
filecolor=blue, % color of file links
urlcolor=blue, % color of external links
colorlinks=true
}
\urlstyle{same}
\typearea{12}
%\bibliographystyle{alpha}
\setcounter{secnumdepth}{4}
\setlength{\parskip}{12pt}
\setlength{\parindent}{0pt}
\renewcommand{\familydefault}{\sfdefault}
%\let\oldtoc\tableofcontents
%\renewcommand{\tableofcontents} {
% \oldtoc
% \newpage
%}
\newcommand*{\tutor}[1]{\gdef\@tutor{#1}}
\renewcommand{\maketitle} {
\begin{titlepage}
\newlength{\unitlengthtmp}
\setlength{\unitlengthtmp}{\unitlength}
\setlength{\unitlength}{1mm}
\setlength{\TPHorizModule}{\textwidth}
\setlength{\TPVertModule}{\textheight}
%
% BFH Logo
\includegraphics[scale=1.25]{images/logo.pdf}
%
% Linien
\begin{textblock}{1}[0,0](0,0)
\begin{picture}(0,130)
\put(20,0){\color{bfhblue}\rule{\textwidth}{1.2mm}}
\put(20,40){\color{bfhblue}\rule{\textwidth}{1.2mm}} %28.5
\end{picture}
\end{textblock}
%
%Zentrierte Titel
\begin{flushleft}
\vspace*{4.08cm}
\textsf{\textbf{\noindent{\Huge{\textcolor{bfhblue}{\@title}}}}}\\[0.4cm]
\textsf{\huge{\textcolor{bfhblue}{\@subtitle}}}
%
%Angaben zum Dokument
\begin{vfill}
\begin{tabularx}{\textwidth}{lX}
\textsf{Author} & \@author\\
\textsf{Tutor} & \@tutor\\
% \textsf{Expert} & \textsf\DozentA\\
% \textsf{Studiengang} & \textsf{\Studiengang}\vspace{5pt}\\
% \textsf{Autoren} & \textsf\AutorA\\
% & \textsf\AutorB\vspace{5pt}\\
% \textsf{Betreuer} & \textsf\DozentA\\
% & \textsf\DozentB\vspace{5pt}\\
% \textsf{Experten} & \textsf\ExpertA\\
% & \textsf\ExpertB\vspace{5pt}\\
\textsf{Date} & \textsf{\@date}\vspace{5pt}\\
% &\\
% &\\
% \multicolumn{2}{p{\columnwidth-\tabcolsep}}{\textsf{\input{titlepage/titlepage_info}}}\\
\end{tabularx}
\end{vfill}
\end{flushleft}
\setlength{\unitlength}{\unitlengthtmp}
\end{titlepage}
}
\pagestyle{fancy}
\fancyhf{}
\fancyfoot[R]{\hrule\thepage/\pageref{LastPage}}
\fancyfoot[L]{\hrule\today}
\fancyhead[L]{\@title}
\fancyhead[R]{
\includegraphics[height=1.5\baselineskip]{images/logo.png}
}
\addtolength{\headheight}{2\baselineskip}
\addtolength{\headheight}{0.61pt}
\lstset{
language=XML, % Code langugage
basicstyle=\ttfamily\scriptsize,
keywordstyle=\color{OliveGreen}, % Keywords font ('*' = uppercase)
stringstyle=\color{blue}, % String font
commentstyle=\color{gray}, % Comments font
numbers=left, % Line nums position
numberstyle=\tiny, % Line-numbers fonts
stepnumber=1, % Step between two line-numbers
numbersep=10pt, % How far are line-numbers from code
backgroundcolor=\color{BackgroundBlue}, % Choose background color
frame=none, % A frame around the code
tabsize=4, % Default tab size
captionpos=b, % Caption-position = bottom
breaklines=true, % Automatic line breaking?
breakatwhitespace=false, % Automatic breaks only at whitespace?
%showspaces=false, % Dont make spaces visible
%showtabs=false, % Dont make tabls visible
columns=fixed, % Column format
morekeywords={Server, Listener, GlobalNamingResources,
Resource, ResourceLink, Service, Connector, Engine,
Host, Context, Environment,
beans, bean, broker, destinationPolicy, policyMap,
policyEntries, policyEntry, dispatchPolicy,
strictOrderDispatchPolicy, subscriptionRecoveryPolicy,
lastImageSubscriptionRecoveryPolicy, managementContext,
persistenceAdapter, systemUsage, memoryUsage,
storeUsage, tempUsage, transportConnectors,
transportConnector, property, jetty, connectors,
nioConnector, handlers, webAppContext},
}
% Shows a listing and creates an attachment with the source
\newcommand{\attachlisting}[2][]{
\hspace{0.95\textwidth}
\attachfile[icon=Paperclip]{#2}
\vspace{-5ex}
\lstinputlisting[#1]{#2}
}
% 1 line number(s)
% 2 variable name
% 3 description
% 4 example values
\newcommand{\listinginfo}[4]{
\colorbox{WhiteSmoke}{
\parbox[t]{0.25\textwidth}{
\printifnotempty{#1}{\texttt{#1:}\\}
\textit{#2}
}
\parbox[t]{0.715\textwidth}{
\printifnotempty{#3}{#3
}
\printifnotempty{#4}{
\par
\vspace{1ex}
\colorbox{BackgroundBlue}{
\parbox{0.69\textwidth}{
\vspace{-2ex}
\ttfamily
\flushleft{#4}
}
}
\par
\vspace{0.5ex}
}
}
}
\par
\vspace{-1.7ex}
}
\newcommand{\printifnotempty}[2]{
\ifthenelse{\equal{#1}{}}{}{#2}
}
% Makes a red box that highlights errors or very important warnings
\newcommand{\errorbox}[1]{
\fcolorbox{Red}{LightPink}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/error.pdf}
\vspace{12pt}
\end{wrapfigure}
#1
}
}
}
% Makes a yellow box that highlights warnings
\newcommand{\warningbox}[1]{
\fcolorbox{Goldenrod}{LightYellow}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/warning.pdf}
\vspace{12pt}
\end{wrapfigure}
#1
}
}
}
% Makes a blue box that highlights special information
\newcommand{\infobox}[1]{
\fcolorbox{CornflowerBlue}{AliceBlue}{
\parbox{0.972\textwidth}{
\begin{wrapfigure}[2]{l}{0.05\textwidth}
\vspace{-12pt}
\includegraphics[width=0.05\textwidth]{images/info.pdf}
\end{wrapfigure}
#1
}
}
}
\RequirePackage{listings}
\definecolor{BackgroundBlue}{cmyk}{0.05,0,0,0}
\let\olditemize=\itemize
\def\itemize{
\olditemize
\setlength{\itemsep}{-1.5ex}
}
\newcommand{\leadingzero}[1]{\ifnum #1<10 0\the#1\else\the#1\fi}
%YYYY-MM-DD
\newcommand{\todayI}{\the\year-\leadingzero{\month}-\leadingzero{\day}}
\endinput

View File

@ -1,29 +0,0 @@
@ONLINE{wiki:protocol,
url = {https://bitmessage.org/wiki/Protocol_specification},
title = {Bitmessage Wiki: Protocol Specification},
publisher = {Bitmessage Wiki},
urldate = {2015-04-24},
author = {Warren, Jonathan 'Atheros' and Coe, Jonathan},
note = {\url{https://bitmessage.org/wiki/Protocol_specification}},
year = {2015},
}
@ONLINE{wiki:prefixfilter,
url = {https://bitmessage.org/wiki/Scalability_through_Prefix_Filtering},
title = {Bitmessage Wiki: Scalability through Prefix Filtering},
publisher = {Bitmessage Wiki},
urldate = {2015-05-22},
author = {Coe, Jonathan},
note = {\url{https://bitmessage.org/wiki/Scalability_through_Prefix_Filtering}},
year = {2015},
}
@ONLINE{issue:112,
url = {https://github.com/Bitmessage/PyBitmessage/issues/112},
title = {BigInv and ping/pong},
publisher = {github.com},
urldate = {2015-05-22},
author = {Warren, Jonathan 'Atheros' and ISibbol},
note = {\url{https://github.com/Bitmessage/PyBitmessage/issues/112}},
year = {2015},
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 477 KiB

View File

@ -1,123 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="116.25"
height="67.5"
xml:space="preserve"
sodipodi:docname="logo.pdf"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="m 0,0 922.23,0 0,538.586 L 0,538.586 0,0 z"
id="path20" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview4"
showgrid="false"
inkscape:zoom="3.4962963"
inkscape:cx="58.125"
inkscape:cy="33.75"
inkscape:window-x="271"
inkscape:window-y="47"
inkscape:window-maximized="0"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="logo"
transform="matrix(1.25,0,0,-1.25,0,67.5)"><g
id="g12"
transform="scale(0.1,0.1)"><g
id="g14"><g
id="g16"
clip-path="url(#clipPath18)"><path
d="m 185.602,538.586 c 77.55,0 140.449,-62.867 140.449,-140.449 0,-52.102 -24.153,-97.317 -63.223,-121.828 -0.765,-0.485 -1.32,-1.211 -1.32,-2.161 0,-1.714 1.359,-2.152 1.453,-2.191 50.684,-19.617 82.488,-71.375 82.488,-131.484 C 345.449,62.875 282.535,0 204.977,0 L 19.4961,0.0390625 C 8.73047,0.0390625 0,8.77344 0,19.5156 L 0,519.094 c 0,10.769 8.73047,19.492 19.4961,19.492 l 166.1059,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path22" /><path
d="m 117.695,95.3672 c -2.476,0 -4.593,2.1172 -4.593,4.5937 l 0,112.6291 c 0,2.469 2.117,4.594 4.593,4.594 l 7.071,0 c 2.468,0 4.613,-2.125 4.613,-4.594 l 0,-49.895 43.844,0 0,49.895 c 0,2.469 2.121,4.594 4.593,4.594 l 7.071,0 c 2.472,0 4.593,-2.125 4.593,-4.594 l 0,-112.6291 c 0,-2.4765 -2.121,-4.5937 -4.593,-4.5937 l -7.071,0 c -2.472,0 -4.593,2.1172 -4.593,4.5937 l 0,48.4181 -43.844,0 0,-48.4181 c 0,-2.4765 -2.145,-4.5937 -4.613,-4.5937 l -7.071,0"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path24" /><path
d="m 117.227,321.836 c -2.477,0 -4.594,2.117 -4.594,4.594 l 0,112.644 c 0,2.473 2.117,4.614 4.594,4.614 l 67.757,0 c 2.473,0 4.594,-2.141 4.594,-4.614 l 0,-4.773 c 0,-2.477 -2.121,-4.594 -4.594,-4.594 l -56.078,0 0,-39.148 47.754,0 c 2.488,0 4.613,-2.121 4.613,-4.598 l 0,-4.789 c 0,-2.477 -2.125,-4.594 -4.613,-4.594 l -47.754,0 0,-50.148 c 0,-2.477 -2.121,-4.594 -4.593,-4.594 l -7.086,0"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path26" /><path
d="m 410.621,489.852 8.406,0 c 7.207,0 9.758,2.777 9.758,9.086 0,6.226 -2.324,9.082 -9.461,9.082 l -8.703,0 0,-18.168 z m -0.078,24.027 8.559,0 c 6.078,0 7.429,2.547 7.429,7.957 0,5.398 -1.726,8.184 -7.804,8.184 l -8.184,0 0,-16.141 z m -4.879,-29.805 c -1.051,0 -1.953,0.895 -1.953,1.953 l 0,47.821 c 0,1.047 0.902,1.953 1.953,1.953 l 13.285,0 c 10.891,0 14.864,-5.711 14.864,-13.821 0,-5.398 -1.348,-8.328 -6.301,-10.429 5.027,-1.422 8.633,-5.332 8.633,-12.985 0,-10.285 -6.758,-14.492 -16.372,-14.492 l -14.109,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path28" /><path
d="m 462.32,517.559 c -4.355,0 -7.054,-2.258 -7.586,-11.27 l 14.946,0 c 0,8.645 -1.953,11.27 -7.36,11.27 z m 0.825,-34.465 c -9.832,0 -15.391,5.703 -15.391,19.824 0,14.258 5.855,19.738 14.719,19.738 8.929,0 14.035,-5.097 14.035,-18.691 l 0,-1.348 c 0,-0.672 -0.528,-1.203 -1.199,-1.203 l -20.645,0 c 0.145,-10.281 2.402,-12.84 8.633,-12.84 3.226,0 5.332,0.977 7.277,2.332 0.906,0.676 2.18,0.449 2.781,-0.379 l 1.2,-1.57 c 0.601,-0.832 0.449,-2.113 -0.45,-2.707 -3.074,-2.176 -6.23,-3.156 -10.96,-3.156"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path30" /><path
d="m 491.531,484.074 c -1.047,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.906,1.946 1.953,1.946 l 1.125,0 c 1.129,0 2.106,-0.821 2.328,-1.946 l 0.676,-3.379 c 2.778,3.45 6.231,6.008 10.586,6.008 0.223,0 0.527,0 0.75,-0.078 0.305,-0.078 0.602,-0.371 0.527,-0.676 l -0.527,-5.254 c -0.07,-0.523 -0.601,-0.972 -1.199,-0.906 -0.375,0.078 -0.824,0.078 -1.203,0.078 -3.449,0 -5.781,-1.277 -8.559,-3.828 l 0,-25.672 c 0,-1.058 -0.898,-1.953 -1.949,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path32" /><path
d="m 521.055,484.074 c -1.051,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.902,1.946 1.953,1.946 l 1.125,0 c 1.125,0 2.101,-0.821 2.328,-1.875 l 0.597,-2.774 c 3.309,3.301 7.059,5.625 11.489,5.625 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.469 c 0,-1.058 -0.907,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.949,0.895 -1.949,1.953 l 0,25.446 c 0,4.281 -1.2,5.48 -4.578,5.48 -3.004,0 -6.383,-2.098 -9.086,-4.5 l 0,-26.426 c 0,-1.058 -0.903,-1.953 -1.95,-1.953 l -2.554,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path34" /><path
d="m 573.313,517.559 c -4.36,0 -7.059,-2.258 -7.586,-11.27 l 14.941,0 c 0,8.645 -1.953,11.27 -7.355,11.27 z m 0.824,-34.465 c -9.836,0 -15.391,5.703 -15.391,19.824 0,14.258 5.859,19.738 14.715,19.738 8.934,0 14.039,-5.097 14.039,-18.691 l 0,-1.348 c 0,-0.672 -0.527,-1.203 -1.199,-1.203 l -20.649,0 c 0.153,-10.281 2.407,-12.84 8.633,-12.84 3.231,0 5.328,0.977 7.281,2.332 0.907,0.676 2.18,0.449 2.782,-0.379 l 1.199,-1.57 c 0.601,-0.832 0.449,-2.113 -0.449,-2.707 -3.082,-2.176 -6.231,-3.156 -10.961,-3.156"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path36" /><path
d="m 602.527,484.074 c -1.047,0 -1.953,0.895 -1.953,1.953 l 0,33.707 c 0,1.047 0.906,1.946 1.953,1.946 l 1.125,0 c 1.129,0 2.106,-0.821 2.328,-1.946 l 0.676,-3.379 c 2.778,3.45 6.231,6.008 10.586,6.008 0.223,0 0.528,0 0.75,-0.078 0.305,-0.078 0.602,-0.371 0.528,-0.676 l -0.528,-5.254 c -0.07,-0.523 -0.597,-0.972 -1.199,-0.906 -0.375,0.078 -0.824,0.078 -1.203,0.078 -3.449,0 -5.781,-1.277 -8.559,-3.828 l 0,-25.672 c 0,-1.058 -0.898,-1.953 -1.949,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path38" /><path
d="m 406.41,394.07 c -1.051,0 -1.945,0.903 -1.945,1.953 l 0,47.825 c 0,1.047 0.894,1.953 1.945,1.953 l 21.852,0 c 1.051,0 1.949,-0.906 1.949,-1.953 l 0,-2.032 c 0,-1.043 -0.898,-1.953 -1.949,-1.953 l -16.895,0 0,-15.683 13.363,0 c 1.051,0 1.954,-0.91 1.954,-1.953 l 0,-2.032 c 0,-1.047 -0.903,-1.953 -1.954,-1.953 l -13.363,0 0,-22.219 c 0,-1.05 -0.898,-1.953 -1.949,-1.953 l -3.008,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path40" /><path
d="m 450.371,398.203 c 3.676,0 6.453,2.481 8.258,4.5 l 0,9.992 -2.25,0 c -9.465,0 -11.266,-2.402 -11.266,-7.89 0,-4.95 1.575,-6.602 5.258,-6.602 z m -0.824,-5.105 c -7.207,0 -11.34,3.972 -11.34,11.707 0,8.562 5.031,12.539 17.344,12.539 l 3.078,0 0,2.929 c 0,4.2 -0.527,6.758 -5.406,6.758 -3.227,0 -6.383,-1.133 -9.235,-2.558 -0.976,-0.45 -2.175,-0.071 -2.625,0.91 l -0.754,1.426 c -0.449,0.972 -0.078,2.175 0.899,2.703 3.379,1.797 7.285,3.144 12.387,3.144 7.359,0 11.187,-3.301 11.187,-11.328 l 0,-25.305 c 0,-1.05 -0.898,-1.953 -1.953,-1.953 l -1.121,0 c -1.129,0 -2.18,0.754 -2.481,1.875 l -0.523,1.875 c -2.18,-2.398 -5.332,-4.722 -9.457,-4.722"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path42" /><path
d="m 493.102,393.098 c -9.61,0 -14.942,6.304 -14.942,19.824 0,14.336 5.707,19.734 15.016,19.734 3.601,0 6.457,-0.82 9.16,-3 0.902,-0.672 0.977,-1.875 0.297,-2.703 l -1.203,-1.504 c -0.746,-0.82 -1.95,-0.898 -2.774,-0.222 -1.652,1.277 -3.23,1.953 -5.707,1.953 -5.703,0 -7.883,-2.473 -7.883,-14.258 0,-11.567 2.407,-14.348 8.411,-14.348 2.324,0 3.902,0.899 5.476,2.18 0.828,0.672 2.106,0.601 2.781,-0.227 l 1.352,-1.425 c 0.746,-0.75 0.676,-2.032 -0.152,-2.707 -2.473,-2.176 -5.555,-3.297 -9.832,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path44" /><path
d="m 517.891,394.07 c -1.051,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.902,1.953 1.953,1.953 l 2.554,0 c 1.047,0 1.95,-0.906 1.95,-1.953 l 0,-18.993 c 3.304,3.079 6.683,5.176 11.035,5.176 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.907,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.949,0.903 -1.949,1.953 l 0,25.454 c 0,4.277 -1.2,5.476 -4.579,5.476 -3.003,0 -6.382,-2.098 -9.085,-4.504 l 0,-26.426 c 0,-1.05 -0.903,-1.953 -1.95,-1.953 l -2.554,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path46" /><path
d="m 559.496,394.07 c -1.055,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.055,0 1.953,-0.906 1.953,-1.953 l 0,-18.993 c 3.305,3.079 6.684,5.176 11.035,5.176 5.403,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.902,-1.953 -1.953,-1.953 l -2.555,0 c -1.05,0 -1.953,0.903 -1.953,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.574,5.476 -3.004,0 -6.383,-2.098 -9.086,-4.504 l 0,-26.426 c 0,-1.05 -0.898,-1.953 -1.953,-1.953 l -2.551,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path48" /><path
d="m 612.621,398.203 c 5.707,0 8.41,3.074 8.41,14.641 0,11.629 -2.777,14.715 -8.48,14.715 -5.711,0 -8.41,-3.008 -8.41,-14.637 0,-11.567 2.777,-14.719 8.48,-14.719 z m 0,-5.105 c -9.16,0 -15.391,5.703 -15.391,19.824 0,14.109 6.086,19.734 15.243,19.734 9.16,0 15.465,-5.625 15.465,-19.734 0,-14.121 -6.157,-19.824 -15.317,-19.824"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path50" /><path
d="m 654.23,393.098 c -9.613,0 -14.945,6.304 -14.945,19.824 0,14.336 5.711,19.734 15.016,19.734 3.605,0 6.457,-0.82 9.16,-3 0.898,-0.672 0.977,-1.875 0.305,-2.703 l -1.203,-1.504 c -0.75,-0.82 -1.954,-0.898 -2.778,-0.222 -1.656,1.277 -3.226,1.953 -5.707,1.953 -5.703,0 -7.883,-2.473 -7.883,-14.258 0,-11.567 2.403,-14.348 8.41,-14.348 2.325,0 3.903,0.899 5.477,2.18 0.824,0.672 2.106,0.601 2.777,-0.227 l 1.356,-1.425 c 0.75,-0.75 0.672,-2.032 -0.152,-2.707 -2.477,-2.176 -5.555,-3.297 -9.833,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path52" /><path
d="m 679.023,394.07 c -1.05,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.903,1.953 1.953,1.953 l 2.555,0 c 1.051,0 1.945,-0.906 1.945,-1.953 l 0,-18.993 c 3.309,3.079 6.688,5.176 11.04,5.176 5.402,0 9.085,-2.773 9.085,-9.16 l 0,-27.473 c 0,-1.05 -0.906,-1.953 -1.953,-1.953 l -2.554,0 c -1.051,0 -1.95,0.903 -1.95,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.578,5.476 -3.004,0 -6.383,-2.098 -9.09,-4.504 l 0,-26.426 c 0,-1.05 -0.894,-1.953 -1.945,-1.953 l -2.555,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path54" /><path
d="m 727.582,393.098 c -4.129,0 -8.105,1.343 -10.883,2.925 -0.902,0.598 -1.203,1.797 -0.679,2.707 l 0.832,1.426 c 0.519,0.977 1.722,1.27 2.625,0.75 2.628,-1.504 5.328,-2.398 8.41,-2.398 5.101,0 6.679,2.019 6.679,5.547 0,4.207 -1.953,5.027 -7.961,6.687 -5.253,1.426 -9.609,4.199 -9.609,11.629 0,5.481 3.531,10.285 11.789,10.285 3.602,0 6.309,-0.593 8.711,-1.57 0.977,-0.449 1.426,-1.652 0.977,-2.629 l -0.68,-1.504 c -0.449,-0.976 -1.578,-1.504 -2.625,-1.055 -2.18,0.977 -3.902,1.282 -6.16,1.282 -4.051,0 -5.926,-1.426 -5.926,-4.653 0,-3.535 1.57,-4.429 6.754,-5.855 5.777,-1.574 11.039,-3.828 11.039,-12.317 0,-7.8 -4.434,-11.257 -13.293,-11.257"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path56" /><path
d="m 766.797,393.098 c -9.609,0 -14.942,6.304 -14.942,19.824 0,14.336 5.708,19.734 15.016,19.734 3.602,0 6.453,-0.82 9.16,-3 0.899,-0.672 0.977,-1.875 0.301,-2.703 l -1.199,-1.504 c -0.754,-0.82 -1.953,-0.898 -2.778,-0.222 -1.656,1.277 -3.23,1.953 -5.71,1.953 -5.704,0 -7.879,-2.473 -7.879,-14.258 0,-11.567 2.402,-14.348 8.406,-14.348 2.324,0 3.902,0.899 5.48,2.18 0.825,0.672 2.106,0.601 2.778,-0.227 l 1.351,-1.425 c 0.754,-0.75 0.676,-2.032 -0.148,-2.707 -2.477,-2.176 -5.559,-3.297 -9.836,-3.297"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path58" /><path
d="m 791.586,394.07 c -1.055,0 -1.953,0.903 -1.953,1.953 l 0,50.45 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.054,0 1.953,-0.906 1.953,-1.953 l 0,-18.993 c 3.305,3.079 6.683,5.176 11.035,5.176 5.402,0 9.086,-2.773 9.086,-9.16 l 0,-27.473 c 0,-1.05 -0.902,-1.953 -1.953,-1.953 l -2.555,0 c -1.051,0 -1.953,0.903 -1.953,1.953 l 0,25.454 c 0,4.277 -1.199,5.476 -4.574,5.476 -3.004,0 -6.383,-2.098 -9.086,-4.504 l 0,-26.426 c 0,-1.05 -0.899,-1.953 -1.953,-1.953 l -2.551,0"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path60" /><path
d="m 840.68,393.098 c -5.41,0 -9.61,3.074 -9.61,9.605 l 0,27.031 c 0,1.047 0.899,1.946 1.95,1.946 l 2.55,0 c 1.051,0 1.953,-0.899 1.953,-1.946 l 0,-25 c 0,-4.429 1.5,-5.933 4.879,-5.933 3.004,0 6.231,2.027 9.008,4.512 l 0,26.421 c 0,1.047 0.903,1.946 1.953,1.946 l 2.555,0 c 1.051,0 1.949,-0.899 1.949,-1.946 l 0,-33.711 c 0,-1.05 -0.898,-1.953 -1.949,-1.953 l -1.129,0 c -1.129,0 -2.098,0.832 -2.328,1.875 l -0.602,2.785 c -3.148,-3.234 -6.754,-5.632 -11.179,-5.632"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path62" /><path
d="m 880,393.32 c -4.805,0 -6.832,2.559 -6.832,9.16 l 0,43.993 c 0,1.047 0.898,1.953 1.953,1.953 l 2.551,0 c 1.055,0 1.953,-0.906 1.953,-1.953 l 0,-45.196 c 0,-1.875 0.824,-2.625 2.625,-2.625 0.305,0 0.602,0 0.824,0.078 0.379,0 0.754,-0.222 0.828,-0.605 l 0.375,-2.18 c 0.227,-1.043 -0.449,-2.097 -1.5,-2.324 -0.902,-0.144 -1.879,-0.301 -2.777,-0.301"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path64" /><path
d="m 908.043,427.559 c -4.355,0 -7.059,-2.254 -7.582,-11.27 l 14.937,0 c 0,8.645 -1.953,11.27 -7.355,11.27 z m 0.824,-34.461 c -9.836,0 -15.39,5.703 -15.39,19.824 0,14.258 5.855,19.734 14.714,19.734 8.934,0 14.039,-5.097 14.039,-18.691 l 0,-1.348 c 0,-0.676 -0.527,-1.203 -1.199,-1.203 l -20.644,0 c 0.144,-10.281 2.402,-12.84 8.633,-12.84 3.226,0 5.332,0.977 7.281,2.332 0.902,0.676 2.176,0.449 2.777,-0.379 l 1.199,-1.574 c 0.602,-0.828 0.45,-2.105 -0.449,-2.703 -3.074,-2.18 -6.23,-3.152 -10.961,-3.152"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path66" /></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="130.34865"
height="67.32325"
xml:space="preserve"
sodipodi:docname="logo-en.svg"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="m 0,0 922.23,0 0,538.586 L 0,538.586 0,0 z"
id="path20"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="889"
inkscape:window-height="781"
id="namedview4"
showgrid="false"
inkscape:zoom="6.9925926"
inkscape:cx="64.932998"
inkscape:cy="68.072034"
inkscape:window-x="271"
inkscape:window-y="47"
inkscape:window-maximized="0"
inkscape:current-layer="g10"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="logo"
transform="matrix(1.25,0,0,-1.25,0,67.32325)"><path
inkscape:connector-curvature="0"
id="path22"
style="fill:#467d97;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 18.5602,53.8586 c 7.755,0 14.0449,-6.2867 14.0449,-14.0449 0,-5.2102 -2.4153,-9.7317 -6.3223,-12.1828 -0.0765,-0.0485 -0.132,-0.1211 -0.132,-0.2161 0,-0.1714 0.1359,-0.2152 0.1453,-0.2191 5.0684,-1.9617 8.2488,-7.1375 8.2488,-13.1484 C 34.5449,6.2875 28.2535,0 20.4977,0 L 1.94961,0.00390625 C 0.873047,0.00390625 0,0.877344 0,1.95156 L 0,51.9094 c 0,1.0769 0.873047,1.9492 1.94961,1.9492 l 16.61059,0" /><path
inkscape:connector-curvature="0"
id="path24"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 11.7695,9.53672 c -0.2476,0 -0.4593,0.21172 -0.4593,0.45937 l 0,11.26291 c 0,0.2469 0.2117,0.4594 0.4593,0.4594 l 0.7071,0 c 0.2468,0 0.4613,-0.2125 0.4613,-0.4594 l 0,-4.9895 4.3844,0 0,4.9895 c 0,0.2469 0.2121,0.4594 0.4593,0.4594 l 0.7071,0 c 0.2472,0 0.4593,-0.2125 0.4593,-0.4594 l 0,-11.26291 c 0,-0.24765 -0.2121,-0.45937 -0.4593,-0.45937 l -0.7071,0 c -0.2472,0 -0.4593,0.21172 -0.4593,0.45937 l 0,4.84181 -4.3844,0 0,-4.84181 c 0,-0.24765 -0.2145,-0.45937 -0.4613,-0.45937 l -0.7071,0" /><path
inkscape:connector-curvature="0"
id="path26"
style="fill:#fcd205;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 11.7227,32.1836 c -0.2477,0 -0.4594,0.2117 -0.4594,0.4594 l 0,11.2644 c 0,0.2473 0.2117,0.4614 0.4594,0.4614 l 6.7757,0 c 0.2473,0 0.4594,-0.2141 0.4594,-0.4614 l 0,-0.4773 c 0,-0.2477 -0.2121,-0.4594 -0.4594,-0.4594 l -5.6078,0 0,-3.9148 4.7754,0 c 0.2488,0 0.4613,-0.2121 0.4613,-0.4598 l 0,-0.4789 c 0,-0.2477 -0.2125,-0.4594 -0.4613,-0.4594 l -4.7754,0 0,-5.0148 c 0,-0.2477 -0.2121,-0.4594 -0.4593,-0.4594 l -0.7086,0" /><text
xml:space="preserve"
style="font-size:11.55966663px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#467d97;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="40.459648"
y="-47.22646"
id="text3153"
sodipodi:linespacing="125%"
transform="scale(0.97670303,-1.0238527)"><tspan
sodipodi:role="line"
id="tspan3155"
x="40.459648"
y="-47.22646"
style="font-size:7.06424141px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#467d97;fill-opacity:1;font-family:News Gothic MT;-inkscape-font-specification:News Gothic MT">Bern University</tspan><tspan
sodipodi:role="line"
x="40.459648"
y="-38.396156"
id="tspan3157"
style="font-size:7.06424141px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#467d97;fill-opacity:1;font-family:News Gothic MT;-inkscape-font-specification:News Gothic MT">of Applied Sciences</tspan></text>
</g></svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

View File

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="679.7655"
height="591.2851"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="ports_and_adapters.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="149.17872"
inkscape:cy="85.139761"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1632"
inkscape:window-height="1005"
inkscape:window-x="48"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-18.678419,-26.216821)">
<path
inkscape:transform-center-y="-23.12416"
inkscape:transform-center-x="10.947617"
d="m 465.92439,509.82496 c -1.78891,1.03067 -204.67101,0.84709 -206.45806,-0.18682 -1.78704,-1.03391 -103.06911,-176.82675 -103.06724,-178.89133 0.002,-2.06458 101.6019,-177.67385 103.39081,-178.70452 1.78892,-1.03067 204.67102,-0.84709 206.45806,0.18682 1.78705,1.0339 103.06912,176.82675 103.06725,178.89133 -0.002,2.06458 -101.6019,177.67384 -103.39082,178.70452 z"
inkscape:randomized="9.7491459e-16"
inkscape:rounded="0.01"
inkscape:flatsided="true"
sodipodi:arg2="1.5717012"
sodipodi:arg1="1.0481024"
sodipodi:r2="214.49513"
sodipodi:r1="206.45815"
sodipodi:cy="330.93362"
sodipodi:cx="362.85715"
sodipodi:sides="6"
id="path2997"
style="fill:#5fbcd3;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
sodipodi:type="star"
transform="matrix(1.645857,0,0,1.645857,-238.64982,-222.81004)" />
<path
sodipodi:type="star"
style="fill:#ffd42a;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="path2985"
sodipodi:sides="6"
sodipodi:cx="362.85715"
sodipodi:cy="330.93362"
sodipodi:r1="206.45815"
sodipodi:r2="214.49513"
sodipodi:arg1="1.0481024"
sodipodi:arg2="1.5717012"
inkscape:flatsided="true"
inkscape:rounded="0.01"
inkscape:randomized="9.7491459e-16"
d="m 465.92439,509.82496 c -1.78891,1.03067 -204.67101,0.84709 -206.45806,-0.18682 -1.78704,-1.03391 -103.06911,-176.82675 -103.06724,-178.89133 0.002,-2.06458 101.6019,-177.67385 103.39081,-178.70452 1.78892,-1.03067 204.67102,-0.84709 206.45806,0.18682 1.78705,1.0339 103.06912,176.82675 103.06725,178.89133 -0.002,2.06458 -101.6019,177.67384 -103.39082,178.70452 z"
inkscape:transform-center-x="6.6516253"
inkscape:transform-center-y="-14.049918"
transform="translate(-4.2959915,-9.0742422)" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="358.36584"
y="218.6479"
id="text2987"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="358.36584"
y="218.6479"
id="tspan2995"
style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">Application</tspan></text>
<text
sodipodi:linespacing="125%"
id="text2999"
y="94.647903"
x="359.22522"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
id="tspan3003"
y="94.647903"
x="359.22522"
sodipodi:role="line">Adapters</tspan></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="-100.75645"
y="246.52264"
id="text3042"
sodipodi:linespacing="125%"
transform="matrix(0.47970506,-0.8774298,0.8774298,0.47970506,0,0)"><tspan
sodipodi:role="line"
x="-100.75645"
y="246.52264"
id="tspan3044"
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique">Storage</tspan></text>
<text
transform="matrix(0.53345366,0.84582929,-0.84582929,0.53345366,0,0)"
sodipodi:linespacing="125%"
id="text3046"
y="-357.84464"
x="471.47845"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique"
y="-357.84464"
x="471.47845"
sodipodi:role="line"
id="tspan3050">Proof of Work</tspan></text>
<text
transform="matrix(-0.51536966,-0.85696798,0.85696798,-0.51536966,0,0)"
sodipodi:linespacing="125%"
id="text3054"
y="-85.847336"
x="-455.38437"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
xml:space="preserve"><tspan
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique"
id="tspan3056"
y="-85.847336"
x="-455.38437"
sodipodi:role="line">User Interface</tspan></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Constantia;-inkscape-font-specification:Constantia"
x="92.095795"
y="-700.29236"
id="text3058"
sodipodi:linespacing="125%"
transform="matrix(-0.51365875,0.85799458,-0.85799458,-0.51365875,0,0)"><tspan
id="tspan3060"
sodipodi:role="line"
x="92.095795"
y="-700.29236"
style="font-size:32px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Oblique">Network</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.7 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

View File

@ -1,78 +0,0 @@
\documentclass{bfh}
\title{Project 2}
\subtitle{Bitmessage -- Communication Without Metadata}
\author{Christian Basler}
\tutor{Kai Brünnler}
\date{\today}
\begin{document}
\maketitle
\tableofcontents
\section{Synopsis}
TODO
% Section basics
\input{basics}
The protocol is described in detail in my Seminar paper.
\section{Goal}
At the moment, there aren't many implementations apart from the official clients. Especially two things are missing: a multi purpose Java library and a usable mobile client. My goal for my \textit{Project 2} is to create the library, to be used next semester as a starting point for an Android\textsuperscript{\texttrademark} client in my Bachelor Thesis.
\section{Issues}
TODO
\subsection{Unsigned Numbers}
Java doesn't support unsigned number types. While Java 8 has some helper classes to address this issue, my goal is to support Java 7, which is needed for Android development, so I wasn't able to leverage them.
\subsection{Proof of Work}
Proof of work is needed for a message to be distributed within the Bitmessage network. This is to protect both the network itself from denial of service attacks and the users from spam.
\section{Architecture}
\subsection{Ports and Adapters}
The library uses a ports and adapters architecture, which allows us to easily replace some implementations that might be platform dependent, such as storage or proof of work calculation.
\includegraphics[width=\textwidth]{images/ports_and_adapters.pdf}
The big advantage of this approach is that it's easy to test the core as well as each adapter by itself.
\subsection{Network Management}
\section{Usage}
TODO
\section{Discussion}
\appendix
\addcontentsline{toc}{section}{Appendix}
\section*{Appendix}
\renewcommand{\thesubsection}{\Alph{subsection}}
\subsection{JavaDoc Documentation}
\subsection{Literature}
\end{document}

View File

@ -1,11 +0,0 @@
@Comment{$ biblatex control file $}
@Comment{$ biblatex version 1.7 $}
Do not modify this file!
This is an auxiliary file used by the 'biblatex' package.
This file may safely be deleted. It will be recreated as
required.
@Control{biblatex-control,
options = {1.7:0:0:1:0:0:1:1:0:0:0:0:1:1:3:1:79:+},
}

Binary file not shown.

View File

@ -1,255 +0,0 @@
\documentclass{bfh}
\usepackage[numbers]{natbib}
\usepackage{xfrac}
\title{Informatikseminar}
\subtitle{Bitmessage -- Communication Without Metadata}
\author{Christian Basler}
\tutor{Kai Brünnler}
\date{\today}
\newcommand{\msg}[1]{\textit{\textcolor{RedOrange}{#1}}}
\newcommand{\obj}[1]{\textbf{\textcolor{OliveGreen}{#1}}}
\newcommand{\node}[1]{\textbf{\textcolor{MidnightBlue}{#1}}}
\begin{document}
\maketitle
\tableofcontents
\listoffigures
\newpage
\section*{Abstract}
Even if we use encryption, we reveal a lot about ourselves in the metadata we produce. Bitmessage prevents this by distributing a message in a way that it's not possible to find out which was the intended recipient.
\newpage
% Section basics
\input{basics}
\newpage
\section{PyBitmessage}
TODO
\newpage
\section{Protocol}
We use the following convention to distinguish different parts of the protocol:
\begin{tabular}{@{}>{$}l<{$}l@{}}
\msg{version} & for messages between nodes \\
\obj{pubkey} & for objects that are spread throughout the network \\
\node{A} & for individual nodes \\
\end{tabular}
\subsection{Nomenclature}
There are a few terms that are easily mixed up. Here's a list of the most confusing ones:
\subsubsection{message, msg}
A \msg{message} is sent from one node to another, i.e. to announce new objects or to initialize the network connection.
An \obj{msg} on the other hand is the object payload containing content written by a user.
In the protocol section, the term 'message' is never used to describe information exchange between users.
\subsubsection{payload}
There are three kinds of payload:
\begin{enumerate}
\item Message payload for message types, e.g. containing inventory vectors.
\item Object payload, which is distributed throughout the network.\footnote{And part of the message payload.}
\item Encrypted payload, which is the ciphertext with some metadata needed for decryption.\footnote{Which, again, is part of the object payload.}
\end{enumerate}
\subsubsection{object}
An object is a kind of message whose payload is distributed among all nodes. Somtimes just the payload is meant. To send an object, proof of work is required.
\subsection{Process Flow}
The newly started node \node{A} connects to a random node \node{B} from its node registry and sends a \msg{version} message, announcing the latest supported protocol version. If \node{B} accepts the version,\footnote{A version is accepted by default if it is higher or equal to a nodes latest supported version. Nodes supporting experimental protocol versions might accept older versions.} it responds with a \msg{verack} message, followed by a \msg{version} message announcing its own latest supported protocol version. Node \node{A} then decides whether it supports \node{B}'s version and sends its \msg{verack} message.
If both nodes accept the connection, they both send an \msg{addr} message containing up to 1000 of its known nodes, followed by one or more \msg{inv} messages announcing all valid objects they are aware of. They then send \msg{getobject} request for all objects still missing from their inventory.
\msg{Getobject} requests are answered by \msg{object} messages containing the requested objects.
A node actively connects to eight other nodes, allowing any number of incoming connections. If a user creates a new object on node \node{A}, it is offered via \msg{inv} to eight of the connected nodes. They will get the object and distribute it to up to eight of their connections, and so on, until all nodes have it in their inventory.
\subsection{Messages}
The messages, objects and binary format are very well discribed in the Bitmessage wiki \cite{wiki:protocol}, the message description is therefore narrowed down to a description of what they do and when they're used.
\subsubsection{version / verack}
A \msg{version} message contains the latest protocol version supported by a node, as well as the streams it is interested in and which features it supports. If the other node accepts, it acknowledges with a \msg{verack} message. The connection is initialized when both nodes sent a \msg{verack} message.
\subsubsection{addr}
Contains up to 1000 known nodes with their IP addresses, ports, streams and supported features.
\subsubsection{inv}
One \msg{inv} message contains the hashes of up to 50000 valid objects. If your inventory is larger, several messages can be sent.
\subsubsection{getdata}
Can request up to 50000 objects by sending their hashes.
\subsubsection{object}
Contains one requested object, which might be one of:
\listinginfo{}{getpubkey}{A request for a public key, which is needed to encrypt a message to a specific user.}{}
\listinginfo{}{pubkey}{A public key. See \ref{subsec:addr} \nameref{subsec:addr}}{}
\listinginfo{}{msg}{Content intended to be received by one user.}{}
\listinginfo{}{broadcast}{Content sent in a way that the Addresses public key can be used to decrypt it, allowing any subscriber who knows the address to receive the such a message}{}
\subsubsection{ping / pong / getbiginv}
People looking at the PyBitmessage's source code might be irritated by some other messages that seem to be implemented, but aren't mentioned in the official protocol specification. \msg{ping} does actually cause the node that implements this to send a \msg{pong} message, but this feature isn't actually used anywhere. \msg{getbiginv} seems to be thought for requesting the inventory, but as I understand it can't be used. \cite{issue:112}
\subsection{Addresses}
\label{subsec:addr}
\textit{BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h}: Addresses start with "BM-" and are, like Bitcoin addresses, Base58 encoded.\footnote{Which uses characters 1-9, A-Z and a-z without the easily confused characters I, l, 0 and O.}
\listinginfo{}{version}{Address version.}{}
\listinginfo{}{stream}{Stream number.}{}
\listinginfo{}{ripe}{Hash of both public signing and encryption key. Please note that the keys are sent without the leading 0x04 in \obj{pubkey} objects, but for creating the ripe it must be prepended. This is also necessary for most other applications, so it's a good idea to do it by default.}{ripemd160(sha512(pubSigKey + pubEncKey))}
\listinginfo{}{checksum}{First four bytes of a double SHA-512 hash of the above.}{sha512(sha512(version + stream + ripe))}
\subsection{Encryption}
Bitmessage uses Elliptic Curve Cryptography for both signing and encryption. While the mathematics behind elliptic curves is even harder to understand than the older approach of multiplying huge primes, it's based on the same principle of doing some mathematical operation that can be done fast one way but is very hard to reverse. Instead of two very large primes, we multiply a point on the elliptic curve by a very large number.\footnote{Please don't ask me how to do it. If you really want to know, start at \url{http://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication} and \url{http://en.wikipedia.org/wiki/Elliptic_curve_cryptography}. If you want to make something that works, use a library like Bouncy Casle that does the heavy lifting for you.}
The user, let's call her Alice, needs a key pair, consisting of a private key
$$k$$
which represents a huge random number, and a public key
$$K = G k$$
which represents a point on the agreed on curve.\footnote{Bitmessage uses a curve called \textit{secp256k1}.} Please note that this is not a simple multiplication, but the multiplication of a point along an elliptic curve. $G$ is the starting point for all operations on a specific curve.
Another user, Bob, knows the public key. To encrypt a message, Bob creates a temporary key pair
$$r$$
and
$$R = G r$$
He then calculates
$$K r$$
uses the resulting Point to encrypt the message\footnote{A double SHA-512 hash over the x-coordinate is used to create the actual key.} and sends $K$ along with the message.
When Alice receives the message, she uses the fact that
$$K r = G k r = G r k = R k$$
so she just uses $R k$ to decrypt the message.
The exact method used in Bitmessage is called Elliptic Curve Integrated Encryption Scheme or ECIES, which is described in detail on Wikipedia (\url{http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme}).
\subsubsection{Signature}
To sign objects, Bitmessage uses Elliptic Curve Digital Signature Algorithm or ECDSA. This is slightly more complicated, if you want the details, Wikipedia is once again a fine starting point: \url{http://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm}.
A detail that's interesting for people who want to implement a Bitmessage client, particularly if they do it using some object oriented approach: the signature covers everything from the object header sans nonce, and everything from the object payload except for the signature itself. Of course, not all objects are signed.\footnote{My approach was: think first, do it wrong, then refactor a lot.}
\newpage
\section{Issues}
\subsection{Scalability}
Bitmessage doen't scale.\footnote{Yet.} If there are very few users, anonymity isn't given anymore. With just a handful users, it's easy (for, let's say the NSA) to analyse traffic between nodes to find out who they might be writing to. Or let's just put them all under surveilance.
With many users, traffic and storage use grows quadratically. This, because with more users there are more people who write messages as well as more users to write to for existing users.
\subsubsection{Proof of Work}
Proof of work has two uses. It helps to protect the network by preventing single nodes from flooding it with objects, and to protect users from spam. There's minimal proof of work required for the network to distribute objects, but users can define higher requirements for their addresses if they get spammed with cheap Viagra\texttrademark{} offers. The proof of work required for an address is defined in the \obj{pubkey}, and senders that are in a user's contacts should not be required to do the higher proof of work.
The difficulty is calculated from both message size as well as time to live, meaning that a message that is larger or stored longer in the network will be more expensive to send.
$$ d = \frac{2^{64}}{n (l + \frac{t l}{2^{16}})} $$
\begin{tabular}{@{}>{$}l<{$}l@{}}
d & target difficulty \\
n & required trials per byte \\
l & payload length + extra bytes (in order to not make it too easy to send a lot of tiny messages) \\
t & time to live \\
\end{tabular}
To do the proof of work, a nonce must be found such that the first eight bytes of the hash of the object (including the nonce) represent a lower number than the target difficulty.
\subsubsection{Message Size Limitation}
To prevent malicious users from clogging individual nodes, messages must not be larger than 256 KiB. Because of the proof of work, large objects arent' practical for normal use, but might be used to occupy nodes by sending them garbage.
\subsubsection{Streams}
The intended solution for this problem is splitting traffic -- addresses, more precisely -- into streams. A node listens only on the streams that concern its addresses. If it wants to send an object to another stream, it just connects to a node in this stream to send the object, then disconnects. When all active streams are full, a new one is created which should be used for new addresses.
The unsolved problem is to determine when a stream is full. Another issue is the fact that, as the overall network grows, traffic on full streams still grows, as there are more users who might wanto to write someone on the full stream.
\subsubsection{Prefix Filtering}
Jonathan Coe proposed this interesting way of handling traffic. This would need an update to the protocol, but allows for much finer grained control of how much traffic a node wants to handle.\cite{wiki:prefixfilter}
Instead of streams, we imagine an address as a leave of a binary tree of height 65. The position is defined by the first 64 bits of the address' ripe. A prefix value $n$ defines the node at wich we start to listen. A client sending a message sets a 64 bit nonce where the first $n$ bits are copied from the recipient's ripe, and the rest is set randomly.
\begin{figure}[htp]
\centering
\includegraphics[width=\textwidth]{images/prefix-filter-binary-tree.pdf}
\caption[prefix filter: binary tree]{Note that the prefix value goes up to 64, i.e. each yellow triangle is itself a subtree of height 61.}
\label{fig:bintree}
\end{figure}
Now let's assume Bob's address' ripe starts with \texttt{00101001\ldots} and his prefix value is 3. Alice sends a message tagged with \texttt{00110100\ldots}. The first three bits must be the same, but the rest is random. Bob's client now gets only objects that match his prefix, meaning he must only handle \sfrac{1}{8} of the overall traffic.\footnote{At the moment, the overall traffic is around 1 GiB per month.}
As Bitmessage might get more popular, it would produce more and more traffic. Bob therefore might want to raise his prefix value to 4, further reducing the traffic he handles to \sfrac{1}{16} of the overall traffic. To do this, he simply publishes his \obj{pubkey} with the updated prefix value. This means of course that either must there always be a pubkey published, or Alice needs to be online at least once while the pubkey is published. Otherwise there's a 50\% chance (in our scenario) that the message won't reach Bob.
While this would allow for a mobile client to only process messages meant for its addresses,\footnote{Choosing a prefix value of 64 would most certainly mean that it's alone on this stream.} this would mean to give up anonymity almost completely.
TODO
.
.
.
.
.
.
\subsection{Forward Secrecy}
Obviously it's trivial for an attacker to collect all (encrypted) objects distributed through the Bitmessage network -- as long as disk space is not an issue. If this attacker can somehow get the private key of a user, they can decrypt all stored messages intended for that user, as well as impersonate said user.\footnote{The latter might be more difficult if they got the key through a brute force attack.}
Plausible deniability can, in some scenarios, help against this. This action, called "nuking an address", is done by anonymously publishing the private keys somewhere publicly accessible.\footnote{See \url{https://bitmessage.ch/nuked/} for an example.}
Perfect forward secrecy seems impractical to implement, as it requires to exchange messages prior to sending encrypted content. That would in turn need proof of work to protect the network, resulting in twice the work for the sender and three times longer to send --- that is, if both clients are online. Exchanging messages would be all but impossible if both users are online sporadically.
\newpage
\section{Discussion}
Anonymity has its price. With Bitmessage it's traffic and disk space, with E-Mail it's trust. If we can't trust our e-mail providers (who can?), Bitmessage is a very interesting alternative, albeit not fully matured.
I find the idea of trustless protocols, and peer to peer networks that typically leverage them, intriguing. In the beginning, the internet was a huge network of equal participants, but nowadays it all seems to end up at google or facebook. P2P and trustless protocols give us back some of that freedom that got lost in the cloud.
That there is now a p2p e-mail replacement I think is absolutely amazing.
Yes, it doen't scale as well as e-mail. But as I don't think we'll have the spamming problem with Bitmessage, thanks to Proof of Work, it might not have to.
TODO
.
.
.
.
.
.
\bibliographystyle{plain}
\bibliography{bibliography}
\appendix
\addcontentsline{toc}{section}{Appendix}
\section*{Appendix}
\renewcommand{\thesubsection}{\Alph{subsection}}
\subsection{TODO}
\end{document}

Binary file not shown.

View File

@ -1,44 +0,0 @@
\documentclass{bfh}
\title{Bachelor Thesis}
\subtitle{Android Client for Bitmessage}
\author{Christian Basler}
\tutor{Kai Brünnler}
\date{\today}
\begin{document}
\maketitle
\tableofcontents
\newpage
\section{Project Setup}
\subsection{Current state -- why is it bad?}
Until recently there was not mobile client for the Bitmessage protocol, and the client that turned up since is very wasteful to the devices resources, draining the battery in no time.
\subsection{How should it be?}
We need mobile Bitmessage clients that allows the user to choose the levels of convenience, privacy and resource hunger.
\subsection{Why is it hard to do?}
Bitmessage is very wasteful with resources by design. All messages are being sent to and stored on all nodes, and to protect the network a proof of work (POW) is required for all objects that are distributed.
\subsection{How do I intend to do it?}
As I developed Jabit, a Java implementation of the Bitmessage client, as my last project, I have great knowledge about the Bitmessage protocol. There are a few optimisations that I intend to do;
\begin{itemize}
\item Connect to only one reliable node instead of eight random nodes
\item Don't save objects we can't decrypt
\item Only connect to the network if we're on Wi-Fi and charging
\end{itemize}
Of course every option has its own drawbacks, so they will be configurable. As for the POW: Jabit highly optimises its calculation, which might be enough for modern smartphones.
Further optimisations might introduce a server component that might do
\begin{itemize}
\item POW
\item Request public keys, requiring us to give up some anonymity towards the server.
\item Inform the client about new messages sent to its addresses. This would mean to give up our anonymity towards the server in the best case (which isn't supported by the protocol yet), towards the whole network (which is somewhat supported), or give up the private key to the server (which is just a big NOPE).
\end{itemize}
\end{document}

View File

@ -1,3 +1,15 @@
uploadArchives {
repositories {
mavenDeployer {
pom.project {
name 'Jabit Domain'
artifactId = 'jabit-domain'
description 'A Java implementation of the Bitmessage protocol. This is the core part. You\'ll either need the networking and repositories modules, too, or implement your own.'
}
}
}
}
dependencies { dependencies {
compile 'org.slf4j:slf4j-api:1.7.12' compile 'org.slf4j:slf4j-api:1.7.12'
compile 'org.bouncycastle:bcprov-jdk15on:1.52' compile 'org.bouncycastle:bcprov-jdk15on:1.52'

View File

@ -32,10 +32,7 @@ import ch.dissem.bitmessage.utils.UnixTime;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.TreeSet;
import static ch.dissem.bitmessage.entity.Plaintext.Status.*; import static ch.dissem.bitmessage.entity.Plaintext.Status.*;
import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
@ -43,8 +40,7 @@ import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
import static ch.dissem.bitmessage.utils.UnixTime.DAY; import static ch.dissem.bitmessage.utils.UnixTime.DAY;
/** /**
* Use this class if you want to create a Bitmessage client. * <p>Use this class if you want to create a Bitmessage client.</p>
* <p>
* You'll need the Builder to create a BitmessageContext, and set the following properties: * You'll need the Builder to create a BitmessageContext, and set the following properties:
* <ul> * <ul>
* <li>addressRepo</li> * <li>addressRepo</li>
@ -54,9 +50,8 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
* <li>messageRepo</li> * <li>messageRepo</li>
* <li>streams</li> * <li>streams</li>
* </ul> * </ul>
* The default implementations in the different module builds can be used. * <p>The default implementations in the different module builds can be used.</p>
* <p> * <p>The port defaults to 8444 (the default Bitmessage port)</p>
* The port defaults to 8444 (the default Bitmessage port)
*/ */
public class BitmessageContext { public class BitmessageContext {
public static final int CURRENT_VERSION = 3; public static final int CURRENT_VERSION = 3;
@ -167,7 +162,6 @@ public class BitmessageContext {
} }
private void send(long stream, ObjectPayload payload, long timeToLive) { private void send(long stream, ObjectPayload payload, long timeToLive) {
try {
long expires = UnixTime.now(+timeToLive); long expires = UnixTime.now(+timeToLive);
LOG.info("Expires at " + expires); LOG.info("Expires at " + expires);
ObjectMessage object = new ObjectMessage.Builder() ObjectMessage object = new ObjectMessage.Builder()
@ -179,9 +173,6 @@ public class BitmessageContext {
ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes());
ctx.getInventory().storeObject(object); ctx.getInventory().storeObject(object);
ctx.getNetworkHandler().offer(object.getInventoryVector()); ctx.getNetworkHandler().offer(object.getInventoryVector());
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
public void startup(Listener listener) { public void startup(Listener listener) {
@ -267,7 +258,6 @@ public class BitmessageContext {
AddressRepository addressRepo; AddressRepository addressRepo;
MessageRepository messageRepo; MessageRepository messageRepo;
ProofOfWorkEngine proofOfWorkEngine; ProofOfWorkEngine proofOfWorkEngine;
TreeSet<Long> streams;
public Builder() { public Builder() {
} }
@ -307,28 +297,12 @@ public class BitmessageContext {
return this; return this;
} }
public Builder streams(Collection<Long> streams) {
this.streams = new TreeSet<>(streams);
return this;
}
public Builder streams(long... streams) {
this.streams = new TreeSet<>();
for (long stream : streams) {
this.streams.add(stream);
}
return this;
}
public BitmessageContext build() { public BitmessageContext build() {
nonNull("inventory", inventory); nonNull("inventory", inventory);
nonNull("nodeRegistry", nodeRegistry); nonNull("nodeRegistry", nodeRegistry);
nonNull("networkHandler", networkHandler); nonNull("networkHandler", networkHandler);
nonNull("addressRepo", addressRepo); nonNull("addressRepo", addressRepo);
nonNull("messageRepo", messageRepo); nonNull("messageRepo", messageRepo);
if (streams == null) {
streams(1);
}
if (proofOfWorkEngine == null) { if (proofOfWorkEngine == null) {
proofOfWorkEngine = new MultiThreadedPOWEngine(); proofOfWorkEngine = new MultiThreadedPOWEngine();
} }

View File

@ -91,6 +91,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
if (address != null) { if (address != null) {
address.setPubkey(pubkey); address.setPubkey(pubkey);
LOG.debug("Got pubkey for contact " + address); LOG.debug("Got pubkey for contact " + address);
ctx.getAddressRepo().save(address);
List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address); List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address);
LOG.debug("Sending " + messages.size() + " messages for contact " + address); LOG.debug("Sending " + messages.size() + " messages for contact " + address);
for (Plaintext msg : messages) { for (Plaintext msg : messages) {
@ -107,7 +108,6 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
msg.setStatus(SENT); msg.setStatus(SENT);
ctx.getMessageRepository().save(msg); ctx.getMessageRepository().save(msg);
} }
ctx.getAddressRepo().save(address);
} }
} catch (DecryptionFailedException ignore) { } catch (DecryptionFailedException ignore) {
} }

View File

@ -49,7 +49,7 @@ public class InternalContext {
private final MessageRepository messageRepository; private final MessageRepository messageRepository;
private final ProofOfWorkEngine proofOfWorkEngine; private final ProofOfWorkEngine proofOfWorkEngine;
private final TreeSet<Long> streams; private final TreeSet<Long> streams = new TreeSet<>();
private final int port; private final int port;
private long networkNonceTrialsPerByte = 1000; private long networkNonceTrialsPerByte = 1000;
private long networkExtraBytes = 1000; private long networkExtraBytes = 1000;
@ -65,7 +65,7 @@ public class InternalContext {
this.clientNonce = Security.randomNonce(); this.clientNonce = Security.randomNonce();
port = builder.port; port = builder.port;
streams = builder.streams; streams.add(1L); // FIXME
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine); init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine);
} }
@ -199,7 +199,6 @@ public class InternalContext {
} }
public void requestPubkey(BitmessageAddress contact) { public void requestPubkey(BitmessageAddress contact) {
try {
long expires = UnixTime.now(+2 * DAY); long expires = UnixTime.now(+2 * DAY);
LOG.info("Expires at " + expires); LOG.info("Expires at " + expires);
ObjectMessage response = new ObjectMessage.Builder() ObjectMessage response = new ObjectMessage.Builder()
@ -210,9 +209,6 @@ public class InternalContext {
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes); Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
inventory.storeObject(response); inventory.storeObject(response);
networkHandler.offer(response.getInventoryVector()); networkHandler.offer(response.getInventoryVector());
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
public long getClientNonce() { public long getClientNonce() {

View File

@ -88,7 +88,7 @@ public class ObjectMessage implements MessagePayload {
return stream; return stream;
} }
public InventoryVector getInventoryVector() throws IOException { public InventoryVector getInventoryVector() {
return new InventoryVector(Bytes.truncate(Security.doubleSha512(nonce, getPayloadBytesWithoutNonce()), 32)); return new InventoryVector(Bytes.truncate(Security.doubleSha512(nonce, getPayloadBytesWithoutNonce()), 32));
} }
@ -163,7 +163,8 @@ public class ObjectMessage implements MessagePayload {
Encode.varInt(stream, out); Encode.varInt(stream, out);
} }
public byte[] getPayloadBytesWithoutNonce() throws IOException { public byte[] getPayloadBytesWithoutNonce() {
try {
if (payloadBytes == null) { if (payloadBytes == null) {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
writeHeaderWithoutNonce(out); writeHeaderWithoutNonce(out);
@ -171,6 +172,9 @@ public class ObjectMessage implements MessagePayload {
payloadBytes = out.toByteArray(); payloadBytes = out.toByteArray();
} }
return payloadBytes; return payloadBytes;
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
public static final class Builder { public static final class Builder {

View File

@ -17,6 +17,7 @@
package ch.dissem.bitmessage.entity.payload; package ch.dissem.bitmessage.entity.payload;
import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.Streamable;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.utils.*; import ch.dissem.bitmessage.utils.*;
import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher;
@ -37,6 +38,8 @@ import java.io.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import static ch.dissem.bitmessage.entity.valueobject.PrivateKey.PRIVATE_KEY_SIZE;
public class CryptoBox implements Streamable { public class CryptoBox implements Streamable {
private static final Logger LOG = LoggerFactory.getLogger(CryptoBox.class); private static final Logger LOG = LoggerFactory.getLogger(CryptoBox.class);
@ -59,7 +62,7 @@ public class CryptoBox implements Streamable {
initializationVector = Security.randomBytes(16); initializationVector = Security.randomBytes(16);
// 3. Generate a new random EC key pair with private key called r and public key called R. // 3. Generate a new random EC key pair with private key called r and public key called R.
byte[] r = Security.randomBytes(64); byte[] r = Security.randomBytes(PRIVATE_KEY_SIZE);
R = Security.createPublicKey(r); R = Security.createPublicKey(r);
// 4. Do an EC point multiply with public key K and private key r. This gives you public key P. // 4. Do an EC point multiply with public key K and private key r. This gives you public key P.
ECPoint P = K.multiply(Security.keyToBigInt(r)).normalize(); ECPoint P = K.multiply(Security.keyToBigInt(r)).normalize();

View File

@ -32,8 +32,9 @@ import java.io.*;
* Created by chris on 18.04.15. * Created by chris on 18.04.15.
*/ */
public class PrivateKey implements Streamable { public class PrivateKey implements Streamable {
private final byte[] privateSigningKey; // 32 bytes public static final int PRIVATE_KEY_SIZE = 32;
private final byte[] privateEncryptionKey; // 32 bytes private final byte[] privateSigningKey;
private final byte[] privateEncryptionKey;
private final Pubkey pubkey; private final Pubkey pubkey;
@ -44,8 +45,8 @@ public class PrivateKey implements Streamable {
byte[] pubEK; byte[] pubEK;
byte[] ripe; byte[] ripe;
do { do {
privSK = Security.randomBytes(64); privSK = Security.randomBytes(PRIVATE_KEY_SIZE);
privEK = Security.randomBytes(64); privEK = Security.randomBytes(PRIVATE_KEY_SIZE);
pubSK = Security.createPublicKey(privSK).getEncoded(false); pubSK = Security.createPublicKey(privSK).getEncoded(false);
pubEK = Security.createPublicKey(privEK).getEncoded(false); pubEK = Security.createPublicKey(privEK).getEncoded(false);
ripe = Pubkey.getRipe(pubSK, pubEK); ripe = Pubkey.getRipe(pubSK, pubEK);

View File

@ -23,6 +23,7 @@ import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.exception.NodeException; import ch.dissem.bitmessage.exception.NodeException;
import ch.dissem.bitmessage.utils.Security;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -107,6 +108,24 @@ public class Factory {
} }
} }
public static BitmessageAddress createIdentityFromPrivateKey(String address,
byte[] privateSigningKey, byte[] privateEncryptionKey,
long nonceTrialsPerByte, long extraBytes,
int behaviourBitfield) {
BitmessageAddress temp = new BitmessageAddress(address);
PrivateKey privateKey = new PrivateKey(privateSigningKey, privateEncryptionKey,
createPubkey(temp.getVersion(), temp.getStream(),
Security.createPublicKey(privateSigningKey).getEncoded(false),
Security.createPublicKey(privateEncryptionKey).getEncoded(false),
nonceTrialsPerByte, extraBytes, behaviourBitfield));
BitmessageAddress result = new BitmessageAddress(privateKey);
if (!result.getAddress().equals(address)) {
throw new IllegalArgumentException("Address not matching private key. Address: " + address
+ "; Address derived from private key: " + result.getAddress());
}
return result;
}
public static BitmessageAddress generatePrivateAddress(boolean shorter, long stream, Pubkey.Feature... features) { public static BitmessageAddress generatePrivateAddress(boolean shorter, long stream, Pubkey.Feature... features) {
return new BitmessageAddress(new PrivateKey(shorter, stream, 1000, 1000, features)); return new BitmessageAddress(new PrivateKey(shorter, stream, 1000, 1000, features));
} }

View File

@ -16,14 +16,11 @@
package ch.dissem.bitmessage.ports; package ch.dissem.bitmessage.ports;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.utils.Property; import ch.dissem.bitmessage.utils.Property;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
/** /**
* Handles incoming messages * Handles incoming messages

View File

@ -57,4 +57,15 @@ public class Collections {
} }
return result; return result;
} }
public static <T> T selectRandom(Collection<T> collection) {
int index = RANDOM.nextInt(collection.size());
for (T item : collection) {
if (index == 0) {
return item;
}
index--;
}
throw new IllegalArgumentException("Empty collection? Size: " + collection.size());
}
} }

View File

@ -20,10 +20,14 @@ package ch.dissem.bitmessage.utils;
* A simple utility class that simplifies using the second based time used in Bitmessage. * A simple utility class that simplifies using the second based time used in Bitmessage.
*/ */
public class UnixTime { public class UnixTime {
/**
* Length of a minute in seconds, intended for use with {@link #now(long)}.
*/
public static final int MINUTE = 60;
/** /**
* Length of an hour in seconds, intended for use with {@link #now(long)}. * Length of an hour in seconds, intended for use with {@link #now(long)}.
*/ */
public static final long HOUR = 60 * 60; public static final long HOUR = 60 * MINUTE;
/** /**
* Length of a day in seconds, intended for use with {@link #now(long)}. * Length of a day in seconds, intended for use with {@link #now(long)}.
*/ */

View File

@ -39,7 +39,7 @@ public class ProofOfWorkEngineTest {
private void testPOW(ProofOfWorkEngine engine) { private void testPOW(ProofOfWorkEngine engine) {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
byte[] initialHash = Security.sha512(new byte[]{1, 3, 6, 4}); byte[] initialHash = Security.sha512(new byte[]{1, 3, 6, 4});
byte[] target = {0, 0, 0, -1, -1, -1, -1, -1}; byte[] target = {0, 0, -1, -1, -1, -1, -1, -1};
byte[] nonce = engine.calculateNonce(initialHash, target); byte[] nonce = engine.calculateNonce(initialHash, target);
System.out.println("Calculating nonce took " + (System.currentTimeMillis() - time) + "ms"); System.out.println("Calculating nonce took " + (System.currentTimeMillis() - time) + "ms");

View File

@ -1,3 +1,15 @@
uploadArchives {
repositories {
mavenDeployer {
pom.project {
name 'Jabit Networking'
artifactId = 'jabit-networking'
description 'A Java implementation of the Bitmessage protocol. This is the networking part.'
}
}
}
}
dependencies { dependencies {
compile project(':domain') compile project(':domain')
testCompile 'org.slf4j:slf4j-simple:1.7.12' testCompile 'org.slf4j:slf4j-simple:1.7.12'

View File

@ -37,57 +37,60 @@ import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.util.Arrays; import java.util.*;
import java.util.List; import java.util.concurrent.ConcurrentHashMap;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentMap;
import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT;
import static ch.dissem.bitmessage.networking.Connection.State.*; import static ch.dissem.bitmessage.networking.Connection.State.*;
import static ch.dissem.bitmessage.utils.UnixTime.MINUTE;
/** /**
* A connection to a specific node * A connection to a specific node
*/ */
public class Connection implements Runnable { public class Connection implements Runnable {
public static final int READ_TIMEOUT = 2000;
private final static Logger LOG = LoggerFactory.getLogger(Connection.class); private final static Logger LOG = LoggerFactory.getLogger(Connection.class);
private static final int CONNECT_TIMEOUT = 10000; private static final int CONNECT_TIMEOUT = 5000;
private final ConcurrentMap<InventoryVector, Long> ivCache;
private InternalContext ctx; private InternalContext ctx;
private Mode mode; private Mode mode;
private State state; private State state;
private Socket socket; private Socket socket;
private InputStream in; private InputStream in;
private OutputStream out; private OutputStream out;
private MessageListener listener; private MessageListener listener;
private int version; private int version;
private long[] streams; private long[] streams;
private NetworkAddress host; private NetworkAddress host;
private NetworkAddress node; private NetworkAddress node;
private Queue<MessagePayload> sendingQueue = new ConcurrentLinkedDeque<>(); private Queue<MessagePayload> sendingQueue = new ConcurrentLinkedDeque<>();
private ConcurrentMap<InventoryVector, Long> requestedObjects;
public Connection(InternalContext context, Mode mode, Socket socket, MessageListener listener) throws IOException { public Connection(InternalContext context, Mode mode, Socket socket, MessageListener listener,
this.ctx = context; ConcurrentMap<InventoryVector, Long> requestedObjectsMap) throws IOException {
this.mode = mode; this(context, mode, listener, requestedObjectsMap);
this.state = CONNECTING;
this.socket = socket; this.socket = socket;
this.listener = listener;
this.host = new NetworkAddress.Builder().ipv6(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).port(0).build();
this.node = new NetworkAddress.Builder().ip(socket.getInetAddress()).port(socket.getPort()).stream(1).build(); this.node = new NetworkAddress.Builder().ip(socket.getInetAddress()).port(socket.getPort()).stream(1).build();
} }
public Connection(InternalContext context, Mode mode, NetworkAddress node, MessageListener listener) { public Connection(InternalContext context, Mode mode, NetworkAddress node, MessageListener listener,
ConcurrentMap<InventoryVector, Long> requestedObjectsMap) {
this(context, mode, listener, requestedObjectsMap);
this.socket = new Socket();
this.node = node;
}
private Connection(InternalContext context, Mode mode, MessageListener listener,
ConcurrentMap<InventoryVector, Long> requestedObjectsMap) {
this.ctx = context; this.ctx = context;
this.mode = mode; this.mode = mode;
this.state = CONNECTING; this.state = CONNECTING;
this.socket = new Socket();
this.node = node;
this.listener = listener; this.listener = listener;
this.requestedObjects = requestedObjectsMap;
this.host = new NetworkAddress.Builder().ipv6(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).port(0).build(); this.host = new NetworkAddress.Builder().ipv6(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).port(0).build();
ivCache = new ConcurrentHashMap<>();
} }
public Mode getMode() { public Mode getMode() {
@ -106,8 +109,10 @@ public class Connection implements Runnable {
public void run() { public void run() {
try (Socket socket = this.socket) { try (Socket socket = this.socket) {
if (!socket.isConnected()) { if (!socket.isConnected()) {
LOG.debug("Trying to connect to node " + node);
socket.connect(new InetSocketAddress(node.toInetAddress(), node.getPort()), CONNECT_TIMEOUT); socket.connect(new InetSocketAddress(node.toInetAddress(), node.getPort()), CONNECT_TIMEOUT);
} }
socket.setSoTimeout(READ_TIMEOUT);
this.in = socket.getInputStream(); this.in = socket.getInputStream();
this.out = socket.getOutputStream(); this.out = socket.getOutputStream();
if (mode == CLIENT) { if (mode == CLIENT) {
@ -171,8 +176,8 @@ public class Connection implements Runnable {
} }
} }
} catch (IOException | NodeException e) { } catch (IOException | NodeException e) {
LOG.debug("disconnection from node " + node + ": " + e.getMessage(), e);
disconnect(); disconnect();
LOG.debug("Disconnected from node " + node + ": " + e.getMessage());
} catch (RuntimeException e) { } catch (RuntimeException e) {
disconnect(); disconnect();
throw e; throw e;
@ -180,6 +185,7 @@ public class Connection implements Runnable {
} }
private void activateConnection() { private void activateConnection() {
LOG.info("Successfully established connection with node " + node);
state = ACTIVE; state = ACTIVE;
sendAddresses(); sendAddresses();
sendInventory(); sendInventory();
@ -188,19 +194,74 @@ public class Connection implements Runnable {
} }
private void sendQueue() { private void sendQueue() {
if (sendingQueue.size() > 0) {
LOG.debug("Sending " + sendingQueue.size() + " messages to node " + node); LOG.debug("Sending " + sendingQueue.size() + " messages to node " + node);
}
for (MessagePayload msg = sendingQueue.poll(); msg != null; msg = sendingQueue.poll()) { for (MessagePayload msg = sendingQueue.poll(); msg != null; msg = sendingQueue.poll()) {
send(msg); send(msg);
} }
} }
private void cleanupIvCache() {
Long fiveMinutesAgo = UnixTime.now(-5 * MINUTE);
for (Map.Entry<InventoryVector, Long> entry : ivCache.entrySet()) {
if (entry.getValue() < fiveMinutesAgo) {
ivCache.remove(entry.getKey());
}
}
}
private void updateIvCache(InventoryVector... inventory) {
cleanupIvCache();
Long now = UnixTime.now();
for (InventoryVector iv : inventory) {
ivCache.put(iv, now);
}
}
private void updateIvCache(List<InventoryVector> inventory) {
cleanupIvCache();
Long now = UnixTime.now();
for (InventoryVector iv : inventory) {
ivCache.put(iv, now);
}
}
private void updateRequestedObjects(List<InventoryVector> missing) {
Long now = UnixTime.now();
Long fiveMinutesAgo = now - 5 * MINUTE;
Long tenMinutesAgo = now - 10 * MINUTE;
List<InventoryVector> stillMissing = new LinkedList<>();
for (Map.Entry<InventoryVector, Long> entry : requestedObjects.entrySet()) {
if (entry.getValue() < fiveMinutesAgo) {
stillMissing.add(entry.getKey());
// If it's still not available after 10 minutes, we won't look for it
// any longer (except it's announced again)
if (entry.getValue() < tenMinutesAgo) {
requestedObjects.remove(entry.getKey());
}
}
}
for (InventoryVector iv : missing) {
requestedObjects.put(iv, now);
}
if (!stillMissing.isEmpty()) {
LOG.debug(stillMissing.size() + " items are still missing.");
missing.addAll(stillMissing);
}
}
private void receiveMessage(MessagePayload messagePayload) { private void receiveMessage(MessagePayload messagePayload) {
switch (messagePayload.getCommand()) { switch (messagePayload.getCommand()) {
case INV: case INV:
Inv inv = (Inv) messagePayload; Inv inv = (Inv) messagePayload;
updateIvCache(inv.getInventory());
List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams); List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams);
missing.removeAll(requestedObjects.keySet());
LOG.debug("Received inventory with " + inv.getInventory().size() + " elements, of which are " LOG.debug("Received inventory with " + inv.getInventory().size() + " elements, of which are "
+ missing.size() + " missing."); + missing.size() + " missing.");
updateRequestedObjects(missing);
send(new GetData.Builder().inventory(missing).build()); send(new GetData.Builder().inventory(missing).build());
break; break;
case GETDATA: case GETDATA:
@ -226,6 +287,8 @@ public class Connection implements Runnable {
} catch (IOException e) { } catch (IOException e) {
LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e); LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e);
DebugUtils.saveToFile(objectMessage); DebugUtils.saveToFile(objectMessage);
} finally {
requestedObjects.remove(objectMessage.getInventoryVector());
} }
break; break;
case ADDR: case ADDR:
@ -271,6 +334,11 @@ public class Connection implements Runnable {
sendingQueue.offer(new Inv.Builder() sendingQueue.offer(new Inv.Builder()
.addInventoryVector(iv) .addInventoryVector(iv)
.build()); .build());
updateIvCache(iv);
}
public boolean knowsOf(InventoryVector iv) {
return ivCache.containsKey(iv);
} }
@Override @Override
@ -286,6 +354,13 @@ public class Connection implements Runnable {
return Objects.hash(node); return Objects.hash(node);
} }
public void request(InventoryVector key) {
sendingQueue.offer(new GetData.Builder()
.addInventoryVector(key)
.build()
);
}
public enum Mode {SERVER, CLIENT} public enum Mode {SERVER, CLIENT}
public enum State {CONNECTING, ACTIVE, DISCONNECTED} public enum State {CONNECTING, ACTIVE, DISCONNECTED}

View File

@ -30,6 +30,8 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -43,13 +45,17 @@ import static ch.dissem.bitmessage.utils.DebugUtils.inc;
* Handles all the networky stuff. * Handles all the networky stuff.
*/ */
public class NetworkNode implements NetworkHandler, ContextHolder { public class NetworkNode implements NetworkHandler, ContextHolder {
public final static int NETWORK_MAGIC_NUMBER = 8;
private final static Logger LOG = LoggerFactory.getLogger(NetworkNode.class); private final static Logger LOG = LoggerFactory.getLogger(NetworkNode.class);
private final ExecutorService pool; private final ExecutorService pool;
private final List<Connection> connections = new LinkedList<>(); private final List<Connection> connections = new LinkedList<>();
private InternalContext ctx; private InternalContext ctx;
private ServerSocket serverSocket; private ServerSocket serverSocket;
private Thread serverThread;
private Thread connectionManager; private Thread connectionManager;
private ConcurrentMap<InventoryVector, Long> requestedObjects = new ConcurrentHashMap<>();
public NetworkNode() { public NetworkNode() {
pool = Executors.newCachedThreadPool(); pool = Executors.newCachedThreadPool();
} }
@ -66,18 +72,21 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
} }
try { try {
serverSocket = new ServerSocket(ctx.getPort()); serverSocket = new ServerSocket(ctx.getPort());
pool.execute(new Runnable() { serverThread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
while (!serverSocket.isClosed()) {
try { try {
Socket socket = serverSocket.accept(); Socket socket = serverSocket.accept();
socket.setSoTimeout(10000); socket.setSoTimeout(Connection.READ_TIMEOUT);
startConnection(new Connection(ctx, SERVER, socket, listener)); startConnection(new Connection(ctx, SERVER, socket, listener, requestedObjects));
} catch (IOException e) { } catch (IOException e) {
LOG.debug(e.getMessage(), e); LOG.debug(e.getMessage(), e);
} }
} }
}); }
}, "server");
serverThread.start();
connectionManager = new Thread(new Runnable() { connectionManager = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -96,10 +105,11 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
} }
} }
} }
if (active < 8) { if (active < NETWORK_MAGIC_NUMBER) {
List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses(8 - active, ctx.getStreams()); List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses(
NETWORK_MAGIC_NUMBER - active, ctx.getStreams());
for (NetworkAddress address : addresses) { for (NetworkAddress address : addresses) {
startConnection(new Connection(ctx, CLIENT, address, listener)); startConnection(new Connection(ctx, CLIENT, address, listener, requestedObjects));
} }
} }
Thread.sleep(30000); Thread.sleep(30000);
@ -126,12 +136,12 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
} catch (IOException e) { } catch (IOException e) {
LOG.debug(e.getMessage(), e); LOG.debug(e.getMessage(), e);
} }
pool.shutdown();
synchronized (connections) { synchronized (connections) {
for (Connection c : connections) { for (Connection c : connections) {
c.disconnect(); c.disconnect();
} }
} }
pool.shutdownNow();
} }
private void startConnection(Connection c) { private void startConnection(Connection c) {
@ -147,17 +157,17 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
@Override @Override
public void offer(final InventoryVector iv) { public void offer(final InventoryVector iv) {
List<Connection> active = new LinkedList<>(); List<Connection> target = new LinkedList<>();
synchronized (connections) { synchronized (connections) {
for (Connection connection : connections) { for (Connection connection : connections) {
if (connection.getState() == ACTIVE) { if (connection.getState() == ACTIVE && !connection.knowsOf(iv)) {
active.add(connection); target.add(connection);
} }
} }
} }
LOG.debug(active.size() + " connections available to offer " + iv); LOG.debug(target.size() + " connections available to offer " + iv);
List<Connection> random8 = Collections.selectRandom(8, active); List<Connection> randomSubset = Collections.selectRandom(NETWORK_MAGIC_NUMBER, target);
for (Connection connection : random8) { for (Connection connection : randomSubset) {
connection.offer(iv); connection.offer(iv);
} }
} }

View File

@ -1,3 +1,15 @@
uploadArchives {
repositories {
mavenDeployer {
pom.project {
name 'Jabit Domain'
artifactId = 'jabit-repositories'
description 'A Java implementation of the Bitmessage protocol. This contains JDBC implementations of the repositories.'
}
}
}
}
dependencies { dependencies {
compile project(':domain') compile project(':domain')
compile 'com.h2database:h2:1.4.187' compile 'com.h2database:h2:1.4.187'

View File

@ -45,11 +45,7 @@ public class JdbcConfig {
this("jdbc:h2:~/jabit;AUTO_SERVER=TRUE", "sa", null); this("jdbc:h2:~/jabit;AUTO_SERVER=TRUE", "sa", null);
} }
public Connection getConnection() { public Connection getConnection() throws SQLException {
try {
return DriverManager.getConnection(dbUrl, dbUser, dbPassword); return DriverManager.getConnection(dbUrl, dbUser, dbPassword);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} }
} }

View File

@ -131,7 +131,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
ps.setLong(6, object.getVersion()); ps.setLong(6, object.getVersion());
ps.executeUpdate(); ps.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
LOG.error("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e); LOG.debug("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e);
} catch (Exception e) { } catch (Exception e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
} }

View File

@ -1,144 +0,0 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.repository;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.ports.NodeRegistry;
import ch.dissem.bitmessage.utils.UnixTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import static ch.dissem.bitmessage.utils.UnixTime.HOUR;
public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
private static final Logger LOG = LoggerFactory.getLogger(JdbcNodeRegistry.class);
public JdbcNodeRegistry(JdbcConfig config) {
super(config);
}
@Override
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
List<NetworkAddress> result = doGetKnownNodes(limit, streams);
if (result.isEmpty()) {
try (InputStream in = getClass().getClassLoader().getResourceAsStream("nodes.txt")) {
Scanner scanner = new Scanner(in);
long stream = 1;
while (scanner.hasNext()) {
try {
String line = scanner.nextLine().trim();
if (line.startsWith("#") || line.isEmpty()) {
// Ignore
continue;
}
if (line.startsWith("[stream")) {
stream = Long.parseLong(line.substring(8, line.lastIndexOf(']')));
} else {
int portIndex = line.lastIndexOf(':');
InetAddress inetAddress = InetAddress.getByName(line.substring(0, portIndex));
int port = Integer.valueOf(line.substring(portIndex + 1));
result.add(new NetworkAddress.Builder().ip(inetAddress).port(port).stream(stream).build());
}
} catch (IOException e) {
LOG.warn(e.getMessage(), e);
}
}
offerAddresses(result);
return doGetKnownNodes(limit, streams);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
return result;
}
private List<NetworkAddress> doGetKnownNodes(int limit, long... streams) {
List<NetworkAddress> result = new LinkedList<>();
try (Connection connection = config.getConnection()) {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM Node WHERE stream IN (" + join(streams) + ") ORDER BY RANDOM() LIMIT " + limit);
while (rs.next()) {
result.add(new NetworkAddress.Builder()
.ipv6(rs.getBytes("ip"))
.port(rs.getInt("port"))
.services(rs.getLong("services"))
.stream(rs.getLong("stream"))
.time(rs.getLong("time"))
.build());
}
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
return result;
}
@Override
public void offerAddresses(List<NetworkAddress> addresses) {
try (Connection connection = config.getConnection()) {
PreparedStatement exists = connection.prepareStatement("SELECT time FROM Node WHERE ip = ? AND port = ? AND stream = ?");
PreparedStatement insert = connection.prepareStatement(
"INSERT INTO Node (ip, port, services, stream, time) VALUES (?, ?, ?, ?, ?)");
PreparedStatement update = connection.prepareStatement(
"UPDATE Node SET services = ?, time = ? WHERE ip = ? AND port = ? AND stream = ?");
connection.setAutoCommit(false);
for (NetworkAddress node : addresses) {
exists.setBytes(1, node.getIPv6());
exists.setInt(2, node.getPort());
exists.setLong(3, node.getStream());
ResultSet lastConnectionTime = exists.executeQuery();
if (lastConnectionTime.next()) {
long time = lastConnectionTime.getLong("time");
if (time < node.getTime() && node.getTime() <= UnixTime.now()) {
time = node.getTime();
update.setLong(1, node.getServices());
update.setLong(2, time);
update.setBytes(3, node.getIPv6());
update.setInt(4, node.getPort());
update.setLong(5, node.getStream());
update.executeUpdate();
}
} else if (node.getTime() <= UnixTime.now()) {
insert.setBytes(1, node.getIPv6());
insert.setInt(2, node.getPort());
insert.setLong(3, node.getServices());
insert.setLong(4, node.getStream());
insert.setLong(5, node.getTime());
insert.executeUpdate();
}
connection.commit();
}
if (addresses.size() > 100) {
// Let's clean up after we received an update from another node. This way, we shouldn't end up with an
// empty node registry.
PreparedStatement cleanup = connection.prepareStatement("DELETE FROM Node WHERE time < ?");
cleanup.setLong(1, UnixTime.now(-3 * HOUR));
cleanup.execute();
}
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.repository;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.ports.NodeRegistry;
import ch.dissem.bitmessage.utils.UnixTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static ch.dissem.bitmessage.utils.Collections.selectRandom;
import static ch.dissem.bitmessage.utils.UnixTime.HOUR;
import static java.util.Collections.newSetFromMap;
public class MemoryNodeRegistry implements NodeRegistry {
private static final Logger LOG = LoggerFactory.getLogger(MemoryNodeRegistry.class);
private final Map<Long, Set<NetworkAddress>> stableNodes = new HashMap<>();
private final Map<Long, Set<NetworkAddress>> knownNodes = new ConcurrentHashMap<>();
public MemoryNodeRegistry() {
try (InputStream in = getClass().getClassLoader().getResourceAsStream("nodes.txt")) {
Scanner scanner = new Scanner(in);
long stream = 0;
Set<NetworkAddress> streamSet = null;
while (scanner.hasNext()) {
try {
String line = scanner.nextLine().trim();
if (line.startsWith("#") || line.isEmpty()) {
// Ignore
continue;
}
if (line.startsWith("[stream")) {
stream = Long.parseLong(line.substring(8, line.lastIndexOf(']')));
streamSet = new HashSet<>();
stableNodes.put(stream, streamSet);
} else if (streamSet != null) {
int portIndex = line.lastIndexOf(':');
InetAddress inetAddress = InetAddress.getByName(line.substring(0, portIndex));
int port = Integer.valueOf(line.substring(portIndex + 1));
streamSet.add(new NetworkAddress.Builder().ip(inetAddress).port(port).stream(stream).build());
}
} catch (IOException e) {
LOG.warn(e.getMessage(), e);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
List<NetworkAddress> result = new LinkedList<>();
for (long stream : streams) {
Set<NetworkAddress> known = knownNodes.get(stream);
if (known != null && !known.isEmpty()) {
for (NetworkAddress node : known) {
if (node.getTime() > UnixTime.now(-3 * HOUR)) {
result.add(node);
} else {
known.remove(node);
}
}
} else if (stableNodes.containsKey(stream)) {
// To reduce load on stable nodes, only return one
result.add(selectRandom(stableNodes.get(stream)));
}
}
return selectRandom(limit, result);
}
@Override
public void offerAddresses(List<NetworkAddress> addresses) {
for (NetworkAddress node : addresses) {
if (node.getTime() <= UnixTime.now()) {
if (!knownNodes.containsKey(node.getStream())) {
synchronized (knownNodes) {
if (!knownNodes.containsKey(node.getStream())) {
knownNodes.put(
node.getStream(),
newSetFromMap(new ConcurrentHashMap<NetworkAddress, Boolean>())
);
}
}
}
if (node.getTime() <= UnixTime.now()) {
// TODO: This isn't quite correct
// If the node is already known, the one with the more recent time should be used
knownNodes.get(node.getStream()).add(node);
}
}
}
}
}

View File

@ -1,9 +0,0 @@
CREATE TABLE Node (
ip BINARY(16) NOT NULL,
port INT NOT NULL,
stream BIGINT NOT NULL,
services BIGINT NOT NULL,
time BIGINT NOT NULL,
PRIMARY KEY (ip, port, stream)
);

View File

@ -34,7 +34,7 @@ CREATE TABLE Message_Label (
); );
INSERT INTO Label(label, type, color, ord) VALUES ('Inbox', 'INBOX', X'FF0000FF', 0); INSERT INTO Label(label, type, color, ord) VALUES ('Inbox', 'INBOX', X'FF0000FF', 0);
INSERT INTO Label(label, type, color, ord) VALUES ('Drafts', 'DRAFTS', X'FFFF9900', 10); INSERT INTO Label(label, type, color, ord) VALUES ('Drafts', 'DRAFT', X'FFFF9900', 10);
INSERT INTO Label(label, type, color, ord) VALUES ('Sent', 'SENT', X'FFFFFF00', 20); INSERT INTO Label(label, type, color, ord) VALUES ('Sent', 'SENT', X'FFFFFF00', 20);
INSERT INTO Label(label, type, ord) VALUES ('Unread', 'UNREAD', 90); INSERT INTO Label(label, type, ord) VALUES ('Unread', 'UNREAD', 90);
INSERT INTO Label(label, type, ord) VALUES ('Trash', 'TRASH', 100); INSERT INTO Label(label, type, ord) VALUES ('Trash', 'TRASH', 100);

View File

@ -1 +0,0 @@
UPDATE Label SET type = 'DRAFT' WHERE type = 'DRAFTS';

View File

@ -35,7 +35,7 @@ public class JdbcNodeRegistryTest {
public void setUp() throws Exception { public void setUp() throws Exception {
config = new TestJdbcConfig(); config = new TestJdbcConfig();
config.reset(); config.reset();
registry = new JdbcNodeRegistry(config); registry = new MemoryNodeRegistry();
registry.offerAddresses(Arrays.asList( registry.offerAddresses(Arrays.asList(
createAddress(1, 8444, 1, now()), createAddress(1, 8444, 1, now()),

View File

@ -8,3 +8,4 @@ include 'repositories'
include 'demo' include 'demo'
include 'wif'

18
wif/build.gradle Normal file
View File

@ -0,0 +1,18 @@
uploadArchives {
repositories {
mavenDeployer {
pom.project {
name 'Jabit WIF Import/Export'
artifactId = 'jabit-wif'
description 'A Java implementation of the Bitmessage protocol. This contains methods to import from and export to Wallet Import Format.'
}
}
}
}
dependencies {
compile project(':domain')
compile 'org.ini4j:ini4j:0.5.4'
testCompile 'junit:junit:4.11'
testCompile 'org.mockito:mockito-core:1.+'
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.wif;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.utils.Base58;
import ch.dissem.bitmessage.utils.Security;
import org.ini4j.Ini;
import org.ini4j.Profile;
import java.io.*;
import java.util.Collection;
import static ch.dissem.bitmessage.entity.valueobject.PrivateKey.PRIVATE_KEY_SIZE;
/**
* @author Christian Basler
*/
public class WifExporter {
private final BitmessageContext ctx;
private final Ini ini;
public WifExporter(BitmessageContext ctx) {
this.ctx = ctx;
this.ini = new Ini();
}
public WifExporter addAll() {
for (BitmessageAddress identity : ctx.addresses().getIdentities()) {
addIdentity(identity);
}
return this;
}
public WifExporter addAll(Collection<BitmessageAddress> identities) {
for (BitmessageAddress identity : identities) {
addIdentity(identity);
}
return this;
}
public WifExporter addIdentity(BitmessageAddress identity) {
Profile.Section section = ini.add(identity.getAddress());
section.add("label", identity.getAlias());
section.add("enabled", true);
section.add("decoy", false);
section.add("noncetrialsperbyte", identity.getPubkey().getNonceTrialsPerByte());
section.add("payloadlengthextrabytes", identity.getPubkey().getExtraBytes());
section.add("privsigningkey", exportSecret(identity.getPrivateKey().getPrivateSigningKey()));
section.add("privencryptionkey", exportSecret(identity.getPrivateKey().getPrivateEncryptionKey()));
return this;
}
private String exportSecret(byte[] privateKey) {
if (privateKey.length != PRIVATE_KEY_SIZE) {
throw new IllegalArgumentException("Private key of length 32 expected, but was " + privateKey.length);
}
byte[] result = new byte[37];
result[0] = (byte) 0x80;
System.arraycopy(privateKey, 0, result, 1, PRIVATE_KEY_SIZE);
byte[] hash = Security.doubleSha256(result, PRIVATE_KEY_SIZE + 1);
System.arraycopy(hash, 0, result, PRIVATE_KEY_SIZE + 1, 4);
return Base58.encode(result);
}
public void write(File file) throws IOException {
file.createNewFile();
try (FileOutputStream out = new FileOutputStream(file)) {
write(out);
}
}
public void write(OutputStream out) throws IOException {
ini.store(out);
}
@Override
public String toString() {
StringWriter writer = new StringWriter();
try {
ini.store(writer);
} catch (IOException e) {
throw new RuntimeException(e);
}
return writer.toString();
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.wif;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.utils.Base58;
import ch.dissem.bitmessage.utils.Security;
import org.ini4j.Ini;
import org.ini4j.Profile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
/**
* @author Christian Basler
*/
public class WifImporter {
private final static Logger LOG = LoggerFactory.getLogger(WifImporter.class);
private final BitmessageContext ctx;
private final Ini ini = new Ini();
private final List<BitmessageAddress> identities = new LinkedList<>();
public WifImporter(BitmessageContext ctx, File file) throws IOException {
this(ctx, new FileInputStream(file));
}
public WifImporter(BitmessageContext ctx, String data) throws IOException {
this(ctx, new ByteArrayInputStream(data.getBytes("utf-8")));
}
public WifImporter(BitmessageContext ctx, InputStream in, Pubkey.Feature... features) throws IOException {
this.ctx = ctx;
Ini ini = new Ini();
ini.load(in);
for (Entry<String, Profile.Section> entry : ini.entrySet()) {
if (!entry.getKey().startsWith("BM-"))
continue;
Profile.Section section = entry.getValue();
BitmessageAddress address = Factory.createIdentityFromPrivateKey(
entry.getKey(),
getSecret(section.get("privsigningkey")),
getSecret(section.get("privencryptionkey")),
section.get("noncetrialsperbyte", long.class),
section.get("payloadlengthextrabytes", long.class),
Pubkey.Feature.bitfield(features)
);
address.setAlias(section.get("label"));
identities.add(address);
}
}
private byte[] getSecret(String walletImportFormat) throws IOException {
byte[] bytes = Base58.decode(walletImportFormat);
if (bytes[0] != (byte) 0x80)
throw new IOException("Unknown format: 0x80 expected as first byte, but secret " + walletImportFormat + " was " + bytes[0]);
if (bytes.length != 37)
throw new IOException("Unknown format: 37 bytes expected, but secret " + walletImportFormat + " was " + bytes.length + " long");
byte[] hash = Security.doubleSha256(bytes, 33);
for (int i = 0; i < 4; i++) {
if (hash[i] != bytes[33 + i]) throw new IOException("Hash check failed for secret " + walletImportFormat);
}
return Arrays.copyOfRange(bytes, 1, 33);
}
public List<BitmessageAddress> getIdentities() {
return identities;
}
public WifImporter importAll() {
for (BitmessageAddress identity : identities) {
ctx.addresses().save(identity);
}
return this;
}
public WifImporter importAll(Collection<BitmessageAddress> identities) {
for (BitmessageAddress identity : identities) {
ctx.addresses().save(identity);
}
return this;
}
public WifImporter importIdentity(BitmessageAddress identity) {
ctx.addresses().save(identity);
return this;
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.wif;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.ports.*;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class WifExporterTest {
private AddressRepository repo = mock(AddressRepository.class);
private BitmessageContext ctx;
private WifImporter importer;
private WifExporter exporter;
@Before
public void setUp() throws Exception {
ctx = new BitmessageContext.Builder()
.networkHandler(mock(NetworkHandler.class))
.inventory(mock(Inventory.class))
.messageRepo(mock(MessageRepository.class))
.nodeRegistry(mock(NodeRegistry.class))
.addressRepo(repo)
.build();
importer = new WifImporter(ctx, getClass().getClassLoader().getResourceAsStream("nuked.dat"));
assertEquals(81, importer.getIdentities().size());
exporter = new WifExporter(ctx);
}
@Test
public void testAddAll() throws Exception {
when(repo.getIdentities()).thenReturn(importer.getIdentities());
exporter.addAll();
String result = exporter.toString();
int count = 0;
for (int i = 0; i < result.length(); i++) {
if (result.charAt(i) == '[') count++;
}
assertEquals(importer.getIdentities().size(), count);
}
@Test
public void testAddAllFromCollection() throws Exception {
exporter.addAll(importer.getIdentities());
String result = exporter.toString();
int count = 0;
for (int i = 0; i < result.length(); i++) {
if (result.charAt(i) == '[') count++;
}
assertEquals(importer.getIdentities().size(), count);
}
@Test
public void testAddIdentity() throws Exception {
String expected = "[BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn]\n" +
"label = Nuked Address\n" +
"enabled = true\n" +
"decoy = false\n" +
"noncetrialsperbyte = 320\n" +
"payloadlengthextrabytes = 14000\n" +
"privsigningkey = 5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9\n" +
"privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck\n\n";
importer = new WifImporter(ctx, expected);
exporter.addIdentity(importer.getIdentities().get(0));
assertEquals(expected, exporter.toString());
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.wif;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.ports.*;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
public class WifImporterTest {
private AddressRepository repo = mock(AddressRepository.class);
private BitmessageContext ctx;
private WifImporter importer;
@Before
public void setUp() throws Exception {
ctx = new BitmessageContext.Builder()
.networkHandler(mock(NetworkHandler.class))
.inventory(mock(Inventory.class))
.messageRepo(mock(MessageRepository.class))
.nodeRegistry(mock(NodeRegistry.class))
.addressRepo(repo)
.build();
importer = new WifImporter(ctx, getClass().getClassLoader().getResourceAsStream("nuked.dat"));
}
@Test
public void testImportSingleIdentity() throws Exception {
importer = new WifImporter(ctx, "[BM-2cWJ4UFRTCehWuWNsW8fJkAYMxU4S8jxci]\n" +
"label = Nuked Address\n" +
"enabled = true\n" +
"decoy = false\n" +
"noncetrialsperbyte = 320\n" +
"payloadlengthextrabytes = 14000\n" +
"privsigningkey = 5JU5t2JA58sP5aJwKAcrYg5EpBA9bJPrBSaFfaZ7ogmwTMDCfHL\n" +
"privencryptionkey = 5Kkx5MwjQcM4kyduKvCEPM6nVNynMdRcg88VQ5iVDWUekMz1igH");
assertEquals(1, importer.getIdentities().size());
BitmessageAddress identity = importer.getIdentities().get(0);
assertEquals("BM-2cWJ4UFRTCehWuWNsW8fJkAYMxU4S8jxci", identity.getAddress());
assertEquals("Nuked Address", identity.getAlias());
assertEquals(320, identity.getPubkey().getNonceTrialsPerByte());
assertEquals(14000, identity.getPubkey().getExtraBytes());
assertNotNull("Private key", identity.getPrivateKey());
assertEquals(32, identity.getPrivateKey().getPrivateEncryptionKey().length);
assertEquals(32, identity.getPrivateKey().getPrivateSigningKey().length);
}
@Test
public void testGetIdentities() throws Exception {
List<BitmessageAddress> identities = importer.getIdentities();
assertEquals(81, identities.size());
}
@Test
public void testImportAll() throws Exception {
importer.importAll();
verify(repo, times(81)).save(any(BitmessageAddress.class));
}
@Test
public void testImportAllFromCollection() throws Exception {
List<BitmessageAddress> identities = importer.getIdentities();
importer.importAll(identities);
for (BitmessageAddress identity : identities) {
verify(repo, times(1)).save(identity);
}
}
@Test
public void testImportIdentity() throws Exception {
List<BitmessageAddress> identities = importer.getIdentities();
importer.importIdentity(identities.get(0));
verify(repo, times(1)).save(identities.get(0));
}
}

View File

@ -0,0 +1,768 @@
[bitmessagesettings]
settingsversion = 10
port = 8444
timeformat = %%a, %%d %%b %%Y %%I:%%M %%p
blackwhitelist = black
startonlogon = False
minimizetotray = True
showtraynotifications = True
startintray = False
socksproxytype = none
sockshostname = localhost
socksport = 9050
socksauthentication = False
socksusername =
sockspassword =
keysencrypted = false
messagesencrypted = false
defaultnoncetrialsperbyte = 1000
defaultpayloadlengthextrabytes = 1000
minimizeonclose = false
maxacceptablenoncetrialsperbyte = 0
maxacceptablepayloadlengthextrabytes = 0
sockslisten = False
namecoinrpctype = namecoind
namecoinrpchost = localhost
namecoinrpcuser =
namecoinrpcpassword =
namecoinrpcport = 8336
userlocale = system
sendoutgoingconnections = True
useidenticons = True
identiconsuffix = yB9avLvDXVq8
stopresendingafterxdays =
stopresendingafterxmonths =
willinglysendtomobile = True
maxdownloadrate = 0
maxuploadrate = 0
replybelow = False
[BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9
privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck
[BM-2D9U2hv3YBMHM1zERP32anKfVKohyPN9x2]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KXhtUnwRwd5TMfAiyH3YXJRe7hRmLVykYUVrbvKEHjyxUg7QE4
privencryptionkey = 5KLgiRubeZZpyX9jzyNtWcjoDxuDh11t67uaZ8r4qAKQrid6exk
[BM-2DCNKCHG6WWLbPTLT46C7g9dn4ZbpH19eo]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JEcuEVKvx1x3ssw9BSyyddDWEgMv8vc45RZQYUCwoyjx761koX
privencryptionkey = 5KHXRSRatva4VR9kHSVDbyUbed3daW8Cb31xXmThkKgZG461Bt7
[BM-2DAGGcH6PYkn9Bw9TKtNsZbAJ2Cw3hu7vr]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KfqrS44Wq5BpA6fuSf5x1wf4gq5ZmwWgSVrAwF68AWVWh8temr
privencryptionkey = 5JGvJyYTmVZjYiCxSP75tJC4PSNoPr1oVy2ukVzLxyfVQRT9vp8
[BM-2DAdRGnXYMKxsjcGXqwQ9WfzTPwHW9RbNK]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JPHNR9nTHHep5wTFYS46e2zyMVmta2vFCEGvDwG8bELFfHncHD
privencryptionkey = 5KR2USNzgvbFthCQt4bQsttpC2WA2pVt9Q744ffdRykHvfSdzEH
[BM-2DA3fBqzy74zxTxcwDACMbcE2fGwk65BKm]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HpSiNEPb5ZCZj32oxzdb8id29jeEcuqRxzk48VEDcNAWHA2aKk
privencryptionkey = 5JT8LmLHVNcok7phR13H2bYe6gzGgpDCqxiX9PTUrz2BAr2w9Gj
[BM-2D8LDiQM5iiwdmS3L44EVmK1CwzV6ib5W3]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KNPe2if2anrzrdnxSm3t8dSXXz4G9nm2jbpQsR9g61me3Br7sL
privencryptionkey = 5JUFCyai2hoY8XXStAiKF33fWGjRSoN8HPNhfJCRpPxCmHEMSxK
[BM-2DBWYzED6ycuUtTyiTwNrhbUMTrkbRbG5M]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HrPjG418ZgHyocfSfBWaf4XnxaFVopYSzXwzsF1sNfnSsyKcfv
privencryptionkey = 5JSzoJLzx4Rb7PcYdvsD2b7h3xXK8n9o4Ki6uzaCT8kLQrNkPXr
[BM-2D9L1tVWexWv1FXhJNj4vmi8SqDk16yuM5]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HxYyTnwx1gb2AKNLvL66JgXSTt1nTMbc5asoznR42fF3jnF8sE
privencryptionkey = 5Kesd4ygu8o36YET25Qg3b4FjKf6BvwcZbgCyZo7MySYKtvpzoz
[BM-2DAKUSuRSrz6p46EUDZwvB797yaPYeFt3S]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K3EK58h8MoJrHykg6vorYBScsYsirmmHMDz29KGbzGtSXmQuxu
privencryptionkey = 5JozadFrRsHa5A6haPp5cRFNJTL4oM96FnEmWFxSPAJg8y4PgKH
[BM-2D9Pq9fzetLncBamAPkzy9XpY8hMLAa8Fa]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JhvpUDYSaYupCn7U4GHfoT4StM4K7zr2X41yhGuydomoGSaUmG
privencryptionkey = 5Ja5YCvok42RHVwVh4xUCXjhFkEeLMVGb8zX9bmCSRF89zj65wf
[BM-2DB7JrxVujDAnATPqjFiXTQiH2Y4938XXK]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JdKfLaVPtkpNaS6AKtVXqqh2M7tggA93DbSvRCkbPQUz1uZnsh
privencryptionkey = 5KTxqVeSTbk6o94Gp53NjWWpgD6Q8Z1oVibpKrUEEx7xJW2D5YK
[BM-2DB7mtsU1mir7ogbRkhYXJGJ2tRVoPausv]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KaegVTNE2rSB3wCvMKEBqsLqwzdHayoucypfS2kQTUPt9NqSHY
privencryptionkey = 5HwgyCUHmd594BXMbwDyRsVJo931faaXipGNrsRwG87XDrRWC1X
[BM-2D7dUFgpgFny6FRvjhWLTPNvfYmBv824BN]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KJcVvoDgZyCXYMrZ6hMj2a5WLgQeCKZKh5sqjk2bcsEEhBpPXi
privencryptionkey = 5JPcsY7myguBp28WR1pZgSZmddyS2pnukMAde5XZgL35rqzf14n
[BM-2D8BKyZNzj9bsZBSL7gDZVJ3MJjgP46fKH]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HtvTWwzByXtAPCcokMkfhc8UkQUuuk32zzW2fVw6Q1NjcSYJ5h
privencryptionkey = 5K88CUFo4LzFFx2udMAKwFnzeD28ThYT1X8VEgNF1JhqoE9WmwW
[BM-2D7iV3w5JoRs5GtLWFGsoVPHLDnWTSPM96]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K1Vp37dgw8zyMFgpjWq2xAqkr2HjmDaTJgAyvZgAjngdeGTJXx
privencryptionkey = 5JDX3RZpg1bk9YpaECUtCCuGJHr2c7JQVutAaUzBFJnLzkzucbE
[BM-2D9mrrsBS2aUq5Vb5qoGiGfKERW91rybT4]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K1e2WXbt4e1uCqgStmufi8uB8a1BsQueTDoTUo3aaL8TJALg1K
privencryptionkey = 5KC3R9m5ebLNnDJGAVKp7xRz7PocF4wKJ9bhLQndA671sBueJz5
[BM-2D9Mv1kQVLroMPU8QyHiAVXy9DRJgAy1Vu]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JkP8rNxwGTSx3G9Apht1Sxwand6cTqstGCvGTAUXoQBFTdEQXA
privencryptionkey = 5Htevivearmy6fKznQJN8jjXLmZYmeTic1MamAUjsBuVpC4RRiZ
[BM-2DCA9QTUoh1kif8U4TfefUherRFgcn8dNk]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KN5jvhChJ48a6kbjAG5iDp4mQ7kjGVdevAKoFL3DVT32XXpSip
privencryptionkey = 5J4Vz9Jd5g4k4GSWQCccb17R1avCaapBRU3TddHX1AfxdU6ZNQG
[BM-2D7B7XxGBpjP1JafR1zzYk1pDLBRq3h8di]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KjtTbS9BKZLMgZrsXRMa2M67Ymd1ZfPUwik34V1rjAiV9xVNHq
privencryptionkey = 5Jvo923BYvzoodLceQAmJybXhq5j6tgd3cngXKuXgQ1wFQHZt9E
[BM-2D7uUsJsVbpUiDniXoDJcesMgkskofH5sz]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KA8usSRS3bFGP7Z9JigztNpgjFsp8JnhZ8MoriyauzqSmYvi6W
privencryptionkey = 5Jaz7gqwSxa1DYiYxBrYsDz8VCbx2Z5en8za5ZfvzCAb5YLTwje
[BM-2D8LUnD7j7gjJ8GWT6GH7SP2fiK1xCiSX1]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JmR6MBk5Bty8Hf7SK47KMYczhxSaan9bwwpuBQ5dZqqNWW7Gqr
privencryptionkey = 5JRTvg47nhQSj9PJtN2gpBCGZoNjaA7yGJx7B9J4NN7fWmG9aVm
[BM-2DBeDovYwjHjHr8Hu49aBsQ3fEuhAYsWDf]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J5ZGXSu4KzqNPYJNwYSJqCgvntG6icBgom1u4EFGSUQtYrp1C8
privencryptionkey = 5K9w4H5Tv4unvXHbA4RTrTkw7c7yA6qhPuuW3FjBoecujzg1tNm
[BM-2D8UrqSKCgyrcrRuKmt8ovM739nkmGopvZ]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Hvpr6HkmNDwBwB6ay2knNyrD8K7uNVxvwmdgHmyQeKptjaWPGN
privencryptionkey = 5JKUynmyBwZ8LXf1CfaTXKgPR82qPiUt9mPzQdJFRghKMPJx5HV
[BM-2D99A1wN3uCgoznQo1sFKHWbDNpTWLEvHV]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KNNvizhq6dcj3jtk9raLeRLAtMG3hSHX7awa6e2JEfWw3wTtz3
privencryptionkey = 5JKUPdsn5YhG8SGrDsDA87znPUuUiWSUkso195f3bWThwARfsFv
[BM-2D7AuMPHkv1UuxKViWEA17sfp9cQs89Znm]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JMhqMCNY51sVfP584KYbbmZkRgNNdBUr8oSja9cGqZhxT4He2q
privencryptionkey = 5KbC9WfBML1nJkS1qq9rcinq68Vq1cZUr5KNW8H5N7gzkgowS3n
[BM-2cXpehUjQFtmQwUvJpa9ov4w147G1idTXm]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K9ewJHdeNT5yc5AEUbhUyLVMqvfG2ee8hX5aDVkVGhQwnwgNar
privencryptionkey = 5J1eyzU885egejHZ1himtsGe7U1gg1GrLhYenWup7KYSFnDS43N
[BM-2cVqXwUZahBWXzPoY2VyeAhqgVnotfH9Ey]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JvaiFEtsRzNBzcZLuJjFPZ99kjm3oJBUQoxBKtTpEBbFEsP2Mu
privencryptionkey = 5HqduUtt33z1JidXhZS6Q74rszoNehpTQBko8QnHBJrXjZGr7ga
[BM-2DBnGTJmRVvQfbSCYAReabamRSdp4KqXhB]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J7KtaKBP6fw9g6Ucg4p6ab9HXfBbjd3gdC6dpqi8WFt9WzqpcP
privencryptionkey = 5KcACCTtYfUTJJnPnpTuffw5BfqBH5Rfe6ALJapjBnqzarhy96N
[BM-2cT7CDzjxPAuwaRhVH86ogQuRL694Wdp2w]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JN9WMYKUGiKX5m9b3C6LomgXkzRDGHuDPJPruV5DUMGSfv4EDC
privencryptionkey = 5Jr9EC1EBYLyfGvDRSJrjUBWdvLc9HY4EVTC71bfwmKLSeArD85
[BM-2cX2Ywo9xm46g4NfJ2fkBSPmsq2ZgwFkaz]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JsoMruq1fwJyyfkH9xPuufaaCHMqjiDd9RyRTtUq2kVYrsE2n3
privencryptionkey = 5Hwrv93tRXHsFL3LyjiwUFrpqPzivtmw2wNzLCeDhVubeg7tEnA
[BM-2cSjXbZbCimFcdRmyrVn8g5x36RRmhwhgj]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KgPc9CdMCP5x84v3BGrHh7h69TDvAuDxzdm9T3XapGBJxGkWpB
privencryptionkey = 5HwvFPJHNzfAScinj5WVbPZMN6zMUa8yC6m7hCU4wzCRhoy4RsN
[BM-2cXVjgABMxhhNDYbVpbhowDE8aX1PAq48s]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J3XTcnxHqhzB4xsDvLhSoFhaC3KwpzhgTbvz1C5i1K7yV9Jfb7
privencryptionkey = 5JBJwSLYx7GoH7Cbmjm7FCxu7UYP4bnbJsBFJPVZSoCxz15k933
[BM-2cU6VQbNmbbeN2PNyZFymCmvtFZcpDCZFy]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JbHhBsnP5PdXd6JhcB2fsAjzDHKZhvsGUiGjh9mKLTVxjhoEW4
privencryptionkey = 5JoPbYK81WwuFkAGDFan3skWbwuFkb5KdBGLBH7pdf4BBKD4dD8
[BM-2cTgSnGeXpZ7QG22jB5gqvYRiCumLJvoK3]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JXGLbLF2ZYoavyusgZL7TaFMngeChFwyNYRSFx2H2QudYkmK8M
privencryptionkey = 5JLvnDJY2JHKQWv78xcsCENmzqidousgxmDH4btznMWZt2CTBXX
[BM-2cWoFJz6DxG9zjHgzcbVnCvquYXNFktFCk]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KehnNoUFZaH6KwydArEersMXRDe7dAZCe3V3B1MWijz9k5kztL
privencryptionkey = 5HsmLfdmzL5hUXGV4RZ4XKkr6sjA67GnJo4Vr8eXquaEw984tvK
[BM-2cXTcpQaRTNRsSXqkQE1j6Ro5QDNmijP1q]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JKttSMq4FHQzoX7BSL857CaZ5kUJpvFudw95tpmnkrCZwCdpAH
privencryptionkey = 5KPLASpXBTUvrqFcvqGBHZxVsjWu5gbxQu587y4ZsmTebfLt5KS
[BM-2DArvbStMuH61ZDSiuynvksm5yLTxsc9mn]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Ke28hguTUCzMDjK7TxLVnb68Z8W3PwbusddyjJa2RtGqdWc4De
privencryptionkey = 5KaJHSdukjGLf64X9uJHaPgvZnqfH6R3fSTFebzi3L3hfws7JUn
[BM-2cX6f2355Rf5AAjcdfxYSXmuwsCsy1YLFH]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JGnGjk6385CbEb4EG3YDDmf8JGSAEtFwGnhAxL2q4Q2kk5shB5
privencryptionkey = 5KPgrnNoHvah9E9atxBdEEcVBj5SphpQc5oVpba2XrgQK9kgt95
[BM-2cW2kNooDnqt6gHJNZDqo2dn9GpzZDRvxr]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JqaqTpLk4nMtac6UD3ioVQBpu6XGQRH9nyRMDyhPwnWxDoV71u
privencryptionkey = 5JsV7cqsWkAWLwrYVTvTU9LvxQZ8Gww7rSADUsggvEi9RcKKAPd
[BM-2cXvXF3Am4whhZFq4LV2kAcoyAMoKnQ8Wm]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JjhoV9w932braCezpYQT82rMuPumg5cS4Lz3EVcuTjbZvVDBVy
privencryptionkey = 5JFVdGAURPNfiNRzXXwDJKs42uEgErsh8Wh2niKWYmv6MheFjyw
[BM-2cWHh9d3p6bGvoSk3EdcjuZK3NtEJQz7os]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HwZoFT9fVjUXJEC7TVTbaWbU7Yg3Lcngoa2UWS64z57wDqtA88
privencryptionkey = 5J4TEKHNU6BLkUPRRsJwtzWJASbFv5PFJ4vKca688noUwT4Pamg
[BM-2DARPn97uwYdq94nGsGVqMLR7xdB61kTxH]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JRe6vguERZvCHudoZaq2tDXDDqjQqubgECooq52912H6bZW7vr
privencryptionkey = 5K8hMVLx9baTqLDsUwUdX8SJbXHy2s7Biirhjd5kxtvFvqsmaL4
[BM-2cVtAD2kbM7bYzMhmHBitpwWexAvyu6gck]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JxVeKm3tqAejRw5AyFGxBi3yqJ4RAfJ727tmoHFH1MVCdcSqcC
privencryptionkey = 5KhudVzj4h7ZWD9s5buEAGrrPw8fRtg7ReGRV3LF7FXhxnc4CSz
[BM-2cT8cuYey2mvHZvgKAF7tWwKDPjieFYG4w]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5HuDuj5Uo6jRBVYQNsYtoh2d6Mp55e3BAeRq9TpYAgvCwjR75c8
privencryptionkey = 5K22uL1VxYom5FJRPAADpyQP9PPJJQQ5jP2iMxhXZ35V1ouan9P
[BM-2cX38WKpJXYyBvhsopkYegWd14EqrubaTJ]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KkS1jrNfayeFxYQEu8UAm4wWyyk12eu3EY8zGYMjvnHjbjCSGR
privencryptionkey = 5JkDmyTZC8HzqFNigboCraDhAYSYSyKHERPkFkX1SMEx3umjhwi
[BM-2cT1PGqh2nmRf5e3BcpVGcSg44CzsADSu9]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JvACRXT5bxq55bsdpK2uQZ8yN4BwoB1zQjf6kZAJFbjN74yqmR
privencryptionkey = 5JwTTCACiQrbNaGU5Bjhqp4tfB1uiXsR3snn4gQufoHRt9vsrU1
[BM-2cVEefYLC7bCUTwjSqPMX3t4r1YcfjDbLJ]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K6x7cJvQSkjs4LuEVXinFLW4hwJE8Gn32y4tfFJspvFjjqJtNa
privencryptionkey = 5Jg1sK9chFvEZp5pG5iJh3L2L4kxXTWTQ9guqxBLPoEFEyXnmES
[BM-2cVLR8vzEu6QUjGkYAPHQQTUenPVC62f9B]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JvnKKDF1vWDBnnjCPGMVVzsX2EinsXbiiJj7JUwZ9La4xJ9FWt
privencryptionkey = 5JTYsHKSzDx6636UatMppek1QzKYL8b5RLeZdayHoi1Qa5yJjJS
[BM-2cW7cD5cDQJDNkE7ibmyTxfvGAmnPqa9Vt]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Hs858sfv3yhgpiuZZrWPBAPEAvEvggx2E9gErUTu6kdhVzMqoe
privencryptionkey = 5JKWnNvioVg2BFnbToGgp2DJqye86DUcbKxh2idHAeQ6swjYHh2
[BM-2cWGm3LmYYdvWMuAGzJz6uD9WDTMbs8437]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JUFe7HjmsAmPwe3q44wuB1BTV2Y1uXafpizpDckEzDiphJSGuH
privencryptionkey = 5JvMrLJYFxgiUQCtYPPQPXkSjCcpGZxpC2ewDj8dyGMnQwG2ysF
[BM-2cWeF1pYd2AYYDxCRBW3CKvsg2TyJqKqjG]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KjJGuDyHQftvzMSGxUYoL6oFutqCP8MmikScAZvYaxsBfxjyzM
privencryptionkey = 5KbfzpMTsac1JgDPZSQCtrVZuKm61EzQmSGYjKuKBAaez4rnfts
[BM-2cUuzjWQjDWyDfYHL9C93jcJYKW1B8JyS5]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KWFoFRXVHraujrFWuXfNn1fnP4euVUq79QnMWE2QPv3kWhbjs1
privencryptionkey = 5JYcPUZuMjzgSHmsmcsQcpzFGqM7DdEVtxwNjRZg7KfUTqmepFh
[BM-2cVocv4a4k9PhKvLUrSw34z78tKk13g12w]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J5M836NLn3vrxXGmKAzSMm5CNJLn4AyVnbBzRTieUJaXJqkCtQ
privencryptionkey = 5JPTURbrWDbRmPnBdC64Pu24X2pYPQ5CDwrQoEPAXyJwt2gTm8N
[BM-2cUFrQFzG8jjKTfnZo5BCBtZDkfyk9LhWg]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JVh1K937EGcJQ49gc31iGwrWqkakP8zRJKhBCF825Fyv2P6WBo
privencryptionkey = 5JFYLwvBsor3G3G71d9Db4mqKBhHTRXwP9XTENQF7Vo4VmHNzd7
[BM-2cVwSf2HsDfBGEiXjFfhgJ9LWDKDGRqRQy]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Jsp39NFNFAL5hm9bo8nmm4P4Z2gXQ15eNCRJB9wQCaBrAfo768
privencryptionkey = 5KJxAYpf6ftSPNWJk6Z6fzY5TwCa6yeqbodLLEfLQrDFaxdoLNk
[BM-2cVADvyuTBJAMFRnST3NVCCydqqPgW3pgr]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JCzkpcu9F4EVkrC6Z4bhJRKoCyYrTCMjy4HtBKN7n9ndN7qdcb
privencryptionkey = 5J9BRpXyEjbDAsnFKz3AU57WLfM21PCt4D8NmDG3xkZ6W4YXN7o
[BM-2cVM6521amU8w7CiLHUVCEHesZNH41ERp8]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JpQ6EDck3BZqALZQfswQadi2dffQRVfc2GEK8VrycMq4Lc1Xek
privencryptionkey = 5JA6KCA8gknz1vdS8dqbextW4WqkpL7ANm2fNSQhoeoF6beikFH
[BM-2cVUJSDtvTqrJ8iDJG7oVjm6NiNXeTxbLG]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Jcf3Dd1SMgHVfyhLjrps7hxQyXVW5FmkkEsiLEzZkWxj25DpRo
privencryptionkey = 5JatvXsTr5pTKf3SRHRBsVetFduTfGmrHi76dhvKsxkfHprvETg
[BM-2cVhwaUHhDyEUkzFFv6knFpXp8QrqnbFm7]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KC5MaxSexz9xwAJjGZ9DhZP74HP2D2jEvgpq8AqFZmpqzLjJ3P
privencryptionkey = 5Jeuw6uTQwcjAwtA4Mm3tr4SXpZrHGbXQsTcKJJi6uKuS8UKSqn
[BM-2cWvi3Afxsy8R4ZY3uUeVsQc7yWCWJZESE]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JeMaVMNasJ6E6Ldr9T6f4QWppVPXRL1eeYDefzQvo47B1VyRP4
privencryptionkey = 5KSVWmMUnFkGteampznhr8o9gGnW45DzunhUQaCN9KdamDK5cuU
[BM-2cUzpPfJ5Rz1xQQhSxrFYPmtsE1G1ExmuL]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Ki9cpiiNJQ5xBKchU6PHFCapWS9gxiP1Ld8HdvNVs7PJGV9LYB
privencryptionkey = 5KYTe4NMnrBwM8cmg9Y6b6mnNCdVDa2D9c9xFhdr4roVphXmk6o
[BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5K91i1cVACYJrqFu5yQEG2dVYS9jd2fgrr9TnuNuEJrnad7Tdy2
privencryptionkey = 5JjxUkny9JWu1w9hwntCDtqezg3VYt7mieSHSdT2u2DbofyTPoh
[BM-2cWKgkRASMb2Q6x8hJJ8rZUEJNzboi5nA6]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Jox2H4mLCm3iLMsUwRcY2hdNa7RTgdtaq7ioWw9dizGN3xaQWh
privencryptionkey = 5JXYkHycRQuR8Lg7JryswxhNnLu5UTTxp97nrYrSofAwKwW4GZo
[BM-2cWgHUw6xtGuiNrxw1VBZGdRigt7XGkABa]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KT9EajuHRMh3p97JDoTbRrdjyWmLDNDHGSqeHnryDSKSgrAhDY
privencryptionkey = 5Hy5UydAXjU23ZbKAPib5dH1PxfNA6E6z5GVTvwF7PZPevHy9A6
[BM-2cXGxfuziGt7t8yJdhR7vkgdoHB6TEq1aT]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KLwQLcpjBH25SwHjqQJfbJmwK99J33QMdrZqnSqbtTSinoqPYj
privencryptionkey = 5JoKAn7dxMhrryTk6n6oKEi4RrQXsg6NBcjpHLbqppnA3xz6Pjv
[BM-2cWXFpesNTjttWCZLiA8sGSBG51N5E9iM1]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J7ELD2d6Y7awLeFgQuQfcfUNgGtgv6D6bkHt1UDFdAkbdr5FMC
privencryptionkey = 5HsPMpRDkoVMswx1hFiiW7weS1ttoG9dn9czcf2PBjWw7YxR3vw
[BM-2cXZXdtGqwRGEC7V2gy9jhmhTbXs9UEuJc]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5Jyms61QTseJYZxVP7FNVaLA24WkkiXaJyppgTe6qzFK9ZpWDdy
privencryptionkey = 5Jqj4NhcpKiECEUwULn1naRn7C9e3ps9uhG19pSJtztsUDS8ghT
[BM-2cSzVfzZKw8T2nGUKeVX4FFYpkevYZz28X]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KLupHGu2f8Nv1cvQPqEiuzTLJWbg4BMg9JTg2t5fvJxprdiyv4
privencryptionkey = 5KCCcATyhPqdYsBc7sY1rryFwYQ6mVPxWR3SJJRYcq7SgsookqX
[BM-2cSwb9C6dT3WnKofmBMX5vZTJp4sSLAfsQ]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JeMEiiLjoW1PUdexCn7WPKG4o6VDqsqieE6QHG3fZHb1bxXxHb
privencryptionkey = 5KiDwGMxx3BkrrtDg3igbxYAQkbVZaxYsLAQogA3nLHFJZkYx2e
[BM-2cUXfm1rExvCxNUPZwLrxUMWRMTocxyJQp]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KfekquwzKL7ZaPQnZfupVJgxdbfCEG7scaqhADKd87EkZ3Y2eu
privencryptionkey = 5KTiypcqHMw8cDJdv8EEnbVSrgViRyXsUszXoWXBTeVF2aHGUhr
[BM-2cXtnTMWth7aFU3AP4C72X5uQYJtnz3pWM]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KEEe39PtftTHQJP9T1CpWNB6hVpAkfGKDRwagi9yc2AYuSbciv
privencryptionkey = 5Jo2Q3PqvKMDNUXEQtENEGKMBv3WuF5EYZXZwCpAHLsbJFEroBz
[BM-2cTzVrzE4vxTHZooyWxc5v84avdkuHJTUn]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KJCDei1233JqV14xZKbSTMvXbKhEd1C6cbhs3f5uQyXySKChFf
privencryptionkey = 5JJ7Z1EqyN5Ex7W35W2XCNtxgE3EwqnNc6Cqgeo1Buwfw4PNEko
[BM-2cVvoiFs5BgAZs3hh23G9BPUNfZzxHqxWb]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5J3NHste55fKtx7ym6pV3kwb8RwRjzgiEN3ifALSnDJSErbieJ8
privencryptionkey = 5KYq4oNwHSKGxvc6QreXDXJXYp218KDddU2qj5hg2K8xXgFwP7N
[BM-2cXgouAATySWGSjNamhwgGySHhRAGKrSaP]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JpJRaBEUHDyBtyZKcbQSmzKTA1aw77BwJXbnLMtD2mMjZXzgYT
privencryptionkey = 5KimQsWfbMWeX1RQKP78WQJhn5McHKRehPB5bbHYeY7M68wuQa6
[BM-2cWJ4UFRTCehWuWNsW8fJkAYMxU4S8jxci]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JU5t2JA58sP5aJwKAcrYg5EpBA9bJPrBSaFfaZ7ogmwTMDCfHL
privencryptionkey = 5Kkx5MwjQcM4kyduKvCEPM6nVNynMdRcg88VQ5iVDWUekMz1igH
[BM-2cWgJBJy5NruuohhZWRAd2oy9yEp4zQVHx]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JANShMAgoG3vZ8BcLBksc6EdmZfRL7JfoRM8QQEyTGSJADivAe
privencryptionkey = 5J89ZroJf9Vu1JS6CpCJJC5qxn8xaSsfNXH43CFhDyinUJggqL1
[BM-2cXr7pRcKcmwhvL3SasAAg3A39FXx72H42]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KKKo56Zh36Y4fXpvZ7cpSHpSREJjm23tQEWBQyAFwVCx1s1qkF
privencryptionkey = 5JcNUy8Em4P8WFXKcKuJKQKfpAS9hqNFRgUDR63VwBQnpQSeLiN
[BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KMWqfCyJZGFgW6QrnPJ6L9Gatz25B51y7ErgqNr1nXUVbtZbdU
privencryptionkey = 5JXXWEuhHQEPk414SzEZk1PHDRi8kCuZd895J7EnKeQSahJPxGz
[BM-2cXJE8qP12RLiqFW2ZJNRg8Q7EUKsPeFwG]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5JNARqdxHnJqEuExZRF3yXSBbjaWK2n4Z4C7mv9H9uuzFXtVYoU
privencryptionkey = 5Jbwrxdj39Mik2oauT1QD2ZJZ7pg5gz9fPKH6t5x2L1DPnMU6gg
[BM-2cVSPCJPmx5Q8A7BZaVEcTCq6wuuwm2ndW]
label = Nuked Address
enabled = true
decoy = false
noncetrialsperbyte = 320
payloadlengthextrabytes = 14000
privsigningkey = 5KUP7gxNmrKK7NyW2V41Geg9cPz51SEGpZ4kqg7u69X9PWh4DdU
privencryptionkey = 5JcysgNhoBmhvb5zVjMHkbhza12xgZ493Z5H2pshDWPV2ajWxyv