Trusted timestamps that you can physically include in photos, videos and live streams using QR codes and audible data signals.

Overview

QR Date - Signed timestamps inside QR codes for verifying dates in realtime reporting.

QR Date

CI passing

This is the reference implementation for the first version of QR Date, a signed timestamp inside a QR code that you can use to verify the date in (near-) real-time photojournalism, photo/video uploads and live streams.

We are actively working on both the specification and this library. Things may change dramatically in the coming weeks.

What is it?

QR Date is a trusted timestamp that you can physically include in photos, videos and live streams using QR codes and audible data signals. It is for newsrooms, citizen journalists and social media users who wish to verify dates in videos, live streams and photos by visibly and/or audibly including trusted timestamps in the content.

  • For newsrooms, it helps publishers to make better informed editorial decisions on which media to trust from professional and citizen journalists.
  • For citizen journalists, it allows the public to play an active role in news, helping to verify when what's being recorded happened.
  • For social media users, it works via rapid dissemination to people around the world who can help to verify the QR Date and the media's authenticity.

How is it used?

QR Dates are included in photos and videos using physical means to make faking them harder (but not impossible) within a reasonable amount of time.

  • QR Codes: Physically hold a device or piece of paper displaying the QR code to the camera. With photos, take several with different codes. With video, you can move the device or paper around a little.
  • Sonify: Play the data signal from a speaker over the air close enough so that the microphone on your camera can pick it up over background noise. It does not need to be played loud in a quiet environment. Natural reverb and other ambient sounds will make the signal harder to fake.

Observers of QR Dates included in photos and videos can look for normal signs of tampering and verify the date independently without any proprietary tools.

  • QR codes: Any QR code reader will work with QR Dates visible within photos and videos.
  • Data signals: Programs such as fldigi can be used to decode the MT63 encoded signal.

Security and limitations

Like all media, QR Dates can be faked by embedding new codes into old photos and videos. It is a new tool that does not replace old ones. It can and should be combined with other forensic tools to determine if an image has been manipulated.

How does it work?

A server returns the current time, which it signs using a private key to produce a verification signature.

The URL embedded within the QR Date contains the timestamp and the signature.

Accessing the URL will take observers to QRDate.org, or your website if you run your own implementation, which tells them if the date and signature is valid. The signature can also be verified using a public key without access to the internet.

Distributed clock source

We are working on making qrdate compatible with Roughtime for a distributed, auditable clock source.

Want to help? Feel free to raise issues with your ideas!

Offline use

We are also working to specify QR Dates to work offline using a chained certificate and mobile apps.

Using this library

This library does NOT generate the QR code image for you! It only aims to help you conform to the QR Date spec. You need to feed the output of the date creation function (specifically, the url value) into a QR code image generator to get the correct output image.

This is an ES module written in TypeScript. CommonJS is not supported. The minimum NodeJS version is 14.19.0.

Installation

npm i --save qrdate

API

createDynamicQRDate(params: { privateKey: KeyLike; urlBase?: string; formatter?: CustomQRDateURLFormatter; }): DynamicQRDate

Create a Dynamic QR Date spec object with web-based verification. Use this function to create QR Date that users can verify on your website. The client flow is:

  1. User requests your website.
  2. Your server calls createDynamicQRDate, returning the results to the client.
  3. Draw the QR code on the client from the url property on the return object.

Input object

Attribute Type Required Explanation
params.urlBase string Either params.urlBase or params.formatter are required. If params.formatter is defined, params.urlBase is not used. Your verification base URL - do NOT change this once you have decided on it without some kind of redirection in place! All your QR codes will start with the base URL.
params.formatter CustomQRDateURLFormatter See above A formatter
params.privateKey KeyLike (string / Buffer / KeyObject) Yes Your ed25519 private key. The key can be base64url encoded, and the function will try to parse it for you.

Output object

All the return values are designed to be safe to be shown to the client:

Attribute Type Explanation
timestamp number UNIX timestamp
url string The text to render into a QR code.
signature string Base64url-encoded signed timestamp
version number The version of the QR Date

Example

import { createDynamicQRDate } from 'qrdate';

const urlBase = 'https://localhost/v';
const privateKey = `-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIDgQtOtTyj6rlKFp2+qwlrgzGeA2sxJz4agZKzsCFGKw\n-----END PRIVATE KEY-----`;

const qrDateDynamic = createDynamicQRDate({
  urlBase,
  privateKey, // or a Buffer or KeyObject
});

console.log(qrDateDynamic);
// -----------^
// {
//   timestamp: 1646109781467,
//   url: "https://qrdate.org/v?s=x9hKYrJH0e0BPyVqwnKMAMmxEudkvJccqzjHgaheWFJEd86rW_XdwCKZid7k0teMq7Ygp1PfAJhnT64WcyD6CA&t=1646109781467&v=1",
//   signature: "x9hKYrJH0e0BPyVqwnKMAMmxEudkvJccqzjHgaheWFJEd86rW_XdwCKZid7k0teMq7Ygp1PfAJhnT64WcyD6CA",
// }

createStaticQRDate(privateKey: KeyLike): StaticQRDate

Note: This is not production ready. The certificate chain is still on a concept level.

Create a Static QR Date spec object for offline verification. Use this function to create QR Date that users can verify without your website using a certificate chain. The client flow is:

For users wanting to display codes:

  1. User requests your website or uses an offline app.
  2. Your server calls createStaticQRDate, returning the results to the client.
  3. Draw the QR code on the client from the url property on the return object.

For users wanting to verify the codes:

  1. You publish your public key either in a public or private place, depending on what sort of a setup you wish.
  2. The user inserts your public key into their key store, with the store creating a SHA256 hash of it as the fingerprint.
  3. The user can verify the signature by looking up the public key in their keystore using the fingerprint supplied in the QR Date and use that to perform the verification.
Attribute Type Required Explanation
privateKey KeyLike (string / Buffer / KeyObject) Yes Your ed25519 private key. The key can be base64url encoded, and the function will try to parse it for you.

Output object

All the return values are designed to be safe to be shown to the client:

Attribute Type Explanation
timestamp number UNIX timestamp
url string The text to render into a QR code.
signature string Base64url-encoded signed timestamp
fingerprint string Base64url-encoded fingerprint hashed from your public key
version number The version of the QR Date

Example

import { createStaticQRDate } from 'qrdate';

const privateKey = `-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIDgQtOtTyj6rlKFp2+qwlrgzGeA2sxJz4agZKzsCFGKw\n-----END PRIVATE KEY-----`;

const qrDateStatic = createStaticQRDate({
  privateKey // or a Buffer or KeyObject
});

console.log(qrDateStatic);
// -----------^
// {
//   timestamp: 1646142017145,
//   url: 'qrdate://v?s=tyYD957Q3i6TGUJi7-xzypIl4Be6mM8Jqvc2-nAswRuTadlCEELtMnXWqykcpzneuXJa772vNXc3T0pQFcPBBw&t=1646142017145&f=soyUshlcjtJZ8LQVqu4_ObCykgpFN2EUmfoESVaReiE&v=1',
//   signature: 'tyYD957Q3i6TGUJi7-xzypIl4Be6mM8Jqvc2-nAswRuTadlCEELtMnXWqykcpzneuXJa772vNXc3T0pQFcPBBw',
//   fingerprint: 'soyUshlcjtJZ8LQVqu4_ObCykgpFN2EUmfoESVaReiE',
//   version: 1
// }
//
// In the above url, `/v` has been added after qrdate:// automatically.
// If you are making your own implementation, be sure to include the `/v` for compatibility.
// A static URL should always start with `qrdate://v` to keep it universal and not to clutter the produced QR code further.
// Please see the spec for V1 Static URLs for further info.
//

verifyDynamicQRDate(params: { signature: string; timestamp: string|number; publicKey: KeyLike }): boolean

Verify that the signature on a signed dynamic QR Date timestamp is valid.

Attribute Type Required Explanation
params.signature string Yes Signature passed from client
params.timestamp number / string Yes Signature passed from client
params.publicKey KeyLike (string / Buffer / KeyObject) Yes Your ed25519 public key. The key can be base64url encoded, and the function will try to parse it for you.

Example

import { verifyDynamicQRDate } from 'qrdate';

const valid = verifyDynamicQRDate({
  signature: "x9hKYrJH0e0BPyVqwnKMAMmxEudkvJccqzjHgaheWFJEd86rW_XdwCKZid7k0teMq7Ygp1PfAJhnT64WcyD6CA", 
  timestamp: 1646109781467,
  version: 1,
  publicKey: `-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAJH6tPGKF1ZCMP3DUdpiin7rDLmVb/9A1zyllxaU6cjg=\n-----END PUBLIC KEY-----`; // or a Buffer or KeyObject
});

console.log(valid);
// boolean ---^

verifyStaticQRDate(params: { signature: string; timestamp: string|number; fingerprint: string; publicKey: KeyLike }): boolean

Note: This is not production ready. The certificate chain is still on a concept level.

Verify that the signature on a signed static QR Date timestamp is valid.

Attribute Type Required Explanation
params.signature string Yes Signature passed from qrdate:// URL
params.timestamp number / string Yes Timestamp passed from qrdate:// URL
params.fingerprint string Yes Public key fingerprint passed from qrdate:// URL
params.publicKey KeyLike (string / Buffer / KeyObject) Yes Ed25519 public key corresponding to the fingerprint. The key can be base64url encoded, and the function will try to parse it for you.

Example

import { verifyStaticQRDate } from 'qrdate';

const valid = verifyDynamicQRDate({
  timestamp: 1646147373409,
  signature: 'SARv4c8pJYVxqEK8BCcPy8dgXEAkyWDPRAhvT70RotaHgnko1BkBh-maNzqAicDzqcz7EV65OwLDno7HWT1iAg',
  fingerprint: 'soyUshlcjtJZ8LQVqu4_ObCykgpFN2EUmfoESVaReiE',
  version: 1,
  publicKey: `-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAyHAuTvSG6RZaKGOfzI6iZ8NVaebZpFAFEN/85o6c3nE=\n-----END PUBLIC KEY-----` // or Buffer or KeyObject
});

console.log(valid);
// boolean ---^

generateKeys(): { privateKey: string|KeyObject; publicKey: string|KeyObject }

Use to generate a pair of keys. You can use only the privateKey to interact with the library - any public keys that are required can be derived from it. Store your private key in a safe place! When used with QR Date it is essentially a key to the future.

Example

import { generateKeys } from 'qrdate';
const { privateKey, publicKey } = generateKeys(true);
// true will return keys as string (default)
// false returns them as KeyObjects
console.log(privateKey); // -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
console.log(publicKey); // -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----

QR Date URL Specification

This is the initial version of the specification. If you have any ideas or input, feel free to raise an issue.

Dynamic QR Date v1 spec

Use this spec when you're hosting a verification page for QR Dates on your server. Anyone scanning a QR Date will load your website for verification. The public key will not be included in the generated URL, so it can be shorter.

https://qrdate.org/v?s=twBgNlHANnq5BX1IJb6qAWyfeQkARwIFGiOysZAAIcyba08piw30358RiK9GmCbl3LfloNxoUfsdt6eeKJkyDQ&t=1646148299484&v=1

Important security considerations

  • DO NOT LEAK PRIVATE INFORMATION BY STORING ANY SORT OF STATE IN THE URL.
  • DO NOT STORE IP ADDRESSES OF PEOPLE WHO REQUEST DATES.

It is imperative that you stick to the spec. Do not create any sort of unintended tracking mechanisms by adding your own parameters or state.

Required query parameters

The query parameters are the contract for parsing the URL. You need to provide these for the URL to be considered a QR Date.

Parameter Explanation
t Timestamp (UNIX)
s Signature (ed25519)
v Version (1)

Format the beginning of the URL

Do not point to qrdate.org in your implementation, as we do not host your private key! https://qrdate.org/v is only a placeholder for your domain and hosting setup.

Static QR Date v1 spec

Use this spec when you want to use QR Date without hosting a separate verification page.

qrdate://v?s=d4pOIiiOpOv5q0FPaPUYgZDJERwpZ5JKYOex3nOKLCgMWUL9t3VKCHAdRZJs4a6x5HVTeMaSfSyVi4hK3GhCDQ&t=1646148299487&f=soyUshlcjtJZ8LQVqu4_ObCykgpFN2EUmfoESVaReiE&v=1

Don't add your own parameters in this one either

Sticking to the spec means you're only doing the bare necessary thing- signing a timestamp, and not leaking someone's private information by mistake.

Required origin and pathname

All v1 static URLs should start with qrdate://v and then immediately proceed to the query parameters. Do not add your own parameters or change the URL format in any way. The order of the query parameters does not matter.

Required query parameters

Parameter Explanation
t Timestamp (UNIX)
s Signature
f Public key fingerprint (SHA256) - NOT the public key
v Version (1)

This type of URL can be parsed without external parties as it contains both the signature and public key fingerprint (not the public key itself), which can be compared against a key store that you need to implement in a client application consuming these URLs. Therefore, for example, a system that generates QR Dates every minute through a script to serve on a static website is possible, without needing further web-based validation as long as the user has added the public key (that you must publish elsewhere) into their trusted list. For automatic validation, the consuming client must then implement some sort of a key store, which is outside the scope of this package.

Contact

Contributors

  • miunau
  • Kris
  • Cendyne
  • ...and others preferring to stay anonymous

Want to help out? We welcome contributions and people adopting this idea into other languages and environments. Please conform to the QR Date specification to keep things interoperable. If you have ideas for the spec, please file an issue!

Thanks

Hosting for QRDate.org is sponsored by Vercel.

Powered by Vercel

License

INTELLECTUAL PROPERTY

QR Date, QR Time, and QRDate.org are the property of QRDate.org.
Contact: [email protected]

THIS LIBRARY IS LICENSED UNDER:

MIT © QRDate.org + contributors

THE QR DATE SPEC IS LICENSED UNDER:

CC Attribution 4.0 International (CC BY 4.0) © QRDate.org + contributors

You might also like...

Smart Time Ago is a little jQuery library to update the relative timestamps in your document.

Smart Time Ago Smart Time Ago is a little jQuery library to update the relative timestamps in your document intelligently. (e.g "3 hours ago"). It's o

Dec 6, 2022

Reduce image size of 1000s of photos as a batch.

downsizer A tiny tool to reduce size of images in bulk. Helps you to bulk reduce size of images in a folder or individual images. Install Install Node

Sep 15, 2022

Multi-chain sniper bot to buy and sell tokens on ETH compatible chains. Features include instant or mempool sniping, rug protection, and sell management.

Multi-chain sniper bot to buy and sell tokens on ETH compatible chains. Features include instant or mempool sniping, rug protection, and sell management.

An open-source defi sniper. defi-sniper is free to download. NEW Community telegram group: https://t.me/+aBLUmP1UnypiNTVh Premium Services Now Availab

May 3, 2022

no-comma is a javascript library for dealing with inputted numbers that include commas

no-comma no-comma is a javascript library for dealing with inputted numbers that include commas. Nocomma will allow you to check if the number contain

Jan 27, 2022

A simple javascript utility library to include partial html (iframe alternate) without a framework or jQuery.

alt-iframe A simple javascript utility library to include partial html (iframe alternate) without a framework or jQuery. !doctype html html lang="e

Dec 30, 2022

A simple To-do app project made using JavaScript ES6 and Webpack - Microverse. You can add, remove, check tasks, and remove all the tasks that were done at the same time. Feel free to see the live version, if you like it please give it a star!

To Do List a to do list javascript app buit using webpack and es6. Built With HTML CSS JavaScript Wepack Live Demo (if available) Live Demo Link Getti

Dec 17, 2022

Asciifly is a webapp where you can asciify images and youtube videos on the fly.

Asciifly is a webapp where you can asciify images and youtube videos on the fly.

Asciifly Asciifly is a webapp where you can asciify images and youtube videos on the fly. Come visit at https://asciifly.com Hosting I'm hosting this

May 23, 2022
Comments
  • Static specification (qrdate://)

    Static specification (qrdate://)

    Currently the static specification is a somewhat functional stub. We've been talking about using some sort of a certificate chain, but need more people to chime in on what the actual recommendation for the implementation would look like.

    There's a couple of ways it should be possible to use:

    • As a part of an organisation, you get provisioned a private key based on a certificate chain. You then use that private key in an application provided to you by your organisation (say, a mobile app).
    • With your own private key, on your device, if you want to be considered an authority.
    • Any others?

    Any ideas and input are welcome!

    help wanted 
    opened by miunau 0
Releases(v0.5.0)
  • v0.5.0(Mar 16, 2022)

    • Added a version number to signatures and URLs
    • Added eslint and prettier
    • Updated tests for version number

    Full Changelog: https://github.com/qrdate/qrdate/compare/v0.4.4...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.4(Mar 2, 2022)

Owner
QR Date
Trusted timestamps physically embedded inside photos, videos and live streams
QR Date
Open source software from Lifecast Inc for immersive volumetric VR videos and photos.

Lifecast Inc. Open Source Lifecast makes software for immersive volumetric VR videos and photos. Lifecast's 6DOF format for 3D photos and videos can b

Forrest Briggs 15 Jan 1, 2023
App that allows you to control and watch YouTube videos using hand gestures. Additionally, app that allows you to search for videos, playlists, and channels.

YouTube Alternative Interaction App An app I made with Edward Wu that allows you to search and watch videos from YouTube. Leverages Google's YouTube D

Aaron Lam 2 Dec 28, 2021
This is a project that is used to execute python codes in the web page. You can install and use it in django projects, You can do any operations that can be performed in python shell with this package.

Django execute code This is a project that is used to execute python codes in the web page. You can install and use it in django projects, You can do

Shinu 5 Nov 12, 2022
This plugin can generate timestamps for video, audio and Bilibili video, it takes you to the corresponding video/audio position when clicked.

logseq-plugin-media-ts 本插件能够生成视频、音频以及 B 站视频的时间戳,点击时间戳后会跳转到对应的音视频位置。 This plugin can generate timestamps for video, audio and Bilibili video, it takes

Seth Yuan 58 Jan 3, 2023
Patronum: Ethereum RPC proxy that verifies RPC responses against given trusted block hashes

Patronum Ethereum RPC proxy that verifies RPC responses against given trusted block hashes. Currently, most of the DAPPs and Wallets interact with Eth

null 14 Dec 7, 2022
Use real-time computing technology and web technology to build a big data Kanban l to solve the problem. Among them, practical technologies include MySQL, Kafka, Flink, Redis, Flask and Echarts

实时计算(English Version) 运用实时计算技术、Web 技术构建一个大数据看板来解决问题。其中实用技术包括Mysql、Kafka、Flink、Redis、Flask和Echarts 目录 1.问题需求 2.方案分析 3.安装环境 4.环境启动命令和运行代码的方法 5.代码目录结构说明

Serendipity 2 Jan 8, 2022
Another logger in JS. This one offers a console.log-like API and formatting, colored lines and timestamps (or not if desired), all that with 0 dependencies.

hellog Your new logger ! hellog is a general-purpose logging library. It offers a console.log-like API and formatting, extensible type-safety colored

Maxence Lecanu 4 Jan 5, 2022
A self-hosted solution for backing up and viewing backed up mobile photos

Photostore Photostore is a self-hosted, client-server solution for backing up, viewing and downloading photos. How it works The Photostore API (writte

null 38 Oct 25, 2022
Embed panorama photos on your website with Panorama Viewer

#Panorama Viewer by Pete R. Embed interactive Panorama Pictures on your site with this simple plugin. Created by Pete R., Founder of Travelistly and B

Pete R. 474 Oct 8, 2022