Skip to content

Commit 939d55f

Browse files
committed
Initial commit
0 parents  commit 939d55f

File tree

10 files changed

+881
-0
lines changed

10 files changed

+881
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.pio
2+
.vscode/.browse.c_cpp.db*
3+
.vscode/c_cpp_properties.json
4+
.vscode/launch.json
5+
.vscode/ipch

.vscode/extensions.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
// See http://go.microsoft.com/fwlink/?LinkId=827846
3+
// for the documentation about the extensions.json format
4+
"recommendations": [
5+
"platformio.platformio-ide"
6+
],
7+
"unwantedRecommendations": [
8+
"ms-vscode.cpptools-extension-pack"
9+
]
10+
}

README.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# ESP32 Arduino SSH wrapper class
2+
3+
This is a wrapper class and example program for [LibSSH-ESP32] Arduino SSH library.
4+
This program features are:
5+
- ssh connection to the server using
6+
- Password authentication
7+
- Public key authentication
8+
- Public key authentication with passphrase encrypted private key
9+
- execute a command over ssh connection (sshCommand)
10+
- copy file from ESP32 to the server using scp (scpPut)
11+
- copy file from the server to ESP32 using scp (scpGet)
12+
- different file systems in ESP32
13+
- SPIFFS (path prefix is /spiffs/)
14+
- SD card (path prefix is /sd/)
15+
- LittleFS (path prefix is /littlefs/)
16+
17+
## Usage
18+
You can compile this project in platformIO and upload it to ESP32. Modify main.cpp as per testing instructions below.
19+
20+
Alternatively, you can add this library to your platformIO project by adding these two dependencies in platformio.ini under lib_dep.
21+
22+
```
23+
lib_deps =
24+
ewpa/LibSSH-ESP32@^3.0.1
25+
https://github.com/hpirila/ESP32-Arduino-SSH.git
26+
```
27+
28+
## Testing
29+
Have a Linux server ready where you can ssh using a password or public key authentication. Password authentication may be easier to do first.
30+
### Linux server
31+
You need a Linux server where to access using ssh. You can create one, for example, to Google or Amazon cloud. This program follows an example where the Linux server is Ubuntu in the Amazon cloud, but any Linux distribution shall work.
32+
To access the Linux server, you need to know its
33+
- IP address or domain name
34+
- Username and password
35+
or
36+
- Username and have the public and private key available for connection
37+
38+
### Configure Wifi
39+
You need to set your WiFi SSID and password to this part in main.cpp.
40+
41+
```WiFi.begin("ssid", "Wifi_password");```
42+
43+
### Configure SSH connection for password authentication
44+
#### In Linux server
45+
By default, Ubuntu in Amazon AWS does not allow ssh using password authentication. You need to do three things to enable password authentication.
46+
47+
Set password for ubuntu user:
48+
49+
```sudo passwd ubuntu```
50+
51+
In this example, I set the password to ```System#1```
52+
53+
Enable ssh password authentication
54+
55+
```sudo nano /etc/ssh/sshd_config```
56+
57+
Change this line from
58+
59+
```PasswordAuthentication no```
60+
61+
to
62+
63+
```PasswordAuthentication yes```
64+
65+
Restart sshd process
66+
67+
```sudo systemctl restart sshd```
68+
69+
#### In main.cpp file
70+
71+
Set your Linux server domain name or IP address in this line. You can find the domain name in the Amazon AWS EC2 console, Instance summary, Public IPv4 DNS.
72+
73+
```ssh.connectWithPassword("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com","ubuntu","System#1");```
74+
75+
That's all. You can now compile and upload the program to ESP32.
76+
- It should connect to the server using username ubuntu and password System#1.
77+
- create a file in the server called testFile1
78+
- copy that file to the ESP32 SPIFFS file system
79+
- copy the file back to server using different filename testFile2
80+
- compares testFile1 and testFile2 and writes the result to result.txt
81+
82+
Login to the server and see if the files exist and the content of the result file.
83+
```
84+
ubuntu@my-server:~$ ls -l testFile* result.txt
85+
-rw-rw-r-- 1 ubuntu ubuntu 44 Jan 22 10:25 result.txt
86+
-rw-rw-r-- 1 ubuntu ubuntu 56 Jan 22 10:25 testFile1
87+
-rw-rw-r-- 1 ubuntu ubuntu 56 Jan 22 10:25 testFile2
88+
ubuntu@my-server:~$ cat result.txt
89+
Files testFile1 and testFile2 are identical
90+
ubuntu@my-server:~$
91+
```
92+
93+
### Configure SSH connection for public key authentication
94+
Now that we can copy files to ESP32, it is easy to configure public key authentication. We need first to generate the keys, add the public key to authorized_keys and copy the key files to ESP32
95+
#### In Linux server
96+
Generate key pair using ssh-keygen without a passphrase. Just press enter when it asks to enter a passphrase.
97+
```
98+
ubuntu@my-server:~$ ssh-keygen -f key1
99+
Generating public/private rsa key pair.
100+
Enter passphrase (empty for no passphrase):
101+
Enter same passphrase again:
102+
Your identification has been saved in key1
103+
Your public key has been saved in key1.pub
104+
The key fingerprint is:
105+
SHA256:g21tszp4PlPBZp9ToOxgyWOog+HbahI8d5ABj7FbaAE ubuntu@my-server
106+
The key's randomart image is:
107+
+---[RSA 3072]----+
108+
|E+. |
109+
| B. . |
110+
| = oo o + . . |
111+
|. +o .oB.B . |
112+
|.o o...oS*+o o |
113+
|.oo.o. . ooo+ |
114+
| .oo.. . .. . |
115+
|. o . . =. |
116+
| o.. oo+ |
117+
+----[SHA256]-----+
118+
ubuntu@my-server:~$
119+
```
120+
And another key pair with a passphrase. Set passphrase to MyPassPhrase.
121+
```
122+
ubuntu@my-server:~$ ssh-keygen -f key2
123+
Generating public/private rsa key pair.
124+
Enter passphrase (empty for no passphrase):
125+
Enter same passphrase again:
126+
Your identification has been saved in key2
127+
Your public key has been saved in key2.pub
128+
The key fingerprint is:
129+
SHA256:GL7UTforSMOQ2N1mSHmcdCM7NBPPnoc7jpsgvKPNVG4 ubuntu@my-server
130+
The key's randomart image is:
131+
+---[RSA 3072]----+
132+
| +Boo |
133+
| o.+O . |
134+
| o +.+o + |
135+
| . +.o++* o |
136+
| o=oS = . |
137+
| . ++. . o |
138+
| +.Eo + |
139+
| +.+...+ o |
140+
| ..+. +oo |
141+
+----[SHA256]-----+
142+
```
143+
Now add the two public keys to .ssh/authorized_keys file
144+
```
145+
cat key1.pub >> ~/.ssh/authorized_keys
146+
cat key2.pub >> ~/.ssh/authorized_keys
147+
chmod 600 ~/.ssh/authorized_keys
148+
```
149+
#### In main.cpp file
150+
Uncomment these lines to copy the key files to ESP32
151+
```
152+
ssh.scpGetFile("key1", "/spiffs/key1");
153+
ssh.scpGetFile("key1.pub", "/spiffs/key1.pub");
154+
ssh.scpGetFile("key2", "/spiffs/key2");
155+
ssh.scpGetFile("key2.pub", "/spiffs/key2.pub");
156+
```
157+
Upload the program to ESP32 and run it.
158+
159+
#### In Linux server
160+
Now the key files are copied to ESP32, and we can remove the password from the ubuntu user and disable password authentication.
161+
162+
Remove password from user ubuntu
163+
164+
```sudo passwd -d ubuntu```
165+
166+
Disable ssh password authentication
167+
168+
```sudo nano /etc/ssh/sshd_config```
169+
170+
Change this line from
171+
172+
```PasswordAuthentication yes```
173+
174+
to
175+
176+
```PasswordAuthentication no```
177+
178+
Restart sshd process
179+
180+
```sudo systemctl restart sshd```
181+
182+
Remove files testFile1, testFile2 and result.txt
183+
184+
```rm ~/testFile1 ~/testFile2 ~/result.txt```
185+
186+
### Test public key authentication, no passphrase
187+
#### In main.cpp file
188+
Comment password authentication line and uncomment and edit public key authentication without passphrase line.
189+
```
190+
// ssh.connectWithPassword("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com", "ubuntu","System#1");
191+
ssh.connectWithKey("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com", "ubuntu","/spiffs/key1.pub","/spiffs/key1");
192+
```
193+
Upload the program to ESP32 and run it. Check again on the Linux server that testFile1, testFile2 and result.txt are back with the correct content. Remove testFile1, testFile2 and result.txt again.
194+
### Test public key authentication with a passphrase
195+
#### In main.cpp file
196+
Comment public key authentication without passphrase line and uncomment public key authentication with passphrase line
197+
```
198+
// ssh.connectWithKey("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com", "ubuntu","/spiffs/key1.pub","/spiffs/key1");
199+
ssh.connectWithKey("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com", "ubuntu","/spiffs/key2.pub","/spiffs/key2","MyPassPhrase");
200+
```
201+
Upload the program to ESP32 and run it. Check again on the Linux server that testFile1, testFile2 and result.txt are back with the correct content.
202+
## Troubleshooting
203+
SPIFFS and LittleFS may not be formatted when you try the first time. You can see this error `E (3332) SPIFFS: mount failed`. Just press the ESP32 board reset button or re-upload to try again.
204+
205+
It can be helpful to download files from ESP32 back to the computer using Visual Studio Code and platformIO. It is possible using this [file system downloader plugin].
206+
207+
208+
[LibSSH-ESP32]: <https://github.com/ewpa/LibSSH-ESP32>
209+
[file system downloader plugin]: <https://github.com/maxgerhardt/pio-esp32-esp8266-filesystem-downloader>
210+
211+

platformio.ini

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; PlatformIO Project Configuration File
2+
;
3+
; Build options: build flags, source filter
4+
; Upload options: custom upload port, speed and extra flags
5+
; Library options: dependencies, extra library storages
6+
; Advanced options: extra scripting
7+
;
8+
; Please visit documentation for the other options and examples
9+
; https://docs.platformio.org/page/projectconf.html
10+
11+
[env:esp32dev]
12+
platform = espressif32
13+
board = esp32dev
14+
framework = arduino
15+
monitor_speed = 115200
16+
lib_deps = ewpa/LibSSH-ESP32@^3.0.1

src/main.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include <WiFi.h>
2+
#include "ssh.hpp"
3+
4+
const unsigned int configSTACK = 40960;
5+
TaskHandle_t sshHandle = NULL;
6+
7+
void sshTask(void* pvParameter) {
8+
SSH ssh{};
9+
10+
// Pick one of the ssh authentication methods to connect
11+
Serial.println("SSH Connecting to server...");
12+
13+
// With password (in server side create password for the user and allow
14+
// password authentication in /etc/ssh/sshd_config)
15+
ssh.connectWithPassword("ec2-111-112-113-114.ap-southeast-1.compute.amazonaws.com", "ubuntu","System#1");
16+
17+
// With public key
18+
// ssh.connectWithKey("101.102.103.104", "ubuntu","/spiffs/key1.pub","/spiffs/key1");
19+
// With public key, encrypted private key
20+
// ssh.connectWithKey("192.168.1.200", "hpirila","/spiffs/key2.pub","/spiffs/key2","MyPassPhrase");
21+
22+
if (ssh.isConnected) {
23+
Serial.println("SSH is connected!\n");
24+
25+
Serial.println("Lets create a test file in server");
26+
ssh.sendCommand("echo \"This is a test file for ESP32 Arduino SSH wrapper class\" > testFile1");
27+
28+
Serial.println("Copying testFile1 from server to ESP32 spiffs file system");
29+
ssh.scpGetFile("testFile1", "/spiffs/testFile1");
30+
31+
Serial.println("Copying testFile1 from ESP32 back to server with new name testFile2");
32+
ssh.scpPutFile("/spiffs/testFile1", "testFile2");
33+
34+
Serial.println("Compare testFile1 and testFile2 and print the result to result.txt\n");
35+
Serial.println("Login to server and cat result.txt");
36+
Serial.println("It should say testFile1 and testFile2 are identical.\n");
37+
ssh.sendCommand("diff -s testFile1 testFile2 > result.txt");
38+
39+
// ssh.scpGetFile("key1", "/spiffs/key1");
40+
// ssh.scpGetFile("key1.pub", "/spiffs/key1.pub");
41+
// ssh.scpGetFile("key2", "/spiffs/key2");
42+
// ssh.scpGetFile("key2.pub", "/spiffs/key2.pub");
43+
44+
} else {
45+
Serial.println("SSH connection failed.");
46+
}
47+
48+
Serial.println("Close ssh connection");
49+
ssh.end();
50+
Serial.println("Kill ssh task");
51+
vTaskDelete(NULL);
52+
}
53+
54+
void setup(void) {
55+
Serial.begin(115200);
56+
57+
WiFi.begin("ssid", "Wifi_password");
58+
59+
Serial.println("Connecting to WiFi...");
60+
while (WiFi.status() != WL_CONNECTED) {
61+
Serial.print(".");
62+
delay(100);
63+
}
64+
Serial.println("\nConnected to the WiFi network");
65+
Serial.print("Local ESP32 IP: ");
66+
Serial.println(WiFi.localIP());
67+
68+
xTaskCreatePinnedToCore(sshTask, "ctl", configSTACK, NULL,
69+
(tskIDLE_PRIORITY + 3), &sshHandle,
70+
portNUM_PROCESSORS - 1);
71+
}
72+
73+
void loop(void) {
74+
delay(1);
75+
}

0 commit comments

Comments
 (0)