mirror of https://github.com/status-im/op-geth.git
Merge remote-tracking branch 'upstream/develop' into pr/evmjit
This commit is contained in:
commit
3aa0410f6e
|
@ -46,7 +46,7 @@ Go Ethereum comes with several binaries found in
|
||||||
* `mist` Official Ethereum Browser
|
* `mist` Official Ethereum Browser
|
||||||
* `ethereum` Ethereum CLI
|
* `ethereum` Ethereum CLI
|
||||||
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
|
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
|
||||||
`ethtest "`cat myfile.json`"`.
|
`cat file | ethtest`.
|
||||||
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
|
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
|
||||||
10000 -price 0 -dump`. See `-h` for a detailed description.
|
10000 -price 0 -dump`. See `-h` for a detailed description.
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,16 @@ import Ethereum 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: window
|
id: window
|
||||||
objectName: "browserView"
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#00000000"
|
color: "#00000000"
|
||||||
|
|
||||||
property var title: "Browser"
|
property var title: "DApps"
|
||||||
property var iconSource: "../browser.png"
|
property var iconSource: "../browser.png"
|
||||||
property var menuItem
|
property var menuItem
|
||||||
|
property var hideUrl: true
|
||||||
|
|
||||||
property alias url: webview.url
|
property alias url: webview.url
|
||||||
|
property alias windowTitle: webview.title
|
||||||
property alias webView: webview
|
property alias webView: webview
|
||||||
|
|
||||||
property var cleanPath: false
|
property var cleanPath: false
|
||||||
|
@ -66,8 +67,7 @@ Rectangle {
|
||||||
webview.url = "http://etherian.io"
|
webview.url = "http://etherian.io"
|
||||||
}
|
}
|
||||||
|
|
||||||
signal messages(var messages, int id);
|
function messages(messages, id) {
|
||||||
onMessages: {
|
|
||||||
// Bit of a cheat to get proper JSON
|
// Bit of a cheat to get proper JSON
|
||||||
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
||||||
webview.postEvent("eth_changed", id, m);
|
webview.postEvent("eth_changed", id, m);
|
||||||
|
@ -164,22 +164,10 @@ Rectangle {
|
||||||
id: webview
|
id: webview
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
function injectJs(js) {
|
|
||||||
webview.experimental.navigatorQtObjectEnabled = true;
|
|
||||||
webview.experimental.evaluateJavaScript(js)
|
|
||||||
webview.experimental.javascriptEnabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessage(data) {
|
function sendMessage(data) {
|
||||||
webview.experimental.postMessage(JSON.stringify(data))
|
webview.experimental.postMessage(JSON.stringify(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
for (var i in experimental.preferences) {
|
|
||||||
console.log(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
experimental.preferences.javascriptEnabled: true
|
experimental.preferences.javascriptEnabled: true
|
||||||
experimental.preferences.webAudioEnabled: true
|
experimental.preferences.webAudioEnabled: true
|
||||||
experimental.preferences.pluginsEnabled: true
|
experimental.preferences.pluginsEnabled: true
|
||||||
|
@ -219,8 +207,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
|
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
|
||||||
experimental.onMessageReceived: {
|
experimental.onMessageReceived: {
|
||||||
console.log("[onMessageReceived]: ", message.data)
|
//console.log("[onMessageReceived]: ", message.data)
|
||||||
// TODO move to messaging.js
|
|
||||||
var data = JSON.parse(message.data)
|
var data = JSON.parse(message.data)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -350,13 +337,13 @@ Rectangle {
|
||||||
|
|
||||||
case "eth_newFilterString":
|
case "eth_newFilterString":
|
||||||
require(1)
|
require(1)
|
||||||
var id = eth.newFilterString(data.args[0])
|
var id = eth.newFilterString(data.args[0], window)
|
||||||
postData(data._id, id);
|
postData(data._id, id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "eth_newFilter":
|
case "eth_newFilter":
|
||||||
require(1)
|
require(1)
|
||||||
var id = eth.newFilter(data.args[0])
|
var id = eth.newFilter(data.args[0], window)
|
||||||
|
|
||||||
postData(data._id, id);
|
postData(data._id, id);
|
||||||
break;
|
break;
|
||||||
|
@ -425,11 +412,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function post(seed, data) {
|
function post(seed, data) {
|
||||||
postData(data._id, data)
|
postData(data._id, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function require(args, num) {
|
function require(args, num) {
|
||||||
if(args.length < num) {
|
if(args.length < num) {
|
||||||
throw("required argument count of "+num+" got "+args.length);
|
throw("required argument count of "+num+" got "+args.length);
|
||||||
|
@ -441,12 +426,10 @@ Rectangle {
|
||||||
function postEvent(event, id, data) {
|
function postEvent(event, id, data) {
|
||||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
|
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWatchedCb(data, id) {
|
function onWatchedCb(data, id) {
|
||||||
var messages = JSON.parse(data)
|
var messages = JSON.parse(data)
|
||||||
postEvent("watched:"+id, messages)
|
postEvent("watched:"+id, messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNewBlockCb(block) {
|
function onNewBlockCb(block) {
|
||||||
postEvent("block:new", block)
|
postEvent("block:new", block)
|
||||||
}
|
}
|
||||||
|
@ -460,7 +443,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: sizeGrip
|
id: sizeGrip
|
||||||
color: "gray"
|
color: "gray"
|
||||||
|
|
|
@ -13,7 +13,6 @@ ApplicationWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var ethx : Eth.ethx
|
property var ethx : Eth.ethx
|
||||||
property var browser
|
|
||||||
|
|
||||||
width: 1200
|
width: 1200
|
||||||
height: 820
|
height: 820
|
||||||
|
@ -21,6 +20,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
title: "Mist"
|
title: "Mist"
|
||||||
|
|
||||||
|
/*
|
||||||
// This signal is used by the filter API. The filter API connects using this signal handler from
|
// This signal is used by the filter API. The filter API connects using this signal handler from
|
||||||
// the different QML files and plugins.
|
// the different QML files and plugins.
|
||||||
signal messages(var messages, int id);
|
signal messages(var messages, int id);
|
||||||
|
@ -30,6 +30,7 @@ ApplicationWindow {
|
||||||
messages(data, receiverSeed);
|
messages(data, receiverSeed);
|
||||||
root.browser.view.messages(data, receiverSeed);
|
root.browser.view.messages(data, receiverSeed);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: copyElementHax
|
id: copyElementHax
|
||||||
|
@ -45,8 +46,6 @@ ApplicationWindow {
|
||||||
// Takes care of loading all default plugins
|
// Takes care of loading all default plugins
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||||
var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
|
||||||
root.browser = browser;
|
|
||||||
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||||
|
|
||||||
addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
|
addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
|
||||||
|
@ -55,17 +54,17 @@ ApplicationWindow {
|
||||||
addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
|
addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
|
||||||
addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
|
addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
|
||||||
|
|
||||||
addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
|
|
||||||
|
|
||||||
mainSplit.setView(wallet.view, wallet.menuItem);
|
mainSplit.setView(wallet.view, wallet.menuItem);
|
||||||
|
|
||||||
|
newBrowserTab("http://etherian.io");
|
||||||
|
|
||||||
// Command setup
|
// Command setup
|
||||||
gui.sendCommand(0)
|
gui.sendCommand(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function activeView(view, menuItem) {
|
function activeView(view, menuItem) {
|
||||||
mainSplit.setView(view, menuItem)
|
mainSplit.setView(view, menuItem)
|
||||||
if (view.objectName === "browserView") {
|
if (view.hideUrl) {
|
||||||
urlPane.visible = false;
|
urlPane.visible = false;
|
||||||
mainView.anchors.top = rootView.top
|
mainView.anchors.top = rootView.top
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,6 +118,13 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function newBrowserTab(url) {
|
||||||
|
var window = addPlugin("./browser.qml", {noAdd: true, close: true, section: "apps", active: true});
|
||||||
|
window.view.url = url;
|
||||||
|
window.menuItem.title = "Browser Tab";
|
||||||
|
activeView(window.view, window.menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
menuBar: MenuBar {
|
menuBar: MenuBar {
|
||||||
Menu {
|
Menu {
|
||||||
title: "File"
|
title: "File"
|
||||||
|
@ -130,13 +136,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
MenuItem {
|
|
||||||
text: "Browser"
|
|
||||||
onTriggered: eth.openBrowser()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Add plugin"
|
text: "Add plugin"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
@ -146,6 +145,14 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "New tab"
|
||||||
|
shortcut: "Ctrl+t"
|
||||||
|
onTriggered: {
|
||||||
|
newBrowserTab("http://etherian.io");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
|
@ -205,21 +212,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
/*
|
|
||||||
MenuItem {
|
|
||||||
id: miningSpeed
|
|
||||||
text: "Mining: Turbo"
|
|
||||||
onTriggered: {
|
|
||||||
gui.toggleTurboMining()
|
|
||||||
if(text == "Mining: Turbo") {
|
|
||||||
text = "Mining: Normal";
|
|
||||||
} else {
|
|
||||||
text = "Mining: Turbo";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
|
@ -350,9 +342,6 @@ ApplicationWindow {
|
||||||
views[i].menuItem.setSelection(false)
|
views[i].menuItem.setSelection(false)
|
||||||
}
|
}
|
||||||
view.visible = true
|
view.visible = true
|
||||||
|
|
||||||
//menu.border.color = "#CCCCCC"
|
|
||||||
//menu.color = "#FFFFFFFF"
|
|
||||||
menu.setSelection(true)
|
menu.setSelection(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +501,15 @@ ApplicationWindow {
|
||||||
|
|
||||||
this.view.destroy()
|
this.view.destroy()
|
||||||
this.destroy()
|
this.destroy()
|
||||||
|
for (var i = 0; i < mainSplit.views.length; i++) {
|
||||||
|
var view = mainSplit.views[i];
|
||||||
|
if (view.menuItem === this) {
|
||||||
|
mainSplit.views.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
gui.removePlugin(this.path)
|
gui.removePlugin(this.path)
|
||||||
|
activeView(mainSplit.views[0].view, mainSplit.views[0].menuItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,7 +573,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "APPS"
|
text: "NET"
|
||||||
font.bold: true
|
font.bold: true
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
|
@ -653,7 +650,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
Keys.onReturnPressed: {
|
||||||
if(/^https?/.test(this.text)) {
|
if(/^https?/.test(this.text)) {
|
||||||
activeView(root.browser.view, root.browser.menuItem);
|
newBrowserTab(this.text);
|
||||||
} else {
|
} else {
|
||||||
addPlugin(this.text, {close: true, section: "apps"})
|
addPlugin(this.text, {close: true, section: "apps"})
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ Rectangle {
|
||||||
property var identity: ""
|
property var identity: ""
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
identity = shh.newIdentity()
|
identity = shh.newIdentity()
|
||||||
console.log("New identity:", identity)
|
|
||||||
|
|
||||||
var t = shh.watch({}, root)
|
var t = shh.watch({}, root)
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,20 +316,15 @@ func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (i
|
||||||
filter := qt.NewFilterFromMap(object, self.eth)
|
filter := qt.NewFilterFromMap(object, self.eth)
|
||||||
filter.MessageCallback = func(messages state.Messages) {
|
filter.MessageCallback = func(messages state.Messages) {
|
||||||
view.Call("messages", xeth.ToJSMessages(messages), id)
|
view.Call("messages", xeth.ToJSMessages(messages), id)
|
||||||
//self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id)
|
|
||||||
}
|
}
|
||||||
id = self.filterManager.InstallFilter(filter)
|
id = self.filterManager.InstallFilter(filter)
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *UiLib) NewFilterString(typ string) (id int) {
|
func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
|
||||||
filter := core.NewFilter(self.eth)
|
filter := core.NewFilter(self.eth)
|
||||||
filter.BlockCallback = func(block *types.Block) {
|
filter.BlockCallback = func(block *types.Block) {
|
||||||
if self.win != nil && self.win.Root() != nil {
|
view.Call("messages", "{}", id)
|
||||||
self.win.Root().Call("invokeFilterCallback", "{}", id)
|
|
||||||
} else {
|
|
||||||
fmt.Println("QML is lagging")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
id = self.filterManager.InstallFilter(filter)
|
id = self.filterManager.InstallFilter(filter)
|
||||||
return id
|
return id
|
||||||
|
|
112
crypto/crypto.go
112
crypto/crypto.go
|
@ -1,11 +1,20 @@
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"code.google.com/p/go-uuid/uuid"
|
||||||
|
"code.google.com/p/go.crypto/pbkdf2"
|
||||||
"code.google.com/p/go.crypto/ripemd160"
|
"code.google.com/p/go.crypto/ripemd160"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
|
@ -101,7 +110,11 @@ func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||||
sig, err = secp256k1.Sign(hash, prv.D.Bytes())
|
if len(hash) != 32 {
|
||||||
|
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,3 +126,100 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
|
||||||
key := ecies.ImportECDSA(prv)
|
key := ecies.ImportECDSA(prv)
|
||||||
return key.Decrypt(rand.Reader, ct, nil, nil)
|
return key.Decrypt(rand.Reader, ct, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
|
||||||
|
func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
|
||||||
|
key, err := decryptPreSaleKey(keyJSON, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
id := uuid.NewRandom()
|
||||||
|
key.Id = &id
|
||||||
|
err = keyStore.StoreKey(key, password)
|
||||||
|
return key, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
|
||||||
|
preSaleKeyStruct := struct {
|
||||||
|
EncSeed string
|
||||||
|
EthAddr string
|
||||||
|
Email string
|
||||||
|
BtcAddr string
|
||||||
|
}{}
|
||||||
|
err = json.Unmarshal(fileContent, &preSaleKeyStruct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
||||||
|
iv := encSeedBytes[:16]
|
||||||
|
cipherText := encSeedBytes[16:]
|
||||||
|
/*
|
||||||
|
See https://github.com/ethereum/pyethsaletool
|
||||||
|
|
||||||
|
pyethsaletool generates the encryption key from password by
|
||||||
|
2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
|
||||||
|
16 byte key length within PBKDF2 and resulting key is used as AES key
|
||||||
|
*/
|
||||||
|
passBytes := []byte(password)
|
||||||
|
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
||||||
|
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||||
|
ethPriv := Sha3(plainText)
|
||||||
|
ecKey := ToECDSA(ethPriv)
|
||||||
|
key = &Key{
|
||||||
|
Id: nil,
|
||||||
|
PrivateKey: ecKey,
|
||||||
|
}
|
||||||
|
derivedAddr := ethutil.Bytes2Hex(key.Address())
|
||||||
|
expectedAddr := preSaleKeyStruct.EthAddr
|
||||||
|
if derivedAddr != expectedAddr {
|
||||||
|
err = errors.New("decrypted addr not equal to expected addr")
|
||||||
|
}
|
||||||
|
return key, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
|
||||||
|
aesBlock, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return plainText, err
|
||||||
|
}
|
||||||
|
decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
|
||||||
|
paddedPlainText := make([]byte, len(cipherText))
|
||||||
|
decrypter.CryptBlocks(paddedPlainText, cipherText)
|
||||||
|
plainText = PKCS7Unpad(paddedPlainText)
|
||||||
|
if plainText == nil {
|
||||||
|
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
|
||||||
|
}
|
||||||
|
return plainText, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
|
||||||
|
func PKCS7Pad(in []byte) []byte {
|
||||||
|
padding := 16 - (len(in) % 16)
|
||||||
|
if padding == 0 {
|
||||||
|
padding = 16
|
||||||
|
}
|
||||||
|
for i := 0; i < padding; i++ {
|
||||||
|
in = append(in, byte(padding))
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
func PKCS7Unpad(in []byte) []byte {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
padding := in[len(in)-1]
|
||||||
|
if int(padding) > len(in) || padding > aes.BlockSize {
|
||||||
|
return nil
|
||||||
|
} else if padding == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
|
||||||
|
if in[i] != padding {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return in[:len(in)-int(padding)]
|
||||||
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func BenchmarkSha3(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test0Key(t *testing.T) {
|
func Test0Key(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
|
key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
|
||||||
|
|
||||||
p, err := secp256k1.GeneratePubKey(key)
|
p, err := secp256k1.GeneratePubKey(key)
|
||||||
|
@ -60,3 +60,15 @@ func Test0Key(t *testing.T) {
|
||||||
fmt.Printf("%x\n", p)
|
fmt.Printf("%x\n", p)
|
||||||
fmt.Printf("%v %x\n", err, addr)
|
fmt.Printf("%v %x\n", err, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidSign(t *testing.T) {
|
||||||
|
_, err := Sign(make([]byte, 1), nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected sign with hash 1 byte to error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Sign(make([]byte, 33), nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected sign with hash 33 byte to error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ type encryptedKeyJSON struct {
|
||||||
|
|
||||||
func (k *Key) Address() []byte {
|
func (k *Key) Address() []byte {
|
||||||
pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
|
pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
|
||||||
return Sha3(pubBytes)[12:]
|
return Sha3(pubBytes[1:])[12:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *Key) MarshalJSON() (j []byte, err error) {
|
func (k *Key) MarshalJSON() (j []byte, err error) {
|
||||||
|
@ -99,9 +99,10 @@ func NewKey(rand io.Reader) *Key {
|
||||||
privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
|
privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
|
||||||
privateKeyECDSA := ToECDSA(privateKeyMarshalled)
|
privateKeyECDSA := ToECDSA(privateKeyMarshalled)
|
||||||
|
|
||||||
key := new(Key)
|
|
||||||
id := uuid.NewRandom()
|
id := uuid.NewRandom()
|
||||||
key.Id = &id
|
key := &Key{
|
||||||
key.PrivateKey = privateKeyECDSA
|
Id: &id,
|
||||||
|
PrivateKey: privateKeyECDSA,
|
||||||
|
}
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,22 +178,10 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||||
AES256Block, err := aes.NewCipher(derivedKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
AES256CBCDecrypter := cipher.NewCBCDecrypter(AES256Block, iv)
|
|
||||||
paddedPlainText := make([]byte, len(cipherText))
|
|
||||||
AES256CBCDecrypter.CryptBlocks(paddedPlainText, cipherText)
|
|
||||||
|
|
||||||
plainText := PKCS7Unpad(paddedPlainText)
|
|
||||||
if plainText == nil {
|
|
||||||
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes = plainText[:len(plainText)-32]
|
keyBytes = plainText[:len(plainText)-32]
|
||||||
keyBytesHash := plainText[len(plainText)-32:]
|
keyBytesHash := plainText[len(plainText)-32:]
|
||||||
if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
|
if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
|
||||||
|
@ -211,35 +199,3 @@ func getEntropyCSPRNG(n int) []byte {
|
||||||
}
|
}
|
||||||
return mainBuff
|
return mainBuff
|
||||||
}
|
}
|
||||||
|
|
||||||
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
|
|
||||||
func PKCS7Pad(in []byte) []byte {
|
|
||||||
padding := 16 - (len(in) % 16)
|
|
||||||
if padding == 0 {
|
|
||||||
padding = 16
|
|
||||||
}
|
|
||||||
for i := 0; i < padding; i++ {
|
|
||||||
in = append(in, byte(padding))
|
|
||||||
}
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
|
|
||||||
func PKCS7Unpad(in []byte) []byte {
|
|
||||||
if len(in) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
padding := in[len(in)-1]
|
|
||||||
if int(padding) > len(in) || padding > aes.BlockSize {
|
|
||||||
return nil
|
|
||||||
} else if padding == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
|
|
||||||
if in[i] != padding {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in[:len(in)-int(padding)]
|
|
||||||
}
|
|
||||||
|
|
|
@ -83,3 +83,16 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImportPreSaleKey(t *testing.T) {
|
||||||
|
// file content of a presale key file generated with:
|
||||||
|
// python pyethsaletool.py genwallet
|
||||||
|
// with password "foo"
|
||||||
|
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
|
||||||
|
ks := NewKeyStorePassphrase(DefaultDataDir())
|
||||||
|
pass := "foo"
|
||||||
|
_, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ func (self *peer) broadcast(envelopes []*Envelope) error {
|
||||||
if err := self.ws.WriteMsg(msg); err != nil {
|
if err := self.ws.WriteMsg(msg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.peer.Infoln("broadcasted", i, "message(s)")
|
self.peer.DebugDetailln("broadcasted", i, "message(s)")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in New Issue