Created
November 19, 2016 02:35
-
-
Save grrowl/ca94e47a6da2062e9bd6dad211588597 to your computer and use it in GitHub Desktop.
React component to provide ed25519 key generation, signing and verification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react' | |
import elliptic, { eddsa as EdDSA } from 'elliptic' | |
function toHex(arr) { | |
return elliptic.utils.toHex(arr).toUpperCase() | |
} | |
function fromHex(hex) { | |
return elliptic.utils.toArray(hex, 'hex') | |
} | |
export default class Signature extends Component { | |
constructor(props) { | |
super(props); | |
// Create and initialize EdDSA context | |
this.ec = new EdDSA('ed25519'); | |
this.state = { | |
privateKey: null, | |
publicKey: null, | |
} | |
this._identity = null | |
this.signMessage = this.signMessage.bind(this) | |
this.verifyMessage = this.verifyMessage.bind(this) | |
this.generateKey = this.generateKey.bind(this) | |
} | |
componentWillMount() { | |
// if the keys are set in localStorage, initiate our state and this.key | |
if (localStorage && localStorage['privateKey'] && localStorage['publicKey']) { | |
const key = this.key = this.ec.keyFromSecret(fromHex(localStorage['privateKey'])) | |
this.setState({ | |
privateKey: toHex(key.getSecret()), | |
publicKey: toHex(key.getPublic()) | |
}) | |
} | |
} | |
generateKey() { | |
let secret; | |
if (window.crypto && window.crypto.getRandomValues) { | |
secret = new Uint8Array(256) | |
window.crypto.getRandomValues(secret) | |
} else { | |
console.warn('Warning: Using insecure methods to generate private key') | |
secret = [] | |
for (let i = 0; i < 256; i++) { | |
secret.push(Math.random() * 9007199254740991) // aka Number.MAX_SAFE_INTEGER | |
} | |
} | |
const key = this.key = this.ec.keyFromSecret(secret) | |
// Save keys to localStorage | |
localStorage['privateKey'] = toHex(key.getSecret()) | |
localStorage['publicKey'] = toHex(key.getPublic()) | |
// Create key pair from secret | |
this.setState({ | |
privateKey: toHex(key.getSecret()), | |
publicKey: toHex(key.getPublic()) | |
}) | |
} | |
// Sign message (must be an array, or it'll be treated as a hex sequence) | |
codifyMessage(message) { | |
message.split('').map(m => m.charCodeAt(0)) | |
} | |
// signs a message with your own key | |
signMessage(message) { | |
// return signature | |
if (this.key) { | |
// ~1ms on my machine | |
return this.key.sign(this.codifyMessage(message)).toHex() | |
} | |
return null | |
} | |
// verify message against our private key | |
verifyOwnMessage(message, signature) { | |
// Verify signature | |
this.key.verify(message, signature) | |
} | |
// verify with no private key | |
verifyMessage(message, signature, publicKey) { | |
// Import public key | |
const key = this.ec.keyFromPublic(publicKey, 'hex') | |
// Verify signature | |
// 7~10ms on my machine | |
return key.verify(this.codifyMessage(message), signature) | |
} | |
render() { | |
const | |
signatureProps = { | |
publicKey: this.state.publicKey, | |
privateKey: this.state.privateKey, | |
generateKey: this.generateKey, | |
signMessage: this.signMessage, | |
verifyMessage: this.verifyMessage, | |
} | |
return ( | |
<div> | |
{ | |
React.Children.map( | |
this.props.children, | |
(child => React.cloneElement(child, signatureProps)) | |
) | |
} | |
</div> | |
) | |
} | |
} | |
Signature.propTypes = { | |
children: PropTypes.node.isRequired, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment