Microsoft MVP성태의 닷넷 이야기
닷넷: 2372. C# - ssh-ed25519 유형의 Public Key 파일 해석 [링크 복사], [링크+제목 복사],
조회: 1284
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일

(시리즈 글이 15개 있습니다.)
.NET Framework: 292. RSACryptoServiceProvider의 공개키와 개인키 구분
; https://www.sysnet.pe.kr/2/0/1218

.NET Framework: 327. RSAParameters와 System.Numerics.BigInteger 이야기
; https://www.sysnet.pe.kr/2/0/1295

.NET Framework: 329. C# - Rabin-Miller 소수 생성방법을 이용하여 RSACryptoServiceProvider의 개인키를 직접 채워보자
; https://www.sysnet.pe.kr/2/0/1300

.NET Framework: 356. (공개키를 담은) 자바의 key 파일을 닷넷의 RSACryptoServiceProvider에서 사용하는 방법
; https://www.sysnet.pe.kr/2/0/1401

.NET Framework: 383. RSAParameters의 ToXmlString과 ExportParameters의 결과 비교
; https://www.sysnet.pe.kr/2/0/1491

.NET Framework: 565. C# - Rabin-Miller 소수 생성 방법을 이용하여 RSACryptoServiceProvider의 개인키를 직접 채워보자 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/10925

.NET Framework: 566. openssl의 PKCS#1 PEM 개인키 파일을 .NET RSACryptoServiceProvider에서 사용하는 방법
; https://www.sysnet.pe.kr/2/0/10926

.NET Framework: 638. RSAParameters와 RSA
; https://www.sysnet.pe.kr/2/0/11140

.NET Framework: 1037. openssl의 PEM 개인키 파일을 .NET RSACryptoServiceProvider에서 사용하는 방법 (2)
; https://www.sysnet.pe.kr/2/0/12598

.NET Framework: 2093. C# - PKCS#8 PEM 파일을 이용한 RSA 개인키/공개키 설정 방법
; https://www.sysnet.pe.kr/2/0/13245

닷넷: 2297. C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성
; https://www.sysnet.pe.kr/2/0/13739

닷넷: 2297. C# - ssh-keygen으로 생성한 ecdsa 유형의 Public Key 파일 해석
; https://www.sysnet.pe.kr/2/0/13742

닷넷: 2300. C# - OpenSSH의 공개키 파일에 대한 "BEGIN OPENSSH PUBLIC KEY" / "END OPENSSH PUBLIC KEY" PEM 포맷
; https://www.sysnet.pe.kr/2/0/13747

닷넷: 2302. C# - ssh-keygen으로 생성한 Private Key와 Public Key 연동
; https://www.sysnet.pe.kr/2/0/13749

닷넷: 2372. C# - ssh-ed25519 유형의 Public Key 파일 해석
; https://www.sysnet.pe.kr/2/0/14029




C# - ssh-ed25519 유형의 Public Key 파일 해석

SSH 서버의 경우 /etc/ssh 경로에 ssh_host_*_key.pub와 같은 유형의 공개키 파일이 존재하고, 그중 하나가 (제약이 유독 심한) ssh_host_ed25519_key.pub 파일입니다.

# cat /etc/ssh/ssh_host_ed25519_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs root@6747bfaa58b8

# ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:x9Y3qATAqJjoaOUnV8eqj5SLZ9fnoqJd7Nz5VsT7Dbo root@6747bfaa58b8 (ED25519)

// -l: [-v] [-E fingerprint_hash] [-f input_keyfile]

그런데, pscp와 같은 프로그램에서는 SshHostKeyFingerprint의 유형을 MD5 형식의 포맷으로 지정해야 하는데요,

SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Sftp,
    HostName = "example.com",
    UserName = "user",
    Password = "mypassword",
    SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:..." // 이 값이 md5 형식
};

이것을 알아내는 방법은 여러 가지가 있겠지만, 제 경우에는 그냥 아무 디렉터리나 pscp로 복사 시도를 해보는 것입니다.

c:\temp> pscp -P 23022 -v -r c:\temp\empty root@192.168.100.50:/home/root/test
Connecting to 192.168.100.50 port 23022
We claim version: SSH-2.0-PuTTY_Release_0.70
Server version: SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.7
Using SSH protocol version 2
Doing ECDH key exchange with curve Curve25519 and hash SHA-256
Server also has ecdsa-sha2-nistp256/ssh-rsa host keys, but we don't know any of them
Host key fingerprint is:
ssh-ed25519 256 b4:7f:29:5c:fd:e1:ea:f5:7d:6d:73:df:01:79:cf:2c
The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's ssh-ed25519 key fingerprint is:
ssh-ed25519 256 b4:7f:29:5c:fd:e1:ea:f5:7d:6d:73:df:01:79:cf:2c
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)

그럼, 실행 결과에 저렇게 md5 형식의 fingerprint 값이 출력되므로 그대로 사용하면 됩니다. 또 다른 방법으론 ssh-keygen 명령어를 사용할 수 있습니다.

get SSH key fingerprint in (old) hex format on new version of openssh
; https://superuser.com/questions/1088165/get-ssh-key-fingerprint-in-old-hex-format-on-new-version-of-openssh

// ssh 서버가 설치된 서버에서, 또는 public key 파일만 구할 수 있다면!

# ssh-keygen -l -E md5 -f /etc/ssh/ssh_host_ed25519_key.pub
256 MD5:b4:7f:29:5c:fd:e1:ea:f5:7d:6d:73:df:01:79:cf:2c root@6747bfaa58b8 (ED25519)

그나저나, 이걸 코드로도 알아낼 수 있겠죠? ^^ 방법은 매우 간단한데요, 저 md5 해시값은 단순히 ssh_host_ed25519_key.pub의 키 정보를 나타내는 텍스트로부터 구한 것입니다. 즉, "AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs" 문자열을 base64 디코딩한 후, 그걸 그대로 MD5 해시로 변환하면 됩니다.

// ssh_host_ed25519_key.pub 파일의 내용 중 공개키 정보 문자열
string text = "AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs";

// base64 decode
byte[] data = Convert.FromBase64String(text);

byte[] buffer = MD5.Create().ComputeHash(data);
Console.WriteLine(BitConverter.ToString(buffer).Replace("-", ":"));

/* 출력 결과
B4:7F:29:5C:FD:E1:EA:F5:7D:6D:73:DF:01:79:CF:2C
*/




마침 지난 경험도 있고 하니,

C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성
; https://www.sysnet.pe.kr/2/0/13739

기왕 하는 김에 ssh_host_ed25519_key.pub 파일의 내용도 해석해 보겠습니다. 결국 이것도 ANS.1 인코딩 방식일 거라는 추측을 할 수 있는데요,

# cat /etc/ssh/ssh_host_ed25519_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs root@6747bfaa58b8

  [The key type]  [A chunk of PEM-encoded data] [A comment]
예)ssh-ed25519     AAA...[생략]...onHbYs         root@6747bfaa58b8

// ssh-rsa 형식인 경우의 해석은 "https://www.sysnet.pe.kr/2/0/13739#rfc4253" 참조.

따라서 "AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs" 문자열을, 즉 "[A chunk of PEM-encoded data]" 영역을 base64 디코딩하면 다음과 같은 정보를 담은 바이트 배열이 나옵니다.

[4바이트 길이(big endian)] [algorithm name, ("ssh-ed25519")]
[4바이트 길이(big endian)] [public key (ASN.1)] 

코딩으로 구현하면 이렇고!

string text = "AAAAC3NzaC1lZDI1NTE5AAAAIF18y7iEZwsx99NueMWE+tTVdhaDLfudFYU4fonJHbYs";

byte[] data = Convert.FromBase64String(text);

(string algorithmName, byte[] publicKey) = DecodeSSHED25519PublicKey(data);

private static (string algorithmName, byte[] publicKey) DecodeSSHED25519PublicKey(byte[] bytesEncoded)
{
    string algorithmName;
    byte[] publicKey;

    using (var stream = new MemoryStream(bytesEncoded))
    using (var reader = new BinaryReader(stream))
    {
        int algorithmLength = reader.ReadInt32BE();
        algorithmName = Encoding.ASCII.GetString(reader.ReadBytes(algorithmLength));

        int publicKeyLength = reader.ReadInt32BE();
        publicKey = reader.ReadBytes(publicKeyLength);
    }

    return (algorithmName, publicKey);
}

사실 저 코드를 직접 만들 필요는 없는데요, 이미 예전 글에서 SSH.NET 라이브러리에서 제공하는 PublicKeyFile 클래스로 다룬 적이 있었습니다.

C# - ssh-keygen으로 생성한 Private Key와 Public Key 연동
; https://www.sysnet.pe.kr/2/0/13749#enc_dec_src

저 예제 코드의 "PublicKeyFile.DecodeEdDSA" 메서드가 했던 작업이 바로 위에서 살펴본 DecodeSSHED25519PublicKey 메서드입니다. 따라서 (이젠 DecodeEdDSA 메서드 대신) 다음과 같이 우리가 구한 공개키로 Ed25519Signer를 초기화할 수 있습니다.

(string algorithmName, byte[] publicKey) = DecodeSSHED25519PublicKey(data);
Console.WriteLine(algorithmName); // 출력 결과: "ssh-ed25519"

Ed25519PublicKeyParameters publicKeyParam = new Ed25519PublicKeyParameters(publicKey);

Ed25519Signer signer = new Ed25519Signer();
signer.Init(false, publicKeyParam);
// ... 개인키로 서명한 데이터 검증...
/*
signer.BlockUpdate(plainTextBuffer);
bool verified = signer.VerifySignature(signedBuffer);
*/

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 10/17/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 151  152  153  [154]  155  156  157  158  159  160  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1309정성태7/13/201235661개발 환경 구성: 155. 윈도우 운영체제에서 기본적으로 사용할 수 있는 압축 해제 방법
1308정성태7/3/201231442.NET Framework: 330. IEnumerator는 언제나 읽기 전용일까?파일 다운로드1
1307정성태6/30/201234308개발 환경 구성: 154. Sysnet, Azure를 만나다. [5]
1306정성태6/29/201234023제니퍼 .NET: 22. 눈으로 확인하는 connectionManagement의 maxconnection 설정값 [4]
1305정성태6/28/201232549오류 유형: 157. IIS 6 - WCF svc 호출 시 404 Not Found 발생
1304정성태6/27/201233625개발 환경 구성: 153. sysnet 첨부 파일을 Azure Storage에 마이그레이션 [3]파일 다운로드1
1303정성태6/26/201233066개발 환경 구성: 152. sysnet DB를 SQL Azure 데이터베이스로 마이그레이션
1302정성태6/25/201235075개발 환경 구성: 151. Azure 웹 사이트에 사용자 도메인 네임 연결하는 방법
1301정성태6/20/201230822오류 유형: 156. KB2667402 윈도우 업데이트 실패 및 마이크로소프트 Answers 웹 사이트 대응
1300정성태6/20/201239021.NET Framework: 329. C# - Rabin-Miller 소수 생성방법을 이용하여 RSACryptoServiceProvider의 개인키를 직접 채워보자 [1]파일 다운로드2
1299정성태6/18/201240154제니퍼 .NET: 21. 제니퍼 닷넷 - Ninject DI 프레임워크의 성능 분석 [2]파일 다운로드2
1298정성태6/14/201239632VS.NET IDE: 72. Visual Studio에서 pfx 파일로 서명한 경우, 암호는 어디에 저장될까? [2]
1297정성태6/12/201236223VC++: 63. 다른 프로세스에 환경 변수 설정하는 방법파일 다운로드1
1296정성태6/5/201232968.NET Framework: 328. 해당 DLL이 Managed인지 / Unmanaged인지 확인하는 방법 - 두 번째 이야기 [4]파일 다운로드1
1295정성태6/5/201229855.NET Framework: 327. RSAParameters와 System.Numerics.BigInteger 이야기파일 다운로드1
1294정성태5/27/201255653.NET Framework: 326. 유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리 [7]파일 다운로드2
1293정성태5/24/201234734.NET Framework: 325. System.Drawing.Bitmap 데이터를 Parallel.For로 처리하는 방법 [2]파일 다운로드1
1292정성태5/24/201227893.NET Framework: 324. First-chance exception에 대해 조건에 따라 디버거가 멈추게 할 수는 없을까? [1]파일 다운로드1
1291정성태5/23/201235588VC++: 62. 배열 초기화를 위한 기계어 코드 확인 [2]
1290정성태5/18/201240154.NET Framework: 323. 관리자 권한이 필요한 작업을 COM+에 대행 [7]파일 다운로드1
1289정성태5/17/201245204.NET Framework: 322. regsvcs.exe로 어셈블리 등록 시 시스템 변경 사항 [5]파일 다운로드2
1288정성태5/17/201231119.NET Framework: 321. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (3) - Type Library파일 다운로드1
1287정성태5/17/201234277.NET Framework: 320. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (2) - .NET 4.0 + .NET 2.0 [2]
1286정성태5/17/201243113.NET Framework: 319. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (1) - .NET 2.0 + x86/x64/AnyCPU [5]
1285정성태5/16/201238485.NET Framework: 318. gacutil.exe로 어셈블리 등록 시 시스템 변경 사항파일 다운로드1
1284정성태5/15/201230580오류 유형: 155. Windows Phone 연결 상태에서 DRIVER POWER STATE FAILURE 블루 스크린 뜨는 현상
... 151  152  153  [154]  155  156  157  158  159  160  161  162  163  164  165  ...