Mark all the exectaubles as +x, as they should have been all along.
[macgdbp.git] / dev / signer-ed25519.go
1 /*
2 * MacGDBp
3 * Copyright (c) 2019, Blue Static <https://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 /*
18 signer-ed25519 provides a sign/verify interface for ED25519 operations.
19
20 Until https://github.com/openssl/openssl/issues/6988 is fixed, OpenSSL cannot
21 be used to generate and verify signatures of files using ED25519 keys. Sparkle
22 only supports ED25519 keys, so this tool is used to bridge the gap.
23
24 Usage:
25
26 Create a new key pair:
27
28 ./signer-ed25519 -new-key
29
30 Get base64 signature:
31
32 ./signer-ed25519 -sign -key privkey.pem -file file.zip | openssl enc -a -A
33
34 Verify signature:
35
36 ./signer-ed25519 -verify -signature <(openssl enc -d -a sig.b64) -key pubkey.pem -file file.zip
37
38 Usage Notes:
39
40 - Encrypted private keys are not supported as no password input is provided.
41 */
42
43 package main
44
45 import (
46 "crypto"
47 "crypto/ed25519"
48 "encoding/pem"
49 "flag"
50 "fmt"
51 "io/ioutil"
52 "os"
53 )
54
55 var (
56 keyPath = flag.String("key", "", "Path to the key file.")
57 inPath = flag.String("file", "", "Path to the file to sign/verify.")
58 sigPath = flag.String("signature", "", "Path to the signature file.")
59 doSign = flag.Bool("sign", false, "Sign the given file.")
60 doVerify = flag.Bool("verify", false, "Verify the given file.")
61 doNewKey = flag.Bool("new-key", false, "Generate a new keypair.")
62 )
63
64 func main() {
65 flag.Parse()
66
67 if *doNewKey {
68 newKey()
69 os.Exit(0)
70 }
71
72 if (!*doSign && !*doVerify) || (*doSign && *doVerify) {
73 fmt.Fprintf(os.Stderr, "Must specify either -sign or -verify.\n")
74 os.Exit(1)
75 }
76
77 keyPemData, err := ioutil.ReadFile(*keyPath)
78 if err != nil {
79 fmt.Fprintf(os.Stderr, "Failed to read key: %v.\n", err)
80 os.Exit(1)
81 }
82
83 keyPem, _ := pem.Decode(keyPemData)
84 if keyPem == nil {
85 fmt.Fprintf(os.Stderr, "Failed to decode PEM.\n", err)
86 os.Exit(1)
87 }
88
89 if *doSign {
90 sign(keyPem)
91 }
92
93 if *doVerify {
94 verify(keyPem)
95 }
96 }
97
98 func newKey() {
99 pub := &pem.Block{Type: "PUBLIC KEY"}
100 priv := &pem.Block{Type: "PRIVATE KEY"}
101 var err error
102 pub.Bytes, priv.Bytes, err = ed25519.GenerateKey(nil)
103 if err != nil {
104 fmt.Fprintf(os.Stderr, "Failed to generate new key pair: %v.\n", err)
105 os.Exit(1)
106 }
107
108 if err := pem.Encode(os.Stdout, pub); err != nil {
109 fmt.Fprintf(os.Stderr, "Failed to write public key: %v.\n", err)
110 }
111 if err := pem.Encode(os.Stdout, priv); err != nil {
112 fmt.Fprintf(os.Stderr, "Failed to write private key: %v.\n", err)
113 }
114 }
115
116 func sign(keyPem *pem.Block) {
117 if keyPem.Type != "PRIVATE KEY" {
118 fmt.Fprintf(os.Stderr, "Signing expects a private key.\n")
119 os.Exit(1)
120 }
121
122 key := ed25519.PrivateKey(keyPem.Bytes)
123
124 signature, err := key.Sign(nil, readInput(), crypto.Hash(0))
125 if err != nil {
126 fmt.Fprintf(os.Stderr, "Failed to sign file: %v.\n", err)
127 os.Exit(1)
128 }
129
130 if _, err := os.Stdout.Write(signature); err != nil {
131 fmt.Fprintf(os.Stderr, "Failed to write output: %v.\n", err)
132 os.Exit(1)
133 }
134 }
135
136 func verify(keyPem *pem.Block) {
137 if keyPem.Type != "PUBLIC KEY" {
138 fmt.Fprintf(os.Stderr, "Verifying expects a public key.\n")
139 os.Exit(1)
140 }
141
142 key := ed25519.PublicKey(keyPem.Bytes)
143
144 signature, err := ioutil.ReadFile(*sigPath)
145 if err != nil {
146 fmt.Fprintf(os.Stderr, "Failed to read signature file: %v.\n", err)
147 os.Exit(1)
148 }
149
150 if ed25519.Verify(key, readInput(), signature) {
151 fmt.Println("Verify OK.")
152 } else {
153 fmt.Println("Verify FAILED!")
154 }
155 }
156
157 func readInput() (fileData []byte) {
158 fileData, err := ioutil.ReadFile(*inPath)
159 if err != nil {
160 fmt.Fprintf(os.Stderr, "Failed to read input file: %v.\n", err)
161 os.Exit(1)
162 }
163 return
164 }