A command-line tool to enable the sharing of sensitive data

secret.go 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. package main
  2. import (
  3. "bytes"
  4. "code.google.com/p/go.crypto/openpgp"
  5. "encoding/base64"
  6. "errors"
  7. "fmt"
  8. "github.com/azlyth/mdns"
  9. "github.com/codegangsta/cli"
  10. "github.com/howeyc/gopass"
  11. "github.com/koding/kite"
  12. "io"
  13. "io/ioutil"
  14. "log"
  15. "net"
  16. "os"
  17. "os/user"
  18. "strconv"
  19. "strings"
  20. )
  21. // General values
  22. const LogLevel = kite.FATAL
  23. const Author = "Peter Valdez"
  24. const Email = "peter@nycmesh.net"
  25. const Name = "secret"
  26. const Usage = "Send secrets with ease."
  27. const Version = "0.1.0"
  28. var currentUser *user.User
  29. var context *cli.Context
  30. var entity *openpgp.Entity
  31. var entityList openpgp.EntityList
  32. var secretKeyring, publicKeyring string
  33. // Convenience
  34. var InternalAddrs []string
  35. var InvalidPrefixes []string
  36. // Flags
  37. var Flags = []cli.Flag{
  38. cli.BoolFlag{
  39. Name: "verbose",
  40. Usage: "print verbose output",
  41. },
  42. }
  43. // Subcommands
  44. var Commands = []cli.Command{
  45. {
  46. Name: "send",
  47. ShortName: "s",
  48. Usage: "Sends a secret",
  49. Action: handle(send),
  50. },
  51. {
  52. Name: "receive",
  53. ShortName: "r",
  54. Usage: "Waits for secrets",
  55. Action: handle(receive),
  56. Flags: Flags,
  57. },
  58. }
  59. func handle(f func() error) func(*cli.Context) {
  60. return func(c *cli.Context) {
  61. // Store the context globally
  62. context = c
  63. // Run the function
  64. err := f()
  65. if err != nil {
  66. fmt.Println(err)
  67. os.Exit(1)
  68. }
  69. }
  70. }
  71. // Receive subcommand
  72. func receive() error {
  73. // Decrypt the key we'll be using to decrypt messages
  74. err := decryptKey()
  75. if err != nil {
  76. return errors.New("Unable to decrypt key.")
  77. }
  78. // Create and configure the kite
  79. k := kite.New("secret", Version)
  80. k.Config.Port = 4321
  81. k.HandleFunc("secret", secret).DisableAuthentication()
  82. k.HandleFunc("identify", identify).DisableAuthentication()
  83. // Prepare the kite
  84. k.SetLogLevel(LogLevel)
  85. k.Config.Region = "secret"
  86. k.Config.Username = "secret"
  87. k.Config.Environment = "secret"
  88. if err != nil {
  89. return err
  90. }
  91. // Get the interface and IPs that'll be used
  92. iface, err := autoSelectInterface()
  93. if err != nil {
  94. return err
  95. }
  96. ips, err := getIPsFromInterface(iface, true)
  97. if err != nil {
  98. return err
  99. }
  100. // Register the mdns service
  101. host, _ := os.Hostname()
  102. info := []string{"Sharing secrets."}
  103. service, err := mdns.NewMDNSService(host, "_secret._tcp", "", "", 4321, ips, info)
  104. if err != nil {
  105. return err
  106. }
  107. server, _ := mdns.NewServer(&mdns.Config{Zone: service, Iface: &iface})
  108. defer server.Shutdown()
  109. // Run the kite
  110. fmt.Println("Waiting for secrets...")
  111. k.Run()
  112. return nil
  113. }
  114. func identify(r *kite.Request) (interface{}, error) {
  115. // Open the file
  116. buf, err := ioutil.ReadFile(publicKeyring)
  117. if err != nil {
  118. return nil, err
  119. }
  120. // Encode the contents of the file to base64
  121. str := base64.StdEncoding.EncodeToString(buf)
  122. return str, nil
  123. }
  124. func secret(r *kite.Request) (interface{}, error) {
  125. // Retrieve the encrypted secret
  126. encrypted := r.Args.One().MustString()
  127. // Decrypt and print the secret
  128. decrypted, err := decryptMessage(encrypted)
  129. if err != nil {
  130. return nil, err
  131. }
  132. fmt.Printf("From %s: %s\n", r.Client.Name, decrypted)
  133. // Return an acknowledgment
  134. return "Received.", nil
  135. }
  136. // Return true if s is prefixed by any of the prefixes
  137. func prefixedByAny(s string, prefixes []string) bool {
  138. for _, prefix := range prefixes {
  139. if strings.HasPrefix(s, prefix) {
  140. return true
  141. }
  142. }
  143. return false
  144. }
  145. func getIPsFromInterface(iface net.Interface, ignoreInternal bool) ([]net.IP, error) {
  146. // Get the addresses
  147. addrs, err := iface.Addrs()
  148. if err != nil {
  149. return nil, err
  150. }
  151. // Get the IPs from the Addrs
  152. ips := make([]net.IP, 0, len(addrs))
  153. for _, addr := range addrs {
  154. // Ignore internal addresses
  155. if ignoreInternal && prefixedByAny(addr.String(), InternalAddrs) {
  156. continue
  157. }
  158. // Convert to IP
  159. ip, _, err := net.ParseCIDR(addr.String())
  160. if err != nil {
  161. return nil, err
  162. }
  163. ips = append(ips, ip)
  164. }
  165. return ips, nil
  166. }
  167. func autoSelectInterface() (net.Interface, error) {
  168. // Get the interfaces
  169. allInterfaces, err := net.Interfaces()
  170. if err != nil {
  171. return net.Interface{}, err
  172. }
  173. // Get the list of addressable IPs
  174. for _, iface := range allInterfaces {
  175. // Ignore certain interfaces
  176. if prefixedByAny(iface.Name, InvalidPrefixes) {
  177. continue
  178. }
  179. // Get the interface IPs
  180. ips, err := getIPsFromInterface(iface, true)
  181. if err != nil {
  182. return net.Interface{}, err
  183. }
  184. // Return if any valid IPs retrieved
  185. if len(ips) > 0 {
  186. return iface, nil
  187. }
  188. }
  189. err = errors.New("Unable to automatically choose an IP address.")
  190. return net.Interface{}, err
  191. }
  192. func selectIPs() ([]net.IP, error) {
  193. // Get the interfaces
  194. allInterfaces, err := net.Interfaces()
  195. if err != nil {
  196. return nil, err
  197. }
  198. // Filter out the ones with no addresses
  199. choices := make([]net.Interface, 0, 4)
  200. for _, iface := range allInterfaces {
  201. // Get the addresses
  202. addrs, err := iface.Addrs()
  203. if err != nil {
  204. return nil, err
  205. }
  206. // The interface is a valid choice if it has addresses
  207. if len(addrs) > 0 {
  208. choices = append(choices, iface)
  209. }
  210. }
  211. // Error if there are no interfaces
  212. if len(choices) == 0 {
  213. err = errors.New("No interfaces with addresses to listen on.")
  214. return nil, err
  215. }
  216. // Display the choices
  217. fmt.Println("- Your network interfaces -")
  218. for i, choice := range choices {
  219. ips, err := getIPsFromInterface(choice, false)
  220. if err != nil {
  221. return nil, err
  222. }
  223. fmt.Println(strconv.Itoa(i), "-", choice.Name, ips)
  224. }
  225. // Gather the user's input
  226. choice := -1
  227. for choice < 0 || choice >= len(choices) {
  228. fmt.Println("\nListen on which? (Enter a number)")
  229. fmt.Print("> ")
  230. _, err = fmt.Scanf("%d", &choice)
  231. if err != nil {
  232. return nil, err
  233. }
  234. }
  235. // Get the interface addresses
  236. ips, err := getIPsFromInterface(choices[choice], false)
  237. if err != nil {
  238. return nil, err
  239. }
  240. return ips, nil
  241. }
  242. // Send subcommand
  243. func send() error {
  244. // Retrieve the argument
  245. if len(context.Args()) != 1 {
  246. return errors.New("Invalid number of arguments.")
  247. }
  248. secret := context.Args().First()
  249. // Find secret peers on the network
  250. entriesCh := make(chan *mdns.ServiceEntry, 4)
  251. mdns.Lookup("_secret._tcp", entriesCh)
  252. close(entriesCh)
  253. var e *mdns.ServiceEntry
  254. for entry := range entriesCh {
  255. e = entry
  256. }
  257. // Create the kite
  258. k := kite.New(currentUser.Username, Version)
  259. k.SetLogLevel(LogLevel)
  260. // Connect to the peer
  261. client := k.NewClient(fmt.Sprintf("http://%s:%d/kite", e.AddrV4, e.Port))
  262. client.Dial()
  263. // Retrieve the public key
  264. response, _ := client.Tell("identify")
  265. str := response.MustString()
  266. buf, err := base64.StdEncoding.DecodeString(str)
  267. if err != nil {
  268. return err
  269. }
  270. reader := bytes.NewReader(buf)
  271. // Send them a secret
  272. encrypted, err := encryptMessage(reader, secret)
  273. if err != nil {
  274. return err
  275. }
  276. response, _ = client.Tell("secret", encrypted)
  277. fmt.Println("Secret sent.")
  278. return nil
  279. }
  280. func encryptMessage(publicKey io.Reader, str string) (string, error) {
  281. // Read in public key
  282. entityList, err := openpgp.ReadKeyRing(publicKey)
  283. if err != nil {
  284. return "", err
  285. }
  286. // Encrypt string
  287. buf := new(bytes.Buffer)
  288. w, err := openpgp.Encrypt(buf, entityList, nil, nil, nil)
  289. if err != nil {
  290. return "", err
  291. }
  292. _, err = w.Write([]byte(str))
  293. if err != nil {
  294. return "", err
  295. }
  296. err = w.Close()
  297. if err != nil {
  298. return "", err
  299. }
  300. // Encode to base64
  301. bytesp, err := ioutil.ReadAll(buf)
  302. if err != nil {
  303. return "", err
  304. }
  305. encstr := base64.StdEncoding.EncodeToString(bytesp)
  306. return encstr, nil
  307. }
  308. func decryptMessage(encstr string) (string, error) {
  309. // Decode the base64 string
  310. dec, err := base64.StdEncoding.DecodeString(encstr)
  311. if err != nil {
  312. return "", err
  313. }
  314. // Decrypt it with the contents of the private key
  315. md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entityList, nil, nil)
  316. if err != nil {
  317. return "", err
  318. }
  319. bytess, err := ioutil.ReadAll(md.UnverifiedBody)
  320. if err != nil {
  321. return "", err
  322. }
  323. decstr := string(bytess)
  324. return decstr, nil
  325. }
  326. func decryptKey() error {
  327. // Open the private key file
  328. keyringFileBuffer, err := os.Open(secretKeyring)
  329. if err != nil {
  330. return err
  331. }
  332. defer keyringFileBuffer.Close()
  333. entityList, err = openpgp.ReadKeyRing(keyringFileBuffer)
  334. if err != nil {
  335. return err
  336. }
  337. entity = entityList[0]
  338. // Get the password
  339. passphrase := os.Getenv("SECRET_PASSWORD")
  340. passphrasebyte := []byte(passphrase)
  341. if passphrase == "" {
  342. fmt.Printf("Enter your PGP key password: ")
  343. passphrasebyte = gopass.GetPasswd()
  344. fmt.Println()
  345. }
  346. // Decrypt the key and subkeys
  347. err = entity.PrivateKey.Decrypt(passphrasebyte)
  348. if err != nil {
  349. return err
  350. }
  351. for _, subkey := range entity.Subkeys {
  352. err = subkey.PrivateKey.Decrypt(passphrasebyte)
  353. if err != nil {
  354. return err
  355. }
  356. }
  357. return nil
  358. }
  359. func main() {
  360. // Disable the log
  361. log.SetOutput(ioutil.Discard)
  362. // Setup the filenames
  363. currentUser, _ = user.Current()
  364. prefix := currentUser.HomeDir
  365. secretKeyring = fmt.Sprintf("%s/.gnupg/secring.gpg", prefix)
  366. publicKeyring = fmt.Sprintf("%s/.gnupg/pubring.gpg", prefix)
  367. // Setup the convenience values
  368. InvalidPrefixes = []string{"docker", "vbox", "awdl"}
  369. InternalAddrs = []string{"127.0.0.1/8", "fe80::1/64", "::1/128"}
  370. // Setup the app
  371. app := cli.NewApp()
  372. app.Name = Name
  373. app.Email = Email
  374. app.Usage = Usage
  375. app.Author = Author
  376. app.Version = Version
  377. app.Commands = Commands
  378. // Run the app
  379. app.Run(os.Args)
  380. }