Ler dados de Cartão de Cidadão – C#

Data de última actualização: 18-07-2018

Requisitos:

  • Leitor de Smart Cards
  • Windows com .NET 4.5 ou superior instalado
  • Middleware do cartão de cidadão instalado (link para v1.62, 2.4.11 e 3.0.13 em baixo)
  • Visual Studio 2015 ou superior

Fiz um projecto C# com a leitura completa dos dados do cartão de cidadão, incluindo morada (pede password), imagem, nome, data de nascimento, etc.

A solução tem 2 projectos principais: CCReader e CCReaderTests. O CCReader é o que gera a dll que pode ser utilizada noutros projectos que queiram, sendo o CCReaderTests a implementação de testes unitários.

Utiliza a dll mais recente do cartão de cidadão à data da actualização.

Um exemplo de utilização da dll, é a minha solução para ler os dados a partir do browser.

GitHub

Download das dlls

OneDrive

NOTAS:

  • Para ler as fotografias utilizei uma lib externa CSJ2K.dll, pois as imagens estão no cartão em formato JPEG2000.

Tenho também uma pequena biblioteca para assinar dados a partir do cartão de cidadão:

Assinar dados digitalmente a partir de certificados do cartão de cidadão

49 responses to “Ler dados de Cartão de Cidadão – C#

  1. Rafael Maria 2 de Maio de 2017 às 11:59

    Excelente! Ajudou-me imenso, obrigado.

  2. jpaquete 8 de Julho de 2017 às 21:21

    Funcionou muito bem. Muito Obrigado !
    Só precisei de alterar a função do encoding para o seguinte, porque os caracteres acentuados estavam a aparecer marados:

    private string Convert2UTF8(string input)
    {
    return Encoding.UTF8.GetString((Encoding.Default).GetBytes(input));
    }

    • ruimpt 9 de Julho de 2017 às 9:27

      Obrigado pelo feedback. Vou deixar essa nota para alguém que tenha esse problema no futuro.

    • Sergio 28 de Fevereiro de 2018 às 19:12

      Boa Tarde, não estou a conseguir compilar / executar o exemplo, estou a utilizar Visual studio 2017 express, o sistema dá o seguinte erro:
      Debug:
      “LeitorCC.exe” (CLR v4.0.30319: DefaultDomain): Carregado “C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll”. Carregamento de símbolos ignorado. O módulo está otimizado e a opção do depurador ‘Apenas Meu Código’ está habilitada.
      “LeitorCC.exe” (CLR v4.0.30319: DefaultDomain): Carregado “C:\LIXO\LeitorCC\bin\Debug\LeitorCC.exe”. Símbolos carregados.
      Ocorreu uma exceção sem tratamento do tipo “System.IO.FileNotFoundException” em Módulo Desconhecido.
      Não foi possível carregar o ficheiro ou assemblagem ‘pteidlib_dotnet.dll’ ou uma das respectivas dependências. Impossível localizar o módulo especificado.

      Alguém tem uma ideia como resolver isto, qualquer ajuda agradecia. Obrigado

  3. Macedo 27 de Julho de 2017 às 9:54

    ruimpt há alguma forma de extrair os dados do CC sem ser necessária a instalação do middleware?

    • ruimpt 27 de Julho de 2017 às 10:05

      Olá Macedo,
      tens sempre de ter um middleware para aceder aos dados do cartão (neste caso ao SmartCard). Creio que podes desenvolver o teu próprio middleware, mas uma vez que o do cartão de cidadão é grátis e até não funciona mal, não vejo razão para reinventares a roda 🙂

      • Macedo 27 de Julho de 2017 às 11:34

        No meu caso, o objetivo é apenas ler os dados do CC para serem carregados/guardados numa aplicação externa e neste caso a ideia era não ter de fazer uso do middleware.

      • Macedo 27 de Julho de 2017 às 11:43

        Quando desinstalo o middleware o erro que me dá é:
        System.IO.FileNotFoundException: ‘Não foi possível carregar o ficheiro ou assemblagem ‘pteidlib_dotnet.dll’ ou uma das respectivas dependências. Impossível localizar o módulo especificado.’
        Há forma de contornar esta situação? (creio solucionando este problema já seria possivel utilizar o leitor sem necessidade de utilizar o middleware).

      • ruimpt 27 de Julho de 2017 às 14:33

        Podes tentar copiar a dll pteidlib_dotnet.dll para um local à tua escolha e adicionar a dependência ao projecto

      • Macedo 28 de Julho de 2017 às 9:48

        ruimpt sabes onde posso encontrar o código fonte do middleware?

  4. ngc 1 de Agosto de 2017 às 9:13

    Ajudou imenso. Obrigado.
    Tenho apenas um problema com a imagem. No código “var bmap = j2kImg.As();” gera uma exceção:
    Message “Cannot cast to ‘Bitmap’; type must be assignable from ‘ImageSource'”

    Alguém me pode ajudar?

  5. João Cruz 8 de Janeiro de 2018 às 9:58

    Bom dia Rui, estou a ter dificuldades em conseguir a morada, mais precisamente o nome da rua… obtenho nº da porta e andar, mas morada não…

    Penso estar a usar a última versão (2.4.0.5284):
    PteidAddr dadosMorada = Pteid.GetAddr();

    Consegues ajudar-me?

    Obrigado

    • ruimpt 8 de Janeiro de 2018 às 14:06

      Boas João, a aplicação do cartão de cidadão foi actualizada para a versão que tens instalada, o problema deve estar relacionado com isso. Para o meu exemplo funcionar correctamente tens de ter instalada a versão 1.6 do middleware (que está no link no meu post). Quando actualizar a minha app actualizo o post.

  6. Gabriel 16 de Março de 2018 às 12:31

    Tambem esta resolvido o anterior.

    tenho este agora 😦

    System.IO.FileLoadException
    HResult=0x80131040
    Message=Não foi possível carregar o ficheiro ou assemblagem ‘CSJ2K, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0ca7be2ec378a773’ ou uma das respectivas dependências. A definição do manifesto de assemblagem localizada não corresponde à referência de assemblagem. (Excepção de HRESULT: 0x80131040)
    Source=LeitorCC
    StackTrace:
    at LeitorCC.CartaoCidadaoAPI.Read() in D:\visualStudioProjects\LeitorCC\CartaoCidadaoAPI.cs:line 103
    at LeitorCC.Program.Main(String[] args) in D:\visualStudioProjects\LeitorCC\Program.cs:line 18

    • ruimpt 16 de Março de 2018 às 12:37

      Oi Gabriel, esse erro está relacionado com o carregamento da dll CSJ2K, mudaste as dlls de sitio? Alteraste as configurações do projecto? Os ficheiros que disponibilizo em conjunto com o middleware instalado deveriam correr sem problemas.

      E por favor tenta não “spammar” os comentários 🙂 Não é que não queira ajudar, mas para as pessoas que vêm aqui, ver as tuas stacktraces a cada run que fazes não ajuda em nada.

      Abraço

  7. Gabriel 16 de Março de 2018 às 12:53

    BitmapImageCreator nao existe no conceito atual.

    ou seja BitmapImageCreator.Register(); posso trocar por ??

  8. Gabriel 16 de Março de 2018 às 14:49

    ok problema resolvido

  9. Joao 20 de Março de 2018 às 17:44

    Boa tarde Rui, obrigado pelo tua aplicação. Estou com um pequeno problema. estou a usar um parametro de entrada para escrever ou não a estrutura Address: if (args[0] == “1”)
    if (args[0] == “1”)
    {
    var ccMoradaFilePath = @”C:\Temp\Morada.txt”;
    using (System.IO.StreamWriter file =
    new System.IO.StreamWriter(ccMoradaFilePath, true))
    {
    file.WriteLine(string.Format(“[addressF={0}”, citizen.Address.AddressF + “]”));
    …}
    contudo a minha dificuldade está em vedar na classe CartaoCidaddaoAPI.cs, no public Citizen Read(), o aparecimento do form para a introdução do código de desbloqueio
    ReadAddress(citizen); // will request address password
    Poderias dar uma dica.
    Obrigado.

  10. O Gago 29 de Março de 2018 às 11:04

    Bom dia,

    É possível invocar a assinatura digital?
    Pode-me dar um exemplo?

    Obrigado.

  11. henriquejgclaudio 15 de Maio de 2018 às 12:58

    Boa tarde,
    Já tenho a leitura a funcionar correctamente numa web app mas a correr localmente.
    Ao colocar no servidor não encontra o cartão.
    Pelos vistos é necessário fazer um pedido SAML.

    Alguém pode ajudar?

    • ruimpt 15 de Maio de 2018 às 14:08

      Olá Henrique,
      a app nunca vai funcionar dessa forma, como a leitura é feita no cliente, o middleware e o seu software tem obrigatoriamente de estar instalado no cliente.
      Implementei um sistema idêntico ao seu, que passou por desenvolver um plugin chrome que por sua vez chama a minha aplicação (que usa esta minha classe de leitura de dados) e devolve os dados para o plugin.
      Não tem de ser obrigatoriamente assim, mas a execução da leitura dos dados tem obrigatoriamente de ser feita no cliente, não vai funcionar da forma que mencionou.

  12. rcrd 13 de Julho de 2018 às 15:43

    Boas,
    Obrigado pela partilha. Consegui por tudo a funcionar. Agora tenho tal problema de ter de obter os dados de uma aplicação web…
    É pedir muito que partilhes os passos para a criação do plugin do chrome que permita a ligação entre as aplicações.

    Thks

  13. Pingback: Ler dados de cartão de cidadão a partir do chrome | GeekZone

  14. Fernando Fonseca 20 de Julho de 2018 às 11:16

    Perfeito Rui.
    Fácil de usar, testar, implementar…. Agora com esta base é só dar continuidade ao resto.
    Uma pequena ajuda. Em geral, praticamente os códigos de acesso à morada estão como default(000).

    Tens como enviar o código 000 como default para o Pteid?

    Abraço e parabéns pelo excelente esforço e pela excelente solução desenvolvida.

    TOP

    • ruimpt 20 de Julho de 2018 às 11:31

      Olá Fernando e muito obrigado pelo feedback 😉
      Quanto ao enviar os dados automaticamente, creio não ser possível. Também tive o mesmo dilema para o código de assinatura digital, mas não encontrei forma pois o pedido de PIN é lançado pelo próprio windows, não é algo controlável no nosso código. Perdi algumas horas a investigar e não consegui, mas se alguém souber como enviar os códigos automaticamente, que partilhe que também me dava jeito 🙂

      Abraço

      • Fernando Fonseca 20 de Julho de 2018 às 16:36

        De nada,
        Há que reconhecer o trabalho uns dos outros.

        Cá vai o meu contributo.
        De uma forma simplificada, agora o código 0000 é colocado de forma automática aquando solicitado. Pode/deve depois ser trabalhado em caso de erro para se questionar se deseja colocar uma novo codigo tendo em conta que o 0000 pode ter sido alterado. (só para não bloquear o acesso ao dono do cartão)
        No entanto, deixo a base, e cada um pode alterar no futuro ao seu gosto essa opção.
        Contudo, se alguém desenvolver uma boa class para essa lógica, seria agradável recebe-la.

        Só precisam adicionar estas duas classes depois da class “class CartaoCidadaoAPI”
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        class BackgroundTask
        {
        public void RunLoop()
        {
        MyProcess myProcesss = new MyProcess();
        bool running = myProcesss.IsRunning(“pteiddlgsrv”);
        while (running != true)
        {
        running = myProcesss.IsRunning(“pteiddlgsrv”);
        }
        Thread.Sleep(250);
        bool envia_codigo = myProcesss.EnviaCodMorada(“pteiddlgsrv”);
        }
        }

        class MyProcess
        {
        [DllImport(“User32.dll”)]
        static extern int SetForegroundWindow(IntPtr point);

        //verifica se processo está ativo
        public bool IsRunning(string name) => Process.GetProcessesByName(name).Length > 0;
        //envia texto para o processo em questão
        public bool EnviaCodMorada(string name) {
        var processes = Process.GetProcessesByName(“pteiddlgsrv”).FirstOrDefault();
        IntPtr h = processes.MainWindowHandle;
        SetForegroundWindow(h);
        SendKeys.SendWait(“0000”);
        SendKeys.SendWait(“{ENTER}”);
        return true;
        }
        }

        //////////////////////////////////////////////////////////////////////////////

        E adicionar este código na função: “ReadAddress”

        //inicia background para aguardar a janela de codigo de morada
        Console.WriteLine(“TRY Auto code 0000 for default address”);
        BackgroundTask longTask= new BackgroundTask();
        Thread backgroundThread =
        new Thread(new ThreadStart(longTask.RunLoop));
        backgroundThread.IsBackground = true;
        backgroundThread.Start();

        Creio ser tudo…..

        Dá feedback Rui.

        Abraço

      • ruimpt 20 de Julho de 2018 às 16:59

        Boas de novo, isto também dá para aplicar à assinatura digital? Reparei agora que o popup para a morada é diferente do da assinatura digital. Talvez o da morada seja mesmo da app do cartão de cidadão, mas o da assinatura digital é do windows, será que dá para aplicar?
        Ainda não testei (e não vou conseguir tão cedo pois vou hoje entrar em férias), mas parece-me uma muito boa solução! Como dizes, talvez seja boa ideia encapsular isso numa classe e talvez criar uma configuração para definir se deve ou não submeter automaticamente o código, e qual o código em si. Isto porque podem haver pessoas já com 2 tentativas falhadas e se vamos submeter automaticamente, bloquear.

        Mas de qualquer forma, muito bom e obrigado pela partilha! Quando voltar de férias, se não o fizeres entretanto, ver se pego nisso e integro na classe 😉

  15. Daniel 29 de Julho de 2018 às 1:08

    Boas, antes demais parabéns pelo trabalho. Eu já desenvolvi uma aplicação que lê os dados do cartão é envia para um webserver. A foto usei base64 e funcionou muito bem. O meu problema agora é na distribuição, pois o cliente tem que ter instalado a aplicação da autenticação.gov para funcionar. Existe alguma forma de instalar as 2 aplicação no mesmo exe. Ou outra forma de simplificar a vida ao utilizador? Sugestões? 😉

    • ruimpt 30 de Julho de 2018 às 16:32

      Creio haver forma de teres um instalador que instala, opcionalmente, um outro instalador, neste caso seria o do cartão de cidadão. Mas nunca o fiz e neste momento estou de férias, pelo que também não posso ajudar muito mais 🙂 Para gerar instaladores, uso o InstallShield, grátis, que tem várias opções que nunca explorei, se conseguires resolver o problema partilha aqui a solução, estou certo que muita gente poderá estar interessada 😉

  16. Décio Machado 18 de Março de 2019 às 17:02

    Boa tarde, fiz o donwload do CCReader, tenho fazer o debug e start e dá um erro ” A project with an Output type of Class Library cannot be started directly. ”
    O que poderá ser?

    • ruimpt 19 de Março de 2019 às 15:16

      tem de mudar o startup project. no visual studio está a tentar correr o CCReader que não é um executável. tem de criar um projecto executável (command line por exemplo) e usar o CCReader. Esse projecto é uma biblioteca, não é uma aplicação, daí não conseguir correr 😊

  17. Eduardo Brás 15 de Novembro de 2019 às 17:09

    Boa tarde. Fiz uma aplicação de leitura de dados do cartão de cidadão com recurso à versão 1.62.
    Se instalar a aplicação do cartão de cidadão mais recente 3.0.19 não consigo sequer conectar-me através do Pteid.Init(null); Já adicionei nas referências o novo dll do 3.0.19 mas dá me sempre o mesmo erro. {“O inicializador de tipo para ‘pt.portugal.eid.pteidlib_dotNetPINVOKE’ accionou uma excepção.”}. E nem estou a fazer o using do pt.portgugal.eid.pteidlib mas sim do eidpt na sua versão de compatibilidade. Alguma sugestão do que possa ser? Obrigado.

    • ruimpt 19 de Novembro de 2019 às 10:17

      Boas. Se bem estou a entender estás a usar a ultima versão da app do cartão de cidadão em conjunto com a minha app para a versão 3.0.13 do cartão de cidadão, é isso? Pode ser esse o problema… Não tenho tido muito tempo para manter isto, mas vou tentar disponibilizar uma nova versão.

      • Eduardo Brás 20 de Novembro de 2019 às 9:43

        Boas! Sim, estou a usar a última versão da app do CC mas não é com a tua app. É com uma feita por mim que teve como base a app do CC da versão 1.62. Tendo feito mais uns testes descobri que a minha aplicação funciona bem até à app do CC 3.0.13. Com a nova 3.0.19 é que não consigo com que funcione. Haverá algum problema com o dll da nova versão?

      • ruimpt 20 de Novembro de 2019 às 14:57

        Deve ter havido alguma alteração na dll que requer que alteres a tua app. Se bem entendi estás tu a fazer a inicialização e etc, pelo que terás de alterar de acordo com a nova dll (não sei quais as alterações). Se estás a usar a minha dll, vou tentar fazer os ajustes nos próximos dias.

  18. Joaqum Nunes 20 de Novembro de 2019 às 14:30

    Tenho exactamente o mesmo problema….

  19. O Gago 26 de Novembro de 2019 às 12:38

    E que de acordo com o Manual SDK versão 3.0 que é o último manual acessível nem o PTEID_ReaderSet.initSDK(); consigo com que funcione. Dá-me imediatamente erro… Só se desconheço a existência de um manual novo para a versão 3.0.19…

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão /  Alterar )

Google photo

Está a comentar usando a sua conta Google Terminar Sessão /  Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão /  Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão /  Alterar )

Connecting to %s

%d bloggers like this: