+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <title>Petter Reinholdtsen: New and improved sqlcipher in Debian for accessing Signal database</title>
+ <link rel="stylesheet" type="text/css" media="screen" href="https://people.skolelinux.org/pere/blog/style.css" />
+ <link rel="stylesheet" type="text/css" media="screen" href="https://people.skolelinux.org/pere/blog/vim.css" />
+
+
+ </head>
+ <body>
+ <div class="title">
+ <h1>
+ <a href="https://people.skolelinux.org/pere/blog/">Petter Reinholdtsen</a>
+
+ </h1>
+
+</div>
+
+
+ <div class="entry">
+ <div class="title">New and improved sqlcipher in Debian for accessing Signal database</div>
+ <div class="date">12th November 2023</div>
+ <div class="body"><p>For a while now I wanted to have direct access to the
+<a href="https://signal.org/">Signal</a> database of messages and
+channels of my Desktop edition of Signal. I prefer the enforced end
+to end encryption of Signal these days for my communication with
+friends and family, to increase the level of safety and privacy as
+well as raising the cost of the mass surveillance government and
+non-government entities practice these days. In August I came across
+a nice
+<a href="https://www.yoranbrondsema.com/post/the-guide-to-extracting-statistics-from-your-signal-conversations/">recipe
+on how to use sqlcipher to extract statistics from the Signal
+database</a> explaining how to do this. Unfortunately this did not
+work with the version of sqlcipher in Debian. The
+<a href="http://tracker.debian.org/sqlcipher/">sqlcipher</a>
+package is a "fork" of the sqlite package with added support for
+encrypted databases. Sadly the current Debian maintainer
+<a href="https://bugs.debian.org/961598">announced more than three
+years ago that he did not have time to maintain sqlcipher</a>, so it
+seemed unlikely to be upgraded by the maintainer. I was reluctant to
+take on the job myself, as I have very limited experience maintaining
+shared libraries in Debian. After waiting and hoping for a few
+months, I gave up the last week, and set out to update the package. In
+the process I orphaned it to make it more obvious for the next person
+looking at it that the package need proper maintenance.</p>
+
+<p>The version in Debian was around five years old, and quite a lot of
+changes had taken place upstream into the Debian maintenance git
+repository. After spending a few days importing the new upstream
+versions, realising that upstream did not care much for SONAME
+versioning as I saw library symbols being both added and removed with
+minor version number changes to the project, I concluded that I had to
+do a SONAME bump of the library package to avoid surprising the
+reverse dependencies. I even added a simple
+autopkgtest script to ensure the package work as intended. Dug deep
+into the hole of learning shared library maintenance, I set out a few
+days ago to upload the new version to Debian experimental to see what
+the quality assurance framework in Debian had to say about the result.
+The feedback told me the pacakge was not too shabby, and yesterday I
+uploaded the latest version to Debian unstable. It should enter
+testing today or tomorrow, perhaps delayed by
+<a href="https://bugs.debian.org/1055812">a small library
+transition</a>.</p>
+
+<p>Armed with a new version of sqlcipher, I can now have a look at the
+SQL database in ~/.config/Signal/sql/db.sqlite. First, one need to
+fetch the encryption key from the Signal configuration using this
+simple JSON extraction command:</p>
+
+<pre>/usr/bin/jq -r '."key"' ~/.config/Signal/config.json</pre>
+
+<p>Assuming the result from that command is 'secretkey', which is a
+hexadecimal number representing the key used to encrypt the database.
+Next, one can now connect to the database and inject the encryption
+key for access via SQL to fetch information from the database. Here
+is an example dumping the database structure:</p>
+
+<pre>
+% sqlcipher ~/.config/Signal/sql/db.sqlite
+sqlite> PRAGMA key = "x'secretkey'";
+sqlite> .schema
+CREATE TABLE sqlite_stat1(tbl,idx,stat);
+CREATE TABLE conversations(
+ id STRING PRIMARY KEY ASC,
+ json TEXT,
+
+ active_at INTEGER,
+ type STRING,
+ members TEXT,
+ name TEXT,
+ profileName TEXT
+ , profileFamilyName TEXT, profileFullName TEXT, e164 TEXT, serviceId TEXT, groupId TEXT, profileLastFetchedAt INTEGER);
+CREATE TABLE identityKeys(
+ id STRING PRIMARY KEY ASC,
+ json TEXT
+ );
+CREATE TABLE items(
+ id STRING PRIMARY KEY ASC,
+ json TEXT
+ );
+CREATE TABLE sessions(
+ id TEXT PRIMARY KEY,
+ conversationId TEXT,
+ json TEXT
+ , ourServiceId STRING, serviceId STRING);
+CREATE TABLE attachment_downloads(
+ id STRING primary key,
+ timestamp INTEGER,
+ pending INTEGER,
+ json TEXT
+ );
+CREATE TABLE sticker_packs(
+ id TEXT PRIMARY KEY,
+ key TEXT NOT NULL,
+
+ author STRING,
+ coverStickerId INTEGER,
+ createdAt INTEGER,
+ downloadAttempts INTEGER,
+ installedAt INTEGER,
+ lastUsed INTEGER,
+ status STRING,
+ stickerCount INTEGER,
+ title STRING
+ , attemptedStatus STRING, position INTEGER DEFAULT 0 NOT NULL, storageID STRING, storageVersion INTEGER, storageUnknownFields BLOB, storageNeedsSync
+ INTEGER DEFAULT 0 NOT NULL);
+CREATE TABLE stickers(
+ id INTEGER NOT NULL,
+ packId TEXT NOT NULL,
+
+ emoji STRING,
+ height INTEGER,
+ isCoverOnly INTEGER,
+ lastUsed INTEGER,
+ path STRING,
+ width INTEGER,
+
+ PRIMARY KEY (id, packId),
+ CONSTRAINT stickers_fk
+ FOREIGN KEY (packId)
+ REFERENCES sticker_packs(id)
+ ON DELETE CASCADE
+ );
+CREATE TABLE sticker_references(
+ messageId STRING,
+ packId TEXT,
+ CONSTRAINT sticker_references_fk
+ FOREIGN KEY(packId)
+ REFERENCES sticker_packs(id)
+ ON DELETE CASCADE
+ );
+CREATE TABLE emojis(
+ shortName TEXT PRIMARY KEY,
+ lastUsage INTEGER
+ );
+CREATE TABLE messages(
+ rowid INTEGER PRIMARY KEY ASC,
+ id STRING UNIQUE,
+ json TEXT,
+ readStatus INTEGER,
+ expires_at INTEGER,
+ sent_at INTEGER,
+ schemaVersion INTEGER,
+ conversationId STRING,
+ received_at INTEGER,
+ source STRING,
+ hasAttachments INTEGER,
+ hasFileAttachments INTEGER,
+ hasVisualMediaAttachments INTEGER,
+ expireTimer INTEGER,
+ expirationStartTimestamp INTEGER,
+ type STRING,
+ body TEXT,
+ messageTimer INTEGER,
+ messageTimerStart INTEGER,
+ messageTimerExpiresAt INTEGER,
+ isErased INTEGER,
+ isViewOnce INTEGER,
+ sourceServiceId TEXT, serverGuid STRING NULL, sourceDevice INTEGER, storyId STRING, isStory INTEGER
+ GENERATED ALWAYS AS (type IS 'story'), isChangeCreatedByUs INTEGER NOT NULL DEFAULT 0, isTimerChangeFromSync INTEGER
+ GENERATED ALWAYS AS (
+ json_extract(json, '$.expirationTimerUpdate.fromSync') IS 1
+ ), seenStatus NUMBER default 0, storyDistributionListId STRING, expiresAt INT
+ GENERATED ALWAYS
+ AS (ifnull(
+ expirationStartTimestamp + (expireTimer * 1000),
+ 9007199254740991
+ )), shouldAffectActivity INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'contact-removed-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ ), shouldAffectPreview INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'contact-removed-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ ), isUserInitiatedMessage INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'contact-removed-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'group-v2-change',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ ), mentionsMe INTEGER NOT NULL DEFAULT 0, isGroupLeaveEvent INTEGER
+ GENERATED ALWAYS AS (
+ type IS 'group-v2-change' AND
+ json_array_length(json_extract(json, '$.groupV2Change.details')) IS 1 AND
+ json_extract(json, '$.groupV2Change.details[0].type') IS 'member-remove' AND
+ json_extract(json, '$.groupV2Change.from') IS NOT NULL AND
+ json_extract(json, '$.groupV2Change.from') IS json_extract(json, '$.groupV2Change.details[0].aci')
+ ), isGroupLeaveEventFromOther INTEGER
+ GENERATED ALWAYS AS (
+ isGroupLeaveEvent IS 1
+ AND
+ isChangeCreatedByUs IS 0
+ ), callId TEXT
+ GENERATED ALWAYS AS (
+ json_extract(json, '$.callId')
+ ));
+CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
+CREATE TABLE jobs(
+ id TEXT PRIMARY KEY,
+ queueType TEXT STRING NOT NULL,
+ timestamp INTEGER NOT NULL,
+ data STRING TEXT
+ );
+CREATE TABLE reactions(
+ conversationId STRING,
+ emoji STRING,
+ fromId STRING,
+ messageReceivedAt INTEGER,
+ targetAuthorAci STRING,
+ targetTimestamp INTEGER,
+ unread INTEGER
+ , messageId STRING);
+CREATE TABLE senderKeys(
+ id TEXT PRIMARY KEY NOT NULL,
+ senderId TEXT NOT NULL,
+ distributionId TEXT NOT NULL,
+ data BLOB NOT NULL,
+ lastUpdatedDate NUMBER NOT NULL
+ );
+CREATE TABLE unprocessed(
+ id STRING PRIMARY KEY ASC,
+ timestamp INTEGER,
+ version INTEGER,
+ attempts INTEGER,
+ envelope TEXT,
+ decrypted TEXT,
+ source TEXT,
+ serverTimestamp INTEGER,
+ sourceServiceId STRING
+ , serverGuid STRING NULL, sourceDevice INTEGER, receivedAtCounter INTEGER, urgent INTEGER, story INTEGER);
+CREATE TABLE sendLogPayloads(
+ id INTEGER PRIMARY KEY ASC,
+
+ timestamp INTEGER NOT NULL,
+ contentHint INTEGER NOT NULL,
+ proto BLOB NOT NULL
+ , urgent INTEGER, hasPniSignatureMessage INTEGER DEFAULT 0 NOT NULL);
+CREATE TABLE sendLogRecipients(
+ payloadId INTEGER NOT NULL,
+
+ recipientServiceId STRING NOT NULL,
+ deviceId INTEGER NOT NULL,
+
+ PRIMARY KEY (payloadId, recipientServiceId, deviceId),
+
+ CONSTRAINT sendLogRecipientsForeignKey
+ FOREIGN KEY (payloadId)
+ REFERENCES sendLogPayloads(id)
+ ON DELETE CASCADE
+ );
+CREATE TABLE sendLogMessageIds(
+ payloadId INTEGER NOT NULL,
+
+ messageId STRING NOT NULL,
+
+ PRIMARY KEY (payloadId, messageId),
+
+ CONSTRAINT sendLogMessageIdsForeignKey
+ FOREIGN KEY (payloadId)
+ REFERENCES sendLogPayloads(id)
+ ON DELETE CASCADE
+ );
+CREATE TABLE preKeys(
+ id STRING PRIMARY KEY ASC,
+ json TEXT
+ , ourServiceId NUMBER
+ GENERATED ALWAYS AS (json_extract(json, '$.ourServiceId')));
+CREATE TABLE signedPreKeys(
+ id STRING PRIMARY KEY ASC,
+ json TEXT
+ , ourServiceId NUMBER
+ GENERATED ALWAYS AS (json_extract(json, '$.ourServiceId')));
+CREATE TABLE badges(
+ id TEXT PRIMARY KEY,
+ category TEXT NOT NULL,
+ name TEXT NOT NULL,
+ descriptionTemplate TEXT NOT NULL
+ );
+CREATE TABLE badgeImageFiles(
+ badgeId TEXT REFERENCES badges(id)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE,
+ 'order' INTEGER NOT NULL,
+ url TEXT NOT NULL,
+ localPath TEXT,
+ theme TEXT NOT NULL
+ );
+CREATE TABLE storyReads (
+ authorId STRING NOT NULL,
+ conversationId STRING NOT NULL,
+ storyId STRING NOT NULL,
+ storyReadDate NUMBER NOT NULL,
+
+ PRIMARY KEY (authorId, storyId)
+ );
+CREATE TABLE storyDistributions(
+ id STRING PRIMARY KEY NOT NULL,
+ name TEXT,
+
+ senderKeyInfoJson STRING
+ , deletedAtTimestamp INTEGER, allowsReplies INTEGER, isBlockList INTEGER, storageID STRING, storageVersion INTEGER, storageUnknownFields BLOB, storageNeedsSync INTEGER);
+CREATE TABLE storyDistributionMembers(
+ listId STRING NOT NULL REFERENCES storyDistributions(id)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE,
+ serviceId STRING NOT NULL,
+
+ PRIMARY KEY (listId, serviceId)
+ );
+CREATE TABLE uninstalled_sticker_packs (
+ id STRING NOT NULL PRIMARY KEY,
+ uninstalledAt NUMBER NOT NULL,
+ storageID STRING,
+ storageVersion NUMBER,
+ storageUnknownFields BLOB,
+ storageNeedsSync INTEGER NOT NULL
+ );
+CREATE TABLE groupCallRingCancellations(
+ ringId INTEGER PRIMARY KEY,
+ createdAt INTEGER NOT NULL
+ );
+CREATE TABLE IF NOT EXISTS 'messages_fts_data'(id INTEGER PRIMARY KEY, block BLOB);
+CREATE TABLE IF NOT EXISTS 'messages_fts_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
+CREATE TABLE IF NOT EXISTS 'messages_fts_content'(id INTEGER PRIMARY KEY, c0);
+CREATE TABLE IF NOT EXISTS 'messages_fts_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
+CREATE TABLE IF NOT EXISTS 'messages_fts_config'(k PRIMARY KEY, v) WITHOUT ROWID;
+CREATE TABLE edited_messages(
+ messageId STRING REFERENCES messages(id)
+ ON DELETE CASCADE,
+ sentAt INTEGER,
+ readStatus INTEGER
+ , conversationId STRING);
+CREATE TABLE mentions (
+ messageId REFERENCES messages(id) ON DELETE CASCADE,
+ mentionAci STRING,
+ start INTEGER,
+ length INTEGER
+ );
+CREATE TABLE kyberPreKeys(
+ id STRING PRIMARY KEY NOT NULL,
+ json TEXT NOT NULL, ourServiceId NUMBER
+ GENERATED ALWAYS AS (json_extract(json, '$.ourServiceId')));
+CREATE TABLE callsHistory (
+ callId TEXT PRIMARY KEY,
+ peerId TEXT NOT NULL, -- conversation id (legacy) | uuid | groupId | roomId
+ ringerId TEXT DEFAULT NULL, -- ringer uuid
+ mode TEXT NOT NULL, -- enum "Direct" | "Group"
+ type TEXT NOT NULL, -- enum "Audio" | "Video" | "Group"
+ direction TEXT NOT NULL, -- enum "Incoming" | "Outgoing
+ -- Direct: enum "Pending" | "Missed" | "Accepted" | "Deleted"
+ -- Group: enum "GenericGroupCall" | "OutgoingRing" | "Ringing" | "Joined" | "Missed" | "Declined" | "Accepted" | "Deleted"
+ status TEXT NOT NULL,
+ timestamp INTEGER NOT NULL,
+ UNIQUE (callId, peerId) ON CONFLICT FAIL
+ );
+[ dropped all indexes to save space in this blog post ]
+CREATE TRIGGER messages_on_view_once_update AFTER UPDATE ON messages
+ WHEN
+ new.body IS NOT NULL AND new.isViewOnce = 1
+ BEGIN
+ DELETE FROM messages_fts WHERE rowid = old.rowid;
+ END;
+CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
+ WHEN new.isViewOnce IS NOT 1 AND new.storyId IS NULL
+ BEGIN
+ INSERT INTO messages_fts
+ (rowid, body)
+ VALUES
+ (new.rowid, new.body);
+ END;
+CREATE TRIGGER messages_on_delete AFTER DELETE ON messages BEGIN
+ DELETE FROM messages_fts WHERE rowid = old.rowid;
+ DELETE FROM sendLogPayloads WHERE id IN (
+ SELECT payloadId FROM sendLogMessageIds
+ WHERE messageId = old.id
+ );
+ DELETE FROM reactions WHERE rowid IN (
+ SELECT rowid FROM reactions
+ WHERE messageId = old.id
+ );
+ DELETE FROM storyReads WHERE storyId = old.storyId;
+ END;
+CREATE VIRTUAL TABLE messages_fts USING fts5(
+ body,
+ tokenize = 'signal_tokenizer'
+ );
+CREATE TRIGGER messages_on_update AFTER UPDATE ON messages
+ WHEN
+ (new.body IS NULL OR old.body IS NOT new.body) AND
+ new.isViewOnce IS NOT 1 AND new.storyId IS NULL
+ BEGIN
+ DELETE FROM messages_fts WHERE rowid = old.rowid;
+ INSERT INTO messages_fts
+ (rowid, body)
+ VALUES
+ (new.rowid, new.body);
+ END;
+CREATE TRIGGER messages_on_insert_insert_mentions AFTER INSERT ON messages
+ BEGIN
+ INSERT INTO mentions (messageId, mentionAci, start, length)
+
+ SELECT messages.id, bodyRanges.value ->> 'mentionAci' as mentionAci,
+ bodyRanges.value ->> 'start' as start,
+ bodyRanges.value ->> 'length' as length
+ FROM messages, json_each(messages.json ->> 'bodyRanges') as bodyRanges
+ WHERE bodyRanges.value ->> 'mentionAci' IS NOT NULL
+
+ AND messages.id = new.id;
+ END;
+CREATE TRIGGER messages_on_update_update_mentions AFTER UPDATE ON messages
+ BEGIN
+ DELETE FROM mentions WHERE messageId = new.id;
+ INSERT INTO mentions (messageId, mentionAci, start, length)
+
+ SELECT messages.id, bodyRanges.value ->> 'mentionAci' as mentionAci,
+ bodyRanges.value ->> 'start' as start,
+ bodyRanges.value ->> 'length' as length
+ FROM messages, json_each(messages.json ->> 'bodyRanges') as bodyRanges
+ WHERE bodyRanges.value ->> 'mentionAci' IS NOT NULL
+
+ AND messages.id = new.id;
+ END;
+sqlite>
+</pre>
+
+<p>Finally I have the tool needed to inspect and process Signal
+messages that I need, without using the vendor provided client. Now
+on to transforming it to a more useful format.</p>
+
+<p>As usual, if you use Bitcoin and want to show your support of my
+activities, please send Bitcoin donations to my address
+<b><a href="bitcoin:15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b">15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b</a></b>.</p>
+</div>
+
+ <div class="tags">Tags: <a href="https://people.skolelinux.org/pere/blog/tags/debian">debian</a>, <a href="https://people.skolelinux.org/pere/blog/tags/english">english</a>, <a href="https://people.skolelinux.org/pere/blog/tags/sikkerhet">sikkerhet</a>, <a href="https://people.skolelinux.org/pere/blog/tags/surveillance">surveillance</a>.</div>
+
+
+ </div>
+
+
+
+
+ <div id="sidebar">
+
+
+
+<h2>Archive</h2>
+<ul>
+
+<li>2023
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/01/">January (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/02/">February (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/04/">April (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/05/">May (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/06/">June (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/08/">August (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/10/">October (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/11/">November (3)</a></li>
+
+</ul></li>
+
+<li>2022
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/02/">February (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/03/">March (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/04/">April (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/07/">July (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/10/">October (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/12/">December (1)</a></li>
+
+</ul></li>
+
+<li>2021
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/01/">January (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/02/">February (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/05/">May (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/06/">June (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/07/">July (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/08/">August (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/10/">October (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2021/12/">December (1)</a></li>
+
+</ul></li>
+
+<li>2020
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/02/">February (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/03/">March (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/04/">April (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/05/">May (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/07/">July (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/10/">October (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2020/11/">November (1)</a></li>
+
+</ul></li>
+
+<li>2019
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/01/">January (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/02/">February (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/03/">March (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/05/">May (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/06/">June (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/07/">July (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/08/">August (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/11/">November (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2019/12/">December (4)</a></li>
+
+</ul></li>
+
+<li>2018
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/01/">January (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/02/">February (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/03/">March (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/04/">April (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/07/">July (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/08/">August (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/09/">September (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/10/">October (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/11/">November (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2018/12/">December (4)</a></li>
+
+</ul></li>
+
+<li>2017
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/01/">January (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/02/">February (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/03/">March (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/04/">April (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/06/">June (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/07/">July (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/08/">August (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/09/">September (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/10/">October (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/11/">November (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2017/12/">December (4)</a></li>
+
+</ul></li>
+
+<li>2016
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/01/">January (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/02/">February (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/03/">March (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/04/">April (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/05/">May (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/07/">July (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/08/">August (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/09/">September (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/10/">October (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/11/">November (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2016/12/">December (5)</a></li>
+
+</ul></li>
+
+<li>2015
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/01/">January (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/02/">February (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/03/">March (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/04/">April (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/05/">May (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/06/">June (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/07/">July (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/08/">August (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/09/">September (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/10/">October (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/11/">November (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2015/12/">December (3)</a></li>
+
+</ul></li>
+
+<li>2014
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/01/">January (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/02/">February (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/03/">March (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/04/">April (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/05/">May (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/07/">July (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/08/">August (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/09/">September (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/10/">October (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/11/">November (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2014/12/">December (5)</a></li>
+
+</ul></li>
+
+<li>2013
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/01/">January (11)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/02/">February (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/03/">March (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/04/">April (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/05/">May (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/06/">June (10)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/07/">July (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/08/">August (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/09/">September (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/10/">October (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/11/">November (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2013/12/">December (3)</a></li>
+
+</ul></li>
+
+<li>2012
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/01/">January (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/02/">February (10)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/03/">March (17)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/04/">April (12)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/05/">May (12)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/06/">June (20)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/07/">July (17)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/08/">August (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/09/">September (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/10/">October (17)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/11/">November (10)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2012/12/">December (7)</a></li>
+
+</ul></li>
+
+<li>2011
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/01/">January (16)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/02/">February (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/03/">March (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/04/">April (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/05/">May (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/06/">June (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/07/">July (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/08/">August (6)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/09/">September (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/10/">October (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/11/">November (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2011/12/">December (1)</a></li>
+
+</ul></li>
+
+<li>2010
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/01/">January (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/02/">February (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/03/">March (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/04/">April (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/05/">May (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/06/">June (14)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/07/">July (12)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/08/">August (13)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/09/">September (7)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/10/">October (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/11/">November (13)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2010/12/">December (12)</a></li>
+
+</ul></li>
+
+<li>2009
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/01/">January (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/02/">February (8)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/03/">March (12)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/04/">April (10)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/05/">May (9)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/06/">June (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/07/">July (4)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/08/">August (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/10/">October (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/11/">November (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2009/12/">December (3)</a></li>
+
+</ul></li>
+
+<li>2008
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2008/11/">November (5)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2008/12/">December (7)</a></li>
+
+</ul></li>
+
+</ul>
+
+
+
+<h2>Tags</h2>
+<ul>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/3d-printer">3d-printer (19)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/amiga">amiga (1)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/aros">aros (1)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/bankid">bankid (4)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/betalkontant">betalkontant (9)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/bitcoin">bitcoin (12)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/bootsystem">bootsystem (17)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/bsa">bsa (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/chrpath">chrpath (3)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/debian">debian (197)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/debian edu">debian edu (159)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/debian-handbook">debian-handbook (9)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/digistan">digistan (11)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/dld">dld (18)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/docbook">docbook (32)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/drivstoffpriser">drivstoffpriser (4)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/english">english (454)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/fiksgatami">fiksgatami (23)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/fildeling">fildeling (14)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/freeculture">freeculture (34)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/freedombox">freedombox (9)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/frikanalen">frikanalen (20)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/h264">h264 (20)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/intervju">intervju (43)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/isenkram">isenkram (16)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/kart">kart (23)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/kodi">kodi (6)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/ldap">ldap (9)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/lego">lego (5)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/lenker">lenker (8)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/linuxcnc">linuxcnc (5)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/lsdvd">lsdvd (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/ltsp">ltsp (1)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/madewithcc">madewithcc (3)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/mesh network">mesh network (8)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/multimedia">multimedia (46)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/nice free software">nice free software (15)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/noark5">noark5 (23)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/norsk">norsk (322)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/nuug">nuug (198)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/offentlig innsyn">offentlig innsyn (40)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/open311">open311 (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/opensnitch">opensnitch (4)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/opphavsrett">opphavsrett (75)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/personvern">personvern (114)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/raid">raid (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/reactos">reactos (1)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/reprap">reprap (11)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/rfid">rfid (3)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/robot">robot (17)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/rss">rss (1)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/ruter">ruter (7)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/scraperwiki">scraperwiki (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/sikkerhet">sikkerhet (60)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/sitesummary">sitesummary (4)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/skepsis">skepsis (5)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/standard">standard (74)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/stavekontroll">stavekontroll (7)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/stortinget">stortinget (14)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/surveillance">surveillance (65)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/sysadmin">sysadmin (5)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/usenix">usenix (2)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/valg">valg (9)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/verkidetfri">verkidetfri (20)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/video">video (79)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/vitenskap">vitenskap (4)</a></li>
+
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/web">web (42)</a></li>
+
+</ul>
+
+
+ </div>
+ <p style="text-align: right">
+ Created by <a href="http://steve.org.uk/Software/chronicle">Chronicle v4.6</a>
+</p>
+
+ </body>
+</html>